当前位置: 首页 > 知识库问答 >
问题:

从JFrame修改独立的JPanels

东方乐
2023-03-14

我有一个带有两个独立JPanels的JFrame。其中一个JPanels填充了JButtons,而另一个则有几个文本字段。我通过JFrame向按钮添加了鼠标监听器,我想让它在第一个JPanel触发一个事件时,第二个JPanel中的文本字段发生变化。这两个面板有自己的类。我该如何着手做这件事?

共有1个答案

裴浩歌
2023-03-14
  1. 使用 MVC、模型-视图-控制、关注点分离。
  2. 让用于存放侦听器的控件更改模型的状态。
  3. 视图 -- 您的 GUI 具有控件添加到它们的侦听器,以便将用户输入传输到控件,从而传输到模型。
  4. View 还可以直接向模型添加侦听器,以便在模型更改时可以更改其显示,或者通常通过控件间接执行此操作。
  5. 不要将 MouseListeners 添加到 JButtons。使用 ActionListeners,因为这就是它们的用途。例如,如果禁用 JButton,则附加到它的任何操作列表都不起作用 - 这是正确的行为。MouseListeners的情况并非如此。

有关更具体的帮助,请考虑创建和发布一个最小的示例程序。

编辑<br>例如:

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

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.SwingPropertyChangeSupport;

public class MvcMain {
   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            MvcView view = new MvcView();
            MvcModel model = new MvcModel();
            MvcControl control = new MvcControl(view, model);
            view.createAndDisplay();
         }
      });
   }
}

class MvcView {
   private MvcModel model;
   private ButtonPanel buttonPanel = new ButtonPanel();
   private TextFieldPanel textFieldPanel = new TextFieldPanel();
   private JPanel mainPanel = new JPanel();

   public MvcModel getModel() {
      return model;
   }

   public ButtonPanel getButtonPanel() {
      return buttonPanel;
   }

   public TextFieldPanel getTextFieldPanel() {
      return textFieldPanel;
   }

   public MvcView() {
      mainPanel.setLayout(new GridLayout(0, 1));
      mainPanel.add(textFieldPanel);
      mainPanel.add(buttonPanel);
   }

   public void setModel(MvcModel model) {
      this.model = model;
      model.addPropertyChangeListener(new ModelListener());
   }

   public void createAndDisplay() {
      JFrame frame = new JFrame("MVC Test");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(mainPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   private class ModelListener implements PropertyChangeListener {
      @Override
      public void propertyChange(PropertyChangeEvent evt) {
         if (ButtonTitle.class.getCanonicalName().equals(evt.getPropertyName())) {
            ButtonTitle newValue = model.getButtonTitle();
            textFieldPanel.textFieldSetText(newValue.getTitle());
         }
      }
   }
}

enum ButtonTitle {
   START("Start"), STOP("Stop"), PAUSE("Pause");
   private String title;

   private ButtonTitle(String title) {
      this.title = title;
   }

   public String getTitle() {
      return title;
   }
}

@SuppressWarnings("serial")
class ButtonPanel extends JPanel {
   public ButtonPanel() {
      setBorder(BorderFactory.createTitledBorder("Button Panel"));
      setLayout(new GridLayout(1, 0, 5, 0));
      for (ButtonTitle btnTitle : ButtonTitle.values()) {
         add(new JButton(new ButtonAction(btnTitle)));
      }
   }

   private class ButtonAction extends AbstractAction {
      private ButtonTitle btnTitle;

      public ButtonAction(ButtonTitle btnTitle) {
         super(btnTitle.getTitle());
         this.btnTitle = btnTitle;
      }

      public void actionPerformed(java.awt.event.ActionEvent e) {
         Object oldValue = null;
         ButtonTitle newValue = btnTitle;
         ButtonPanel.this.firePropertyChange(
               ButtonTitle.class.getCanonicalName(), oldValue, newValue);
      };
   }
}

@SuppressWarnings("serial")
class TextFieldPanel extends JPanel {
   private JTextField textField = new JTextField(15);

   public TextFieldPanel() {
      setBorder(BorderFactory.createTitledBorder("TextField Panel"));
      add(textField);
   }

   public void textFieldSetText(String text) {
      textField.setText(text);
   }
}

class MvcControl {
   private MvcView view;
   private MvcModel model;

   public MvcControl(MvcView view, MvcModel model) {
      this.view = view;
      this.model = model;
      view.setModel(model);
      view.getButtonPanel().addPropertyChangeListener(new ButtonPanelListener());
   }

   private class ButtonPanelListener implements PropertyChangeListener {
      @Override
      public void propertyChange(PropertyChangeEvent evt) {
         if (ButtonTitle.class.getCanonicalName().equals(evt.getPropertyName())) {
            ButtonTitle newValue = (ButtonTitle) evt.getNewValue();
            model.setButtonTitle(newValue);
         }
      }
   }
}

class MvcModel {
   private ButtonTitle buttonTitle;
   private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
         this);

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      pcSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      pcSupport.removePropertyChangeListener(listener);
   }

