[英]Using a JFileChooser with Swing GUI classes and listeners
這是我目前的菜單:
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
方法,在這里:
/**
* 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( "\n" ) ;
}
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
}
使用menu
的初始代碼和Jpanel
,我在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);
}
}
問題是,現在,當我點擊Load
Under File
,沒有任何事情發生。 為什么?
我添加了聽眾,但沒有。
作為一般規則,你不應該有你的GUI類,比如擴展JPanel的類,實現任何監聽器接口,實際上你應該爭取恰恰相反 - 分離程序的控制功能(監聽器和喜歡)從程序的視圖功能(GUI)。 因此,我對“如何將JFileChooser附加到actionPerformed方法... [我的DrawingPanel類擴展JPanel]”的問題的答案是努力不這樣做。
相反,您的視圖類實現了允許控件類更容易與它們交互的接口。
編輯1 :您的新代碼永遠不會顯示JFileChooser對話框。 您需要顯示打開的對話框:
// 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中,就是這樣,它試圖從視圖中分離出控制功能。
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();
}
});
}
}
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);
}
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();
}
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);
}
}
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;
}
}
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() + "\n");
}
} 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應用程序一起使用並取得了很好的成功。 當我需要在創建幾個月后調試或增強程序時,我的主要好處就出現了,因為這種關注點和信息與行為的分離使我更容易在程序的一個部分進行更改而不會冒犯或擾亂另一部分程序該程序。
此外,接口的原因是您可以創建看起來不同的新的或不同的GUI,但可以以相同的方式響應。 我也經常使用它們來幫助創建模擬類,使我能夠更好地單獨測試我的模塊。
我建議使用Action(s)在那里使用。 在每個操作中,您都有一些特定的actionlistener,如果您願意,可以將面板設置為偵聽器:
快速解決您的問題是提供一個處理程序,以便您可以附加ActionListener。 您在main()
創建了JMenus,但在DrawingPanel
沒有它們的可見性。 完成這項工作的一種便宜方法是將JMenuItems傳遞給DrawingPanel構造函數。 將構造函數修改為:
DrawingPanel(JMenuItem save, JMenuItem open) {
// the stuff you already got
this.save = save;
this.open = open;
save.addActionListener(this);
open.addActionListener(this);
}
然后你將它們傳遞到main
的DrawingPanel:
JMenuItem loadMenuItem = new JMenuItem("Load");
JMenuItem saveMenuItem = new JMenuItem("Save");
...
frame.getContentPane(new DrawingPanel(saveMenuItem, loadMenuItem));
從Java風格的角度來看,不清楚DrawingPanel
是否是處理保存和加載操作的最佳位置。 正如其他人所提到的,為每個JMenuItem創建(單獨)Actions通常是一種更好的模式。 在您的情況下,您可能能夠在DrawingPanel中提供其他訪問者或幫助程序方法,這些方法將為saver / loader工作人員提供他們執行Action所需的信息。
編輯:(解決OP的“新代碼”編輯)
我認為“新代碼”的問題在於你在actionPerformed
方法中創建一個new
JFileChooser,而不是使用你之前創建並添加到框架中的現有JFileChooser。 如果你將第一個作為final
那么你可以在actionPerformed
方法中使用相同的JFileChooser。
要詳細說明Kitesurfer所說的我將使用Action,因為我經常使用工具欄按鈕或其他組件執行與菜單項相同的操作。 為了避免在類中的某個地方(或者我能夠從當前類訪問它的任何地方)重復或不必要的代碼,我創建一個Action
字段,如果需要我可以重用,如果我決定重構我的代碼則移動。 這是一個例子。
JMenuItem miLoad = new JMenuItem(actionLoad);
Action actionLoad = new AbstractAction("Load") {
public void actionPerformed(ActionEvent e) {
//your code to load the file goes here like a normal ActionListener
}
};
絕對檢查API以查看哪些參數可以傳遞到AbstractAction
類,我使用了一個String
所以JMenuItem
會顯示字符串,你也可以設置Icon
,我不記得所有的構造函數所以它值得看看。 哦,將JMenuItems
傳遞給DrawingPanel
類的構造函數不一定是個壞主意,但如果它繼承自JPanel
我不相信你可以向JPanel
添加一個菜單欄,所以要確保它也被添加到你的JFrame
。 希望有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.