Почему setText не обновляет JLabel?

Я проверил другие темы здесь и не нашел решения.

1) JFrame имеет значение setVisible (true).

2) Что это означает: «Интересно, является ли ваша проблема проблемой параллелизма, что вы выполняете длительный процесс в потоке событий Swing и что это не позволяет вашей метке обновлять свой текст». Я читал это где-то еще.

3) Я не инициализировал несколько раз JPanel, содержащий метку.

РЕДАКТИРОВАТЬ: 4) updateTurn вызывается из JPanel, который содержит TrackingPanel (т.е. gamePanel). Я вызываю метод changeTurns(); и вот его код:

public void changeTurns() {
    if(turnPlayer == playerX)
        turnPlayer = playerO;
    else
        turnPlayer = playerX;

    trackingPanel.updateTurn();
}   

Вот соответствующий код полностью:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TrackingPanel extends JPanel{

    /*TURN STUFF*/
    private JPanel turnPanel; //turns panel to keep track of whose turn it is
    private JLabel turnLabel;
    private String turn;

    /*OTHER*/
    private GamePanel gamePanel;


    public TrackingPanel( GamePanel gamePan ) {

        setLayout( new GridLayout(1,4) );
        setBorder(BorderFactory.createMatteBorder(2,2,4,2,Color.BLACK));

        gamePanel = gamePan;

        /*THIS PANEL DISPLAYS THE TEXT*/
        turnPanel = new JPanel( new GridLayout(2,1) );
        turn = gamePanel.getPlayerTurn().getLetter();
        turnLabel = new JLabel("      Player " + turn + "'s turn");
        add( turnPanel);

    }//end constructor

    /*THIS IS WHERE THINGS GO WRONG*/
    public void updateTurn() {

        turn = gamePanel.getPlayerTurn().getLetter();
        turnLabel.setText( "      Player" + turn + "'s turn" );
        System.out.println(turn);
    }
}

Перед вызовом updateTurn() turnLabel говорит "Ход игрока X". После этого должно быть написано «Ход PlayerO». Распечатав turn (я получаю строку «O» вместо «X»), я знаю, что то, что отображается («Ход ИгрокаX»), не должно отображаться («Ход Игрока0»).

Заранее спасибо умникам!

РЕДАКТИРОВАТЬ. Пробовал дать SSCCE, но не знаю, как включить файлы изображений. Прости!


person Alex Silverman    schedule 08.07.2013    source источник
comment
где вы вызываете updateTurn() ?   -  person David Hofmann    schedule 09.07.2013
comment
Что происходит, когда вы пытаетесь добавить вызов validate после добавления ярлыка?   -  person crand6    schedule 09.07.2013
comment
мне просто написать validate() после добавления метки? Если да, то ничего не произошло. Кроме того, я должен отметить, что JLabel не нужно добавлять. setText() должен просто изменить текст для текущей JLabel. Я вынул второй вызов panel.add(JLabel) в вопросе выше.   -  person Alex Silverman    schedule 09.07.2013
comment
Вам следует создать и опубликовать sscce, минимальную компилируемую и исполняемую программу, которая демонстрирует вашу проблему, но делает только это и не более того. так что мы можем протестировать код для себя и помочь вам найти проблему. В противном случае мы вынуждены делать дикие догадки.   -  person Hovercraft Full Of Eels    schedule 09.07.2013
comment
Кажется, это так много работы, потому что у меня сотни строк кода, и я не уверен, что здесь уместно. я буду работать над этим   -  person Alex Silverman    schedule 09.07.2013
comment
@Alex: если ты не уверен, что имеет значение, то мы, черт возьми, тоже не уверены. Если вы не получите решение в ближайшее время, попробуйте, так как это стоящее упражнение. По мере вашего продвижения в обучении кодированию вы обнаружите, что в любом случае вы будете создавать больше этих sscce — вы будете создавать больше (почти все) классов, которые можно тестировать изолированно, а затем будете тестировать их, прежде чем добавлять в любую большую сложную программу.   -  person Hovercraft Full Of Eels    schedule 09.07.2013
comment
Ваша ссылка на код не является sscce, поскольку она не компилируется для нас без изменений, она использует недоступные нам ресурсы, включая изображения. , и в нем много кода, не связанного с рассматриваемой проблемой. Проблема в том, что это означает, что нам нужно пройти через много кода, который не имеет отношения к проблеме, что затрудняет нам понимание проблемы и помощь в ее устранении. Пожалуйста, поймите, что мы волонтеры, и у нас ограниченное время, чтобы помочь. Чтобы создать полезный sscce, нужно немного потрудиться, чтобы убрать ненужный код.   -  person Hovercraft Full Of Eels    schedule 09.07.2013
comment
извините, я вынул сотни строк кода. Я хотел убедиться, что его можно компилировать и запускать, что требует включения некоторых других фрагментов кода. У меня возникли проблемы с выяснением того, как сделать SSCCE, который компилируется и содержит изображения и прочее.   -  person Alex Silverman    schedule 09.07.2013
comment
Кроме того, ваш код даже не добавляет отслеживание JLabel к чему-либо, отображаемому в графическом интерфейсе. Даже если я смогу заставить ваш код работать (и с некоторыми усилиями он работает), я нигде не вижу JLabel, потому что он ни к чему не добавляется. также не включайте изображения, а вместо этого запустите sscce без изображений. Просто покажите текст письма, установив текст JButton, а не его значок.   -  person Hovercraft Full Of Eels    schedule 09.07.2013
comment
Я случайно удалил строку, добавляющую метку в JPanel. ЭТО делает это. Вы правы насчет изображений. Итак, что мне сделать, чтобы он автоматически компилировался?   -  person Alex Silverman    schedule 09.07.2013
comment
Начните с кода, который я разместил. Подумайте о том, чтобы поместить этот код в другой пакет и запустить его. Вы увидите, что метка меняет текст.   -  person Hovercraft Full Of Eels    schedule 09.07.2013
comment
Я не видел код, который вы разместили, но SSCCE был отличной идеей. Я понял это, просто работая в обратном направлении. Это было из-за paintComponent и какой-то глупости, которую я где-то видел.   -  person Alex Silverman    schedule 09.07.2013
comment
Код, который я разместил, находится в моем ответе ниже. Блин, я выложил это 2 часа назад. 1/2 часа моей жизни... пропали.   -  person Hovercraft Full Of Eels    schedule 09.07.2013


Ответы (3)


Попробуйте использовать это:

 private void setText(final JLabel label, final String text){
    label.setText(text);
    label.paintImmediately(label.getVisibleRect());
 }
person Community    schedule 23.08.2013
comment
нет, определенно не нужно - плюс это может иметь катастрофические последствия, если отменить EDT - person kleopatra; 24.08.2013
comment
Это сработало именно так, как мне было нужно, так как после этого я сразу запускал функцию зависания. - person Robobenklein; 03.11.2014
comment
В чем причина использования paintImmediately - person Shiladittya Chakraborty; 07.01.2016
comment
Это действительно сработало для меня! Мне нужно было обновить метку, показывающую текущее имя файла, которое обрабатывает моя программа. Он делает свою работу, без каких-либо побочных эффектов! - person FonzTech; 02.09.2017

Я хотел бы убедиться, что ваш метод updateTurn() вызывает свой код в потоке Swing, используя метод SwingUtilities.invokeLater(new Runnable()).

person P. Lalonde    schedule 08.07.2013
comment
Жаль, что я не знаком с этим методом. Я вижу, что он должен быть включен в метод main(), но что мне добавить в метод SwingUtilities? - person Alex Silverman; 09.07.2013
comment
Часть setText должна быть помещена туда, это гарантирует, что обновление компонента Swing будет выполнено в правильном потоке. - person P. Lalonde; 09.07.2013

Я изменил ваш код, чтобы он не требовал изображений, и теперь добавлена ​​функция turnLabel. Он все еще слишком велик, но работает и показывает некоторые особенности поведения:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.*;

public class GameFrame extends JFrame {

   public static void main(String[] args) {

      JFrame gameFrame = new JFrame("MyGame");

      gameFrame.setResizable(false);
      gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      gameFrame.add(new GamePanel());
      gameFrame.pack();
      gameFrame.setVisible(true);

   }
}

class GamePanel extends JPanel implements ActionListener {

   private BoardPanel boardPanel; // comprised of 9 mini panels
   /* RELEVANT */
   private static TrackingPanel trackingPanel; // keeps track of score, turn,
                                               // and stuff
   private static Player playerX, playerO, turnPlayer;
   private ArrayList<MiniGame> miniGames;
   private Graphics graphics;
   private Graphics2D graphics2D;

