首页 > 解决方案 > JFrame 不显示内容

问题描述

我正在尝试构建一个简单的 Swing 应用程序,用于在 GUI 中插入文件路径。(我知道有 JOptionPane 可以解决这个问题,但我想在用户键入时检查插入的路径是否存在。)
我构建了一个 JFrame 并添加了一个 JTextField 和一个 JButton。它只是另一个程序的一部分,因此它应该在主程序处于活动状态时暂停。
现在,当我启动程序时,JFrame 本身会正常构建。但它不加载内容,它不可关闭,当我尝试调整窗口大小时,整个程序挂起,我不得不从 IDE 强行停止它。

该程序不会抛出任何异常。我试图插入一些日志来测试程序是否在任何时候挂起,我什至照顾了getSize()的组件,但一切都应该是 - 除了 JFrame 的内容在屏幕上不可见。最奇怪的是,我还有另一种基本相同的方法,只是使用了其他组件——而且效果很好。
我已经搜索过类似的问题,但没有成功。有谁知道我做错了什么?

这是我的代码:

import java.awt.BorderLayout;
import java.awt.event.InputMethodEvent;
import java.awt.event.InputMethodListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;

public class Test {
    
    public static String showFileDirInputDialog(String title, String dir) {
        boolean ready = false;
        String newFile = "";
        
        Thread windowThread = new Thread(() -> {
            JFrame frame = new JFrame(title);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(600, 150);
            
            JTextField txt = new JTextField(dir);
            frame.getContentPane().add(txt, BorderLayout.CENTER);
            txt.addInputMethodListener(...); // check inserted path while typing
            
            JButton ok = new Button("OK");
            frame.getContentPane().add(ok, BorderLayout.CENTER);
            ok.addActionListener((e) -> {
                newFile = txt.getText();
                frame.dispose();
                ready = true;
            });
            
            frame.setVisible(true);
        }, "window thread");
        windowThread.start();
        
        while(!ready) {
            System.out.print(""); // do nothing while the window is active
        }
        windowThread.interrupt();
        return newFile;
    }
}

标签: javaswingjframe

解决方案


好的,感谢@camickr,我找到了一个解决方案SwingWorker

package test;

import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutionException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingWorker;

public class Test {
    
    public static void main(String[] args) {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(150, 70);
        
        JButton btn = new JButton("Start");
        btn.addActionListener((e) -> {
            SwingWorker<String, Void> worker = new SwingWorker<>() {
                @Override
                protected String doInBackground() throws Exception {
                    return showFileInput("Insert file path");
                }
                
                @Override
                protected void done() {
                    try {
                        System.out.println(get());
                    }
                    catch (InterruptedException | ExecutionException e) {
                        e.printStackTrace();
                    }
                    finally {
                        System.exit(0);
                    }
                }
            };
            worker.execute();
        });
        frame.getContentPane().add(btn);
        
        frame.setVisible(true);
    }
    
    static String newPath = "";
    static boolean ready = false;
    
    static String showFileInput(String title) {
        Thread windowThread = new Thread(() -> {
            JFrame frame = new JFrame(title);
            frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            frame.setSize(500, 70);
            
            JTextField txt = new JTextField("");
            frame.getContentPane().add(txt, BorderLayout.CENTER);
            
            JButton okButton = new JButton("OK");
            okButton.addActionListener((e) -> {
                newPath = txt.getText();
                frame.dispose();
                ready = true;
            });
            frame.getContentPane().add(okButton, BorderLayout.EAST);
            
            Timer checkInputTimer = new Timer("check input thread");
            checkInputTimer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    File f = new File(txt.getText());
                    okButton.setEnabled(f.exists());
                }
            }, 0, 300);
            
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    newPath = txt.getText();
                    frame.dispose();
                    ready = true;
                }
            });
            frame.setVisible(true);
        }, "window thread");
        windowThread.start();
        
        while(!ready) {
            System.out.print("");
        }
        windowThread.interrupt();
        return newPath;
    }
}

推荐阅读