简体   繁体   English

Java Swing:GUI 未更新某些属性

[英]Java Swing: GUI is not updating some properties

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.我正在做一个拉丁方应用程序,它设置了一个大小为 s 的正方形,您需要使用一些限制为其着色,例如在同一行或同一列中使用不同的颜色。

But my trouble is not the problem itself, but Swing.但我的麻烦不是问题本身,而是 Swing。

I'm trying to do it with Swing for some graphics and better appearence.我正在尝试使用 Swing 来实现一些图形和更好的外观。

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()).问题是,当我找到解决方案时,我想停下几秒钟观看它,然后继续寻找其他人(我将使用 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.当我单击解析按钮时,有一个类实现了 ActionListener 接口,该接口具有 actionPerformed 方法,该类调用主框架类的方法,该类解析正方形。 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.所以问题是,如果我在找到解决方案时停止执行,GUI 不会改变,但是在内部,当我检查属性(调试)时,单元格的颜色已更新,但在 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.为此,我使用 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.所以我检查了,如果我给一些方块着色并暂停执行(Scanner.nextLine() 或 Thread.sleep())不会在 GUI 中进行更改,但是当我调试时,方块在属性中被着色,所以我不太明白为什么下降。

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;我想,我真的不知道,但我怀疑,这样做会创建一个新线程或其他东西,因此无法更新 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不要使用Thread.sleep()更新您的 GUI,它会阻止 EDT
  2. You're not placing your program on the EDT, see point number 2 in this answer您没有将程序放在 EDT 上,请参阅此答案中的第 2 点
  3. Don't extend JFrame , instead create an instance of it, see: Extends JFrame vs. creating it inside the program不要扩展JFrame ,而是创建它的一个实例,请参阅: 扩展 JFrame 与在程序中创建它
  4. Don't make your program visible (ie call setVisible(...) ) before adding all the components to it.在将所有组件添加到它之前,不要让您的程序可见(即调用setVisible(...) )。 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)尽量不要创建自己的线程,而是使用Swing TimerSwing Worker (问题评论中的链接)

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.因此,考虑到所有这些,我决定创建一个遵循上述所有规则的新程序,并在该时间过后使单元格蓝色 3 秒或白色,并更新JButton的文本以及禁用防止多个定时器同时执行。

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:您可以复制粘贴它并看到与我相同的结果:

在此处输入图片说明 在此处输入图片说明

Need another Thread for fix it.需要另一个线程来修复它。

Changing the listener class, works fine:更改侦听器类,工作正常:

 class ResolveListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    try {
                        TestContainerButtonJPanel.this.testJPanel.colourCells();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            }).start();
        }


    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM