我有一个像这样初始化的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
编辑。
我的工作线程第一个跨越两个类:
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;
}
}
}
}
答案 0 :(得分:1)
不确定这适用于java版本,我更习惯于C版本,但无论如何......
它不应该是尝试更新主线程的工作线程,而是反过来。从处理clicked
信号的回调中,您应该调用idleAdd
,并创建并运行您的工作线程。在工作线程中,您将更新主线程将具有访问权限的变量,以及将放置进度值的位置。然后,主循环将偶尔运行空闲处理程序,并将读取该值。然后它会更新进度条,但重要的是这个调用是从主线程完成的。
GTK不是线程安全的,因为大多数工具包(java版本可能接近线程安全,但我不是100%肯定,并且在GTK中进行的后续更改可能在将来打破这一点,所以我会不依赖它)。因此,您的工作线程不应该混淆用户界面组件。
带上一粒盐,我在C中知道一点GTK,而不是java-gnome,所以我可能完全错了,idleAdd
文档似乎无论如何都证实了。