Я новичок в Java Swing, и я работал над созданием игры Connect 4, которая поддерживает многопользовательскую систему через сервер с gameRoom. Я работаю над этой конкретной проблемой почти 2 дня, и при ее решении возникли такие проблемы, как прекращение использования Thread.sleep и тщательное тестирование, что объект Game передается правильно на сервер и с сервера.Java Swing 2D массив панелей, не перекраивающихся с помощью таймеров Swing
Способ, которым я сконструирован, состоит в том, что каждое перемещение передается с помощью команды перемещения модели. Чтобы обновить GUI, сервер отправляет обратно новый объект Game в модель и помечает атрибут контроллера setRepaint как истинный. Затем таймер периодически проверяет, является ли этот атрибут истинным и вызывает метод repaintGrid().
После многих часов попыток заставить это работать, я не могу заставить игровые панели перекрашивать.
Некоторые моменты, которые могут помочь:
Если я выйти из приложения и перезапустить его с объектом игры, что уже есть ходы на него, панели окрашены. Проблема заключается в методе repaint.
Модель статична и получает ее. Атрибут игры обновляется каждый раз, когда вызывается Connect4App.model.getGameFromServer(). Не уверен, что это вызовет проблемы, но если я распечатаю панели, которые перекрашиваются как красные/синие, я могу проверить, что игровой объект успешно обновляется сервером на каждой итерации.
Иерархия кадров следующая: GuiMain является контейнером для игрыPanel, который имеет gridlayout, каждый из которых заполняется панелью GridPanel. В сетчатых панелей, по существу, слоты для токенами Connect4 игры и те из них, которые я пытаюсь обновить в методе repaintGrid
import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JPanel; import javax.swing.Timer; public class GameController { MouseAdapter me; private JPanel gamePanel; private boolean setRepaint = false; /** * Constructor for the Game Controller. Takes in a view and a model * * @param view * @param model */ public GameController() { setupGridPanels(); setupMouseAdapter(); Connect4App.frame.setContentPane(Connect4App.guiMain); Connect4App.frame.setTitle("Game View"); goIntoTimer(); } /** * Repaint Boolean used by timer. Set to true by external program */ public void setRepaint() { this.setRepaint = true; } /** * Swing Timer which checks if it needs to repaint every 8 seconds and if * so, calls repaintGrid */ private void goIntoTimer() { Timer timer = new Timer(50, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Connect4App.model.getGameFromServer(); if (setRepaint == true) { repaintGrid(); setRepaint = false; } } }); timer.setRepeats(true); timer.setDelay(8000); timer.start(); } /** * Sets up the Initial Game Panels in the Connect4App.guiMain panel */ private void setupGridPanels() { this.gamePanel = new JPanel(); this.gamePanel.removeAll(); // setting up the layout for, the game board. this.gamePanel.setLayout(new GridLayout(0, Connect4App.model.getGame().getGrid()[0].length)); int numberOfRows = Connect4App.model.getGame().getGrid().length; int numberOfColumns = Connect4App.model.getGame().getGrid()[0].length; for (int r = 0; r < numberOfRows; r++) { for (int c = 0; c < numberOfColumns; c++) { Connect4App.guiMain.setCircleArc(r, c, new GridPanel(r, c)); this.gamePanel.add(Connect4App.guiMain.getCircleArcs()[r][c]); } } Connect4App.guiMain.add(this.gamePanel); } /** * Sets up the mouse pressed event handleres for every panel */ private void setupMouseAdapter() { MouseAdapter mc = new MouseAdapter() { @Override public void mousePressed(MouseEvent mc) { GridPanel cell = (GridPanel) mc.getSource(); // this is the column that should go in the MakeMove message int column = cell.getColumn(); int row = cell.getRow(); if (Connect4App.model.getGame().getGrid()[row][column].getState() == 0) { System.out.println("attempting to make move"); Connect4App.model.makeMove(column); } } }; for (int r = 0; r < Connect4App.model.getGame().getGrid().length; r++) { for (int c = 0; c < Connect4App.model.getGame().getGrid()[0].length; c++) { Connect4App.guiMain.getCircleArcs()[r][c].addMouseListener(mc); } } } void repaintGrid() { // --> This is supposed to be working System.out.println("repainting"); for (int r = 0; r < Connect4App.model.getGame().getGrid().length; r++) { for (int c = 0; c < Connect4App.model.getGame().getGrid()[0].length; c++) { Connect4App.guiMain.getCircleArcs()[r][c].validate(); Connect4App.guiMain.getCircleArcs()[r][c].repaint(); } } } }
Любая помощь будет оценена :-D
Похоже, что использование статичности может быть проблемой. Также может возникнуть проблема между потоками, читающими/записывающими переменную состояния – MadProgrammer
Спасибо за ваш ответ @MadProgrammer. Я тестировал и кажется, что состояние обновляется должным образом в точке, когда метод paintComponent вызывается repaint: -s – mageofzema
Можете ли вы распечатать сообщение об отладке внутри циклов? (Кроме того, я могу ошибаться, но вы уверены, что 'validate()' правильный? Как насчет 'revalidate()' или 'invalidate()'? Это время, так как я сделал что-то вроде этого.) –