java - 不能在 JFrame 中绘制超过一个正方形

标签 java swing jframe paint

无法让程序打印超过一个正方形。

我现在的代码

import java.awt.*;
import javax.swing.*;

public class MyApplication extends JFrame {

    private static final Dimension WindowSize = new Dimension(600, 600);
    private int xCord=9, yCord=32, width=80, height=80;

    public MyApplication() {
        //Create and set up the window
        this.setTitle("Squares");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Display the window centered on the screen
        Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        int x = screensize.width / 2 - WindowSize.width / 2;
        int y = screensize.height / 2 - WindowSize.height / 2;
        setBounds(x, y, WindowSize.width, WindowSize.height);
        setVisible(true);
    }

    public static void main(String args[]) {
        MyApplication window = new MyApplication();
    }

    public void paint(Graphics g) {
        int red = (int) (Math.random() * 255);
        int green = (int) (Math.random() * 255);
        int blue = (int) (Math.random() * 255);
        g.setColor(Color.getHSBColor(red, green, blue));
        g.fillRect(xCord, yCord, width, height);

        while((yCord+height)<600){
            if((xCord+width)>600){
                xCord=9;
                yCord+=80;
            }
            else xCord+=80;
            repaint();
        }
    }
}

我正在尝试用不同颜色的正方形填充 600x600 窗口,一旦一行满,这些正方形就会转到新行。

最佳答案

首先,不要。
不要覆盖 paint顶级容器,如 JFrame .JFrame是一个复合组件,这意味着它们是其表面和用户之间的许多层,并且由于绘画系统的工作方式,这些可以独立于框架进行绘画,这可能会产生奇怪的结果。
A frames layers
顶级容器不是双缓冲的,这意味着您的更新将闪烁。
一定要调用paint方法 super 方法,除非你绝对确定你知道你在做什么。
首先看看Performing Custom PaintingPainting in AWT and Swing有关如何在 Swing 中进行绘画以及如何使用它的更多详细信息。
这...

Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width / 2 - WindowSize.width / 2;
int y = screensize.height / 2 - WindowSize.height / 2;
setBounds(x, y, WindowSize.width, WindowSize.height);
在许多层面上都是一个坏主意。Toolkit#getScreenSize不考虑其他 UI 元素的大小,这将减少屏幕上可用的可视区域,例如某些操作系统上的任务栏/停靠栏或菜单栏
使用 setBounds(x, y, WindowSize.width, WindowSize.height);在基于窗口的类上也是一个坏主意,因为可用的可视区域是窗口大小减去窗口的装饰,这意味着实际可视区域比您指定的要小,并且因为您直接在框架上绘画,所以您运行在框架装饰下绘画的风险。
你可以看看How can I set in the midst?更多细节
关于绘画你现在应该做的一件事是,绘画是破坏性的,也就是说,每次绘画周期发生时,你都应该完全重新绘画组件的当前状态。
目前,这...
public void paint(Graphics g) {
    int red = (int) (Math.random() * 255);
    int green = (int) (Math.random() * 255);
    int blue = (int) (Math.random() * 255);
    g.setColor(Color.getHSBColor(red, green, blue));
    g.fillRect(xCord, yCord, width, height);

    while ((yCord + height) < 600) {
        if ((xCord + width) > 600) {
            xCord = 9;
            yCord += 80;
        } else {
            xCord += 80;
        }
        repaint();
    }
}
将仅绘制一个矩形,基于 xCord 的最后一个值和 yCord最有可能在 paint 之后方法已退出。
Swing 使用被动渲染引擎,这意味着系统将决定要绘制什么以及何时绘制,您无法控制它。您可以通过使用 repaint 向系统发出“请求” ,但是由系统决定何时以及什么将被绘制,这意味着可以将多个请求优化为单个绘制 channel 。
此外,绘画应该只是描绘当前状态。它应该避免直接或间接地改变状态,特别是如果这种改变触发了一个新的绘制 channel ,因为这会突然将你的程序的性能降低到 0,从而削弱它。
那么,答案是什么?
好吧,改变一切……
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MyApplication {

    public static void main(String[] args) {
        new MyApplication();
    }

    public MyApplication() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        private static final Dimension DESIRED_SIZE = new Dimension(600, 600);
        private int width = 80, height = 80;

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return DESIRED_SIZE;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int xCord = 0, yCord = 0;

            while ((yCord) < getHeight()) {
                int red = (int) (Math.random() * 255);
                int green = (int) (Math.random() * 255);
                int blue = (int) (Math.random() * 255);
                g2d.setColor(Color.getHSBColor(red, green, blue));
                g2d.fillRect(xCord, yCord, width, height);
                if ((xCord + width) > getWidth()) {
                    xCord = 0;
                    yCord += 80;
                } else {
                    xCord += 80;
                }
            }
            g2d.dispose();
        }

    }

}
Lots of squares
分解...
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
这将创建 Jframe 的实例, 你真的不想从 JFrame 扩展,您没有向该类添加任何新功能frame.pack()将窗口包装在内容周围,这确保框架始终大于(通过框架装饰的数量)然后是所需的内容大小frame.setLocationRelativeTo(null);将以独立于系统的方式居中窗口。
下一个...
private static final Dimension DESIRED_SIZE = new Dimension(600, 600);
private int width = 80, height = 80;

public TestPane() {
}

@Override
public Dimension getPreferredSize() {
    return DESIRED_SIZE;
}
我用过DESIRED_SIZE为父容器布局管理器提供大小提示。
最后...
@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();
    
    int xCord = 0, yCord = 0;
    while ((yCord) < getHeight()) {
        int red = (int) (Math.random() * 255);
        int green = (int) (Math.random() * 255);
        int blue = (int) (Math.random() * 255);
        g2d.setColor(Color.getHSBColor(red, green, blue));
        g2d.fillRect(xCord, yCord, width, height);
        if ((xCord + width) > getWidth()) {
            xCord = 0;
            yCord += 80;
        } else {
            xCord += 80;
        }
    }
    g2d.dispose();
}
注意这里,我更改了 xCordyCord位置为零,我不再需要在框架装饰上“猜测”。以及制作局部变量,以便在再次调用该方法时,将值重置为零。
您不必“必须”转换 Graphics引用 Graphics2D , 但是 Graphics2D是一个更强大的API。我也喜欢复制它的状态,但这就是我,你的代码很简单,所以它不太可能对你的组件之后可能绘制的任何其他东西产生不利影响。
另请注意,我使用了 getWidthgetHeight而不是“魔数(Magic Number)”,这意味着您可以调整窗口大小并且绘画会适应。

关于java - 不能在 JFrame 中绘制超过一个正方形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53951559/

相关文章:

java - 失去焦点后推迟事件队列

java - JProgressbar 未出现在框架中

java - 制作一个 JFrame 按钮创建一个警告对话框。 Java-Netbeans

java - 如何在appfuse中仅显示子菜单项

java - 为什么我的内容 Pane 不会显示在 JFrame 上?

java - Maven Surefire 插件 : what is meaning of filesystem in runOrder?

java - 是否可以指向特定的 JPanel

java - Android中从Json数组解析Json

java - GridLayout 中的 JLabel 并不总是被绘制

java - 将 JLabel、JButton 等放置在 JFrame 中