Не могу нарисовать более одного квадрата в JFrame - PullRequest
0 голосов
/ 28 декабря 2018

Не удается заставить программу напечатать более одного квадрата.


Мой код сейчас

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 квадратамиразличные цвета, которые переходят на новую строку после заполнения строки.

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Прежде всего, не надо.

Не переопределяйте paint контейнеров верхнего уровня, например JFrame.

JFrame - составной компонент, означающий, что они представляют собой несколько слоев между его поверхностью и пользователем, и из-за того, как работает система рисования, они могут быть нарисованы независимо от рамы, что можетпроизводят странные результаты.

A frames layers

Контейнеры верхнего уровня не имеют двойной буферизации, что означает, что ваши обновления будут мигать.

НЕ вызывайте методы рисованияСупер метод, если вы не уверены, что знаете, что делаете.

Начните с просмотра Выполнение пользовательской живописи и Рисование в 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 не принимает во внимание размер других элементов пользовательского интерфейса, которые уменьшат доступную видимую область, доступную на экране, такие как панель задач / док или строка меню в некоторых ОС

Использование setBounds(x, y, WindowSize.width, WindowSize.height); вокно баКласс sed также является плохой идеей, так как доступная видимая область - это размер окна МИНУС декораций окна, то есть фактически видимая область меньше, чем вы указали, и поскольку вы рисуете непосредственно в рамку, вы рискуете покрасить.под рамкой украшения.

Вы можете взглянуть на Как я могу установить в середине? для получения более подробной информации

Одна вещь, которую вы должны сейчас о живописи, живопись эторазрушительным, то есть каждый раз, когда происходит цикл рисования, вы должны полностью перерисовать текущее состояние компонента.

В настоящее время этот ...

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, но система сама решает, когда и что будет окрашиваться, это означает, что несколько запросов могут быть оптимизированы вплоть до одного прохода рисования.

Кроме того, рисование не должно делать ничего, кроме рисования текущего состояния.Следует избегать прямого или косвенного изменения состояния, особенно если это изменение запускает новый проход рисования, поскольку это может внезапно снизить производительность вашей программы до 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();
}

Обратите внимание,Я изменил позиции xCord и yCord на ноль, мне больше не нужно «угадывать» во фреймеэлектронные украшения.Помимо создания локальных переменных, чтобы при повторном вызове метода значения сбрасывались на ноль.

Вам не «нужно» приводить ссылку Graphics к Graphics2D,но Graphics2D - более мощный API.Мне также нравится копировать его состояние, но это я, ваш код достаточно прост, поэтому вряд ли он будет иметь негативные последствия для всего, что может быть нарисовано после вашего компонента.

Обратите внимание, я использую getWidth и getHeight вместо «магических чисел», то есть вы можете изменить размер окна, и картина адаптируется.

0 голосов
/ 28 декабря 2018

Вы можете попробовать разместить весь механизм рисования внутри цикла, чтобы сделать это за один вызов.Поэтому вам не нужно вызывать 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;
    }
}
...