Java Swing:GUI 未更新某些属性 [英] Java Swing: GUI is not updating some properties

查看:26
本文介绍了Java Swing:GUI 未更新某些属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是一个最简单、最简单和可检查的问题

简历

我正在做一个拉丁方应用程序,它设置了一个大小为 s 的正方形,你需要给它着色一些限制,例如,在同一行或同一列中不能使用相同的颜色.

>

但我的问题不是问题本身,而是 Swing.

我正在尝试使用 Swing 来实现一些图形和更好的外观.

问题是,当我找到解决方案时,我想停下来几秒钟看一下,然后继续看其他人(我会用 Thread.sleep() 来做到这一点).

但我看到正方形没有被着色.只有当完成方法时,才会改变自己.

主要问题

仅显示它找到的最后一个解决方案,并在完成回溯方法时显示.

当我单击解析按钮时,有一个类实现了 ActionListener 接口,该类具有 actionPerformed 方法,该类调用主框架类的方法,该类解析正方形.所以问题是,如果我在找到解决方案时停止执行,GUI 不会改变,但是在内部,当我检查属性(调试)时,单元格的颜色已更新,但在 GUI 中没有.

我不知道为什么:(

更多细节

我的想法是,用两个面板制作一个框架,一个在左边,一个在中间(也许将来会在右边放一些东西).

为此,我使用 BorderLayout.

所以左边的第一个面板,类似于基本配置菜单,用户可以在其中设置正方形的大小并运行它以获得解决方案.

为此我有两个按钮,一个用于修改大小,另一个用于解决它.

所以我需要按钮的事件.尺寸没有给我带来问题,但解决了是的问题.

所以我检查了,如果我给一些正方形上色并暂停执行(Scanner.nextLine() 或 Thread.sleep())不会在 GUI 中进行更改,但是当我调试时,正方形被着色属性,所以我不太明白为什么会下降.

我认为问题出在哪里

所以我有一个按钮,可以在单击时解析方块.我想,我真的不知道,但我怀疑,这样做会创建一个新线程或其他东西,因此无法更新 GUI;并且只有在完成时才去做.

无论如何要改变这个?.

class ResolveListener 实现 ActionListener{@覆盖public void actionPerformed(ActionEvent e){int size = Integer.parseInt(textField.getText());latinSquareFrame.resolve(size);}}

<小时>

一个简单的问题

我已阅读评论以搜索与此类似的最小且易于检查的问题.

所以我做到了.这段代码和我的问题类似,有一个正方形,我想在点击按钮时给它上色.

问题是,如果我暂停它,它不会着色,只有在方法完成时才会着色,我不知道为什么.

我认为这与我之前遇到的问题相似.

这是我能够用于解决我遇到的问题的最少代码.

 包拉丁方;导入 javax.swing.*;导入 java.awt.*;导入 java.awt.event.ActionEvent;导入 java.awt.event.ActionListener;导入 java.util.Scanner;公开课测试{public static void main(String[] args){TestFrame testFrame = new TestFrame();}}类 TestFrame 扩展了 JFrame{公共测试框架(){this.setVisible(true);this.setBounds(400,300,400,300);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setLayout(new BorderLayout());TestJPanel testJPanel = new TestJPanel();this.add(testJPanel,BorderLayout.CENTER);TestContainerButtonJPanel testContainerButtonJPanel = new TestContainerButtonJPanel(testJPanel);this.add(testContainerButtonJPanel, BorderLayout.SOUTH);this.revalidate();this.repaint();}}类 TestContainerButtonJPanel 扩展了 JPanel{私有 JButton 解析;公共 TestJPanel testJPanel;公共 TestContainerButtonJPanel(TestJPanel testJPanel){this.testJPanel = testJPanel;this.setVisible(true);resolve = new JButton("RESOLVE");ActionListener resolveListener = new ResolveListener();resolve.addActionListener(resolveListener);this.add(resolve);}类 ResolveListener 实现 ActionListener{@覆盖public void actionPerformed(ActionEvent e){尝试 {TestContainerButtonJPanel.this.testJPanel.colourCells();} catch (InterruptedException e1) {e1.printStackTrace();}}}}类 TestJPanel 扩展了 JPanel{私人 JButton[][] 板;公共 TestJPanel(){this.board = new JButton[4][4];this.setVisible(true);this.setLayout(new GridLayout(4,4));for(int i=0; i<4;i++){for(int j=0; j<4;j++){JButton 单元格 = new JButton();board[i][j] = 单元格;board[i][j].setBackground(Color.WHITE);this.add(单元格);}}}public void colourCells() 抛出 InterruptedException {for(int i=0; i<4;i++){for(int j=0;j<4;j++){this.board[i][j].setBackground(Color.RED);线程睡眠(300);}}}}

解决方案

好的,首先:

  1. 不要使用 Thread.sleep() 更新您的 GUI,它会阻塞 EDT
  2. 您没有将程序放在 EDT 上,请参阅

    EDIT: A EASIEST, SIMPLE AND CHECKABLE PROBLEM BELOW

    RESUME

    I'm doing a Latin Square application, which, sets a square of size s, and you need to colour it with some restrictions such as, not the same color in the same row, or in the same column.

    But my trouble is not the problem itself, but Swing.

    I'm trying to do it with Swing for some graphics and better appearence.

    The problem it is, than when I have found a solution, I want to stop a few seconds for watch it, and then continue looking others (I will do this with a Thread.sleep()).

    But I'm watching that the square is not getting coloured. Only when finish the method, changes itself.

    MAIN PROBLEM

    Only show the last solution that it founds and shows when finish the Backtracking method.

    When I click on the resolve button, there is a class which implements ActionListener interface which has the actionPerformed method, that calls a method of the main frame class, which resolve the square. So the problem is, that if I stop the execution when it find a solution, the GUI doesn't changes, but internaly, when I check the properties (debugging) the cell has the color updated, but not in the GUI.

    And I don't know why :(

    MORE DETAILED

    My idea, was, to make a frame with two pannels, one on the left, and one on the middle (maybe in the future, put something in the right).

    For that I use a BorderLayout.

    So the first pannel on the left, it's something like basic configuration menu, where the user can set the size of the square and run it for get the solution.

    For that I have two buttons, one for modify the size, and the other for resolve it.

    So I need events for the buttons. Size is not giving me problems, but resolve yes.

    So I checked out, than if I colour some square and pause the execution (Scanner.nextLine() or a Thread.sleep()) is not making changes in the GUI, but when I debug, the square is coloured in the properties, so I don't understand very well why is faling.

    WHERE I THINK IS THE PROBLEM

    So I have a button, which resolve the square when clicking on. And I think, I don't really know, but I suspect, that doing like this, creates a new Thread or something, so, can't updates the GUI; and only when finish, do it.

    There is anyway to change this?.

    class ResolveListener implements  ActionListener
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    int size = Integer.parseInt(textField.getText());
                    latinSquareFrame.resolve(size);
                }
            }
    


    A SIMPLE PROBLEM

    I have read in the comments to search a minimim and easy checkable problem similar to this.

    So I did. This code is similar to my problem, there is a square, I and I want to colour it when click the button.

    The problem is that, if I pause it, it's not coloured, only is coloured when the method finishes, and I don't know why.

    I think it's similar to the problem I have faced before.

    This is the minimum code I'm able to use for the problem I have.

        package LatinSquare;
    
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Scanner;
    
    public class Test
    {
        public static void main(String[] args)
        {
            TestFrame testFrame = new TestFrame();
        }
    }
    
    class TestFrame extends JFrame
    {
    
        public TestFrame()
        {
            this.setVisible(true);
            this.setBounds(400,300,400,300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLayout(new BorderLayout());
            TestJPanel testJPanel = new TestJPanel();
            this.add(testJPanel,BorderLayout.CENTER);
    
            TestContainerButtonJPanel testContainerButtonJPanel = new TestContainerButtonJPanel(testJPanel);
            this.add(testContainerButtonJPanel, BorderLayout.SOUTH);
    
            this.revalidate();
            this.repaint();
        }
    
    }
    
    class TestContainerButtonJPanel extends JPanel
    {
        private JButton resolve;
        public TestJPanel testJPanel;
    
        public TestContainerButtonJPanel(TestJPanel testJPanel)
        {
            this.testJPanel = testJPanel;
            this.setVisible(true);
            resolve = new JButton("RESOLVE");
            ActionListener resolveListener = new ResolveListener();
            resolve.addActionListener(resolveListener);
            this.add(resolve);
    
        }
    
        class ResolveListener implements ActionListener
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                try {
                    TestContainerButtonJPanel.this.testJPanel.colourCells();
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
    
    
        }
    }
    
    
    class TestJPanel extends JPanel
    {
        private JButton[][] board;
        public TestJPanel()
        {
            this.board = new JButton[4][4];
            this.setVisible(true);
            this.setLayout(new GridLayout(4,4));
            for(int i=0; i<4;i++)
            {
                for(int j=0; j<4;j++)
                {
                    JButton cell = new JButton();
                    board[i][j] = cell;
                    board[i][j].setBackground(Color.WHITE);
                    this.add(cell);
                }
            }
    
        }
    
        public void colourCells() throws InterruptedException {
            for(int i=0; i<4;i++)
            {
                for(int j=0;j<4;j++)
                {
                    this.board[i][j].setBackground(Color.RED);
                    Thread.sleep(300);
    
                }
            }
    
        }
    
    
    }
    

    解决方案

    Ok, first things first:

    1. Don't update your GUI using Thread.sleep() it will block the EDT
    2. You're not placing your program on the EDT, see point number 2 in this answer
    3. Don't extend JFrame, instead create an instance of it, see: Extends JFrame vs. creating it inside the program
    4. Don't make your program visible (i.e. call setVisible(...)) before adding all the components to it. It may cause your program to behave in a wrong manner.
    5. Try not creating your own threads, instead use a Swing Timer or a Swing Worker (links in the question's comments)

    So, taking all of that into consideration, I decided to create a new program that follows all the above rules and makes the cells blue for 3 seconds or white after that time has passed, and also updates the text in the JButton as well as disabling to prevent multiple timers executing at once.

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.BoxLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.Timer;
    
    public class Test {
        private JFrame frame;
        private JPanel pane;
        private JPanel cellsPane;
        private MyCell[][] cells;
        private JButton button;
        private Timer timer;
    
        private int counter = 3;
        private boolean isFinished = false;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> new Test().createAndShowGui());
        }
    
        private void createAndShowGui() {
            frame = new JFrame(getClass().getSimpleName());
    
            pane = new JPanel();
            cellsPane = new JPanel();
    
            pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
            cellsPane.setLayout(new GridLayout(4, 4, 5, 5));
    
            cells = new MyCell[4][4];
    
            for (int i = 0; i < cells.length; i++) {
                for (int j = 0; j < cells[i].length; j++) {
                    cells[i][j] = new MyCell(Color.WHITE);
                    cellsPane.add(cells[i][j]);
                }
            }
    
            button = new JButton("Press me!");
            timer = new Timer(1000, listener);
    
            button.addActionListener(e -> {
                button.setEnabled(false);
                isFinished = false;
                updateCellsColors();
                timer.start();
            });
    
            pane.add(cellsPane);
            pane.add(button);
    
            frame.add(pane);
            frame.pack();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    
        private void updateCellsColors() {
            for (int i = 0; i < cells.length; i++) {
                for (int j = 0; j < cells[i].length; j++) {
                    cells[i][j].setCellColor(isFinished ? Color.WHITE : Color.BLUE);
                }
            }
        }
    
        private ActionListener listener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (counter == 0) {
                    timer.stop();
                    counter = 3;
                    isFinished = true;
                    button.setEnabled(true);
                    updateCellsColors();
                }
                if (isFinished) {
                    button.setText("Press me!");
                } else {
                    button.setText("You have " + counter + " seconds remaining");
                }
                counter--;
            }
        };
    }
    
    @SuppressWarnings("serial")
    class MyCell extends JPanel {
        private Color cellColor;
    
        public Color getCellColor() {
            return cellColor;
        }
    
        public void setCellColor(Color cellColor) {
            this.cellColor = cellColor;
            this.setBackground(cellColor);
        }
    
        public MyCell(Color cellColor) {
            this.cellColor = cellColor;
            this.setOpaque(true);
            this.setBackground(cellColor);
        }
    
        @Override
        public Dimension getPreferredSize() {
            // TODO Auto-generated method stub
            return new Dimension(30, 30);
        }
    }
    

    You can copy-paste it and see the same result as me:

    这篇关于Java Swing:GUI 未更新某些属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