I have a simple class that draws a line when mouse dragging or a dot when mouse pressing(releasing).
When I minimize the application and then restore it, the content of the window disappears except the last dot (pixel). I understand that the method super.paint(g)
repaints the background every time the window changes, but the result seems to be the same whether I use it or not. The difference between the two of them is that when I don't use it there's more than a pixel painted on the window, but not all my painting. How can I fix this?
Here is the class.
package painting;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
class CustomCanvas extends Canvas{
Point oldLocation= new Point(10, 10);
Point location= new Point(10, 10);
Dimension dimension = new Dimension(2, 2);
CustomCanvas(Dimension dimension){
this.dimension = dimension;
this.init();
addListeners();
}
private void init(){
oldLocation= new Point(0, 0);
location= new Point(0, 0);
}
public void paintLine(){
if ((location.x!=oldLocation.x) || (location.y!=oldLocation.y)) {
repaint(location.x,location.y,1,1);
}
}
private void addListeners(){
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
@Override
public void mouseReleased(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
});
}
@Override
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.red);
g.drawLine(location.x, location.y, oldLocation.x, oldLocation.y);
}
@Override
public Dimension getMinimumSize() {
return dimension;
}
@Override
public Dimension getPreferredSize() {
return dimension;
}
}
class CustomFrame extends JPanel {
JPanel displayPanel = new JPanel(new BorderLayout());
CustomCanvas canvas = new CustomCanvas(new Dimension(200, 200));
public CustomFrame(String titlu) {
canvas.setBackground(Color.white);
displayPanel.add(canvas, BorderLayout.CENTER);
this.add(displayPanel);
}
}
public class CustomCanvasFrame {
public static void main(String args[]) {
CustomFrame panel = new CustomFrame("Test Paint");
JFrame f = new JFrame();
f.add(panel);
f.pack();
SwingConsole.run(f, 700, 700);
}
}
@Andrew, @Dave, @trashgod Hi, I did some research on this and, finally, this is what I've got. Please correct me if I'm wrong. You cannot override paint() so you call repaint() everytime you need to do app-triggered painting. Repaint() calls update() which its default behavior is to call paint(). update() is used for incremental painting; that explains the flickering screen when paint() was doing all the work, which practically means it was painting the whole image at every step. However, my question is if I add "locationsAdded = 0" in the update method that means everytime I drag the mouse I paint the whole image(like in paint), so why doesn't it blink like before? I've also read something about painting in swing and I didn't understand why update() is never invoked for swing. Can you explain me why?
Yes, but @Dave's approach is perfectly satisfactory for thousands of nodes, as may be seen in
GraphPanel
. Beyond that, consider the flyweight pattern, as used byJTable
renderers and illustrated here.Addendum: Focusing on your
AWTPainting
questions, the variation below may illustrate the difference between System- and App-triggered Painting. As the mouse is dragged,repaint()
invokesupdate()
, which callspaint()
; this is app-triggered. As you resize the window, onlypaint()
is called (no red numbers are drawn); this is system-triggered. Note that there is a flicker when the mouse is released after resizing.Flickering typically occurs when the entire component's background is cleared and redrawn:
You are not storing the state of the points you are drawing. When the panel is repainted, it only has information for the last point it drew.
Response to comment:
You would need to have a collection of Points, for instance
ArrayList<Point> location = new ArrayList<Point>();
Then, in your listeners:
location.add(new Point(me.getX(), me.getY()));
Finally, in paintLine():
The collection
locations
is usually referred to as a Display List. Most graphics programs use them.Response to comment:
Yes, I expect so. I just tossed off an idea based on your code to give you a starting point. It is almost certainly a bad idea to do exactly as I have described.