【问题标题】:Drawing problem in javajava中的绘图问题
【发布时间】:2025-12-27 05:20:12
【问题描述】:

我是 java 新手,我需要实现一个绘图应用程序,我有点卡在开始,我设法画线到我添加到 JFrame 的 JPanel,但绘制的每条线都会重置整个绘图,并且在绘图区域中仅保留最后绘制的线。我希望我能理解,这里是他的代码:

class Shapes extends JFrame {

    public JFrame mf = new JFrame("Paint");
    DrawArea da = new DrawArea();

        JToggleButton lineButton = new JToggleButton(new ImageIcon("line.gif"));
        JToggleButton brushButton = new JToggleButton();
        JToggleButton pencilButton = new JToggleButton();
        JToggleButton eraserButton = new JToggleButton(new ImageIcon("eraser_icon.png"));
        JToggleButton rectangleButton = new JToggleButton();
        JToggleButton ovalButton = new JToggleButton();

    Shapes() {


        da.setBounds(120, 50, 500, 350);
        da.setBackground(Color.YELLOW);
        mf.setSize(700, 500);
        mf.setLayout(null);

        lineButton.setBounds(0, 50, 40, 40);
        brushButton.setBounds(40, 50, 40, 40);
        eraserButton.setBounds(0, 90, 40, 40);
        pencilButton.setBounds(40, 90, 40, 40);
        rectangleButton.setBounds(0, 130, 40, 40);
        ovalButton.setBounds(40, 130, 40, 40);

        mf.setBackground(Color.red);
        mf.add(lineButton);
        mf.add(brushButton);
        mf.add(pencilButton);
        mf.add(eraserButton);
        mf.add(rectangleButton);
        mf.add(ovalButton);
        mf.add(da);
        mf.show();
        mf.addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        mf.addMouseListener(new MouseAdapter() {

            public void mouseClicked(MouseEvent e) {
                System.out.println("x:" + e.getX() + "y:" + e.getY() + "\n" + "x2:" + e.getXOnScreen() + "y2:" + e.getYOnScreen());
            }
        });
        eraserButton.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e)
            {
            eraserButton.setSelectedIcon(new ImageIcon("eraser_icon_selected.png"));
        }
        });
        lineButton.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e)
            {
              lineButton.setSelectedIcon(new ImageIcon("line_selected.png"));
        }
        });
        da.addMouseListener(new MouseAdapter() {

            public void mousePressed(MouseEvent e) {
                da.setXvalue(e.getX());
                da.setYvalue(e.getY());



            }

            public void mouseReleased(MouseEvent e) {

                da.setX2value(e.getX());
                da.setY2value(e.getY());
                da.repaint();
            }
        });
        da.addMouseMotionListener(new MouseAdapter() {

            public void mouseDragged(MouseEvent e) {
                da.repaint();
                da.setX2value(e.getX());
                da.setY2value(e.getY());

            }
        });

    }
}



public class DrawArea extends JPanel {
    int x1value,y1value,x2value,y2value;

    public int getX2value() {
        return x2value;
    }

    public void setX2value(int x2value) {
        this.x2value = x2value;
    }

    public int getY2value() {
        return y2value;
    }

    public void setY2value(int y2value) {
        this.y2value = y2value;
    }
    public JPanel dra=new JPanel();

    public int getXvalue() {
        return x1value;
    }

    public void setXvalue(int xvalue) {
        this.x1value = xvalue;
    }

    public int getYvalue() {
        return y1value;
    }

    public void setYvalue(int yvalue) {
        this.y1value = yvalue;
    }

    public void paint(Graphics g)
    {
      super.paint(g);
      g.setColor(Color.red);
      g.drawLine(getXvalue(),getYvalue(),getX2value(),getY2value());

}
}

    class Paint extends JPanel

{ 

    public static void main(String args[])
            {
               Shapes s=new Shapes();

            }

}

【问题讨论】:

    标签: java draw paint repaint


    【解决方案1】:

    请参阅Custom Painting Approaches 了解两种解决方案。示例绘制矩形,但线的概念是相同的。

    【讨论】:

    • 谢谢,我还需要实现铅笔和画笔工具,+ 几何图形,这样会有所帮助。谢谢
    【解决方案2】:

    覆盖paintComponent(),而不是paint()。阅读此tutorial。当需要重绘面板时,您调用 panels repaint() 方法。

    【讨论】:

    • 这是一个有用的改变,但这不是他的问题的原因。
    【解决方案3】:

    只要窗口管理器认为该区域“不新鲜”,就会调用 Paint。如果按照现在的方式来做,每次都会画最后一条线。

    正确的方法是在内存中创建一个BufferedImage 并利用它。然后,在绘制方法中,将BufferedImage 粘贴到表面上。这也使得滚动和缩放变得非常容易。

    每当您执行此类操作时,使表面无效,以便窗口管理器为您调用绘制方法。

    【讨论】:

      【解决方案4】:

      你只存储一行,并且每次都覆盖它,所以当组件重绘时,旧的会被擦除,新的会被重绘。

      paintComponent 之类的期望是您的实现将在每次调用时绘制您想要出现的每个图形元素。

      而不是存储x1y1x2y2,您应该创建一个 LineSegment 类或类似的类来存储这些值。然后,当您绘画时,您为每个已存储的LineSegment 对象调用g.drawLine()(大概在ArrayList 或类似的地方)。然后,当重新绘制组件时,您的所有线段都应该出现在屏幕上。

      【讨论】:

        【解决方案5】:

        有点跑题了,但我有几分钟不舒服,因为我使用了 update() 而不是 repaint()。我建议所有使用 SWING 的人花一些时间检查哪些方法应该作为线程安全处理,哪些方法必须在 EDT(事件调度程序线程)上,以确保您不会遇到一些意外错误。 This is a good article about this.

        另外,如果您想在您的应用程序中使用撤消/重做系统,请在开始时考虑... 如果是这样,比您要允许撤消多少步。如果您想允许此功能,那么您不能只是绘制并忘记上次绘制的内容。 此外,存储到目前为止绘制的所有图像也不会节省内存。我不是专家,我并不是说这是最佳做法,但我会这样做:

        我会列出两个列表。

        1. 其中一个会存储应用的绘图动作
        2. 另一个将包含撤回的绘图操作

        绘图动作 将是一个接口,并且某个类将为每种特定类型的绘图动作(LineDrawAction、CirceDrawAction...)实现它。

        当您画一条新线或任何内容时,您将清空撤回的操作列表并将其添加到已应用的操作列表中。当有人撤消最后一个动作时,我只会从应用列表中删除最后一个绘图动作并添加到撤回列表(等等......)。取决于您是否只想在列表达到此 x 限制时撤消最后一个 x 操作,我将从列表或队列中删除第一个绘图操作并最终绘制到图片 - 这意味着永久绘图,这不能撤消。

        我希望它清晰有用,即使不是直接回答您的问题。

        【讨论】: