Java 当循环无限大时,框架会弄乱
因此,我有一个程序,它通过扫描仪获取一些值,然后相应地更改Java 当循环无限大时,框架会弄乱,java,swing,while-loop,jframe,swingworker,Java,Swing,While Loop,Jframe,Swingworker,因此,我有一个程序,它通过扫描仪获取一些值,然后相应地更改JFrame上的buffereImage。它改变帧的方式通过无限while循环无限期地继续。这可以快速工作(在几秒钟内清除整个1920x1080帧),并且在没有SwingWorker或InvokeLater或任何东西的情况下工作正常 为了更新远离扫描仪的程序,我决定在主程序开始之前制作另一帧来输入变量。新帧获取值,单击JButton后,会自动处理并将值发送到主程序 问题是,一旦这些变量被传递到主程序,该程序中的主框架将创建自己,但会冻结,
JFrame
上的buffereImage
。它改变帧的方式通过无限while循环无限期地继续。这可以快速工作(在几秒钟内清除整个1920x1080帧),并且在没有SwingWorker
或InvokeLater
或任何东西的情况下工作正常
为了更新远离扫描仪的程序,我决定在主程序开始之前制作另一帧来输入变量。新帧获取值,单击JButton
后,会自动处理并将值发送到主程序
问题是,一旦这些变量被传递到主程序,该程序中的主框架将创建自己,但会冻结,并且是完全透明的。这最初让我措手不及,因为我可以看到我的Eclipse窗口,但无法单击任何东西,因为框架挡住了我,覆盖了整个屏幕
我尝试并成功地使用了SwingWorker
和InvokeLater
,但它们覆盖帧所用的时间都从几秒钟变为30分钟左右(我计算过,实际上没有等那么久)。我不确定为什么我不能用一个帧来获取变量而不是一个扫描器,因为无论哪种方式,变量都会被传递到主程序,并且前一帧会被处理掉。我不太熟悉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, 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, 80, 40);
okButton.addActionListener(event -> {
Color changingColor = new Color(0, 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;
}
}
}
}
}
}
以下代码是重复更改背景颜色的
JFrame
的mre。实施的主要变化包括:
计时器来控制动画
JPanel
而不是JFrame
缓冲图像的情况下更改了背景色(可以使用缓冲图像,但不需要)
JOptionPane
获取用户输入,而不是JFrame
SwingWorker在doInBackground()中发布无限while循环的工作非常有效。出于某种原因,早些时候,当我尝试一个SwingWorker时,我运行了一次,然后在完成后再次运行。显然,对于Swing并发和SwingWorkers来说,这还是一个全新的概念。非常感谢@camickr和@sorifiend 我不太熟悉EDT或Swing事件队列,因此非常感谢您的帮助-请阅读上的Swing教程。对Swing组件的所有更新都应在EDT上进行。如果需要循环代码,请使用
SwingWorker
和“发布”结果。或者为动画使用摆动计时器。本教程还有一节介绍“如何使用Swing计时器”。不要使用扫描仪获取用户输入。在开始处理之前,请使用JOptionPane或自定义JDialog获取用户输入。请注意,使用SwingWorker不应导致此类任务的任何明显减速,但是,如果SwingWorker要正常运行,,而
循环需要在SwingWorker内部,您的代码中是否存在这种情况?如果是这样,请编辑您的问题以显示您对swing worker的尝试。提示:添加@Sorifind(或任何人,@
很重要)以通知此人新的评论。
import java.awt.*;
import java.util.Scanner;
import javax.swing.*;
public class Colors {
public static final int CLI = 0, GUI = 1;
private Color color = Color.RED;//default value
private static final int CYCLE_TIME = 1000;
private static final String[] colorsNames = {"Red", "Green", "Blue"};
public Colors(int userInputBy) {
if(userInputBy == CLI){
cliInput();
}else if (userInputBy == GUI){
guiInput();
}//or else use default
changing();
}
private void guiInput() {
//use JOptionPane to get input from user
JSpinner colorSpinner = new JSpinner(new SpinnerListModel(colorsNames));
int answer = JOptionPane.showOptionDialog(null, colorSpinner, "Select color", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE, null, null, null);
String colorName ="";
if (answer == JOptionPane.OK_OPTION) {// user selected a color
colorName = (String) colorSpinner.getValue();
}
colorByName(colorName);
}
private void cliInput() {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter Color Choice (Red/Green/Blue)");
String colorName = scanner.nextLine();
scanner.close();
colorByName(colorName);
}
private void colorByName(String colorName) {
if (colorName.equals(colorsNames[0])) {
color = Color.RED;
} else if (colorName.equals(colorsNames[1])) {
color = Color.GREEN;
} else if (colorName.equals(colorsNames[2])) {
color = Color.BLUE;
}
}
private void changing() {
JFrame frame = newJFrame("Color Changer // Main");
ChangingColorPane ccp = new ChangingColorPane(color);
frame.add(ccp);
frame.pack();
frame.setVisible(true);
//use swing time to animate
Timer timer = new Timer(CYCLE_TIME, e->{
changeColor();
ccp.setBgColor(color);
frame.repaint();
});
timer.start();
}
private void changeColor() {
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;
}
}
//do custom painting on a JPanel
class ChangingColorPane extends JPanel{
private static final int W = 400, H = 500;
private Color bgColor;
public ChangingColorPane(Color bgColor) {
this.bgColor = bgColor;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(bgColor);
g.fillRect(0, 0, getWidth(), getHeight());
}
@Override
public Dimension preferredSize() {
return new Dimension(W, H);
}
public void setBgColor(Color bgColor) {
this.bgColor = bgColor;
}
}
public static void main(String[] args) {
new Colors(1);
}
private static JFrame newJFrame(String title) {
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setUndecorated(true);
return frame;
}
}