【问题标题】:Drawing a dynamic graph.绘制动态图。
【发布时间】:2012-01-06 07:43:13
【问题描述】:

我所说的动态图是指用户可以在屏幕上拖动顶点,然后删除等等。

我被困在这一点上,我想绘制多个顶点,并且试图避免让 JVM 在图形更改时重新绘制整个图形。

我必须让它绘制整个图表还是有其他方法可以做到这一点?

这是我的代码:

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);
    }
}    

【问题讨论】:

  • 绘制图形为什么不依赖JFreeChart这样的第三方库?
  • 因为我想弄脏我的手:)
  • 请学习java命名约定并遵守它们
  • 我的命名有什么问题?
  • 将 V 和 R 作为变量名是不习惯的。如果你只为你的眼睛编码,那没关系,但既然你是在寻求公众帮助,请不要让我们的眼睛变脏:)

标签: java swing user-interface paintcomponent


【解决方案1】:

让我们考虑图表是椭圆列表和线条列表。在 Graph 的 paintComponent() 方法中,我们必须绘制所有列表的成员。

添加检查 g.getClipBounds 矩形是否与椭圆(或直线)矩形相交。如果它们相交,我们绘制椭圆或直线。

当顶点移动到某个地方时,我们有旧位置和新位置,并且可以重新绘制矩形。

使用矩形位置和大小并传入图形面板的 repaint()。

这样您将只重绘更改的区域,并且只有椭圆和矩形中可见的线条。

【讨论】:

  • 我不确定,但我认为代码编写 atm 的方式正如您所描述的那样,请注意 repaint 只会重绘更改的矩形......也许如果您将实现添加到它工作的地方,它一定会很满足的。
  • 椭圆和线是形状。使用 getBounds() 获取矩形。 Shape 也有 public boolean intersects(double x, double y, double w, double h) 方法。图形有公共抽象矩形 getClipBounds()
【解决方案2】:

这个example 可以轻松处理数千个顶点。较大的数字可能会受益于使用flyweight pattern 进行渲染;说明了一种方法here

【讨论】:

    猜你喜欢
    • 2010-12-30
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    相关资源
    最近更新 更多