Introduction
I was recently thrust into GUI programming in Java. And I do have to admit that it turned out to be harder than I expected. The primary reason for that is that I thought having done it while working on an ImageJ plugin back in 2010-2012 I would remember every little detail but my memory turned out to be far less effective than I expected it to be.One thing I had sort of forgotten about is how confusing thread and concurrency issues can get in the context of a GUI. Another thing - how many ways that should seemingly work the same way and accomplish the same objective within the AWT/Swing class collections, yet don't always work the same way.
So here I would like to just list a few oddities I discovered this time around as this will hopefully save other people time and effort and help me remember them too. So here we go.
Graphics vs Graphics2D
For some reason, many 2D graphics functions work better when called from a Graphics2D instance than from a Graphics instance. I am not sure why, especially given that the former is a subclass of the latter, but according to many sources I have consulted as well as my own experience that is indeed so. Hence effectively it is best to structure your code as follows:JPanel panel;
/**
*...
Some code that initializes panel, attaches it to the frame, etc.
*/
Graphics g = panel.getGraphics();
Graphics2D g2d = (Graphics2D)g;
/* Now let's draw something */
g2d.drawLine(5, 5, 20, 20);
g2d.drawOval(50, 50, 150, 150);
The snippet above will draw a line and a circle, and in most instances will do so more reliably than an equivalent snippet using a Graphics instance.
paint() and repaint(): how to stop random removal of your graphics
For some reason, default behaviour of the paint()/repaint() methods is to just repaint the whole JPanel instance to blank slate. Not sure why - I guess I could come up with a few rationales but I still view this default behaviour as suboptimal. Be that as it may, the Swing creators thought differently and hence we have what we have.
The practical outcome of this was that at certain junctures my whole panel would lose all its content. The way to overcome it that I came up with was somewhat primitive but effective. I defined a JPanel subclass that looks as follows:
import javax.swing.JPanel; public class MainAppPanel extends JPanel { public MainAppPanel() { // TODO Auto-generated constructor stub } public MainAppPanel(LayoutManager arg0) { super(arg0); // TODO Auto-generated constructor stub } public MainAppPanel(boolean isDoubleBuffered) { super(isDoubleBuffered); // TODO Auto-generated constructor stub } public MainAppPanel(LayoutManager layout, boolean isDoubleBuffered) { super(layout, isDoubleBuffered); // TODO Auto-generated constructor stub } /** * @OVERLOAD */ public void repaint(){ } /** * @OVERLOAD */ public void paint(){ } }
Naturally, I then used MainAppPanel instead of JPanel - and the graphics stayed the way I expected to.
Hat tips
Too many to mention - lots of people on various forums whose input was invaluable. This all happened a few weeks ago but I was just too disorganized to put it all in writing, so I don't remember the URL's and names anymore but that doesn't mean I am any less grateful.
No comments:
Post a Comment