2014-11-11 3 views
0

У меня есть CardLayout, состоящий из множества разных JPanels, которые я показываю по своему усмотрению. Этот GUI связан с бэкэнд, а цель графического интерфейса - позволить пользователю манипулировать данными, которые хранятся в бэкэнд.Обновление JLables в CardLayout при отображении следующей панели

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

Пример: Вот как мой JLabel инициализируется

CurrentBAName = new javax.swing.JLabel(); 
CurrentBAName.setText(GUI.currentBankAccount.getAccountName()); 

Проблема заключается в том, когда я изменить значение GUI.currentBankAccount.getAccountName(), текст на моем JLabel не обновляется. У меня есть JLabels, как это повсюду, и было бы больно пройти и вручную вызвать setText на всех из них каждый раз, когда пользователь делает какие-либо изменения. Есть ли способ, которым я могу заставить JLabel автоматически обновлять себя при изменении значения этой переменной?

Возможно, я мог бы реализовать какой-то шаблон наблюдателя? Как мне это сделать с JLabels?
Или, может быть, я мог бы использовать событие focusGained, чтобы каждый раз, когда я переключался на панель, событие focusGained срабатывало, чтобы я мог обновлять вещи. Я не уверен, как это сделать, и я не уверен, как сфокусироваться на CardLayout. Возможно, это просто метод, который вызывается каждый раз, когда я показываю панель с layout.show(..). Как бы это реализовать?
Есть ли лучший способ?

обновление: Пример кода

GUI.java мой основной класс GUI и будет состоять из JPanel, к которому будут добавлены и показаны на волю всех моих страниц будет.

import javax.swing.*; 

public class GUI extends javax.swing.JFrame 
{ 
    public static String item; 
    private javax.swing.JPanel MainPanel; 

    public GUI() 
    { 
     // creates a JPanel called MainPanel which will hold the cards 
     // in my CardLayout 
     initComponents(); 
    } 

    private void initComponents() 
    { 

     MainPanel = new javax.swing.JPanel(); 

     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

     MainPanel.setBackground(new java.awt.Color(198, 118, 38)); 
     MainPanel.setMaximumSize(new java.awt.Dimension(1000, 1000)); 
     MainPanel.setName(""); // NOI18N 
     MainPanel.setPreferredSize(new java.awt.Dimension(1024, 768)); 
     MainPanel.setLayout(new java.awt.CardLayout()); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(
       layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
       .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 
         .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 
         .addComponent(MainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 
         .addContainerGap()) 
     ); 
     layout.setVerticalGroup(
       layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
       .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 
         .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 
         .addComponent(MainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 
         .addContainerGap()) 
     ); 

     pack(); 
     setLocationRelativeTo(null); 

    } 

    // Grab the panel that was created in initComponents() so that I can add 
    // other panels to it 
    public JPanel getMainPanel() 
    { 
     return MainPanel; 
    } 

    public static void main(String args[]) 
    { 
     java.awt.EventQueue.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       GUI mainGUI = new GUI(); 

       // The JLabel in DisplayPanel.java will initially say root 
       item = "root"; 

       JPanel cardHolder = mainGUI.getMainPanel(); 
       //This panel contains a button which will update the name of 
       //the currentUserAccount 
       MainMenuPanel mainMenu = new MainMenuPanel(cardHolder); 
       cardHolder.add(mainMenu, "MainMenu"); 

       //This panel holds a JLabel that I want to have updated automatically 
       //when the user presses the button on MainMenuPanel 
       DisplayPanel display = new DisplayPanel(cardHolder); 
       cardHolder.add(display, "Display"); 

       mainGUI.pack(); 
       mainGUI.setVisible(true); 
      } 
     }); 
    } 
} 

DisplayPanel.java будет JPanel с JLabel, что я хочу, чтобы обновить на нем

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

public class DisplayPanel extends javax.swing.JPanel 
{ 
    private JPanel MainPanel; 

