问题描述
所以我有一个程序,它通过扫描仪获取一些值,然后相应地更改 BufferedImage
上的 JFrame
。它改变帧的方式通过无限的 while 循环无限期地继续。这可以快速运行(在几秒钟内清除整个 1920x1080 帧)并且在没有 SwingWorker
或 invokelater
或任何东西的情况下工作正常。
为了从扫描仪更新程序,我决定在主程序开始之前制作另一个框架来输入变量。新框架采用这些值,一旦点击 JButton
,就会自行处理并将这些值发送给主程序。
问题是,一旦将这些变量传递给主程序,该程序中的主框架会创建自己但会冻结,并且是完全透明的。这最初让我措手不及,因为我可以看到我的 Eclipse 窗口但无法点击任何东西,因为框架挡住了整个屏幕。
我尝试并成功地使用了 SwingWorker
和 invokelater
,但是它们中的任何一个覆盖帧所花费的时间从几秒钟变为大约三十分钟(我计算过,实际上并没有等待那么长)。我不确定为什么我不能使用框架而不是扫描仪来获取变量,因为无论哪种方式,变量都会传递给主程序,并且前一帧被处理掉。我不太熟悉 EDT 或 Swing 事件队列,因此非常感谢您的帮助。
import java.awt.Color;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Colors {
public static void main(String[] args) {
/*
Scanner scanner = new Scanner(system.in);
System.out.println("Enter Color Choice (Red/Green/Blue)");
String colorInput = scanner.nextLine();
Color changingColor = new Color(0,0);
if (colorInput.equals("Red"))
changingColor = Color.RED;
else if (colorInput.equals("Green"))
changingColor = Color.GREEN;
else if (colorInput.equals("Blue"))
changingColor = Color.BLUE;
scanner.close();
changing(changingColor);
*/
//OR
/*
JFrame frame = newJFrame("Start // Menu");
String[] colors = {"Red","Green","Blue"};
JSpinner colorSpinner = new JSpinner(new SpinnerListModel(colors));
colorSpinner.setBounds(frame.getWidth()/2 - 40,frame.getHeight()/3 - 20,80,40);
frame.add(colorSpinner);
JButton okButton = new JButton("OK");
okButton.setBounds(frame.getWidth()/2 - 40,frame.getHeight()/2 - 20,40);
okButton.addActionListener(event -> {
Color changingColor = new Color(0,0);
if (colorSpinner.getValue().equals("Red"))
changingColor = Color.RED;
else if (colorSpinner.getValue().equals("Green"))
changingColor = Color.GREEN;
else if (colorSpinner.getValue().equals("Blue"))
changingColor = Color.BLUE;
frame.dispose();
changing(changingColor);
});
frame.add(okButton);
frame.setVisible(true);
*/
}
public static JFrame newJFrame(String title) {
JFrame frame = new JFrame(title);
frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.setSize(1920,1080);
frame.setLayout(null);
return frame;
}
public static void changing(Color changingColor) {
Color color = changingColor;
JFrame frame = newJFrame("Color Changer // Main");
BufferedImage image = new BufferedImage(frame.getWidth(),frame.getHeight(),BufferedImage.TYPE_INT_RGB);
JLabel imageL = new JLabel();
imageL.setBounds(frame.getBounds());
imageL.setIcon(new ImageIcon(image));
frame.add(imageL);
frame.setVisible(true);
int x = 0,y = 0;
while (true) {
image.setRGB(x,y,color.getRGB());
imageL.setIcon(new ImageIcon(image));
frame.repaint();
x++;
if (x >= frame.getWidth()) {
x = 0;
y++;
if (y >= frame.getHeight()) {
y = 0;
if (color.equals(Color.RED)) {
color = Color.GREEN;
} else if (color.equals(Color.GREEN)) {
color = Color.BLUE;
} else if (color.equals(Color.BLUE)) {
color = Color.RED;
}
}
}
}
}
}
解决方法
以下代码是重复改变背景颜色的 const newData = async () => {
var x: any = [];
await lookup(
"GET","api/post/",(response: myArrays["posts"],status: number) => {
Object.assign(x,response);
}
);
return x;
};
console.log(newData().then((res) => res));
switch (action.type) {
case "SetData":
return { ...state,data: newData().then((res) => {return res}) };
default:
return state;
}
的 mre。
实施的主要变化是:
- 从 edt 中删除了循环。使用 Swing
JFrame
控制动画 - 在
Timer
而不是JPanel
上进行所有自定义绘画 - 在不使用
JFrame
的情况下更改了背景颜色(可以使用 BufferedImage,但不需要)。 - 使用
BufferedImage
而不是JOptionPane
来获取用户的输入
JFrame
,
在 doInBackground() 中发布无限 while 循环作品的 SwingWorker 效果很好。出于某种原因,当我之前尝试过 SwingWorker 时,我运行了一次,然后在完成后再次运行。显然,对于 Swing 并发性和 SwingWorkers 来说,这又是一个新事物。非常感谢@camickr 和@sorifiend!!