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。
实施的主要变化包括:

  • 已从edt中删除循环。使用Swing
    计时器来控制动画
  • 是否在
    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;
            }
        }