    public DisplayPanel(JPanel MainPanel) 
    { 

     this.MainPanel = MainPanel; 
     initComponents(); // Creates my panel with the JLabels/buttons etc 
    } 

    @SuppressWarnings("unchecked")     
    private void initComponents() 
    { 

     jLabel1 = new javax.swing.JLabel(); 
     GoToMainMenuButton = new javax.swing.JButton(); 

     jLabel1.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N 
     jLabel1.setText(GUI.item); // sets the JLabel to the GUI.item variable 

     GoToMainMenuButton.setText("Go to MainMenuPanel"); 
     GoToMainMenuButton.addMouseListener(new java.awt.event.MouseAdapter() 
     { 
      public void mouseClicked(java.awt.event.MouseEvent evt) 
      { 
       GoToMainMenuButtonMouseClicked(evt); 
      } 
     }); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); 
     this.setLayout(layout); 
     layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 
       .addContainerGap(269, Short.MAX_VALUE) 
       .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
        .addComponent(GoToMainMenuButton) 
        .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 145, javax.swing.GroupLayout.PREFERRED_SIZE)) 
       .addGap(266, 266, 266)) 
     ); 
     layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addGap(168, 168, 168) 
       .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE) 
       .addGap(83, 83, 83) 
       .addComponent(GoToMainMenuButton) 
       .addContainerGap(116, Short.MAX_VALUE)) 
     ); 
    }      

    private void GoToMainMenuButtonMouseClicked(java.awt.event.MouseEvent evt)             
    { 
     // go back to the MainPanel           
     CardLayout layout = (CardLayout) (MainPanel.getLayout()); 
     layout.show(MainPanel, "MainMenu"); 
    }            

    private javax.swing.JButton GoToMainMenuButton; 
    private javax.swing.JLabel jLabel1; 

} 

MainMenuPanel.java будет JPanel с кнопкой на нем, которая при нажата, обновит переменную, для которой установлен текст JLabel в DisplayPanel.

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

public class MainMenuPanel extends javax.swing.JPanel 
{ 

    private JPanel MainPanel; 

    public MainMenuPanel(JPanel MainPanel) 
    { 

     this.MainPanel = MainPanel; 
     initComponents(); // Creates my panel with the JLabels/buttons etc 
    } 

    @SuppressWarnings("unchecked")       
    private void initComponents() 
    { 

     GoToDisplayPanelButton = new javax.swing.JButton(); 

     GoToDisplayPanelButton.setText("Press Me"); 
     GoToDisplayPanelButton.addMouseListener(new java.awt.event.MouseAdapter() 
     { 
      public void mouseClicked(java.awt.event.MouseEvent evt) 
      { 
       GoToDisplayPanelButtonMouseClicked(evt); 
      } 
     }); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); 
     this.setLayout(layout); 
     layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addGap(252, 252, 252) 
       .addComponent(GoToDisplayPanelButton) 
       .addContainerGap(260, Short.MAX_VALUE)) 
     ); 
     layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 
       .addContainerGap(198, Short.MAX_VALUE) 
       .addComponent(GoToDisplayPanelButton) 
       .addGap(175, 175, 175)) 
     ); 
    }      

    private void GoToDisplayPanelButtonMouseClicked(java.awt.event.MouseEvent evt)              
    {               
     // Changes the value of item. I want this change to be reflected on my 
     // JLabel in DisplayPanel.java, but it is not because I do not explicitly 
     // call setText on the JLabel here. I am wondering if there is a way to 
     // have my JLabel automatically update when the variable in its setText 
     // is changed, without having to directly call setText. Or some other 
     // way to update it without calling setText every time I change something. 
     GUI.item = "new value"; 

     // Switches to my DisplayPanel which should show the updated name in its JLabel 
     CardLayout layout = (CardLayout)(MainPanel.getLayout()); 
     layout.show(MainPanel, "Display"); 
    }             

    private javax.swing.JButton GoToDisplayPanelButton;     
} 
+1

