2

By saying dynamic graph i mean that the user can drag Vertices around the screen and later remove and more.

I am stuck at this point where i want to paint more then one Vertex, and am trying to avoid making JVM paint the whole graph all over again when the graph changes.

do i have to make it paint the whole graph or is there another way to do that?

here's my code:

class GraphPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private Vector<Vertex> V=new Vector<Vertex>();
    private Vertex v;
    private int R = 20;

    public GraphPanel() {
        V.add(new Vertex(70,70));
        V.add(new Vertex(10,50));
        paintGraph();
        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                for (int i=0;i<V.size();i++) {
                    if ((V.get(i).getX()<=e.getX() && V.get(i).getX()+R>=e.getX()) && ( V.get(i).getY()<=e.getY() && V.get(i).getY()+R>=e.getY())) {
                        v=V.get(i);
                        moveVertex(e.getX(),e.getY());
                        v.changeState();
                    }
                }
            }
            public void mouseReleased(MouseEvent e) {
                v.changeState();
            }
        });

        addMouseMotionListener(new MouseAdapter() {
            public void mouseDragged(MouseEvent e) {
                if (v.isPressed()) moveVertex(e.getX(),e.getY());
            }
        });
    }

    private void paintGraph() {
        int OFFSET = 1;
        for (int i=0;i<V.size();i++) {
            v=V.get(i);
            repaint(v.getX(),v.getY(),R+OFFSET,R+OFFSET);
        }

    }

    private void moveVertex(int x, int y) {
        int OFFSET = 1;
        if ((v.getX()!=x) || (v.getY()!=y)) {
            repaint(v.getX(),v.getY(),R+OFFSET,R+OFFSET);
            v.setLocation(x-10, y-10);
            repaint(v.getX(),v.getY(),R+OFFSET,R+OFFSET);
        }
    }

    public Dimension getPreferredSize() {
        return new Dimension(250,200);
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (v!=null) {
            g.setColor(Color.RED);
            g.fillOval(v.getX(),v.getY(),R,R);
            g.setColor(Color.BLACK);
            g.drawOval(v.getX(),v.getY(),R,R);
        }
    }
}

public class Vertex {
    private int x,y;
    boolean isPressed;
    Vertex(int x0,int y0) {x=x0;y=y0;isPressed=false;}
    public void setLocation(int x0,int y0) {x=x0;y=y0;}
    public int getX() {return x;}
    public int getY() {return y;}
    public boolean isPressed() {return isPressed;}
    public boolean changeState() {return isPressed=!isPressed;}

}

public class Tester {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI() {
        JFrame f = new JFrame("Swing Paint Demo");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new GraphPanel());
        f.pack();
        f.setVisible(true);
    }
}    
mKorbel
  • 109,525
  • 20
  • 134
  • 319
Ofek Ron
  • 8,354
  • 13
  • 55
  • 103

2 Answers2

2

Let's consider graph is list of Ovals and list of Lines. IN the paintComponent() method of Graph we have to draw all the lists' members.

Add a check that g.getClipBounds rectangle intersects Oval (or Line) rectangle. If they intersect we draw oval or line.

When vertex is moved somewhere we have old and new position and can get rectangle to be repainted.

Use the rectangle location and size and pass in the graph panel's repaint().

That way you will repaint changed region only and only ovals and lines visible in the rectangle.

StanislavL
  • 56,971
  • 9
  • 68
  • 98
  • I am not sure, but i think The way the code is written atm is as you described, notice repaint only repaints the rectangle that changed... maybe if you add your implementation where it works, it would definitely be satisfying. – Ofek Ron Jan 06 '12 at 08:12
  • Oval and Line are Shapes. Use getBounds() to get rectangles. Shape also has public boolean intersects(double x, double y, double w, double h) method. Graphics has public abstract Rectangle getClipBounds() – StanislavL Jan 06 '12 at 09:36
2

This example can easily handle thousands of vertices. Larger numbers may benefit from using the flyweight pattern for rendering; one approach is illustrated here.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045