这是我关于Java Swing的第二篇文章,所以请原谅我,如果我的问题太简单了。我正在尝试让多个JPanels相互通信。我正在构建一个简单的2D网格,我可以添加墙/阻塞单元格,然后运行简单的Floodfill / A *搜索算法(给定开始和目标位置)。
为了解决我的问题,我决定使用一个例子会更容易。所以我创建了一个简单的应用程序,允许用户写一个文本框,提供他/她点击了“开始”按钮。完成对文本框的写入后,用户可以单击“开始”按钮将其翻转为“停止”状态。在“停止”状态下,用户不能向文本框添加任何文本(即应用程序根本不应注册任何键击)。这是一个简单的问题,在这里真正提出了我的问题。这是UI现在的样子:
我的问题: 我应该能够在按钮显示“停止”时写入(因为它处于编辑模式)并且我当按钮显示“开始”时,不应能够在文本区域中书写(因为它不是编辑模式)。但是,从上面的图像中,您可以看到我能够在任何情况下在文本区域中书写。如何在按钮状态下编辑依赖文本区域?
这是我的代码,它尝试在按钮面板和文本面板之间设置连接,但它在某种程度上无法按预期工作。
我查看了StackOverflow帖子here和here,但坦率地说,答案对我来说似乎并不清楚。
SimpleTextPanel:
public class SimpleTextPanel extends JPanel implements PropertyChangeListener, ChangeListener {
private boolean canWrite;
public SimpleTextPanel() {
// set the border properties
canWrite = true;
TitledBorder title = BorderFactory.createTitledBorder("Simple Text Panel");
title.setTitleColor(Color.BLACK);
title.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED,
Color.DARK_GRAY, Color.GRAY));
this.setBorder(title);
JTextArea editSpace = new JTextArea(10, 20);
editSpace.setEditable(true);
editSpace.addPropertyChangeListener(this);
this.add(editSpace);
}
@Override
public void stateChanged(ChangeEvent changeEvent) {
JButton button = (JButton)changeEvent.getSource();
canWrite = button.getText().equals("Start");
}
@Override
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
JTextArea area = (JTextArea)propertyChangeEvent.getSource();
if(!canWrite) area.setText((String)propertyChangeEvent.getOldValue());
}
}
SimpleButtonPanel:
public class SimpleButtonPanel extends JPanel implements ActionListener {
JButton switchButton;
private boolean canWrite = true;
public SimpleButtonPanel(SimpleTextPanel txt) {
// set the border properties
TitledBorder title = BorderFactory.createTitledBorder("Simple Button Panel");
title.setTitleColor(Color.BLACK);
title.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED,
Color.DARK_GRAY, Color.GRAY));
this.setBorder(title);
switchButton = new JButton("Start");
switchButton.addActionListener(this);
switchButton.addChangeListener(txt);
this.add(switchButton);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
if(switchButton.getText().equals("Start")) {
switchButton.setText("Stop");
canWrite = false;
} else if(switchButton.getText().equals("Stop")) {
switchButton.setText("Start");
canWrite = true;
}
}
}
SimpleExampleTest:
public class SimpleExampleTest extends JFrame {
public SimpleExampleTest() {
setLayout(new BorderLayout());
setTitle("Simple Example");
setSize(300, 300);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
SimpleTextPanel text = new SimpleTextPanel();
SimpleButtonPanel button = new SimpleButtonPanel(text);
add(text, BorderLayout.NORTH);
add(button, BorderLayout.SOUTH);
//button.addPropertyChangeListener(text); // so that text editor knows whether to allow writing or not
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
SimpleExampleTest ex = new SimpleExampleTest();
ex.setVisible(true);
}
});
}
}
感谢任何/所有帮助。谢谢!
答案 0 :(得分:4)
一种方法是设计一个可以由小组共享的模型。
文本面板只想知道当前状态是什么以及该状态何时发生变化。按钮面板想知道状态何时发生变化,并希望能够改变状态。
这使得两个面板彼此分离,因为他们并不真正关心状态是如何改变的,或者只是因为他们可以相应地响应变化...
此外,该模型并不关心它们中的任何一个,它只是携带状态并在变化时提供通知。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.BevelBorder;
import javax.swing.border.TitledBorder;
public class TalkToEachOther {
public static void main(String[] args) {
new TalkToEachOther();
}
public TalkToEachOther() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Simple Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MutableSimpleModel model = new DefaultSimpleModel();
SimpleTextPanel text = new SimpleTextPanel(model);
SimpleButtonPanel button = new SimpleButtonPanel(model);
frame.add(text, BorderLayout.NORTH);
frame.add(button, BorderLayout.SOUTH);
//button.addPropertyChangeListener(text); // so that text editor knows whether to allow writing or not
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface SimpleModel {
public boolean isEditable();
public void addPropertyChangeListener(PropertyChangeListener listener);
public void removePropertyChangeListener(PropertyChangeListener listener);
}
public interface MutableSimpleModel extends SimpleModel {
public void setEditable(boolean editable);
}
public class DefaultSimpleModel implements MutableSimpleModel {
private Set<PropertyChangeListener> listeners;
private boolean editable;
public DefaultSimpleModel() {
listeners = new HashSet<>(25);
}
@Override
public void setEditable(boolean value) {
if (value != editable) {
editable = value;
firePropertyChange("editable", !editable, editable);
}
}
@Override
public boolean isEditable() {
return editable;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.add(listener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.remove(listener);
}
protected void firePropertyChange(String editable, boolean oldValue, boolean newValue) {
PropertyChangeEvent evt = new PropertyChangeEvent(this, editable, oldValue, newValue);
for (PropertyChangeListener listener : listeners) {
listener.propertyChange(evt);
}
}
}
public class SimpleTextPanel extends JPanel {
private SimpleModel model;
private JTextArea editSpace = new JTextArea(10, 20);
public SimpleTextPanel(SimpleModel model) {
this.model = model;
model.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateEditableState();
}
});
setLayout(new BorderLayout());
// set the border properties
TitledBorder title = BorderFactory.createTitledBorder("Simple Text Panel");
title.setTitleColor(Color.BLACK);
title.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED,
Color.DARK_GRAY, Color.GRAY));
this.setBorder(title);
editSpace = new JTextArea(10, 20);
this.add(new JScrollPane(editSpace));
updateEditableState();
}
protected void updateEditableState() {
editSpace.setEditable(model.isEditable());
}
}
public class SimpleButtonPanel extends JPanel implements ActionListener {
private MutableSimpleModel model;
private boolean canWrite = true;
private JButton switchButton;
public SimpleButtonPanel(MutableSimpleModel model) {
this.model = model;
model.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateEditableState();
}
});
// set the border properties
TitledBorder title = BorderFactory.createTitledBorder("Simple Button Panel");
title.setTitleColor(Color.BLACK);
title.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED,
Color.DARK_GRAY, Color.GRAY));
this.setBorder(title);
switchButton = new JButton("Start");
switchButton.addActionListener(this);
this.add(switchButton);
updateEditableState();
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
model.setEditable(!model.isEditable());
}
protected void updateEditableState() {
if (model.isEditable()) {
switchButton.setText("Stop");
} else {
switchButton.setText("Start");
}
}
}
}
答案 1 :(得分:2)
我建议您创建一个JPanel
子类,该子类又包含其他JPanel
个对象。通过这种方式,您可以保持对需要交互的GUI元素的引用(即按钮和文本字段)。现在,按钮的ActionListener
可以访问JTextField
,假设ActionListener
是匿名内部类,JTextField
是成员变量。
在更复杂的情况下,这种设计可能并不理想。但是,有些概念是相同的。特别是,您需要一个父JPanel
来促进孩子JPanel
之间的沟通。子JPanel
公开了一个接口以允许这种通信。例如,您可以拥有TextFieldPanel
个enable()
和disable()
方法。