   public ButtonTitle getButtonTitle() {
      return buttonTitle;
   }

   public void setButtonTitle(ButtonTitle buttonTitle) {
      ButtonTitle oldValue = this.buttonTitle;
      ButtonTitle newValue = buttonTitle;
      this.buttonTitle = buttonTitle;
      pcSupport.firePropertyChange(ButtonTitle.class.getCanonicalName(),
            oldValue, newValue);
   }
}

该示例缺乏接口的使用,这些接口将允许进一步分离关注点,从而导致更松散的耦合(这是一件好事)。

 类似资料:
  • 问题内容: 我有一个带有两个单独的JPanels的JFrame。一个JPanels充满了JButton,而另一个则有几个文本字段。我通过JFrame在按钮上添加了鼠标侦听器,我希望这样做,以便从第一个JPanel触发事件时,第二个JPanel中的文本字段会发生更改。这两个面板有各自的类。我将如何去做呢? 问题答案: 使用MVC,Model-View-Control,关注点分离。 让拥有您的听众的控

  • 问题内容: 有没有办法使用python以平台独立的方式修改环境变量? 类似于? 问题答案: 您应该能够进行修改。 由于是分隔不同路径的字符,因此应使用此字符追加每个新路径: 或者,如果要在列表中添加多个路径: 如前所述,在必须从单独的部分构造路径的情况下,也可以用于必须附加的每个路径。

  • 如何在java摆中从第二个JFrame获取数据?我有一个带有JLabel和JButton的帧。单击JButton时,它会打开另一个带有自定义日历的帧。我想选择日期(通过JButton)并将日期放在主JFrame的JLabel中。我不想创建第一帧的新实例,因为还有其他用户可能键入的我不想删除的信息。

  • 发现问题! 假如按照上一讲的制作方法,设定了对话框的话,实际执行游戏时,会是下面的效果: 人物姓名占用了原本对话的第一行位置,并且把对话挤到第二行了。这当然可以通过调整对话框的文字显示范围来修改,但是只做这样的修改的话,名字和对话永远是对齐的,并且距离也是固定的。有没有什么办法作出“姓名和对话分开”的效果呢?答案当然是肯定的,只不过需要一点努力~ 将姓名与对话显示分离 这个修改没有图形界面,不过也

  • 问题内容: 我正在尝试从python启动一个完全独立的进程。我不能使用像os.startfile这样的简单内容,因为我需要传递参数。目前,我正在使用subprocess.popen,它可以让我90%地到达那里。 将带有分离的创建标志和管道的popen用于std *确实会启动一个新进程,该进程在父进程死后仍然存在。这样就很好。问题在于,新的“子级”进程仍然为父级保留一个幻像句柄。因此,如果我尝试卸载

  • 创建验证 任何时候,都可以直接使用think\Validate类而不需要定义验证器类进行独立的验证操作,例如: $validate = Validate::make([ 'name' => 'require|max:25', 'email' => 'email' ]); $data = [ 'name' => 'thinkphp', 'email' => 't