我正在尝试使用Swing进行文件传输通知。这个想法是,当我的应用程序通过网络提供一个文件时,用户收到一个JOptionPane
询问他或她是否想接受该文件提供,如果他们的答案是肯定的,我想打开一个JFileChooser
,这样他们就可以浏览到他们想要保存文件的位置。
我遇到的问题是,两者单独工作都很好,但是当我设置它们时,JOptionPane
打开JFileChooser
,我的应用程序死锁。
有人知道这里出了什么问题吗?我试过调试,但没有发现任何奇怪的行为,可以说明为什么它会死锁。
编辑:下面的示例代码似乎工作得很好,让我相信问题可能在于另一个线程。进一步的细节:
我正在使用一个应用程序线程,ApplicationLayer线程和一个'Main'线程,主线程根据我定义的字符串生成一个字节数组,然后它将生成的字节数组通过我的ApplicationLayer发送到我的应用程序。
ApplicationLayer是一个Observable,而Application是它的Observer。
当ApplicationLayer接收到所述字节数组时,它将其解析回字符串,并通知它的观察者它已经这样做了。
然后依次通知应用程序。在我的例子中,应用程序注意到字符串是一个文件报价,并相应地调用'saveFile'方法,如下面的代码所示。代码:
package application;
public class GUI extends JFrame implements ActionListener, ItemListener, Observer {
private JPanel cp = new JPanel();
private JPanel ulp = new JPanel();
private JTextField myMessage;
private JTextArea taMessages;
// Menu Bar Elements
JMenuBar menuBar;
JMenu menu, submenu;
public GUI(){
super();
this.setLayout(new BorderLayout());
setPreferredSize(new Dimension(800, 600));
setMinimumSize(new Dimension(800, 600));
buildBarMenu();
buildChatMenu();
addWindowListener(new WindowAdapter() {
public void windowClosing(final WindowEvent e) {
e.getWindow().dispose();
}
public void windowClosed(final WindowEvent e) {
System.exit(0);
}
}
);
pack();
validate();
setVisible(true);
}
public static void main(final String[] args) {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
// If Nimbus is not available, fall back to cross-platform
try {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
} catch (Exception ex) {
}
}
new GUI();
}
private void buildBarMenu(){
// Create the menu bar
JMenuBar menuBar = new JMenuBar();
// Create a menu
JMenu menu = new JMenu("File");
menu.setHorizontalTextPosition(SwingConstants.CENTER);
menu.setVerticalTextPosition(SwingConstants.BOTTOM);
menuBar.add(menu);
// SendFile Item
JMenuItem sendFileItem = new JMenuItem("Send File");
sendFileItem.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
saveFile(); // Put whatever here
}
});
// Exit item
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
menu.add(sendFileItem);
menu.add(exitItem);
this.setJMenuBar(menuBar);
}
private void buildChatMenu() {
this.add(cp, BorderLayout.CENTER);
this.add(ulp, BorderLayout.EAST);
}
/**
* Method to be called for saving files when a file transfer
* request is received
* @return the path to save the file to
*/
public String saveFile(){
int choice = JOptionPane.showConfirmDialog(GUI.this, "You are being offered a file, accept?", "File Offer",
JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION){
System.out.println("yes");
JFileChooser c = new JFileChooser();
int rVal = c.showOpenDialog(GUI.this);
if (rVal == JFileChooser.APPROVE_OPTION) {
}
if (rVal == JFileChooser.CANCEL_OPTION) {
}
}else{
System.out.println("no");
}
return null;
}
public void save2(){
JFileChooser c = new JFileChooser();
int rVal = c.showOpenDialog(GUI.this);
if (rVal == JFileChooser.APPROVE_OPTION) {
System.exit(0);
}
if (rVal == JFileChooser.CANCEL_OPTION) {
System.exit(0);
}
}
@Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
@Override
public void update(Observable o, Object arg) {
if(arg instanceof ChatMessage){
cp.addMessage(((ChatMessage) arg).getNickname(), ((ChatMessage) arg).getMessage());
}
else if(arg instanceof FileOfferMessage){
cp.addMessage("FILE OFFER", ((FileOfferMessage) arg).getFileName() + " | File Size: " + ((FileOfferMessage) arg).getFileSize() + " bytes");
saveFile();
}
}
}
任何使用Swing组件的代码都必须在EventDispatchThread中运行。您的main()
方法应该调用invokeLater,并在传递的Runnable
中执行GUI操作(包括外观部分)。
注:这是在关闭窗口时退出应用程序的首选方式。