   // constructor
   public GamePanel() {

      super(new BorderLayout());
      setFocusable(true);

      // create 2 new players, and make it X's turn
      playerX = new Player(true, "X");
      turnPlayer = playerX;
      playerO = new Player(true, "O");

      // create tracking panel that will keep track of turns and stuff
      trackingPanel = new TrackingPanel(this);
      trackingPanel.setBorder(BorderFactory.createLineBorder(Color.red)); //!!
      System.out.println("line border added");

      // create panel that will hold the 9 mini games
      boardPanel = new BoardPanel(this);

      // add actionListeners to each button
      miniGames = boardPanel.getMiniGames();
      for (MiniGame mini : miniGames) {
         for (SquareButton button : mini.getSquares())
            button.addActionListener(this);
      }

      // add the tracking and board panels
      add(trackingPanel, BorderLayout.NORTH);
      add(boardPanel, BorderLayout.CENTER);
   }// end constructor

   public void actionPerformed(ActionEvent e) {

      // loop through mini games
      miniGameLoop: for (int gameNum = 0; gameNum < 9; gameNum++) {
         MiniGame mini = miniGames.get(gameNum);
         SquareButton[] buttons = mini.getSquares();

         // loop through buttons of each mini game
         for (int buttonNum = 0; buttonNum < 9; buttonNum++) {
            SquareButton button = buttons[buttonNum];

            // if user clicked on one of the squares on the board
            if (e.getSource() == button) {

               // if the space isn't already taken
               if (button.isEmpty()) {

                  //  mark the space with the player's letter
                  // !! removed
                  // ImageIcon icon = new ImageIcon(getClass().getResource(
                  // "/Images/" + turnPlayer.getLetter() + ".PNG"));
                  // button.setIcon(icon);
                  button.setText(turnPlayer.getLetter()); //!! added
                  button.setEmpty(false);

                  // change turns
                  changeTurns();

                  // exit loops
                  break miniGameLoop;
               }
            }
         }// end loop through squares
      }// end loop through minigames
   }// end actionPerformed method

   public static Player getPlayer(String letter) {
      if (letter == "X")
         return playerX;
      else
         return playerO;
   }

   public Player getPlayerTurn() {
      return turnPlayer;
   }

   public TrackingPanel getTrackingPanel() {
      return trackingPanel;
   }

   /* RELEVANT */
   public void changeTurns() {
      if (turnPlayer == playerX)
         turnPlayer = playerO;
      else
         turnPlayer = playerX;

      trackingPanel.updateTurn();
   }
}// end class GamePanel

class BoardPanel extends JPanel {

   private ArrayList<MiniGame> miniGames;

   // constructs main panel and places all 9 mini games inside
   public BoardPanel(GamePanel gp) {
      super(new GridLayout(3, 3));

      // add miniGames to arrayList
      miniGames = new ArrayList<MiniGame>(9);
      for (int i = 1; i <= 9; i++)
         miniGames.add(new MiniGame(gp, i));

      // add minigames to board
      for (MiniGame mini : miniGames)
         add(mini);
   }

   public void reset() {
      for (MiniGame mini : miniGames)
         mini.clear();
   }

   public ArrayList<MiniGame> getMiniGames() {
      return miniGames;
   }
}

@SuppressWarnings("serial")
class TrackingPanel extends JPanel {

   /* TURN STUFF */
   private JPanel turnPanel; // turns panel to keep track of whose turn it is
   private JLabel turnLabel;
   private String turn;

   /* OTHER */
   private GamePanel gamePanel;

   public TrackingPanel(GamePanel gamePan) {

      setLayout(new GridLayout(1, 4));
      setBorder(BorderFactory.createMatteBorder(2, 2, 4, 2, Color.BLACK));

      gamePanel = gamePan;

      /* THIS PANEL DISPLAYS THE TEXT */
      turnPanel = new JPanel(new GridLayout(2, 1));
      turn = gamePanel.getPlayerTurn().getLetter();
      turnLabel = new JLabel("      Player " + turn + "'s turn");
      turnPanel.add(turnLabel);
      add(turnPanel);

   }// end constructor

   /* THIS IS WHERE THINGS GO WRONG */
   public void updateTurn() {

      turn = gamePanel.getPlayerTurn().getLetter();
      turnLabel.setText("      Player" + turn + "'s turn");
      System.out.println(turn);
   }
}

class MiniGame extends JPanel {

