簡體   English   中英

無法在JFrame中繪制多個正方形

[英]Can't draw more than one square in JFrame

無法讓程序打印多個方塊。


我的代碼現在

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是一個復合組件,意味着它們在表面和用戶之間是多個層,並且由於繪制系統的工作方式,這些可以獨立於框架繪制,這會產生奇怪的結果。

一個幀層

頂級容器不是雙緩沖的,這意味着您的更新將閃爍。

除非你完全確定你知道自己在做什么,否則請調用繪畫方法超級方法。

首先來看看在AWT和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元素的大小,這將減少屏幕上可用的可用可視區域,例如某些OS上的任務欄/停靠欄或菜單欄

使用setBounds(x, y, WindowSize.width, WindowSize.height); 在基於窗口的類上也是一個壞主意,因為可用的可視區域是窗口大小MINUS窗口的裝飾,這意味着實際可視區域比您指定的要小,並且因為您直接繪制到框架,您運行框架裝飾下的繪畫風險。

你可以看看我如何在中間設置? 更多細節

關於繪畫你應該做的一件事,繪畫是破壞性的,也就是說,每次繪畫周期發生時,你都應該完全重繪組件的當前狀態。

目前,這......

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

將只繪制一個矩形,基於xCordyCord的最后一個值,很可能是在paint方法退出之后。

Swing使用被動渲染引擎,這意味着系統將確定要繪制的內容以及何時不進行控制。 您可以通過使用repaint來向系統發出“請求”,但是由系統來決定何時以及將要繪制什么,這意味着可以將多個請求優化為單個繪制過程。

此外,繪畫應該只是繪制當前狀態。 它應該避免直接或間接地改變狀態,特別是如果該更改觸發了新的繪制過程,因為這會突然將程序的性能降低到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();
        }

    }

}

很多正方形

分解...

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而不是“魔術數字”,這意味着您可以調整窗口大小並且繪畫將適應。

您可以嘗試將整個繪制機制放在循環中,以便在一次調用中完成它。 因此,您不需要在paint方法本身內調用repaint:

public void paint(Graphics g) {

    while((yCord+height)<600){

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM