首先,不要。
不要覆盖顶级容器的paint,例如JFrame。
JFrame 是一个复合组件,这意味着它们是其表面和用户之间的许多层,并且由于绘制系统的工作方式,这些可以独立于框架进行绘制,这会产生奇怪的结果.
顶级容器没有双缓冲,这意味着您的更新将闪烁。
请务必调用paint methods 超级方法,除非您完全确定自己知道自己在做什么。
首先查看Performing Custom Painting 和Painting 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 向系统发出“请求”,但由系统决定何时以及什么将被绘制,这意味着可以将多个请求优化为一次绘制。
此外,绘画应该只是描绘当前状态。它应该避免直接或间接地更改状态,尤其是当该更改触发新的绘制通道时,因为这会突然将您的程序的性能降低到 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();
}
请注意,我已将xCord 和yCord 的位置更改为零,我不再需要“猜测”框架装饰。以及制作局部变量,以便在再次调用该方法时,将值重置为零。
您没有“必须”将Graphics 引用转换为Graphics2D,但Graphics2D 是一个更强大的API。我也喜欢复制它的状态,但就是我,你的代码很简单,所以它不太可能对你的组件之后可能绘制的任何其他东西产生不利影响。
另外请注意,我使用 getWidth 和 getHeight 代替“幻数”,这意味着您可以调整窗口大小,并且绘画会适应。