Для получения дополнительной информации о реализации, вы должны рассмотреть, показывая некоторые детали кода, предпочтительно [минимальный пример программы] (http://stackoverflow.com/help/mcve). –

+0

Спасибо за создание и размещение кода, но он не будет компилироваться и не запускаться для нас. Пожалуйста, исправьте это. –

+0

Теперь ** это ** правильный MCVE. Спасибо и 1+. –

ответ

3

Вы должны использовать систему уведомлений, имея представление (или GUI) уведомляется модель («бэкэнд»), когда данные были изменены. Затем представление может запросить обновленную информацию и использовать ее для обновления дисплея JLabel. Детали этого будут зависеть от особенностей вашего кода, но я часто даю моей модели (или оболочке вокруг модели) поле SwingPropertyChangeSupport, а также addPropertyChangeListener(...) и аналогичным методам удаления слушателя, а затем в методах модели, где свойство (a связанное имущество), запустите метод уведомления SwingPropertyChangeSupport. Для получения дополнительной информации о реализации вам следует рассмотреть некоторые детали вашего кода, предпочтительно minimal example program.

For example


Редактировать

Обратите внимание, что если все, что вы хотите, это уведомление, когда называется шоу, вы всегда можете расширить CardLayout и переопределить его метод show(...). Но если вы это сделаете, не забудьте также вызвать метод super.show(...).


Редактировать
Примечание Изменения, внесенные в код, указанный на // !!

import java.awt.CardLayout; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class GUI extends javax.swing.JFrame { 
    public static final String ITEM = "item"; 
    public String item; // !! this should not be static! 
    private javax.swing.JPanel MainPanel; 

    public GUI() { 
     // creates a JPanel called MainPanel which will hold the cards 
     // in my CardLayout 
     initComponents(); 
    } 

    // !! 
    public void setItem(String item) { 
     String oldValue = this.item; 
     String newValue = item; 
     this.item = item; 
     firePropertyChange(ITEM, oldValue, newValue); 
    } 

    //!! 
    public String getItem() { 
     return item; 
    } 

    private void initComponents() { 

     MainPanel = new javax.swing.JPanel(); 

     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

     MainPanel.setBackground(new java.awt.Color(198, 118, 38)); 
     MainPanel.setMaximumSize(new java.awt.Dimension(1000, 1000)); 
     MainPanel.setName(""); // NOI18N 
     MainPanel.setPreferredSize(new java.awt.Dimension(1024, 768)); 
     MainPanel.setLayout(new java.awt.CardLayout()); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(
      getContentPane()); 
     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(layout.createParallelGroup(
      javax.swing.GroupLayout.Alignment.LEADING).addGroup(
      javax.swing.GroupLayout.Alignment.TRAILING, 
      layout.createSequentialGroup() 
        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, 
         Short.MAX_VALUE) 
        .addComponent(MainPanel, 
         javax.swing.GroupLayout.DEFAULT_SIZE, 
         javax.swing.GroupLayout.DEFAULT_SIZE, 
         javax.swing.GroupLayout.PREFERRED_SIZE) 
        .addContainerGap())); 
     layout.setVerticalGroup(layout.createParallelGroup(
      javax.swing.GroupLayout.Alignment.LEADING).addGroup(
      javax.swing.GroupLayout.Alignment.TRAILING, 
      layout.createSequentialGroup() 
        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, 
         Short.MAX_VALUE) 
        .addComponent(MainPanel, 
         javax.swing.GroupLayout.DEFAULT_SIZE, 
         javax.swing.GroupLayout.DEFAULT_SIZE, 
         javax.swing.GroupLayout.PREFERRED_SIZE) 
        .addContainerGap())); 

     pack(); 
     setLocationRelativeTo(null); 

    } 

    // Grab the panel that was created in initComponents() so that I can add 
    // other panels to it 
    public JPanel getMainPanel() { 
     return MainPanel; 
    } 

    public static void main(String args[]) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      final GUI mainGUI = new GUI(); 

      // The JLabel in DisplayPanel.java will initially say root 
      // !! item = "root"; 
      mainGUI.setItem("root"); // !! 

      JPanel cardHolder = mainGUI.getMainPanel(); 
      // This panel contains a button which will update the name of 
      // the currentUserAccount 
      final MainMenuPanel mainMenu = new MainMenuPanel(cardHolder, 
        mainGUI); // !! 
      cardHolder.add(mainMenu, "MainMenu"); 

      // This panel holds a JLabel that I want to have updated 
      // automatically 
      // when the user presses the button on MainMenuPanel 
      final DisplayPanel display = new DisplayPanel(cardHolder, mainGUI); // !! 
      cardHolder.add(display, "Display"); 

      mainGUI.pack(); 
      mainGUI.setVisible(true); 

      // !! 
      mainGUI.addPropertyChangeListener(ITEM, 
        new PropertyChangeListener() { 

        @Override 
        public void propertyChange(PropertyChangeEvent pcEvt) { 
         String itemText = mainGUI.getItem(); 
         display.setJLabel1Text(itemText); 
        } 
        }); 
     } 
     }); 
    } 
} 

