派发线程以外的线程如何更新swing。
swing设计时是单线程的,同时又是线程不安全的,它并不和主程序在一个线程中,而是自己单独创建的一个线程中,因此在这个让森线程以外的任何线程都不是它的派发线程,如果此时要在主程序或是swing本身线程以外的线程来更新swing的值,就是不安全的,不允许这样做。
但是大多数情况下,我们更新进度条等等这类swing组件的值恰好都是在它的派发线程以外的线程中执行,那么该怎么办呢?芦滑渗?
呵呵,java提供了一个机制:
SwingUtilities.invokeLater(建议好好看看这个,多线程编程用它的地方多着呢)
SwingUtilities.invokeLater的机制网上文章很多,在这就不说了。
解决了这个问题,接下来就容易了。
首先,创建进度条对象,设置相关属性,把它添加到容器中,这个就不用说了。
进度条最关键的问题是:如何获取更新值?
否则会出现,你的任务先执行,然后才执行进度条,两者没有同步。
举个例子:
你要读一个文件,那么获取这个文件长度,设置进度条的最大值为文件长度(把文件长度Long转化为Integer);
当执行文件读写 *** 作时,每次读取一个buffersize(你设置的缓冲大小),让value += count;count记录每读写文件一次,读写的字陪脊节数目
value的最终值是文件长度。用progressbar.setvalue(value)来更新进度条的值,注意,前面已经说过,不能直接在派发线程以外的线程更新swing组件,因此这时进度条并没有更新,不会在界面中反映出来,还是停止不动。因该这样更新: SwingUtilities.invokeLater(progressUpdate)就可以了。
progressUpdate--------------
Runnable progressUpdate = new Runnable() {
public void run() {
pb.setValue(value)
count = (double)100*progress/fileLength
taskOutput.append(String.format(
"Completed %f%% of task.\n", count))
}
开始页面:start.jsp<%@ page contentType="text/htmlcharset=GBK" %>
<% session.removeAttribute("task")%>
<jsp:useBean id="task" scope="session" class="progress.TaskBean"/>
<% task.setRunning(true)%>
<% new Thread(task).start()%>
<jsp:forward page="status.jsp"/>
状态页面:status.jsp
<%@ page contentType="text/htmlcharset=GBK" %>
<jsp:useBean id="task" scope="session" class="progress.TaskBean"/>
<HTML>
<HEAD>
<TITLE>JSP进度条</TITLE>
<% if (task.isRunning()) { %>
<script type="" LANGUAGE="JavaScript">
setTimeout("location='status.jsp'", 1000)
</script>
<% } %>
</HEAD>
<bODY bgcolor="">
<H1 ALIGN="CENTER">JSP进度条</H1>
<H2 ALIGN="CENTER">
结果: <%= task.getResult() %><BR>
<% int percent = task.getPercent()%>
<%= percent %>%
</H2>
<TABLE WIDTH="60%" ALIGN="CENTER"
CELLPADDING=0 CELLSPACING=2>
<TR>
<% for (int i = 10i <= percenti += 10) { %>
<TD WIDTH="10%" height="10" BGCOLOR="red"></TD>
<% } %>
<% for (int i = 100i >percenti -= 10) { %>
<TD WIDTH="10%"></TD>
<% } %>
</TR>
</TABLE>谨斗
<TABLE WIDTH="100%" BORDER=0 CELLPADDING=0 CELLSPACING=0>
<TR>
<TD ALIGN="CENTER">
<% if (task.isRunning()) { %>
正在执行
<% } else { %>
<% if (task.isCompleted()) { %>
完成
<% } else if (!task.isStarted()) { %>
尚未开始
<% } else { %>
已停止
<% } %>
<% } %>
</TD>弯晌裤
</TR>
<TR>
<TD ALIGN="CENTER">
<BR>
<% if (task.isRunning()) { %>
<FORM METHOD="GET" ACTION="stop.jsp">
<INPUT TYPE="SUBMIT" ="停止">
</FORM>
<% } else { %>
<FORM METHOD="GET"埋简 ACTION="start.jsp">
<INPUT TYPE="SUBMIT" ="开始">
</FORM>
<% } %>
</TD>
</TR>
</TABLE>
</BODY></HTML>
停止页面:stop.jsp
<%@ page contentType="text/htmlcharset=GBK" %>
<jsp:useBean id="task" scope="session" class="progress.TaskBean"/>
<% task.setRunning(false)%>
<jsp:forward page="status.jsp"/>
业务逻辑bean:TaskBean.java
package progress
import java.io.Serializable
public class TaskBean
implements Runnable, Serializable {
private int counter
private int sum
private boolean started
private boolean running
private int sleep
public TaskBean() {
counter = 0
sum = 0
started = false
running = false
sleep = 100
}
protected void work() {
try {
Thread.sleep(sleep)
counter++
sum += counter
}
catch (InterruptedException e) {
setRunning(false)
}
}
public synchronized int getPercent() {
return counter
}
public synchronized boolean isStarted() {
return started
}
public synchronized boolean isCompleted() {
return counter == 100
}
public synchronized boolean isRunning() {
return running
}
public synchronized void setRunning(boolean running) {
this.running = running
if (running) {
started = true
}
}
public synchronized Object getResult() {
if (isCompleted()) {
return new Integer(sum)
}
else {
return null
}
}
public void run() {
try {
setRunning(true)
while (isRunning() &&!isCompleted()) {
work()
}
}
finally {
setRunning(false)
}
}
}
你的 action 事件可以放在一个新线程中运行,不要阻挡 Swing 画图。Swing 对事件的响应都是放在一个叫事件派发的线程中去做睁隐高的,如携吵果你的事件响应监听器本身在被事件派发线程调用时你做的事件太花时间了(比如我们来个无限循环啥的)我们就应该把这个 actionPerformed 方法中的事情放在一个新开的线程中去做:
public void actionPerformed(final ActionEvent e) {
new Thread() {
public void run() { // 你的事情都放在这里处理 }
}.start() // 开启一个悉尺新线程来处理,它将不再阻挡 Swing 事件派发线程去绘图。
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)