Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Window's content disappears when minimized

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);
    }
}
like image 588
Carmen Cojocaru Avatar asked Apr 11 '12 16:04

Carmen Cojocaru


2 Answers

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():

for (Point location : locations) {
  repaint(location.x,location.y,1,1); 
}

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.

like image 164
Dave Avatar answered Sep 20 '22 12:09

Dave


Doesn't that mean I will draw all the points(instead of one) everytime I press or drag the mouse?

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 by JTable 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() invokes update(), which calls paint(); this is app-triggered. As you resize the window, only paint() 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:

 4. If the component did not override update(), the default implementation of update() clears the component's background (if it's not a lightweight component) and simply calls paint().

AWTPainting

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;

public class AWTPainting {

    public static void main(String args[]) {
        CustomPanel panel = new CustomPanel();
        Frame f = new Frame();
        f.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.add(panel);
        f.pack();
        f.setVisible(true);
    }
}

class CustomPanel extends Panel {

    public CustomPanel() {
        this.add(new CustomCanvas(new Dimension(320, 240)));
    }
}

class CustomCanvas extends Canvas {

    private MouseAdapter handler = new MouseHandler();
    private List<Point> locations = new ArrayList<Point>();
    private Point sentinel = new Point();
    private Dimension dimension;

    CustomCanvas(Dimension dimension) {
        this.dimension = dimension;
        this.setBackground(Color.white);
        this.addMouseListener(handler);
        this.addMouseMotionListener(handler);
        this.locations.add(sentinel);
    }

    @Override
    public void paint(Graphics g) {
        g.setColor(Color.blue);
        Point p1 = locations.get(0);
        for (Point p2 : locations.subList(1, locations.size())) {
            g.drawLine(p1.x, p1.y, p2.x, p2.y);
            p1 = p2;
        }
    }

    @Override
    public void update(Graphics g) {
        paint(g);
        g.clearRect(0, getHeight() - 24, 50, 20); // to background
        g.setColor(Color.red);
        g.drawString(String.valueOf(locations.size()), 8, getHeight() - 8);
    }

    private class MouseHandler extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            if (locations.get(0) == sentinel) { // reference identity
                locations.set(0, new Point(e.getX(), e.getY()));
            }
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            locations.add(new Point(e.getX(), e.getY()));
            repaint();
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return dimension;
    }
}
like image 34
trashgod Avatar answered Sep 18 '22 12:09

trashgod