问题一、Swing使用Substance皮肤教程
请点链接刚开始遇到的问题基本都有http://insubstantial.github.io/insubstantial/substance/docs/getting-started.html
温馨提示:需要的包:
皮肤包:Subtance.jar
下载的包包括这三个前缀的子包
org.pushingpixels.lafplugin…
org.pushingpixels.substance…
org/pushingpixels/lafwidget…
否则会报NoClassDefFoundError
支持包:trident.jar(6.0以上的版本需要)
问题二、Swing中org.jvnet.substance.api.UiThreadingViolationException: Component state change must be done on Event Dispatch Thread 异常或者Exception in thread “Thread-6” java.lang.IllegalArgumentException: Cannot change state of non-idle timeline异常
这是因为Swing本身的线程不安全所致,swing界面刷新线程必须在由EDT分配,可以在SwingUtilities.invokeLater(()->{refreshCode});
注意,refreshCode()中不可包含耗时的工作,否则会阻塞UI线程,无法及时更新,下面是自己的爬虫界面刷新例子:
部分有关该问题的代码如下:
class FilterProgress extends JProgressBar implements Runnable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int count;
FilterProgress(){
this.setMinimum(0);
this.setMaximum(100);
}
public void run(){
//界面更新代码1
SwingUtilities.invokeLater(()->{
crButton.setEnabled(false);
saveButton.setEnabled(false);
flButton.setEnabled(false);
});
HashSet<IPInfo> list=c.getList();
int size=list.size();
count=1;
float inc=100.0F/size;
Iterator<IPInfo> it=list.iterator();
while(it.hasNext()){
IPInfo ipf=it.next();
String ip=ipf.getIP();
String port=ipf.getPort();
StringBuilder str=new StringBuilder("");
str.append("testing..."+line);
str.append(ipf.toString()+line+"状态:");
long start=System.currentTimeMillis();
if (!IPFilter.filter(ip, port)){
it.remove();
str.append("失败");
text.setForeground(Color.RED);
}else{
str.append("成功");
text.setForeground(Color.green);
}
long end=System.currentTimeMillis();
str.append(line+"耗时:"+(end-start)+"ms"+line);
//界面更新代码2
SwingUtilities.invokeLater(()->{
text.append(str.toString());
this.setValue((int)(count++*inc));
});
}
text.append("剩余IP数"+list.size());
//界面更新代码3
SwingUtilities.invokeLater(()->{
crButton.setEnabled(true);
saveButton.setEnabled(true);
flButton.setEnabled(true);
});
}
}
class CountLabel implements Runnable {
private int now=0,pre=-1;
@Override
public void run() {
// TODO Auto-generated method stub
// TODO Auto-generated meth9od stub
//界面更新代码
SwingUtilities.invokeLater(()->{
crButton.setEnabled(false);
saveButton.setEnabled(false);
flButton.setEnabled(false);
});
String result_start = "共抓取";
String result_end = "条结果";
now=0;
pre=-1;
while (!c.getState()) {
now=c.getList().size();
String str=result_start+now+result_end;
//界面更新代码
if (now!=pre){
SwingUtilities.invokeLater(()->{
countLabel.setText(str);
});
}
pre=now;
}
SwingUtilities.invokeLater(()->{
crButton.setEnabled(true);
saveButton.setEnabled(true);
flButton.setEnabled(true);
});
}
}
@Override
//按钮监听器中的事件
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
if (arg0.getActionCommand().equals("crawler")){
//因为要动态刷新界面所以要另开线程
new Thread(new CountLabel()).start();
//开启爬取任务的线程
new Thread(c).start();
}else if (arg0.getActionCommand().equals("filter")){
if (c.getState())
//进度条的线程
new Thread(progress).start();
else
JOptionPane.showMessageDialog(null, "爬取未完成");
}else if(arg0.getActionCommand().equals("save")){
if (c.getState()){
c.saveUsefulIp();
}
else
JOptionPane.showMessageDialog(null, "爬取未完成");
}
}
姑且分析上述代码,也许有人会直接在actionPerformed中这样写:
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
if (arg0.getActionCommand().equals("crawler")){
//因为要动态刷新界面所以要另开线程
//修改部分****************************
SwingUtilities.invokeLater(new CountLabel());
//开启爬取任务的线程
new Thread(c).start();
}else if (arg0.getActionCommand().equals("filter")){
if (c.getState())
//进度条的线程
new Thread(progress).start();
else
JOptionPane.showMessageDialog(null, "爬取未完成");
}else if(arg0.getActionCommand().equals("save")){
if (c.getState()){
c.saveUsefulIp();
}
else
JOptionPane.showMessageDialog(null, "爬取未完成");
}
}
这样虽然可以去掉CountLabel中的多处调用SwingUtilities.invokeLater问题,但是却看不到界面刷新的情况,原因是CountLabel本身有个while循环,是个耗时任务,会阻塞UI主线程,无法实现上层组件刷新(因为子组件刷新是由父组件触发的)。
问题三、我也不知道答案,在界面刷新的代码里进行运算会造成阻塞
class CountLabel implements Runnable {
private int now=0,pre=-1;
@Override
public void run() {
// TODO Auto-generated method stub
// TODO Auto-generated meth9od stub
//界面更新代码
SwingUtilities.invokeLater(()->{
crButton.setEnabled(false);
saveButton.setEnabled(false);
flButton.setEnabled(false);
});
String result_start = "共抓取";
String result_end = "条结果";
now=0;
pre=-1;
while (!c.getState()) {
now=c.getList().size();
//String str=result_start+now+result_end;
//界面更新代码
if (now!=pre){
SwingUtilities.invokeLater(()->{
//setText中的字符串运算会阻塞线程造成界面无法刷新
countLabel.setText(
result_start+now+result_end);
});
}
pre=now;
}
SwingUtilities.invokeLater(()->{
crButton.setEnabled(true);
saveButton.setEnabled(true);
flButton.setEnabled(true);
});
}
}
如有错误,欢迎批评指正