Java Swing invokeLater从未出现,invokeAndWait抛出错误。我能做什么?
我有以下代码:Java Swing invokeLater从未出现,invokeAndWait抛出错误。我能做什么?,java,swing,Java,Swing,我有以下代码: try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { try { dialog.handleDownload(); } catch (IOException io) { io.printStackTrace(); } } }); } catc
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
dialog.handleDownload();
} catch (IOException io) {
io.printStackTrace();
}
}
});
} catch(Exception io) { io.printStackTrace(); }
在handleDownload
中,我正在读取输入流,计算进度条的值,并将其设置为该值。所以,当我点击一个按钮时,一个新的JFrame就会打开,并完成我上面写的所有工作
如果我有
对话框.handleDownload
本身(在no-SwingUtilities方法中),它将冻结,直到操作完成。如果我将它添加到invokeLater
中,它会很快关闭(我看不到任何东西,操作也没有完成)。如果将其添加到invokeAndWait
中,则无法从事件调度程序线程错误调用invokeAndWait
。我该怎么办?如果您是为了响应按钮单击而这样做的,那么您已经在事件线程中,因此invokeAndWait实际上是在错误的方向上进行的
您需要启动一个新线程来执行handleDownload线程,该线程不是事件调度线程的一部分,而是
在新线程中运行时,请确保任何GUI更新都使用invokeAndWait或最好使用invokeLater返回EDT
要记住的简单规则:
- Swing交给您的任何线程都是EDT,所以您需要在其上执行所有GUI内容
- 在EDT上执行GUI元素的所有更新(仅限)
- 在非EDT线程上执行任何需要较长时间的操作(启动新线程)
- 使用invokeLater从非EDT线程返回EDT
public static void main(String[] args) {
final int SIZE = 1024*1024; //1 MiB
//simulates downloading a 1 MiB file
final InputStream in = new InputStream() {
int read = 0;
public int read() throws IOException {
if ( read == SIZE ) {
return -1;
} else {
if ( read % 200 == 0 ) {
try { Thread.sleep(1); } catch ( InterruptedException e ) {}
}
read++;
return 5;
}
}
};
final JProgressBar progress = new JProgressBar(0, SIZE);
final JButton button = new JButton("Start");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
button.setText("Working...");
SwingWorker<byte[], Integer> worker = new SwingWorker<byte[], Integer>() {
@Override
protected byte[] doInBackground() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
for ( int read = -1; (read = in.read(buff)) != -1; ) {
baos.write(buff, 0, read);
publish(read);
}
return baos.toByteArray();
}
@Override
protected void process(List<Integer> chunks) {
int total = 0;
for ( Integer amtRead : chunks ) {
total += amtRead;
}
progress.setValue(progress.getValue() + total);
}
@Override
protected void done() {
try {
byte[] data = get();
button.setText("Read " + data.length + " bytes");
} catch (Exception e) {
e.printStackTrace();
}
}
};
worker.execute();
}
});
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.add(button, BorderLayout.NORTH);
frame.add(progress, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack(); frame.setVisible(true);
}
publicstaticvoidmain(字符串[]args){
最终int SIZE=1024*1024;//1 MiB
//模拟下载1 MiB文件
最终输入流输入=新输入流(){
int read=0;
public int read()引发IOException{
如果(读取==大小){
返回-1;
}否则{
如果(读取%200==0){
试试{Thread.sleep(1);}catch(InterruptedException e){}
}
读++;
返回5;
}
}
};
最终JProgressBar进度=新JProgressBar(0,大小);
最终JButton按钮=新JButton(“开始”);
addActionListener(新建ActionListener()){
@凌驾
已执行的公共无效操作(操作事件e){
按钮。设置文本(“工作…”);
SwingWorker worker=新SwingWorker(){
@凌驾
受保护字节[]doInBackground()引发异常{
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
字节[]buff=新字节[1024];
对于(int read=-1;(read=in.read(buff))!=-1;){
写入(buff,0,read);
出版(阅读);
}
返回baos.toByteArray();
}
@凌驾
受保护的无效进程(列表块){
int-total=0;
for(整数amtRead:chunks){
总数+=amtRead;
}
progress.setValue(progress.getValue()+总计);
}
@凌驾
受保护的void done(){
试一试{
字节[]数据=get();
button.setText(“读取”+data.length+“字节”);
}捕获(例外e){
e、 printStackTrace();
}
}
};
worker.execute();
}
});
JFrame=新JFrame();
frame.setLayout(新的BorderLayout());
框架。添加(按钮,边框布局。北);
框架。添加(进度,边界布局。南部);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();frame.setVisible(true);
}
编辑:将示例更改为像下载一样驱动进度条。听起来您需要的是一个。这将允许您在一个单独的线程中下载文件,而不会影响EDT 您的代码如下所示:
class Downloader extends SwingWorker<String, Void> {
@Override
public String doInBackground() {
dialog.handleDownload();
return "done";
}
@Override
protected void done() {
try {
someLabel.setText(get());
} catch (Exception ignore) {
}
}
}
类下载程序扩展SwingWorker{
@凌驾
公共字符串doInBackground(){
dialog.handleDownload();
返回“完成”;
}
@凌驾
受保护的void done(){
试试{
setText(get());
}捕获(异常忽略){
}
}
}
这是一个很好的例子。不过,我会将循环更改为:for(inti=0;I<100;I++){num+=5;publish(num);Thread.sleep(100);}
@jjngguy:对于这个示例,我实际上想要的是