如何设置方法优先级以便在运行时从工作线程更新Java-Gnome GUI组件

时间:2013-01-22 07:44:36

标签: java multithreading user-interface gtk gnome

我有一个像这样初始化的Java-Gnome GUI:

public static void main(String[] args) {
    Gtk.init(args);
    new GTK();
    Gtk.main();
}

public GTK() {
    initUI(this);
    //Exit GUI cleanly if close pressed
    connect(this);
    showAll();
}

public void initUI(final GTK gtk) {
    //Add various panes, boxes, buttons etc...
    //All my UI updates made at runtime here work correctly

    start.connect(new Button.Clicked(){

    @Override
    public void onClicked(Button start){
    worker = new worker(fileList, gtk);
    Thread workerThread = new Thread(worker);
    workerThread.start();

    Glib.idleAdd(new Handler(){
    public boolean run(){

    progress = worker.getProgress();

    if(progress != 1){
        progressBar.setFraction(progress);
        return true;
    }
    else{
          progressBar.setFraction(progress);
          return false;
                }
             }
         });
            }
    });
}

其中progressBar是我的GUI(org.gnome.gtk.ProgressBar)中的一个组件,但progressBar在所有内容都运行完之后才更新,看起来好像它被放在队列的后面而只是在结束,而不是像我希望的那样。

http://java-gnome.sourceforge.net/NEWS.html

http://java-gnome.sourceforge.net/doc/api/4.1/org/gnome/glib/Glib.html#idleAdd(org.gnome.glib.Handler)

编辑。

我的工作线程第一个跨越两个类:

public class auCDtect implements Runnable { 

private String processingLog;
private String output;
private String summary;
private Collection<String> fileList;
private double progress = 0.0;
private GTK gtk;

auCDtect(Collection<String> fileList, GTK gtk){this.fileList = fileList; this.gtk = gtk;}

public void run () {

    List<String> command = new ArrayList<String>();
    command.add("./auCDtect");
    command.add("-d");
    command.add("-m10");

    //Add each song passed to this class to the auCDtect command
    for(String file:fileList){

        command.add(file);
    }
    ProcessBuilder processBuilder = new ProcessBuilder(command);

        Process process = null;
        try {
            process = processBuilder.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //Set up error stream thread 
        StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", this); 

        //Set up output stream thread
        StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", this); 

        // Start error and input stream threads
        new Thread(errorGobbler).start(); 
        new Thread(outputGobbler).start(); 
  }

public void update(double progress, String processingLog, String output, String summary){

    this.processingLog = processingLog;
    this.output = output;
    this.summary = summary;
    this.progress = progress/(fileList.size());
    gtk.setOutputUpdated(true);
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public double getProgress(){

    return progress;
}

public String getProcessingLog(){

    return processingLog;
}

public String getOutput(){

    return output;
}

public String getSummary(){

    return summary;
}

}

和第二个产生的第二个:

public class StreamGobbler implements Runnable { 

InputStream inputStream; 
String type;
private String processingLog = null;
private String output = null;
private String summary = null;
protected boolean finished = false;
private auCDtect auCDtect;
private int progress = 0;

StreamGobbler(InputStream inputStream, String type, auCDtect auCDtect){this.inputStream = inputStream; this.type = type; this.auCDtect = auCDtect;} 

public void run(){ 

    Scanner scanner = new Scanner(inputStream);

    while (((scanner.hasNextLine())&&(type == "OUTPUT"))){

        String line = scanner.nextLine();

        if(line.contains("Processing file:")){
            processingLog = line.substring(line.indexOf("P"), (line.indexOf("]")+1));
        }
        if(line.contains("This track looks like")){
            output = line.substring(line.indexOf("This track"), (line.indexOf("%")+1));
            progress = progress + 1;
        }
        if(line.contains("These")){
            summary = line.substring(line.indexOf("These tracks"));
        }

        if((type == "OUTPUT")&&(progress > 0)){

            auCDtect.update(progress, processingLog, output, summary);
            processingLog = null;
            output = null;
            summary = null;
        }
    }

}
}

1 个答案:

答案 0 :(得分:1)

不确定这适用于java版本,我更习惯于C版本,但无论如何......

它不应该是尝试更新主线程的工作线程,而是反过来。从处理clicked信号的回调中,您应该调用idleAdd,并创建并运行您的工作线程。在工作线程中,您将更新主线程将具有访问权限的变量,以及将放置进度值的位置。然后,主循环将偶尔运行空闲处理程序,并将读取该值。然后它会更新进度条,但重要的是这个调用是从主线程完成的。

GTK不是线程安全的,因为大多数工具包(java版本可能接近线程安全,但我不是100%肯定,并且在GTK中进行的后续更改可能在将来打破这一点,所以我会不依赖它)。因此,您的工作线程不应该混淆用户界面组件。

带上一粒盐,我在C中知道一点GTK,而不是java-gnome,所以我可能完全错了,idleAdd文档似乎无论如何都证实了。