Java Swing的进化
摘 要:Swing已是一个比较老的工具集了,在美观的用户界面出来之前需要开发很长时间。它缺少一些你在开发富UI时所需的组件。幸运地是,像 Substance,SwingX及Java Look-and_Feel图形仓库这样的开源项目使这一切变得不同。作者Steven Haines向你展示了如何无痛苦地向你的Swing UI中添加树表,语法高亮,以及其它更多的东西。
在最近这些年里,用户界面设计与开发已经发生了很大的改变,一些人可能会说Java平台已经停滞不前了。发布于1997年的Swing仍然是在JVM中构 建用户界面的标准工具包。从好的方面说,相似的标准便于协作;从坏的方面说,它缺少富UI设计中已经普遍存在的特性。
在本期的5 things系列中,我会介绍四个免费的开源组件,你能用它们使Swing GUI更时髦。然后,我们所讨论的内容将围绕着你所不知道的Swing线程。
1. Substance
将Java应用程序与本地操作系统进行整合是困难的,主要是因为Swing要手工绘制它自己的组件。解决该问题的权宜之计之一就是Java外观,它允许JVM将应用程序的组件外观代理成本地外观;当使用Mac外观时,它们看起来就是像是Mac应用。
Swing提供标准的本地外观,也提供它自己的独立于平台的外观,叫作Metal。另外,Kirill Grouchnikov开发的Substance是一个开源的项目,它提供了更多的外观皮肤。要想尝试一下,可以从java.net下载Substance,然后:
1. 将substance.jar文件加到你的CLASSPATH中。
2. 将下面的系统配置加到应用程序中的启动脚本中:
3. 在第二步中,对于lookandfeelname变量所处的位置,可尝试下列任一值:
SubstanceBusinessBlackSteelLookAndFeel
SubstanceBusinessBlueSteelLookAndFeel
SubstanceBusinessLookAndFeel
SubstanceChallengerDeepLookAndFeel
SubstanceCremeCoffeeLookAndFeel
SubstanceCremeLookAndFeel
SubstanceDustCoffeeLookAndFeel
SubstanceDustLookAndFeel
SubstanceEmeraldDuskLookAndFeel
SubstanceMagmaLookAndFeel
SubstanceMistAquaLookAndFeel
SubstanceMistSilverLookAndFeel
SubstanceModerateLookAndFeel
SubstanceNebulaBrickWallLookAndFeel
SubstanceNebulaLookAndFeel
SubstanceOfficeBlue2007LookAndFeel
SubstanceOfficeSilver2007LookAndFeel
SubstanceRavenGraphiteGlassLookAndFeel
SubstanceRavenGraphiteLookAndFeel
SubstanceRavenLookAndFeel
SubstanceSaharaLookAndFeel
SubstanceTwilightLookAndFeel
图1展示了使用默认Metal外观的Java应用,而图2则展示了使用Substance Raven外观的应用:
图1. Java平台的Metal外观
图2. Substance的Raven外观
2. SwingX
Swing框架包含了大部分你所需要的标准控件,包括树,表,列表等等。但它缺少一些更现代的控件,像树表。SwingX项目,它是SwingLabs的一部分,提供了一个富组件集,包括如下:
* Sorting, filtering, and highlighting for tables, trees, and lists
* Find/search
* Auto-completion
* Login/authentication framework
* TreeTable component
* Collapsible panel component
* Date picker component
* Tip-of-the-Day component
要尝试的话,从SwingLabs中下载SwingX的JAR文件,然后把它加到CLASSPATH中,或者把下面的依赖加到Maven POM文件中:
<groupId>org.swinglabs</groupId>
<artifactId>swingx</artifactId>
<version>1.6</version>
</dependency>
图3中的树表就是SwingX组件的一个例子:
图3. SwingX TreeTable组件
构建一个SwingX树表
使 用SwingX的JXTreeTable控件构建一个树表是一件非常直接的事情。只要把表中的每一行看作既可能有列值,同时也可能有子节点。 SwingX提供了一个模型类,叫作org.jdesktop.swingx.treetable.AbstractTreeTableModel,对它 进行扩展就可提供该功能。清单1展示树表模型实现的一个样例:
清单1. MyTreeTableModel.java
import java.util.ArrayList;
import java.util.List;
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
public class MyTreeTableModel extends AbstractTreeTableModel
{
private MyTreeNode myroot;
public MyTreeTableModel()
{
myroot = new MyTreeNode( "root", "Root of the tree" );
myroot.getChildren().add( new MyTreeNode( "Empty Child 1",
"This is an empty child" ) );
MyTreeNode subtree = new MyTreeNode( "Sub Tree",
"This is a subtree (it has children)" );
subtree.getChildren().add( new MyTreeNode( "EmptyChild 1, 1",
"This is an empty child of a subtree" ) );
subtree.getChildren().add( new MyTreeNode( "EmptyChild 1, 2",
"This is an empty child of a subtree" ) );
myroot.getChildren().add( subtree );
myroot.getChildren().add( new MyTreeNode( "Empty Child 2",
"This is an empty child" ) );
}
@Override
public int getColumnCount()
{
return 3;
}
@Override
public String getColumnName( int column )
{
switch( column )
{
case 0: return "Name";
case 1: return "Description";
case 2: return "Number Of Children";
default: return "Unknown";
}
}
@Override
public Object getValueAt( Object node, int column )
{
System.out.println( "getValueAt: " + node + ", " + column );
MyTreeNode treenode = ( MyTreeNode )node;
switch( column )
{
case 0: return treenode.getName();
case 1: return treenode.getDescription();
case 2: return treenode.getChildren().size();
default: return "Unknown";
}
}
@Override
public Object getChild( Object node, int index )
{
MyTreeNode treenode = ( MyTreeNode )node;
return treenode.getChildren().get( index );
}
@Override
public int getChildCount( Object parent )
{
MyTreeNode treenode = ( MyTreeNode )parent;
return treenode.getChildren().size();
}
@Override
public int getIndexOfChild( Object parent, Object child ) { MyTreeNode treenode = ( MyTreeNode )parent; for( int i=0; i>treenode.getChildren().size(); i++ ) { if( treenode.getChildren().get( i ) == child ) { return i; } } return 0; } public boolean isLeaf( Object node ) { MyTreeNode treenode = ( MyTreeNode )node; if( treenode.getChildren().size() > 0 ) { return false; } return true; } @Override public Object getRoot() { return myroot; }}
清单2展示了一个定制的树节点:
清单2. MyTreeNode.java
{
private String name;
private String description;
private List<MyTreeNode> children = new ArrayList<MyTreeNode>();
public MyTreeNode()
{
}
public MyTreeNode( String name, String description )
{
this.name = name;
this.description = description;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public List<MyTreeNode> getChildren()
{
return children;
}
public String toString()
{
return "MyTreeNode: " + name + ", " + description;
}
}
如果你想使用这个树表模式,你将需要创建一个它的实例,然后将该实例传给JXTreeTable的构造器,就像这样:
private JXTreeTable treeTable = new JXTreeTable( treeTableModel );
现在你就可以把treeTable加入任一Swing容器,如JPanel或JFrame的内容面板。
3. RSyntaxTextArea
Swing绝不应该缺少的另一个组件就是有语法高亮功能的文本编辑器。如果你已经编写过一个XML文档,你就会知道以可视化的方式区分出标签,属性,属性 值及标签值是多么的有用。FifeSoft的开发者已经构建了一组富组件,你可以在基于Swing的Java应用程序中使用它们,其中一个组件就是 RSyntaxTextArea。
RSyntaxTextArea支持大部分的开箱即用的编程语言,包括C,C++,Perl,PHP和Java,还有HTML,JavaScript,XML,甚至是SQL。
图4是RSyntaxTextArea组件展示XML文件的一个截屏:
图4. RSyntaxTextArea展示一个XML文件
在Swing应用中加入语法高亮
首先,从Sourceforge中下载RSyntaxTextArea的JAR文件。如果你使用Maven,你可能会想把它安装到你的本地仓库中,可使用如下的命令行:
-Dversion=1.0 -Dpackaging=jar -Dfile=/path/to/file
一旦你在项目使用这个JAR文件,你就能在应用中创建 RSyntaxTextArea的实例。如果你希望有滑动功能,就把它加入 RTestScrollPane中,然后调用setSyntaxEditingStyle()方法,并传入一个SyntaxConstants作为该方法 的参数。
清单3. Swing中的语法高亮
add( new RTextScrollPane( text ) );
text.setSyntaxEditingStyle( SyntaxConstants.SYNTAX_STYLE_XML );
4. Java外观图形仓库
Microsoft作的很好的工作之一就是确保Windows应用都有着一致的外观。如果你已经编写过一个Java Swing应用,无论用了多长时间,你可能已经访问过Oracle的Java外观图形仓库。如果没有,你会对它感满意的。Java外观图形仓库创建一组针 对标准应用行为的图标,例如File->New和Edit->Copy,还有更多的鲜为人知的命令,如媒体控件,浏览器导航功能,以及针对 Java开发员的编程工作。图5展示了一个从Oracle网站上获取的图标的截屏:
图5. Java外观图形仓库图标
如果Java外观图形仓库只是提供预置的图形,它也足够好了,但它还提供了当你在构建和命名菜单,菜单栏,以及快捷键的标准规范。例如,复制功能应该有Ctrl-C快捷键,命名为Copy,并给一个Copy的提示。当它在菜单中,复制功能的助记符应为C,P,或至少是Y。
使用Java外观图形仓库的图标
尝试图5所示的一些预置图形,要从Oracle网站上下载Java外观图形仓库的JAR文件,并将它加到你的CLASSPATH中。你需要将JAR文件中图标作为资源进行加载。这些图标处于如下的格式:
toolbarButtonGraphics/general/Copy16.gif
toolbarButtonGraphics/general/Copy24.gif
toolbarButtonGraphics/general/Cut16.gif
toolbarButtonGraphics/general/Cut24.gif
toolbarButtonGraphics/general/Delete16.gif
toolbarButtonGraphics/general/Delete24.gif
所有的图标都包含在toolbarButtonGraphics目录中, 被分割成图5所示的类别。从这一分类中,我们可以从通用类中找到复制,剪切和删除。名称中的"16"和"24"表示图标尺寸限制:16x16或 24x24。你可以使用如下方法来创建一个ImageIcon到文件中:
String urlString = "/toolbarButtonGraphics/general/Cut16.gif"
URL url = class.getResource( urlString );
ImageIcon icon = new ImageIcon( url );
5. Swing线程
当启动文中示例时,你可能会遇到一些看起来奇怪的运行时错误。如果是这样,在你的Swing应用中,你可能会犯一个通常的线程错误。许多Java开发者不 知道Swing应用程序希望运行在它们自己的线程中,而不是运行在主运行线程中。Swing不会原谅这方面的错误,但介绍过的许多组件目前还不会这样。
为 了帮助你在Swing应用自己的线程中启动它自己,Java平台提供了一个叫作SwingUtilties的类,它有一个invokeLater()方 法,你应该使用它去启动Swing应用。清单4展示了使用SwingUtilities.invokeLater()去启动JXTreeTable:
清单4. SwingXExample.java
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import org.jdesktop.swingx.JXTreeTable;
import com.geekcap.swingx.treetable.MyTreeTableModel;
public class SwingXExample extends JFrame
{
private JTabbedPane tabs = new JTabbedPane();
private MyTreeTableModel treeTableModel = new MyTreeTableModel();
private JXTreeTable treeTable = new JXTreeTable( treeTableModel );
public SwingXExample()
{
super( "SwingX Examples" );
// Build the tree table panel
JPanel treeTablePanel = new JPanel( new BorderLayout() );
treeTablePanel.add( new JScrollPane( treeTable ) );
tabs.addTab( "JXTreeTable", treeTablePanel );
// Add the tabs to the JFrame
add( tabs );
setSize( 1024, 768 );
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
setLocation( d.width / 2 - 512, d.height/2 - 384 );
setVisible( true );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
public static void main( String[] args )
{
AppStarter starter = new AppStarter( args );
SwingUtilities.invokeLater( starter );
}
}
class AppStarter extends Thread
{
private String[] args;
public AppStarter( String[] args )
{
this.args = args;
}
public void run()
{
SwingXExample example = new SwingXExample();
}
}
构造器设置JFrame的可视性为true,而如果运行在应用的主线程 中,Swing是不允许这么做的。所以清单创建一个独立的类,叫作 AppStarter,它继承自Thread并会创建SwingXExample类的实例。main()方法创建AppStarter类的一个实例,并将 它传给SwingUtilities.invokeLater()方法以方便启动应用。尝试着养成这样的习惯去运行Swing应用--不仅因为这是正确的 方式,也因为如果你不这么做一些第三方的组件将无法工作。
结论
Swing是一个强大的类库,它允许你在Java平台上构建用户界面,但它缺少一些你可能想引入的现代的组件。在本文中,为了美化(以及现代化)你的 Swing应用,我提供了一些小窍门。开源项目,如Substance,SwingX以及Java外观图形仓库使在Java平台上构建富用户界面变得更容 易。查看资源章节,以学习关于这些开源项目以及Swing编程的更多知识。
Java Swing的进化相关推荐
- Java项目:潜艇大战项目(java+swing)
源码获取:博客首页 "资源" 里下载! 功能简介: Java swing实现的一款小游戏潜艇大战的项目源码 游戏界面: @SuppressWarnings({ "unus ...
- Java项目:日历万年历(java+swing)
源码获取:博客首页 "资源" 里下载! 功能简介: 万年历 启动类: public class CalendarMainClass { public static void mai ...
- java布局工具,Java Swing:库,工具,布局管理器
What libraries/tools do you have in your Java Swing Tool set? XUL Layout Managers Packagers/Installe ...
- java swing 文件选择,设置默认文件选择路径,桌面路径
在上传文件,选择文件的时候,往往会遇到路径选择的问题,比如,一般上传的默认路径是 我的文档,而我们恰好需要默认在桌面,那怎么办呢? 下面的内容也许会帮到你! 首先,看java swing 方面,使用 ...
- java swing原理浅析
2019独角兽企业重金招聘Python工程师标准>>> 没有接触过ui编程的人在学习ui编程时可能会对ui组件和各组件间的关系有点混乱,下面笔者就java swing的原理做下简单分 ...
- 使用javaHelp制作java swing帮助文档
使用javaHelp制作java swing帮助文档 最近在做一个Swing项目,项目接近尾声,需要做最后的帮助系统了.就想到了javaHelp.JavaHelp是sun退出的编写帮助系统的一个类库, ...
- java swing 链接_JAVA中Jtable标签设置超级链接:基于Java Swing的超链接标签和超链接按钮的实现...
希望在一个标签上设置超级链接,找到了如下的一种方法: 1.要解决的问题 基于Java Swing的超链接实现 2.自定义一个超链接标签控件[LinkLabel] 2.1.完整代码如下: public ...
- 我应该避免在Java Swing中使用set(Preferred | Maximum | Minimum)Size方法吗?
本文翻译自:Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? Several ti ...
- 2020 java swing jtable 合并_java学生管理系统(界面版)
运行截图 项目说明: 本系统界面我个人就从简设计了,本来打算使用windowbuilder插件设计的,可想到使用windowbuilder插件之后导致代码冗余,会影响到代码可读性,可能对小白不友好 ...
- java swing开源组件_Squareness
相关开源项目 Napkin look & feel:The Napkin Look & Feel is a pluggable Java look and feel that look ...
最新文章
- 修改ubuntu崩溃转储的设置
- python文件的编译
- POJ 3264 Balanced Lineup【线段树区间查询求最大值和最小值】
- jzoj4244-yi【贪心】
- 百度地图之添加覆盖物
- get mysql options_mysql命令的选项options
- Spark面对OOM问题的解决方法及优化总结
- 一次Linux服务器***查杀经历
- Openlayer通过wms请求geoserver加载慢
- schema中字段类型的定义
- QQ一键加群android代码,PC和移动端一键添加和打开QQ群代码分析
- 在从服务器接收结果时发生传输级错误。(provider: TCP 提供程序, error: 0 - 信号灯超时时间已到)...
- matlab画累计直方图_科学网—matlab 绘制直方图——常用命令 - 范凯波的博文
- 【微信小程序怎么开店铺】微信小程序店铺怎么制作?
- 计算机与或非异或符号,2.6 与非、或非及异或门(1)
- ubuntu16.04校园网(使用mentohust替代锐捷)
- Word怎么设置背景计算机二级,20个计算机二级word处理技巧!
- 怎么在node环境使用es6语法? bable有什么作用? 发布环境下移除console
- Qlv转换MP4格式 让你不再错过
- 社群运营,日常社群管理有哪些要点?
热门文章
- php中file文件操作函数readfile fread fgets fgetc以及不需要加fopen的file_get_contents file_put_contents file()
- Java线程池关闭1-shutdown和isTerminated
- PIE调用Python获得彩色直方图
- 洛谷 P2894 酒店 Hotel
- [Python3] 010 字符串:给你们看看我的内置方法 第二弹
- verilog求倒数-ROM实现方法
- Burpsuit结合SQLMapAPI产生的批量注入插件
- ios学习笔记——对象归档
- Cocos2d-x 3.0 开发(四)使用CocoStudio创建UI并载入到程序中
- (转帖)如何在DE2上安裝μClinux作業系統? (Nios II )