【问题标题】:How to repaint in Swing without clearing the window? [duplicate]如何在不清除窗口的情况下在 Swing 中重新绘制? [复制]
【发布时间】:2019-04-01 21:30:57
【问题描述】:

我正在实现一个简单的Canvas,其中可以像现实生活中的人一样用纸和铅笔绘制项目,而无需在每次绘制对象时清除整个页面。

到目前为止我所拥有的......

一个Canvas实现绘图:

public class Canvas extends JPanel {
    private final Random random = new Random();

    public Canvas() {
        setOpaque(false); // I thought setting this flag makes the drawn pixels be preserved...
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(640, 480);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.drawOval(random.nextInt(getWidth()), random.nextInt(getHeight()), 5, 5);
    }
}

Window 作为一个实际的窗口:

public class Window extends JFrame {
    public Window(Canvas canvas) {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        add(canvas);
        pack();
        setVisible(true);
    }
}

还有带有应用程序入口点的Controller。还会启动一个计时器,以便每秒调用 Canvas 上的 repaint 以强制绘制另一个圆圈。

public class Controller {
    public static void main(String[] args) {
        Canvas canvas = new Canvas();
        SwingUtilities.invokeLater(() -> new Window(canvas));
        new Timer(1000, e -> canvas.repaint()).start();
    }
}

问题是每当绘制一个新的圆圈时,前一个圆圈就会被清除。似乎还有一些过程将JPanel 或整个JFrame 填充为白色。

【问题讨论】:

    标签: java swing draw


    【解决方案1】:

    Swing 中的绘画具有破坏性。预期的要求是,每次绘制组件时,都要从头开始绘制。

    您需要定义一个模型来维护从头开始恢复状态所需的信息。

    然后,您的绘画例程将迭代此模型并每次绘制元素。

    这样做的好处是允许您修改模型、删除或插入元素,这样您就可以简单地更新绘制的内容。

    或者,您可以使用一个“缓冲区”(即BufferedImage),在其上完成所有绘制,然后您只需在每次绘制组件时将图像绘制到组件。

    但是,这意味着您无法撤消或分层绘画,它会直接绘制到图像上。它还使调整绘图图像区域的大小变得更加困难,因为您需要手动进行这些更新,而基于“模型”的实现更具适应性

    【讨论】:

    • 我用BufferedImage 做到了,似乎没有其他方法可以以干净的方式实现这一目标。
    • 就我个人而言,我会选择一个模型,但我喜欢它的灵活性,但从技术上讲,你可以同时使用这两个,但需要驱动器;)
    • 我的模型正是我需要保留的信息是图像的当前状态。绘制的所有其他内容都必须绘制在现有的所有内容之上。我永远不需要更改任何现有内容的位置,但是会添加和添加数百万个组件......所以我需要的最大信息量可以存储在单个 BufferedImage 中。
    【解决方案2】:

    考虑调用 repaint(...) 的替代构造函数

    重绘(long tm, int x, int y, int width, int height)

    这允许您设置要重新绘制的指定区域。

    您也可以将绘制的内容存储在列表中,然后在调用 repaint 后将绘图重新打印到画布上。

    【讨论】:

    • 不幸的是,对于这项任务,我将让列表包含数百万个在很长一段时间(几分钟)内绘制的元素。要重新绘制的指定区域将始终为无,因为我希望在应用程序的整个生命周期中保留整个 Canvas。只有手动 clear 才能填充画布。
    • 这个帖子似乎可以帮助你很多。 stackoverflow.com/questions/15621313/repaint-without-clearing
    • 是的,实际上我一直在寻找现有的答案,但之前找不到。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-27
    • 2018-12-28
    • 1970-01-01
    • 2018-09-03
    • 2012-01-11
    相关资源
    最近更新 更多