Java Swing: GUI не обновляет некоторые свойства - PullRequest
2 голосов
/ 16 апреля 2019

РЕДАКТИРОВАТЬ: ПРОСТОЙ, ПРОСТОЙ И ПРОВЕРЯЕМЫЙ ЗАДАЧИ НИЖЕ

РЕЗЮМЕ

Я делаю приложение Латинского квадрата, которое устанавливаетквадрат размера s, и вам нужно покрасить его с некоторыми ограничениями, например, не одного цвета в том же ряду или в том же столбце.

Но моя проблема не в самой проблеме, а в Swing.

Я пытаюсь сделать это с помощью Swing для некоторой графики и лучшего внешнего вида.

Проблема в том, что когда я нашел решение, я хочу остановиться на несколько секунд дляпосмотрите его, а затем продолжайте искать других (я сделаю это с Thread.sleep ()).

Но я наблюдаю, что квадрат не окрашивается.Только когда закончите метод, он изменится.

ОСНОВНАЯ ПРОБЛЕМА

enter image description here

Показать только последнее решение, котороеон появляется и показывает, когда завершается метод Backtracking.

enter image description here

Когда я нажимаю кнопку разрешения, появляется класс, который реализует интерфейс ActionListener, который имеетМетод actionPerformed, который вызывает метод класса основного фрейма, который разрешает квадрат.Так что проблема в том, что если я остановлю выполнение, когда найду решение, графический интерфейс не изменится, но внутренне, когда я проверяю свойства (отладку), в ячейке обновляется цвет, но не в графическом интерфейсе.

И я не знаю почему: (

ПОДРОБНЕЕ

Моя идея состояла в том, чтобы сделать раму с двумя панелями, одна слеваи один посередине (возможно, в будущем, поместите что-нибудь справа).

Для этого я использую BorderLayout.

Итак, первая панель слева, это что-то вроде базовойМеню конфигурации, где пользователь может установить размер квадрата и запустить его для получения решения.

Для этого у меня есть две кнопки, одна для изменения размера, а другая для его разрешения.

Так что мне нужны события для кнопок. Размер не доставляет мне проблем, но решает да.

Итак, я проверил, чем если я раскрасю квадрат и приостановлю выполнение (Scanner.nextLine () илиThread.sleep ()) не вносит изменения в графический интерфейс, но когдаЯ отлаживаю, квадрат в свойствах раскрашен, поэтому я не очень хорошо понимаю, почему это фейлинг.

ГДЕ Я ДУМАЮ, ЧТО ПРОБЛЕМА

Итак, у меня есть кнопка, которая разрешает квадрат при нажатии на.И я думаю, я на самом деле не знаю, но я подозреваю, что при этом создается новый поток или что-то, поэтому не может обновлять графический интерфейс;и только когда закончите, сделайте это.

Есть что-нибудь, чтобы изменить это?.

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

ПРОБНАЯ ПРОБЛЕМА

Iпрочитал в комментариях, чтобы найти минимальную и легко проверяемую проблему, подобную этой.

Так я и сделал.Этот код похож на мою проблему, есть квадрат, я и я хочу покрасить его, когда нажмем кнопку.

Проблема в том, что, если я сделаю паузу, он не цветной, а только цветной, когдаметод завершается, и я не знаю почему.

Я думаю, что это похоже на проблему, с которой я сталкивался ранее.

Это минимальный код, который я могу использовать для решения этой проблемы.иметь.

    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);

            }
        }

    }


}

Ответы [ 2 ]

2 голосов
/ 18 апреля 2019

Хорошо, обо всем по порядку:

  1. Не обновляйте свой графический интерфейс с помощью Thread.sleep(), это заблокирует EDT
  2. Вы не размещаете свою программу на EDT,см. пункт 2 в этом ответе
  3. Не расширяйте JFrame, вместо этого создайте его экземпляр, см .: Расширяет JFrame по сравнению с созданием его внутри программы
  4. Не делайте вашу программу видимой (например, вызывайте setVisible(...)), прежде чем добавлять все компоненты к ней.Это может привести к неправильному поведению вашей программы.
  5. Попробуйте не создавать свои собственные потоки, вместо этого используйте Swing Timer или Swing Worker (ссылки в комментариях к вопросу)

Итак, принимая во внимание все это, я решил создать новую программу, которая следует всем вышеперечисленным правилам и делает ячейки голубыми в течение 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);
    }
}

Вы можете скопировать и вставить его и увидеть тот же результат, что и у меня:

enter image description hereenter image description here

0 голосов
/ 17 апреля 2019

Нужен другой поток для исправления.

Изменение класса слушателя, работает нормально:

 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();
        }


    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...