   private SquareButton[] squares;
   private SquareButton[] line1, line2, line3, line4, line5, line6, line7,
         line8;
   private ArrayList<SquareButton[]> lines;
   private int ThreeinARowButtonCount;
   private int panelNum;
   private TrackingPanel trackingPanel;
   private int[] winningLine;
   private Player winner;
   private boolean gameIsOver;
   private Image gameOverIcon;

   public MiniGame(GamePanel gp, int num) {

      // setlayout of the mini games
      super(new GridLayout(3, 3));
      setFocusable(true);
      setPreferredSize(new Dimension(220, 220));

      // setPreferredSize(new Dimension(100,100));
      trackingPanel = gp.getTrackingPanel();
      panelNum = num;

      if (panelNum == 1)
         setBorder(BorderFactory.createMatteBorder(0, 0, 2, 2, Color.BLACK));
      else if (panelNum == 2)
         setBorder(BorderFactory.createMatteBorder(0, 2, 2, 2, Color.BLACK));
      else if (panelNum == 3)
         setBorder(BorderFactory.createMatteBorder(0, 2, 2, 0, Color.BLACK));
      else if (panelNum == 4)
         setBorder(BorderFactory.createMatteBorder(2, 0, 2, 2, Color.BLACK));
      else if (panelNum == 5)
         setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.BLACK));
      else if (panelNum == 6)
         setBorder(BorderFactory.createMatteBorder(2, 2, 2, 0, Color.BLACK));
      else if (panelNum == 7)
         setBorder(BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK));
      else if (panelNum == 8)
         setBorder(BorderFactory.createMatteBorder(2, 2, 0, 2, Color.BLACK));
      else
         setBorder(BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK));

      // create list of buttons (each square)
      squares = new SquareButton[9];

      // create squares and add squares to mini game
      for (int i = 0; i < squares.length; i++) {
         squares[i] = new SquareButton(i);
         add(squares[i]);
      }
   }// end constructor

   public void clear() {
      // TODO this method was not present!!!!! Trying to reconstruct it

   }

   public int getPanelNum() {
      return panelNum;
   }

   public SquareButton[] getSquares() {
      return squares;
   }

   public boolean isOver() {
      return gameIsOver;
   }
}

class SquareButton extends JButton {

   private boolean empty;
   private String letter;
   private int squareNum;

   public SquareButton(int num) {
      empty = true;
      squareNum = num;

      if (num == 0)
         setBorder(BorderFactory.createMatteBorder(0, 0, 1, 1, Color.BLACK));
      else if (num == 1)
         setBorder(BorderFactory.createMatteBorder(0, 1, 1, 1, Color.BLACK));
      else if (num == 2)
         setBorder(BorderFactory.createMatteBorder(0, 1, 1, 0, Color.BLACK));
      else if (num == 3)
         setBorder(BorderFactory.createMatteBorder(1, 0, 1, 1, Color.BLACK));
      else if (num == 4)
         setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.BLACK));
      else if (num == 5)
         setBorder(BorderFactory.createMatteBorder(1, 1, 1, 0, Color.BLACK));
      else if (num == 6)
         setBorder(BorderFactory.createMatteBorder(1, 0, 0, 1, Color.BLACK));
      else if (num == 7)
         setBorder(BorderFactory.createMatteBorder(1, 1, 0, 1, Color.BLACK));
      else
         setBorder(BorderFactory.createMatteBorder(1, 1, 0, 0, Color.BLACK));

   }

   public String getLetter() {
      return letter;
   }

   public boolean isEmpty() {
      return empty;
   }

   public void setEmpty(boolean em) {
      empty = em;
   }

   public int getSquareNum() {
      return squareNum;
   }
}

class Player {

   private boolean human; // indicates if player is human or cpu
   private int score;
   private String letter;

   // constructor
   public Player(boolean hum, String let) {

      // player is human or computer
      human = hum;
      letter = let;
   }

   /* PLAYER METHODS */
   public boolean isHuman() {
      return human;
   }

   public void setHuman(boolean h) {
      human = h;
   }

   public String getLetter() {
      return letter;
   }
}

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

2) Что это означает: «Интересно, является ли ваша проблема проблемой параллелизма, что вы выполняете длительный процесс в потоке событий Swing и что это не позволяет вашей метке обновлять свой текст». Я читал это где-то еще.

Так что, возможно, у вас есть длительный процесс, который вы не показали нам в приведенном выше коде.

Кроме того, ваш код имеет чрезмерное использование анти-шаблона статических полей. Большинство статических полей не должны быть статическими.

person Hovercraft Full Of Eels    schedule 08.07.2013