@SuppressWarnings("serial") 
class DisplayPanel extends javax.swing.JPanel { 
    private JPanel mainPanel; 
    private GUI mainGui; // !! 

    public DisplayPanel(JPanel mainPanel, GUI mainGui) { // !! 

     this.mainPanel = mainPanel; 
     this.mainGui = mainGui;// !! 
     initComponents(); // Creates my panel with the JLabels/buttons etc 
    } 

    // !! added 
    public void setJLabel1Text(String text) { 
     jLabel1.setText(text); 
    } 

    private void initComponents() { 

     jLabel1 = new javax.swing.JLabel(); 
     GoToMainMenuButton = new javax.swing.JButton(); 

     jLabel1.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N 
     // !! jLabel1.setText(GUI.item); // sets the JLabel to the GUI.item 
     // variable 
     jLabel1.setText(mainGui.getItem()); // !! 

     GoToMainMenuButton.setText("Go to MainMenuPanel"); 
     GoToMainMenuButton.addMouseListener(new java.awt.event.MouseAdapter() { 
     public void mouseClicked(java.awt.event.MouseEvent evt) { 
      GoToMainMenuButtonMouseClicked(evt); 
     } 
     }); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); 
     this.setLayout(layout); 
     layout.setHorizontalGroup(layout 
      .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(
        javax.swing.GroupLayout.Alignment.TRAILING, 
        layout.createSequentialGroup() 
         .addContainerGap(269, Short.MAX_VALUE) 
         .addGroup(
           layout.createParallelGroup(
            javax.swing.GroupLayout.Alignment.LEADING) 
            .addComponent(GoToMainMenuButton) 
            .addComponent(
              jLabel1, 
              javax.swing.GroupLayout.PREFERRED_SIZE, 
              145, 
              javax.swing.GroupLayout.PREFERRED_SIZE)) 
         .addGap(266, 266, 266))); 
     layout.setVerticalGroup(layout.createParallelGroup(
      javax.swing.GroupLayout.Alignment.LEADING).addGroup(
      layout.createSequentialGroup() 
        .addGap(168, 168, 168) 
        .addComponent(jLabel1, 
         javax.swing.GroupLayout.PREFERRED_SIZE, 63, 
         javax.swing.GroupLayout.PREFERRED_SIZE) 
        .addGap(83, 83, 83).addComponent(GoToMainMenuButton) 
        .addContainerGap(116, Short.MAX_VALUE))); 
    } 

    private void GoToMainMenuButtonMouseClicked(java.awt.event.MouseEvent evt) { 
     // go back to the MainPanel 
     CardLayout layout = (CardLayout) (mainPanel.getLayout()); 
     layout.show(mainPanel, "MainMenu"); 
    } 

    private javax.swing.JButton GoToMainMenuButton; 
    private javax.swing.JLabel jLabel1; 

} 

