我正在制作一个在java中使用MVC的程序。我的问题是我不知道如何实现ActionListeners并处理事件,例如单击按钮时。我知道代码应该在控制器中,但我不知道如何实现它。到目前为止,我已经制作了几个按钮,我想让它们在点击时实际执行某些操作。我应该在视图中添加什么代码并在控制器类中编写?
到目前为止,这是我的View类:
package decryptor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.FlowLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.io.File;
public class View
{
private JFrame frame;
private JPanel mainPanel;
private JLabel instructions;
private JLabel frequenciesFileLoadedLabel;
private JLabel cipherFileLoadedLabel;
private JButton frequenciesFileLoadButton;
private JButton cipherFileLoadButton;
private JButton decipherByRankButton;
private JButton decipherByNearestFrequencyButton;
private boolean cipherLoaded;
private boolean frequenciesLoaded;
public enum Buttons
{
FREQUENCIES_LOAD, CIPHER_LOAD, DECIPHER_RANK, DECIPHER_NEAREST;
}
public View()
{
cipherLoaded = false;
frequenciesLoaded = false;
frame = new JFrame("Text Decrypter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
mainPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
mainPanel.setPreferredSize(new Dimension(100,400));
frequenciesFileLoadedLabel = new JLabel("No file with character frequencies loaded");
cipherFileLoadedLabel = new JLabel("No file to decipher loaded");
frequenciesFileLoadButton = new JButton("Load character frequencies file");
cipherFileLoadButton = new JButton("Load file to decipher");
decipherByRankButton = new JButton("Decipher file by rank of character frequencies");
decipherByRankButton.setEnabled(false);
decipherByNearestFrequencyButton = new JButton("Decipher file by the nearest character frequency");
decipherByNearestFrequencyButton.setEnabled(false);
mainPanel.add(frequenciesFileLoadButton);
mainPanel.add(frequenciesFileLoadedLabel);
mainPanel.add(cipherFileLoadButton);
mainPanel.add(cipherFileLoadedLabel);
mainPanel.add(decipherByRankButton);
mainPanel.add(decipherByNearestFrequencyButton);
frame.add(mainPanel);
frame.pack();
frame.setVisible(true);
//label fonts etc
}
private void enableButtons()
{
if (cipherLoaded == true && frequenciesLoaded == true)
{
decipherByRankButton.setEnabled(true);
decipherByNearestFrequencyButton.setEnabled(true);
}
}
private File loadFile()
{
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File( System.getProperty("user.home")));
int fileChooserResult = fileChooser.showOpenDialog(frame);
if (fileChooserResult == JFileChooser.APPROVE_OPTION)
{
return fileChooser.getSelectedFile();
}
else
{
JOptionPane.showMessageDialog(frame, "Error loading file. Please try again.", "Error", JOptionPane.ERROR_MESSAGE);
return null;
}
}
public File loadFrequencies()
{
File loadedFile = loadFile();
if (loadedFile == null)
{
frequenciesLoaded = false;
enableButtons();
frequenciesFileLoadedLabel.setText("No file with character frequencies loaded");
return loadedFile;
}
else
{
frequenciesLoaded = true;
enableButtons();
frequenciesFileLoadedLabel.setText("Character frequencies file loaded");
return loadedFile;
}
}
public File loadCiphered()
{
File loadedFile = loadFile();
if (loadedFile == null)
{
cipherLoaded = false;
enableButtons();
cipherFileLoadedLabel.setText("No file to decipher loaded");
return loadedFile;
}
else
{
cipherLoaded = true;
enableButtons();
cipherFileLoadedLabel.setText("File to decipher loaded");
return loadedFile;
}
}
public void fileOutput()
{
JOptionPane.showMessageDialog(frame, "File deciphered and output to file \"output.txt\".");
}
public JButton getButton(Buttons button)
{
switch (button)
{
case FREQUENCIES_LOAD: return frequenciesFileLoadButton;
case CIPHER_LOAD: return cipherFileLoadButton;
case DECIPHER_RANK: return decipherByRankButton;
case DECIPHER_NEAREST: return decipherByNearestFrequencyButton;
default: return null;
}
}
}
代码有点错误,我会解决它,但我目前的优先事项是让我的按钮工作。如果控制器调用方法,我已经尝试制作将返回按钮的方法,但是我觉得这不是正确的方法。
答案 0 :(得分:1)
我不知道 The Canonical Way ™这样做,但一种方法是使用Swing自己的属性更改支持和PropertyChangeListeners作为通知侦听器的机制更改视图和模型。例如,假设我们创建了您的枚举,并进行了修改:
// smvc for "simple model view controller"
public enum SmvcButtons {
FREQUENCIES_LOAD("Load Frequencies"),
CIPHER_LOAD("Load Cipher"),
DECIPHER_RANK("Decipher Rank"),
DECIPHER_NEAREST("Decipher Nearest");
private String text;
private SmvcButtons(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
并在某种模型中使用它:
public class SmvcModel {
// constant for our single property name
public static final String SMVC_BUTTONS = "smvc buttons";
// a more complex model will have multiple "bound" properties
// the support object will register listeners on the model
// and will notify them of changes in model state
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private SmvcButtons smvcButtons;
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public SmvcButtons getSmvcButtons() {
return smvcButtons;
}
public void setSmvcButtons(SmvcButtons smvcButtons) {
SmvcButtons oldValue = null;
SmvcButtons newValue = smvcButtons;
this.smvcButtons = smvcButtons;
pcSupport.firePropertyChange(SMVC_BUTTONS, oldValue, newValue);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(name, listener);
}
}
这里我们通过在setter方法中触发属性更改方法来通知属性更改支持对象smvcButtons字段的更改:
public void setSmvcButtons(SmvcButtons smvcButtons) {
SmvcButtons oldValue = null;
SmvcButtons newValue = smvcButtons;
this.smvcButtons = smvcButtons;
pcSupport.firePropertyChange(SMVC_BUTTONS, oldValue, newValue);
}
现在将通知听众更改
在Controller中,我们有一个监听器:
private class ModelListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String text = ((SmvcButtons) evt.getNewValue()).getText() + "\n";
view.appendTextAreaText(text);
}
}
假设我们有一个视图(为了说明目的而保持简单),它使用枚举来创建按钮,并使用类似的机制通知侦听器状态的变化:
@SuppressWarnings("serial")
public class SmvcView extends JPanel {
public static final String SMVC_BUTTONS = "smvc buttons";
private JTextArea textArea = new JTextArea(30, 50);
public SmvcView() {
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 3, 0));
for (final SmvcButtons smvcBtn : SmvcButtons.values()) {
JButton button = new JButton(smvcBtn.getText());
btnPanel.add(button);
button.addActionListener(e -> {
Object oldValue = null;
Object newValue = smvcBtn;
firePropertyChange(SMVC_BUTTONS, oldValue, newValue);
});
}
setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
setLayout(new BorderLayout(3, 3));
add(scrollPane);
add(btnPanel, BorderLayout.PAGE_END);
}
public void appendTextAreaText(String text) {
textArea.append(text);
}
}
请注意,视图会将匿名侦听器附加到其按钮上,他们唯一要做的就是通知组件的固有属性更改支持按钮已被按下 - 就是这样。目标是尽可能保持视野:
button.addActionListener(e -> {
Object oldValue = null;
Object newValue = smvcBtn;
firePropertyChange(SMVC_BUTTONS, oldValue, newValue);
});
然后控制器可以使用类似的监听器来监听视图的更改:
private class ViewListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
model.setSmvcButtons((SmvcButtons) evt.getNewValue());
}
}
以上听众所做的就是根据按下按钮改变模型的状态(再次,这个例子非常简单)
整个事情看起来像:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class SimpleMvc {
private static void createAndShowGui() {
SmvcModel model = new SmvcModel();
SmvcView view = new SmvcView();
new Controller(model, view);
JFrame frame = new JFrame("SimpleMvc");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(view);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
enum SmvcButtons {
FREQUENCIES_LOAD("Load Frequencies"),
CIPHER_LOAD("Load Cipher"),
DECIPHER_RANK("Decipher Rank"),
DECIPHER_NEAREST("Decipher Nearest");
private String text;
private SmvcButtons(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
class Controller {
private SmvcModel model;
private SmvcView view;
public Controller(SmvcModel model, SmvcView view) {
this.model = model;
this.view = view;
model.addPropertyChangeListener(SmvcModel.SMVC_BUTTONS, new ModelListener());
view.addPropertyChangeListener(SmvcView.SMVC_BUTTONS, new ViewListener());
}
private class ModelListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String text = ((SmvcButtons) evt.getNewValue()).getText() + "\n";
view.appendTextAreaText(text);
}
}
private class ViewListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
model.setSmvcButtons((SmvcButtons) evt.getNewValue());
}
}
}
class SmvcModel {
public static final String SMVC_BUTTONS = "smvc buttons";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private SmvcButtons smvcButtons;
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public SmvcButtons getSmvcButtons() {
return smvcButtons;
}
public void setSmvcButtons(SmvcButtons smvcButtons) {
SmvcButtons oldValue = null;
SmvcButtons newValue = smvcButtons;
this.smvcButtons = smvcButtons;
pcSupport.firePropertyChange(SMVC_BUTTONS, oldValue, newValue);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(name, listener);
}
}
@SuppressWarnings("serial")
class SmvcView extends JPanel {
public static final String SMVC_BUTTONS = "smvc buttons";
private JTextArea textArea = new JTextArea(30, 50);
public SmvcView() {
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 3, 0));
for (final SmvcButtons smvcBtn : SmvcButtons.values()) {
JButton button = new JButton(smvcBtn.getText());
btnPanel.add(button);
button.addActionListener(e -> {
Object oldValue = null;
Object newValue = smvcBtn;
firePropertyChange(SMVC_BUTTONS, oldValue, newValue);
});
}
setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
setLayout(new BorderLayout(3, 3));
add(scrollPane);
add(btnPanel, BorderLayout.PAGE_END);
}
public void appendTextAreaText(String text) {
textArea.append(text);
}
}
答案 1 :(得分:0)
如果您只是在谈论添加动作监听器,那么您只需实现动作监听器,然后将其添加到按钮中......
public class View implements ActionListener{
cipherFileLoadButton.addActionListener(this);
// etc listener to all buttons
}
@Override
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
if(o == cipherFileLoadButton){
/*
* Do stuff
*/
}
}
答案 2 :(得分:-2)
我无法记住它,但它看起来像这样:
btn.setOnclickListener(new OnclickListener(){
...// Override some methods to implement your business code.
}
);
或lamda方式:
btn.setOnclickListener(()->{
....// Override some methods to implement your business code.
});
我相信你的ide有一些自动修复功能可以帮助你完成这些代码。 :)