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

5
请注意,我只在Mac机器上测试过此方法,不确定它是否也适用于Windows机器...
当我调整Java应用程序的大小时,内容是不可见的。 我已经找到了一种方法来在调整大小之后修复它,但不能在用户调整窗口大小时修复。
我没有使用Swing或其他东西,因为它会使我的二进制文件变得很慢(在我看来)。
结构如下:
- 主窗口“Frame” - 内容视图“Container”属于主窗口 - 基于“Container”的子视图,包括“paint(Graphics g)”方法
我已将所有监听器添加到“我的主窗口”中,现在我能够在调整窗口大小后重绘“Content-view”。
public void componentResized(ComponentEvent e) {
    this.contentView.paint(this.contentView.getGraphics());
}

我意识到使用 paint(getGraphics()) 方法不是一个很好的做法,但是因为 repaint() 方法根本什么都没做,这是唯一可行的方法。

当调整大小时,所有绘制的内容都会变得不可见。然而,当我在我的 Content-view 中添加一个 Button 实例并调整我的 Main-window 大小时,按钮不会变得不可见。

我可以跟踪“实时”调整大小事件:

public void componentMoved(ComponentEvent e) {
    System.out.println("Live-resize");
}
  1. 当我开始调整大小时,这个方法没有被调用。
  2. 在调整大小时,每当我改变窗口大小一个像素,日志中都会生成“实时调整大小”。
  3. 当我停止调整大小时,这个方法没有被调用,会调用componentResized方法。

当我将repaint方法(或官方的repaint方法)添加到“实时”调整大小事件中时,我仍然可以得到输出,但它不会重新绘制或产生其他影响。

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

当我将应用程序最小化到dock并再次将应用程序最大化时,同样的事情发生了,我猜需要相同的代码来修复这个问题。我没有使用Graphics2D或其他东西,只是使用Graphics。您能否请解释一下如何重新绘制视图?谢谢提前, Tim

请参见“AWT和Swing中的绘画”http://java.sun.com/products/jfc/tsc/articles/painting/index.html。 - trashgod
请考虑发布一个简短、自包含、正确(可编译)的示例(SSCCE),以展示问题:http://sscce.org/ - trashgod
1
我建议你调查一下为什么你认为Swing使你的应用程序变得如此缓慢,而不是试图通过使用AWT组件来解决这个限制。 - akf
3个回答

7

供参考,这里是使用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);
        }
    }
}

请参考有关纵横比的这个答案 - trashgod

5

我比较熟悉Swing,但是这篇在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);
        }
    }
}


0

好的,我终于修复了它。

不要在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秒左右,但我并不真的在意这个。

我认为还有更优雅的解决方案 :) - Dzung Nguyen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接