在 Java 中调整大小时绘制的内容不可见

发布于 2024-09-15 05:40:54 字数 1878 浏览 9 评论 0原文

请注意,我没有在 Windows 机器上测试过此功能,仅在 Mac 机器上测试过。我不太确定 Windows 机器上是否也会发生这种情况...

当我调整 Java 应用程序的大小时,内容是不可见的。我已经找到了一种方法来修复它在调整大小之后,但用户调整窗口大小时却找不到。

我没有使用 Swing 或其他东西,因为它使我的二进制文件变得如此缓慢(在我看来)。

结构如下:

  • Frame 我的主窗口
    • 包含r 主窗口的内容视图
      • 基于容器的子视图,包含 paint(Graphics g)-方法

我已将所有侦听器添加到< code>我的主窗口,现在我可以在调整窗口大小后重新绘制内容视图

public void componentResized(ComponentEvent e) {
    this.contentView.paint(this.contentView.getGraphics());
}

我要注意的是,使用 paint(getGraphics()) 方法并不是一个很好的方法,但由于 repaint() 方法不根本不做任何事情,这是唯一的工作可能性。

调整大小时,所有绘制的内容都变得不可见。但是,当我将 Button 实例添加到我的 Content-view 并调整我的 Main-window,按钮不会变得不可见。

能够跟踪“实时”调整大小事件:

public void componentMoved(ComponentEvent e) {
    System.out.println("Live-resize");
}
  1. 当我开始调整大小时,不会调用此方法。
  2. 在调整大小时,它会在我调整窗口大小的每个像素的日志中生成“实时调整大小”。
  3. 当我停止调整大小时,不会调用此方法,而是调用 componentResized-method。

当我将我的重绘方法(或官方重绘方法)添加到像这样的“实时”调整大小事件时,我仍然得到输出,但是,它不是重绘或其他东西

public void componentMoved(ComponentEvent e) {
    System.out.println("Live-resize");
    this.contentView.paint(this.contentView.getGraphics());
}

或者

public void componentMoved(ComponentEvent e) {
    System.out.println("Live-resize");
    this.contentView.repaint();
}

当我最小化我的应用程序到码头并最大化时再次应用程序,发生同样的事情,我猜需要相同的代码来解决这个问题。

我没有使用Graphics2D之类的东西,只是使用Graphics

您能解释一下如何重新绘制视图吗?

提前致谢, 蒂姆

Please note I haven't tested this on a Windows-machine only on a Mac-machine. I'm not so sure whether this also occurs on a Windows-machine...

When I resize my Java-application the content is invisible. I already found a way to fix it after resizing it, but not while the user is resizing the window.

I'm not using Swing or something because it makes my binary so slow (in my opinion).

The structure is like this:

  • Frame My main-window
    • Container Content view of main-window
      • Container-based subviews that including the paint(Graphics g)-method

I've added all listeners to My main-window and now I'm able to redraw the Content-view after resizing the window.

public void componentResized(ComponentEvent e) {
    this.contentView.paint(this.contentView.getGraphics());
}

I am beware of the fact using the paint(getGraphics())-method isn't a really good way to do this, but since the repaint()-method doesn't do anything at all, it's the only working possibility.

While resizing, all painted content becomes invisible. However, when I add a Button-instance to my Content-view and resize my Main-window, the button doesn't get invisible.

I am able to trace the 'live'-resize event:

public void componentMoved(ComponentEvent e) {
    System.out.println("Live-resize");
}
  1. When I start resizing this method is not being called.
  2. While resizing it generates "Live-resize" in my log every single pixel I resize the window.
  3. When I stop resizing this method is not being called, the componentResized-method does.

When I add my repaint-method (or the official repaint-method) to the 'live'-resize event like this, I still get the output, however, it's not repainting or something

public void componentMoved(ComponentEvent e) {
    System.out.println("Live-resize");
    this.contentView.paint(this.contentView.getGraphics());
}

Or

public void componentMoved(ComponentEvent e) {
    System.out.println("Live-resize");
    this.contentView.repaint();
}

When I minimize my application to the dock and maximize the application again, the same thing happens, I guess that the same code is needed to fix this.

I'm not using Graphics2D or something, just Graphics.

Could you please explain me how I can repaint the views?

Thanks in advance,
Tim

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

过潦 2024-09-22 05:40:54

作为参考,这里是使用 Swing 的相同程序。由于 JPanel 是双缓冲的,因此在调整大小后释放鼠标时它不会闪烁。

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;

public class SwingPaint {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.add(new CirclePanel());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private static class CirclePanel extends JPanel {

        private static final Random r = new Random();

        public CirclePanel() {
            this.setPreferredSize(new Dimension(320, 240));
            this.setForeground(new Color(r.nextInt()));
            this.addMouseListener(new MouseAdapter() {

                @Override
                public void mousePressed(MouseEvent e) {
                    CirclePanel.this.update();
                }
            });
        }

        public void update() {
            this.setForeground(new Color(r.nextInt()));
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Dimension size = this.getSize();
            int d = Math.min(size.width, size.height) - 10;
            int x = (size.width - d) / 2;
            int y = (size.height - d) / 2;
            g.fillOval(x, y, d, d);
            g.setColor(Color.blue);
            g.drawOval(x, y, d, d);
        }
    }
}

For reference, here is the same program using Swing. Because JPanel is double buffered, it doesn't flicker as the mouse is released after resizing.

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;

public class SwingPaint {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.add(new CirclePanel());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private static class CirclePanel extends JPanel {