@SuppressWarnings("serial") 
class MainMenuPanel extends javax.swing.JPanel { 

    private JPanel MainPanel; 
    private GUI mainGui; // !! 

    public MainMenuPanel(JPanel MainPanel, GUI mainGui) { // !! 

     this.MainPanel = MainPanel; 
     this.mainGui = mainGui; // !! 
     initComponents(); // Creates my panel with the JLabels/buttons etc 
    } 

    private void initComponents() { 

     GoToDisplayPanelButton = new javax.swing.JButton(); 

     GoToDisplayPanelButton.setText("Press Me"); 
     GoToDisplayPanelButton 
      .addMouseListener(new java.awt.event.MouseAdapter() { 
       public void mouseClicked(java.awt.event.MouseEvent evt) { 
        GoToDisplayPanelButtonMouseClicked(evt); 
       } 
      }); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); 
     this.setLayout(layout); 
     layout.setHorizontalGroup(layout.createParallelGroup(
      javax.swing.GroupLayout.Alignment.LEADING).addGroup(
      layout.createSequentialGroup().addGap(252, 252, 252) 
        .addComponent(GoToDisplayPanelButton) 
        .addContainerGap(260, Short.MAX_VALUE))); 
     layout.setVerticalGroup(layout.createParallelGroup(
      javax.swing.GroupLayout.Alignment.LEADING).addGroup(
      javax.swing.GroupLayout.Alignment.TRAILING, 
      layout.createSequentialGroup() 
        .addContainerGap(198, Short.MAX_VALUE) 
        .addComponent(GoToDisplayPanelButton).addGap(175, 175, 175))); 
    } 

    private void GoToDisplayPanelButtonMouseClicked(java.awt.event.MouseEvent evt) { 
     // Changes the value of item. I want this change to be reflected on my 
     // JLabel in DisplayPanel.java, but it is not because I do not explicitly 
     // call setText on the JLabel here. I am wondering if there is a way to 
     // have my JLabel automatically update when the variable in its setText 
     // is changed, without having to directly call setText. Or some other 
     // way to update it without calling setText every time I change something. 
     // !! GUI.item = "new value"; 
     mainGui.setItem("new value"); // !! 

     // Switches to my DisplayPanel which should show the updated name in its 
     // JLabel 
     CardLayout layout = (CardLayout) (MainPanel.getLayout()); 
     layout.show(MainPanel, "Display"); 
    } 

    private javax.swing.JButton GoToDisplayPanelButton; 
} 
+0

Какая специфика вам понадобится? У меня в основном есть HashTable объектов, которые имеют различные частные члены. Когда один из частных членов изменяется через сеттер, мне нужен графический интерфейс, чтобы обновлять его повсюду. Графический интерфейс - это, по сути, MainPanel (JPanel), который я добавляю ко всем моим другим JPanels (страницам). Различные страницы содержат JLabels, которые необходимо обновить. – Ryan

+0

@Ryan: прочитайте ссылку [mcve] (http://stackoverflow.com/help/mcve), так как она точно скажет вам, что нам нужно. Это ** будет ** требовать работы с вашей стороны, так как мы не хотим видеть всю программу, если она больше, чем страница или две по длине, а это означает, что вам, вероятно, придется создать новую небольшую демонстрационную версию программы, но это хорошо стоит. –

+0

@Ryan: обратите внимание, что если все, что вы хотите, это уведомление о вызове show, вы всегда можете расширить CardLayout и переопределить его метод 'show (...)'. Но если вы это сделаете, не забудьте также вызвать метод 'super.show (...)'. –

Смежные вопросы