gpt4 book ai didi

java - 画有网格的 JPanel,滚动时导致 CPU 使用率高

转载 作者:搜寻专家 更新时间:2023-10-31 20:04:00 25 4
gpt4 key购买 nike

我有 JSrollPane 和 JPanel 作为 ViewPort 组件。在这个 JPanel 上,我使用 paintComponent 绘制一个 64x64px 正方形的网格。 JPanel 相当大,28'672px x 14'336px,仍然立即绘制网格并且一切看起来都很好。问题是垂直或水平滚动会导致 CPU 使用率跳得很高,我滚动得越快它就越高。滚动时 CPU 使用率高达 35-50%。在不绘制网格的情况下滚动相同大小的 JPanel,使用的 CPU 非常少,因此网格肯定是问题的原因。这个网格是我计划在滚动 Pane 中做的最基本的部分,如果它现在表现不好,我担心添加更多“内容”后它会无法使用。

我的问题 为什么在这个网格上滚动会占用这么多 CPU,每次滚动条的位置发生变化时网格都会重新绘制吗?有没有更好或更有效的方法来绘制可滚动的网格?

我的想法是只绘制可见区域的网格(通过坐标),然后在滚动条移动时重新绘制该可见区域,但这会调用重绘。如果可能的话,我想在启动时绘制整个网格,然后只根据命令重新绘制。

这是我的 JPanel 网格的准系统工作示例。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;

public class GridTest extends JFrame
{
static JScrollPane scrollPane;
static JPanel contentPane,gridPane;

public static void main(String[] args) {
GridTest frame = new GridTest();
frame.setVisible(true);
}

public GridTest(){
setTitle("Grid Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setBounds(300, 100, 531, 483);

contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);

scrollPane = new JScrollPane();
scrollPane.setBounds(0, 0, 526, 452);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
contentPane.add(scrollPane);
gridPane = new JPanel() {
public void paintComponent( Graphics g ){
super.paintComponent(g);
drawGrid(g);
g.dispose();
}};
Dimension gridPaneSize = new Dimension(28672,14336);
//Dimension gridPaneSize = new Dimension(4096,4096);
gridPane.setBackground(Color.BLACK);
gridPane.setPreferredSize(gridPaneSize);
scrollPane.setViewportView(gridPane);
}
public static void drawGrid(Graphics g)
{
int width = gridPane.getWidth();
int height = gridPane.getHeight();

g.setColor(Color.gray);
// draw horizontal long lines
for(int h = 0; h < height; h+=64){
g.drawLine(0, h, width, h);
}
// draw even grid vert lines
for(int w = 0; w < width; w+=64){
for(int h = 0; h < height; h+=128){
g.drawLine(w, h, w, h+64);
}
}
// draw odd grid vert lines
for(int w = 32; w < width; w+=64){
for(int h = 64; h < height; h+=128){
g.drawLine(w, h, w, h+64);
}
}
}
}

编辑:此代码的更新/修复版本在下面,在我对问题的回答中。

最佳答案

例如

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.*;

public class TilePainter extends JPanel implements Scrollable {

private static final long serialVersionUID = 1L;

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
JFrame frame = new JFrame("Tiles");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(new TilePainter()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private final int TILE_SIZE = 50;
private final int TILE_COUNT = 100;
private final int visibleTiles = 10;
private final boolean[][] loaded;
private final boolean[][] loading;
private final Random random;

public TilePainter() {
setPreferredSize(new Dimension(TILE_SIZE * TILE_COUNT, TILE_SIZE * TILE_COUNT));
loaded = new boolean[TILE_COUNT][TILE_COUNT];
loading = new boolean[TILE_COUNT][TILE_COUNT];
random = new Random();
}

public boolean getTile(final int x, final int y) {
boolean canPaint = loaded[x][y];
if (!canPaint && !loading[x][y]) {
loading[x][y] = true;
Timer timer = new Timer(random.nextInt(500),
new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
loaded[x][y] = true;
repaint(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
});
timer.setRepeats(false);
timer.start();
}
return canPaint;
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle clip = g.getClipBounds();
int startX = clip.x - (clip.x % TILE_SIZE);
int startY = clip.y - (clip.y % TILE_SIZE);
for (int x = startX; x < clip.x + clip.width; x += TILE_SIZE) {
for (int y = startY; y < clip.y + clip.height; y += TILE_SIZE) {
if (getTile(x / TILE_SIZE, y / TILE_SIZE)) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.RED);
}
g.fillRect(x, y, TILE_SIZE - 1, TILE_SIZE - 1);
}
}
}

@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(visibleTiles * TILE_SIZE, visibleTiles * TILE_SIZE);
}

@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return TILE_SIZE * Math.max(1, visibleTiles - 1);
}

@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}

@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}

@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return TILE_SIZE;
}
}

编辑

关于 Rectagle.intersects(Rectagle) 的很好的例子(HFOE here) Encephalopathic 来自 old.sun.forum57

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class IsRectVisible {

private static void createAndShowUI() {
JFrame frame = new JFrame("IsRectVisible");
frame.getContentPane().add(new IsRectVisibleGui());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowUI();
}
});
}
}

class IsRectVisibleGui extends JPanel {

public static final Rectangle RECT = new Rectangle(250, 200, 100, 100);
public static final Dimension INNER_PANEL_SIZE = new Dimension(600, 800);
private static final Dimension SCROLLPANE_SIZE = new Dimension(250, 300);
private static final String NOT_VISIBLE = "Not Visible";
private static final String VISIBLE = "Visible";
private static final long serialVersionUID = 1L;
private InnerPanel innerPanel = new InnerPanel();
private JViewport viewport = new JViewport();
private JLabel statusLabel = new JLabel(NOT_VISIBLE);

IsRectVisibleGui() {
JScrollPane scrollpane = new JScrollPane();
scrollpane.setViewport(viewport);
viewport.add(innerPanel);
scrollpane.setPreferredSize(SCROLLPANE_SIZE);
viewport.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
Rectangle viewRect = viewport.getViewRect();
if (viewRect.intersects(RECT)) {
statusLabel.setText(VISIBLE);
} else {
statusLabel.setText(NOT_VISIBLE);
}
}
});
setLayout(new BorderLayout());
add(scrollpane, BorderLayout.CENTER);
add(statusLabel, BorderLayout.SOUTH);
}

class InnerPanel extends JPanel {

private static final long serialVersionUID = 1L;

InnerPanel() {
setPreferredSize(INNER_PANEL_SIZE);
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(4));
g2.draw(RECT);
}
}
}

关于java - 画有网格的 JPanel,滚动时导致 CPU 使用率高,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15177367/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com