In my application I need to draw grid lines just like those like Photoshop has - e.g, an user can drag lines over the document to help him align layers. Now, the problem is that I am able to draw such lines (it's just plain simple Java2D painting using Line2D), but I am not being able to keep such lines on top of everything else, because when children components draw themselves, my grid line is erased.
The program structure is something like this: JFrame -> JPanel -> JScrollPane -> JPanel -> [many others JPanels, which are like layers]
As a test, I added the draw code to JFrame, which correctly shows my Line2D instance on top of everything else. However, when I do anything in an child component that requires that child to repaint itself, the line that was drawn in the JFrame is erased.
I understand that this is the expected Swing behavior - that is, it will only repaint those areas that have changed. However, I am looking for some approach that continuously draws line grid lines on top of everything else.
The only way I was able to get it working was to use a Swing Timer that calls repaint() on my root component every 10ms, but it consumes a lot of CPU.
UPDATE
Working code of an example is below. Please mind that in my real application I have dozens of different components that could trigger a repaint(), and none of them have a reference to the component that does the grid line drawing (of course I can pass it to everyone, but that appears to be the latest option)
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Line2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GridTest extends JFrame {
public static void main(String[] args) {
new GridTest().run();
}
private void run() {
setLayout(null);
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel p = new JPanel();
p.setBounds(20, 20, 100, 100);
p.setBackground(Color.white);
add(p);
JButton b = new JButton("Refresh");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// When I call repaint() here, the paint() method of
// JFrame it's not called, thus resulting in part of the
// red line to be erased / overridden.
// In my real application application, I don't have
// easy access to the component that draws the lines
p.repaint();
}
});
b.setBounds(0, 150, 100, 30);
add(b);
pack();
setVisible(true);
}
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D gg = (Graphics2D)g.create();
Line2D line = new Line2D.Double(0, 50, getWidth(), 50);
gg.setStroke(new BasicStroke(3));
gg.setColor(Color.red);
gg.draw(line);
gg.dispose();
}
}