I have JSrollPane with a JPanel as the ViewPort component. On this JPanel I use paintComponent to draw a grid, of 64x64px squares. The JPanel is quite large, 28'672px by 14'336px, still the grid is drawn instantly and all seems fine. The problem is that scrolling vertically or horizontally causes the CPU usage to jump up quite high, the faster I scroll the higher it goes. The CPU usage gets up to between 35-50% while scrolling. Scrolling the same sized JPanel without the grid drawn on it, uses very little CPU, so the grid is certainly the cause of the problem. This grid is the most basic part of what I am planning to do inside the scrollpane, if it performs bad now, I fear it will be unusable after more "content" is added.
My question(s) Why does it use so much CPU to scroll over this grid, is the grid getting repainted every time there is a change in the scrollbar's position? Is there a better or more efficient way to draw a scrollable grid?
I had an idea of only drawing the grid of the visible area(by coord), and then redrawing that visible area when the scrollbars are moved, but this would be calling repaint alot. If possible, I'd like to draw the entire grid at startup, and then only repaint on command.
Here is a barebones working example of my JPanel grid.
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);
}
}
}
}
EDIT: The updated/fixed version of this code is below, in my answer to the question.