问题描述
这是我当前的菜单:
public class DrawPolygons
{
public static void main (String[] args) throws FileNotFoundException
{
/**
* Menu - file reader option
*/
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem;
// Create the menu bar.
menuBar = new JMenuBar();
// Build the first menu.
menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menu.getAccessibleContext().setAccessibleDescription("I have items");
menuBar.add(menu);
// a group of JMenuItems
menuItem = new JMenuItem("Load",KeyEvent.VK_T);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription("Load your old polygons");
menu.add(menuItem);
menuItem = new JMenuItem("Save",KeyEvent.VK_U);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription("Save the contents of your polygons");
menu.add(menuItem);
// attaching the menu to the frame
JFrame frame = new JFrame("Draw polygons");
frame.setJMenuBar(menuBar);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new DrawingPanel());
frame.pack();
frame.setVisible(true);
}
}
Load
和 Save
有两个选项.
现在,我如何将 JFileChooser
附加到 actionPerformed
方法,这里:
Now , how can I attach the JFileChooser
to the actionPerformed
method , here :
/**
* Main class
* @author X2
*
*/
class DrawingPanel extends JPanel implements MouseListener, MouseMotionListener ,KeyListener
{
// code
// code
// and more code
static DrawingPanel app ;
private static final Dimension MIN_DIM = new Dimension(300, 300);
private static final Dimension PREF_DIM = new Dimension(500, 500);
public Dimension getMinimumSize() { return MIN_DIM; }
public Dimension getPreferredSize() { return PREF_DIM; }
JMenuItem open, save;
JTextArea textArea ;
JFileChooser chooser ;
FileInputStream fis ;
BufferedReader br ;
FileOutputStream fos ;
BufferedWriter bwriter ;
public void actionPerformed( ActionEvent event )
{
Object obj = event.getSource() ;
chooser = new JFileChooser() ;
if ( chooser.showOpenDialog( app ) == JFileChooser.APPROVE_OPTION )
if ( obj == open )
{
try
{
fis = new FileInputStream(
chooser.getSelectedFile() ) ;
br = new BufferedReader(
new InputStreamReader( fis ) ) ;
String read ;
StringBuffer text = new StringBuffer() ;
while( ( read = br.readLine() ) != null )
{
text.append( read ).append( "
" ) ;
}
textArea.setText( text.toString() ) ;
}
catch( IOException e )
{
JOptionPane.showMessageDialog( this , "Error in File Operation"
,"Error in File Operation" ,JOptionPane.INFORMATION_MESSAGE) ;
}
}
}
/**
* The constructor
*/
DrawingPanel()
{
super();
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(this);
setFocusable(true);
requestFocusInWindow();
}
// a lot of code more
// and more
// and more
}
使用我在 main
中创建的 menu
和 Jpanel
的初始代码?
With the initial code of the menu
and the Jpanel
, that I created in main
?
问候
------------------------
新"代码:
public class DrawPolygons
{
public static void main (String[] args) throws FileNotFoundException
{
// attaching the menu to the frame
JFrame frame = new JFrame("Draw polygons");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// JMenuBar
// Create the menu and JmenuBar
JMenuBar menuBar = new JMenuBar();
// Build the first menu.
JMenu menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menu.getAccessibleContext().setAccessibleDescription("I have items");
menuBar.add(menu);
// menu option - load
// create the load option
final JMenuItem loadItem = new JMenuItem("Load",KeyEvent.VK_T);
// add the shortcut
loadItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK));
// short description
loadItem.getAccessibleContext().setAccessibleDescription("Load your old polygons");
// JFileChooser with filter
JFileChooser fileChooser = new JFileChooser(".");
// apply the filter to file chooser
FileNameExtensionFilter filter = new FileNameExtensionFilter("scn files (*.scn)", "scn");
fileChooser.setFileFilter(filter);
fileChooser.setControlButtonsAreShown(false);
frame.add(fileChooser, BorderLayout.CENTER);
final JLabel directoryLabel = new JLabel(" ");
directoryLabel.setFont(new Font("Serif", Font.BOLD | Font.ITALIC, 36));
final JLabel filenameLabel = new JLabel(" ");
filenameLabel.setFont(new Font("Serif", Font.BOLD | Font.ITALIC, 36));
// add listener to LOAD
loadItem.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent actionEvent)
{
JFileChooser theFileChooser = new JFileChooser();
String command = actionEvent.getActionCommand();
if (command.equals(JFileChooser.APPROVE_SELECTION)) {
File selectedFile = theFileChooser.getSelectedFile();
directoryLabel.setText(selectedFile.getParent());
filenameLabel.setText(selectedFile.getName());
} else if (command.equals(JFileChooser.CANCEL_SELECTION)) {
directoryLabel.setText(" ");
filenameLabel.setText(" ");
}
}} // end listener
); // end listener to loadItem
menu.add(loadItem);
// now SAVE
// create the option for save
JMenuItem saveItem = new JMenuItem("Save",KeyEvent.VK_U);
// key shortcut for save
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.ALT_MASK));
saveItem.getAccessibleContext().setAccessibleDescription("Save the contents of your polygons");
// add the save to the menu
menu.add(saveItem);
frame.setJMenuBar(menuBar);
frame.setContentPane(new DrawingPanel());
frame.pack();
frame.setVisible(true);
}
}
问题是,现在,当我在 File
下点击 Load
时,什么也没有发生.为什么 ?
The problem is , now , when I hit Load
Under File
, nothing is happening . Why ?
我添加了监听器,但什么都没有.
I added the listener , but nothing .
推荐答案
作为一般规则,你不应该让你的 GUI 类,比如扩展 JPanel 的类,实现任何侦听器接口,实际上你应该争取只是相反——将程序的控制功能(监听器等)与程序的视图功能(GUI)分开.因此,我对我如何将 JFileChooser 附加到 actionPerformed 方法... [到扩展 JPanel 的我的 DrawingPanel 类] 的问题的回答是努力不这样做.
As a general rule, you should not have your GUI classes, such as the class extending JPanel, implement any listener interfaces, and in fact you should strive for just the opposite -- to separate the control functions of the program (the listeners and the like) from the view functions of the program (the GUI). So my answer to your question of "how can I attach the JFileChooser to the actionPerformed method... [to my DrawingPanel class which extends JPanel], is to strive to not do this.
相反,让您的视图类实现接口,使控件类可以更轻松地与其交互.
Instead have your view classes implement interfaces that would allow the control classes to more easily interact with them.
编辑 1:您的新代码永远不会显示 JFileChooser 对话框.您需要显示打开的对话框:
Edit 1: your new code you never display the JFileChooser dialog. You need to display the open dialog:
// first make sure that you've declared the JFrame frame as final
int result = theFileChooser.showOpenDialog(frame);
if (result == JFileChooser.APPROVE_OPTION) {
// ... code goes here
}
编辑 2
例如,这是一个 MVC 或 Model-View-Control 实现,它显示了视图、模型和控件.这一切都非常简单,它目前所做的只是打开一个文本文件并在JTextField中显示它,就是这样,它试图将控件功能与视图分开.
For example, here's an MVC or Model-View-Control implementation that shows the view, the model and the control. This is all very simplistic, and all it does at present is to open a text file and display it in a JTextField, that's it, and it tries to seperate out the control functions from the view.
import javax.swing.SwingUtilities;
public class MvcMain {
private static void createAndShowGui() {
MvcView view = new ShowTextView("Show Text");
MvcModel model = new ShowTextModel();
ShowTextControl control = new ShowTextControl(view, model);
control.showView(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
MvcModel 接口
import java.beans.PropertyChangeListener;
public interface MvcModel {
static final String TEXT = "text";
static final String STATUS = "STATUS";
String getText();
String getStatus();
void setText(String text);
void setStatus(String text);
void addPropertyChangeListener(PropertyChangeListener listener);
void removePropertyChangeListener(PropertyChangeListener listener);
}
MvcView 接口
import java.awt.Window;
import javax.swing.Action;
public interface MvcView {
void setVisible(boolean visible);
void setFileAction(Action fileAction);
void setOpenFileAction(Action openFileAction);
void setSaveToFileAction(Action saveToFileAction);
void setExitAction(Action exitAction);
void setStatusText(String string);
String getTextAreaText();
void setTextAreaText(String text);
Window getTopWindow();
}
ShowTextView 类
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Window;
import javax.swing.*;
public class ShowTextView implements MvcView {
private JFrame frame = new JFrame();
private JMenuBar menuBar = new JMenuBar();
private JMenu fileMenu = new JMenu();
private StatusBar statusBar = new StatusBar();
private ViewDisplayText displayText = new ViewDisplayText();
public ShowTextView(String title) {
menuBar.add(fileMenu);
frame.setTitle(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(displayText.getMainComponent(), BorderLayout.CENTER);
frame.getContentPane().add(statusBar.getComponent(), BorderLayout.PAGE_END);
frame.setJMenuBar(menuBar);
}
@Override
public void setVisible(boolean visible) {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
@Override
public void setOpenFileAction(Action action) {
displayText.setOpenFileButtonAction(action);
fileMenu.add(new JMenuItem(action));
}
@Override
public void setSaveToFileAction(Action action) {
displayText.setSaveToFileAction(action);
fileMenu.add(new JMenuItem(action));
}
@Override
public void setExitAction(Action exitAction) {
displayText.setExitAction(exitAction);
fileMenu.add(new JMenuItem(exitAction));
}
@Override
public void setFileAction(Action fileAction) {
fileMenu.setAction(fileAction);
}
@Override
public String getTextAreaText() {
return displayText.getTextAreaText();
}
@Override
public void setTextAreaText(String text) {
displayText.setTextAreaText(text);
}
@Override
public Window getTopWindow() {
return frame;
}
@Override
public void setStatusText(String text) {
statusBar.setText(text);
}
}
class ViewDisplayText {
private static final int TA_ROWS = 30;
private static final int TA_COLS = 50;
private static final int GAP = 2;
private JPanel mainPanel = new JPanel();
private JButton openFileButton = new JButton();
private JButton saveToFileButton = new JButton();
private JButton exitButton = new JButton();
private JTextArea textArea = new JTextArea(TA_ROWS, TA_COLS);
public ViewDisplayText() {
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
buttonPanel.add(openFileButton);
buttonPanel.add(saveToFileButton);
buttonPanel.add(exitButton);
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.setLayout(new BorderLayout());
mainPanel.add(new JScrollPane(textArea), BorderLayout.CENTER);
mainPanel.add(buttonPanel, BorderLayout.PAGE_END);
}
public void setExitAction(Action exitAction) {
exitButton.setAction(exitAction);
}
public JComponent getMainComponent() {
return mainPanel;
}
public void setOpenFileButtonAction(Action action) {
openFileButton.setAction(action);
}
public void setSaveToFileAction(Action action) {
saveToFileButton.setAction(action);
}
public String getTextAreaText() {
return textArea.getText();
}
public void setTextAreaText(String text) {
textArea.setText(text);
}
}
class StatusBar {
private static final String STATUS = "Status: ";
private JLabel label = new JLabel(STATUS);
public StatusBar() {
label.setBorder(BorderFactory.createLineBorder(Color.black));
}
public JComponent getComponent() {
return label;
}
public void setText(String text) {
label.setText(STATUS + text);
}
}
ShowTextModel 类
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
public class ShowTextModel implements MvcModel {
private String text;
private String status;
private SwingPropertyChangeSupport propChangeSupport =
new SwingPropertyChangeSupport(this);
@Override
public String getText() {
return text;
}
@Override
public void setText(String text) {
String newValue = text;
String oldValue = this.text;
this.text = newValue;
propChangeSupport.firePropertyChange(TEXT, oldValue, newValue);
}
@Override
public void setStatus(String status) {
String newValue = status;
String oldValue = this.status;
this.status = newValue;
propChangeSupport.firePropertyChange(STATUS, oldValue, newValue);
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
propChangeSupport.addPropertyChangeListener(listener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
propChangeSupport.removePropertyChangeListener(listener);
}
@Override
public String getStatus() {
return status;
}
}
ShowTextControl 类
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class ShowTextControl {
private MvcView view;
private MvcModel model;
public ShowTextControl(MvcView view, MvcModel model) {
this.view = view;
this.model = model;
view.setFileAction(new FileAction("File", KeyEvent.VK_F));
view.setOpenFileAction(new OpenFileAction(view, model, "Open File",
KeyEvent.VK_O));
view.setSaveToFileAction(new SaveToFileAction(view, model,
"Save to File", KeyEvent.VK_S));
view.setExitAction(new ExitAction(view, model, "Exit", KeyEvent.VK_X));
model.addPropertyChangeListener(new ModelListener(view, model));
}
public void showView(boolean visible) {
view.setVisible(visible);
}
}
@SuppressWarnings("serial")
class OpenFileAction extends AbstractAction {
private MvcView view;
private MvcModel model;
public OpenFileAction(MvcView view, MvcModel model, String name, int keyCode) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
this.model = model;
}
@Override
public void actionPerformed(ActionEvent evt) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setMultiSelectionEnabled(false);
int result = fileChooser.showOpenDialog(view.getTopWindow());
if (result == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
if (file.exists()) {
if (file.getName().endsWith(".txt")) {
model.setStatus("Opening file "" + file.getName() + """);
OpenFileWorker openFileWorker = new OpenFileWorker(file);
openFileWorker.addPropertyChangeListener(
new OpenFileWorkerListener(model));
openFileWorker.execute();
} else {
model.setStatus("File "" + file.getName()
+ "" is not a text file");
}
} else {
model.setStatus("File "" + file.getName() + "" does not exist");
}
}
}
}
class OpenFileWorker extends SwingWorker<String, Void> {
private File file;
public OpenFileWorker(File file) {
this.file = file;
}
public File getFile() {
return file;
}
@Override
protected String doInBackground() throws Exception {
StringBuilder stringBuilder = new StringBuilder();
Scanner scan = null;
try {
scan = new Scanner(file);
while (scan.hasNextLine()) {
stringBuilder.append(scan.nextLine() + "
");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (scan != null) {
scan.close();
}
}
return stringBuilder.toString();
}
}
class OpenFileWorkerListener implements PropertyChangeListener {
private MvcModel model;
public OpenFileWorkerListener(MvcModel model) {
this.model = model;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
OpenFileWorker openFileWorker = (OpenFileWorker) evt.getSource();
try {
String text = openFileWorker.get();
model.setText(text);
model.setStatus("File "" + openFileWorker.getFile().getName() + "" opened");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
@SuppressWarnings("serial")
class FileAction extends AbstractAction {
public FileAction(String name, int keyCode) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
}
@Override
public void actionPerformed(ActionEvent arg0) {
// pretty much empty
}
}
@SuppressWarnings("serial")
class SaveToFileAction extends AbstractAction {
private MvcView view;
private MvcModel model;
public SaveToFileAction(MvcView view, MvcModel model, String name,
int keyCode) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
this.model = model;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO finish!
}
}
@SuppressWarnings("serial")
class ExitAction extends AbstractAction {
private MvcView view;
// private MvcModel model; // TODO: may use this later
public ExitAction(MvcView view, MvcModel model, String name, int keyCode) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
// this.model = model; // TODO: may use this later
}
@Override
public void actionPerformed(ActionEvent e) {
view.getTopWindow().dispose();
}
}
class ModelListener implements PropertyChangeListener {
private MvcView view;
private MvcModel model;
public ModelListener(MvcView view, MvcModel model) {
this.view = view;
this.model = model;
}
@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (MvcModel.TEXT.equals(pcEvt.getPropertyName())) {
view.setTextAreaText(model.getText());
}
else if (MvcModel.STATUS.equals(pcEvt.getPropertyName())) {
view.setStatusText(model.getStatus());
}
}
}
在本例中,为简洁起见,我将 java 类组合在一个文件中,但在应用程序中,它们将位于自己的文件中,但都将共享相同的包.请注意,虽然这对于这个简单的应用程序来说可能是过度杀伤",但我已经在几个非常大的 Swing 应用程序中使用了这种结构,并取得了很好的成功.对我来说,主要的好处是当我需要在创建几个月后调试或增强程序时,因为这种关注点、信息和行为的分离使我更容易在程序的一部分中进行更改,而不会冒犯或扰乱另一部分程序.
In this example, I've combined java classes in one file for brevity, but in the application, they'd be in their own files but would all share the same package. Note that while this may be "over-kill" for this simple application, I've used this sort of structure with several very large Swing applications with good success. The main benefit for me comes when I need to debug or enhance a program months after creation, since this separation of concerns and information and behavior hading makes it much easier for me make changes in one part of the program without offending or upsetting another part of the program.
此外,界面的原因是您可以创建新的或不同的 GUI,它们看起来不同,但可以以相同的方式响应.我还经常使用它们来帮助创建模拟类,让我能够更好地单独测试我的模块.
Also, the reason for the interfaces is so that you can create new or different GUI's that look differently, but that can respond in the same way. I've also used them frequently to help create mock classes that allow me to better test my modules in isolation.
这篇关于将 JFileChooser 与 Swing GUI 类和侦听器一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!