Прежде всего, не надо.
Не переопределяйте paint
контейнеров верхнего уровня, например JFrame
.
JFrame
- составной компонент, означающий, что они представляют собой несколько слоев между его поверхностью и пользователем, и из-за того, как работает система рисования, они могут быть нарисованы независимо от рамы, что можетпроизводят странные результаты.
![A frames layers](https://i.stack.imgur.com/UlJUr.gif)
Контейнеры верхнего уровня не имеют двойной буферизации, что означает, что ваши обновления будут мигать.
НЕ вызывайте методы рисованияСупер метод, если вы не уверены, что знаете, что делаете.
Начните с просмотра Выполнение пользовательской живописи и Рисование в 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](https://i.stack.imgur.com/owMrm.png)
Разбейте ...
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
вместо «магических чисел», то есть вы можете изменить размер окна, и картина адаптируется.