        private static final Random r = new Random();

        public CirclePanel() {
            this.setPreferredSize(new Dimension(320, 240));
            this.setForeground(new Color(r.nextInt()));
            this.addMouseListener(new MouseAdapter() {

                @Override
                public void mousePressed(MouseEvent e) {
                    CirclePanel.this.update();
                }
            });
        }

        public void update() {
            this.setForeground(new Color(r.nextInt()));
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Dimension size = this.getSize();
            int d = Math.min(size.width, size.height) - 10;
            int x = (size.width - d) / 2;
            int y = (size.height - d) / 2;
            g.fillOval(x, y, d, d);
            g.setColor(Color.blue);
            g.drawOval(x, y, d, d);
        }
    }
}
罗罗贝儿 2024-09-22 05:40:54

我对 Swing 比较熟悉,但是文章 Painting在 AWT 和 Swing 中 区分系统触发的绘制和应用程序触发的绘制。下面的示例显示了系统如何在调整窗口大小时调用 paint(),而应用程序如何调用 repaint(),后者又调用 update() >,响应鼠标事件。该行为是跨平台的。

import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class AWTPaint {

    public static void main(String[] args) {
        Frame frame = new Frame();
        frame.add(new CirclePanel());
        frame.addWindowListener(new WindowAdapter() {

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

    private static class CirclePanel extends Panel {

        private static final Random r = new Random();

        public CirclePanel() {
            this.setPreferredSize(new Dimension(320, 240));
            this.setForeground(new Color(r.nextInt()));
            this.addMouseListener(new MouseAdapter() {

                @Override
                public void mousePressed(MouseEvent e) {
                    CirclePanel.this.repaint();
                }
            });
        }

        @Override
        public void update(Graphics g) {
            this.setForeground(new Color(r.nextInt()));
        }

        @Override
        public void paint(Graphics g) {
            Dimension size = this.getSize();
            int d = Math.min(size.width, size.height) - 10;
            int x = (size.width - d) / 2;
            int y = (size.height - d) / 2;
            g.fillOval(x, y, d, d);
            g.setColor(Color.blue);
            g.drawOval(x, y, d, d);
        }
    }
}

I'm more familiar with Swing, but the article Painting in AWT and Swing distinguishes between system- and application-triggered painting. The example below shows how the system invokes paint() as the window is resized, while the application invokes repaint(), which calls update(), in response to a mouse event. The behavior is cross-platform.

import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class AWTPaint {

    public static void main(String[] args) {
        Frame frame = new Frame();
        frame.add(new CirclePanel());
        frame.addWindowListener(new WindowAdapter() {

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

    private static class CirclePanel extends Panel {

        private static final Random r = new Random();

        public CirclePanel() {
            this.setPreferredSize(new Dimension(320, 240));
            this.setForeground(new Color(r.nextInt()));
            this.addMouseListener(new MouseAdapter() {

                @Override
                public void mousePressed(MouseEvent e) {
                    CirclePanel.this.repaint();
                }
            });
        }

        @Override
        public void update(Graphics g) {
            this.setForeground(new Color(r.nextInt()));
        }

        @Override
        public void paint(Graphics g) {
            Dimension size = this.getSize();
            int d = Math.min(size.width, size.height) - 10;
            int x = (size.width - d) / 2;
            int y = (size.height - d) / 2;
            g.fillOval(x, y, d, d);
            g.setColor(Color.blue);
            g.drawOval(x, y, d, d);
        }
    }
}
蓝眼泪 2024-09-22 05:40:54

好吧,我终于修好了。

您不需要每次在 Paint(Graphics g) 方法中重绘它,而是需要缓冲输出并仅重绘该图像(我有点希望 Java 已经这样做了,就像 Obj-C 一样) )。

public BufferedImage buffer;

public void redraw() {
    buffer = new BufferedImage(
            200, // height
            300, // width
            BufferedImage.TYPE_4BYTE_ABGR); // ABGR = RGBA, 4-byte (r, g, b, a) per pixel
    Graphics g = buffer.getGraphics();
    // do your drawing here
    if (this.getGraphics()) {
        // 'this' is already shown, so it needs a redraw
        this.paint(this.getGraphics()); // little hack
    }
}

public void update(Graphics g) {
    this.paint(g);
}

public void paint(Graphics g) {
    g.drawImage(buffer, 0, 0, this);
}

现在,当您最小化窗口并再次最大化它时,画作仍然存在。只是,窗口现在闪烁了 0.1 秒左右,但我并不关心这一点。

Okay, I finally fixed it.

Instead of redrawing it every time in the paint(Graphics g)-method, you need to buffer the output and only redraw that image (I kinda hoped Java would be already doing that, just like Obj-C).

public BufferedImage buffer;

public void redraw() {
    buffer = new BufferedImage(
            200, // height
            300, // width
            BufferedImage.TYPE_4BYTE_ABGR); // ABGR = RGBA, 4-byte (r, g, b, a) per pixel
    Graphics g = buffer.getGraphics();
    // do your drawing here
    if (this.getGraphics()) {
        // 'this' is already shown, so it needs a redraw
        this.paint(this.getGraphics()); // little hack
    }
}

public void update(Graphics g) {
    this.paint(g);
}

public void paint(Graphics g) {
    g.drawImage(buffer, 0, 0, this);
}

Now, when you minimize the window and maximize it again, the paintings remain. Only, the window's flickering now for .1-second or so, but I don't really care about that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文