前言 N年之前,在eclipse刚问世的时候,就惊讶于JAVA居然能开发出这么原生,操作灵敏的界面,那时知道eclipse是基于SWT开发的,却没机会使用swt开发任何项目,最近个人出于兴趣写了一个小工具,就抱着试试看的心态使用swt编写界面。

SWT由来 SWT(Standard Widget Toolkit)即标准小窗口工具箱,是IBM公司推出的一种在Eclipse中使用的集成开发环境,SWT提供可移植的API,并与底层本机OS GUI平台紧密集成,它是一个与本地窗口系统集成在一起的小部件集和图形库。SWT由JNI(Java Native Interface,Java本机接口)调用操作系统的内部API,因此运行速度快,能够获得与操作系统的内部应用程序相同的外观。

java swing界面设计位置_开发工具

Swt和SWING的比较

AWT/SWING是sun公司发布的jdk里的,由于有了虚拟机这一层的屏蔽,SWING不依赖于直接调用本地系统的组件,拥有较强的跨平台性,所以在不同操作系统上显示的都是同个外观。SWING组件博大精深,学习起来更加困难,需要加以时日才能轻松驾驭,但是功能也更加强大。

SWT通过JNI直接调用了操作系统的图形库,从而使得Java应用程序的Look & Feel 与操作系统的习惯完全一致,所以SWT开发的界面在不同的操作系统上显示都是不同的外观;更为重要的是,对本地方法的直接调用大幅度的提高了基于SWT的Java应用程序的运行速度。SWT的缺点主要在于两点:(1) 不是Java语言标准;和(2)支持的平台太少。


开发第一个SWT程序

eclipse的plugins目录下,找到文件org.eclipse.swt.win32.win32.x86_3.2.1.v3235.jar,文件名中中3.2.1是eclipse 的版本号,v3235是SWT 的序列号,不同的eclipse版本这两个数字也不同。

操作步骤:

1 新建一个Java 项目,项目名为:sample4_1。

2 配置构建路径,将org.eclipse.swt.win32.win32.x86_3.2.1.v3235.jar加入到项目中,名称太长这里我直接改名为swt.jar。eclipse包资源管理器可以看到导入的原生库文件和引入的jar文件

java swing界面设计位置_开发工具_02

3 在项目中新建一个类,文件名为HelloSWT.java。

4

HelloSWT.java文件内容如下:

<span >import org.eclipse.swt.SWT;

import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.Text;

import org.eclipse.swt.widgets.Shell;

import org.eclipse.swt.graphics.*;

 

class HelloSWT {

       public static void main(String[] args) {

              Display display = new Display();// 创建一个display对象。

              Shell shell = new Shell(display);// shell是程序的主窗体

              shell.setLayout(null); // 设置shell的布局方式

              Text hello = new Text(shell, SWT.MULTI); // 声明一个可以显示多行信息的文本框

              shell.setText("Java应用程序"); // 设置主窗体的标题

              shell.setSize(200, 100); // 设置主窗体的大小

              Color color = new Color(Display.getCurrent(), 255, 255, 255);// 声明颜色对象

              shell.setBackground(color); // 设置窗体的背景颜色

              hello.setText("Hello, SWT World!\n\n你好,SWT世界!");// 设置文本框信息

              hello.pack(); // 自动调整文本框的大小

              // shell.pack(); //自动调整主窗体的大小

              shell.open(); // 打开主窗体

              while (!shell.isDisposed()) { // 如果主窗体没有关闭则一直循环

                     if (!display.readAndDispatch()) { // 如果display不忙

                            display.sleep(); // 休眠

                     }

              }

              display.dispose(); // 销毁display

       }

}

</span>


在包资源管理器中,右单击文件名HelloSWT.java→运行方式→Java应用程序,程序运行

结果如图所示。该窗体具有典型的Windows风格。

java swing界面设计位置_shell_03

分析本例的源代码,可以看到,创建一个典型的SWT应用程序需要以下步骤:

①创建一个Display

②创建一个或多个Shell

③设置Shell的布局

④创建Shell中的组件

⑤用open()方法打开Shell窗体

⑥写一个事件转发循环

⑦销毁 display



开发一个搜车的小工具

下面来做一个稍微复杂一些的界面,直接上代码,先看最终效果图:

java swing界面设计位置_eclipse_04

注意:本文仅讨论SWT界面的内容,因此把代码里包含别的业务逻辑的代码都注释掉了


package com.findcar.swt;


import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

//import com.findcar.MainController;
//import com.findcar.client.ToolsClient;


public class MainApp {

	private Shell shell = null;
	//private MainController control = null;
	private static Text logText = null; // 创建日志打印框Text对象
	Button startButton;
	List filtersList = null;
	Text maillist = null;;
	Text carType = null;
	Text price = null;
	Text miles = null;
	Text syear = null;

	public void init() {
		//control = new MainController();
		Display display = new Display();

		shell = new Shell(display);
		shell.setSize(600, 450);
		shell.setText("搜 车");

		FillLayout fillLayout = new FillLayout(); // 创建FillLayout对象
		GridLayout gridLayout1 = new GridLayout(); // 创建GridLayout对象
		gridLayout1.makeColumnsEqualWidth = true;
		gridLayout1.numColumns = 1;
		gridLayout1.verticalSpacing = 2;
		shell.setLayout(gridLayout1); // 将FillLayout对象用于shell上

		Group conditionGroup = new Group(shell, SWT.NONE); // 创建分组框
		conditionGroup.setText("设置搜索条件"); // 设置分组框说明信息
		GridData gridData1 = new GridData(GridData.FILL_BOTH
				| GridData.HORIZONTAL_ALIGN_CENTER);
		gridData1.grabExcessVerticalSpace = false; // 抢占垂直方向额外空间

		GridLayout gridLayout2 = new GridLayout();
		gridLayout2.numColumns = 6;
		gridLayout2.horizontalSpacing = 10;
		// gridLayout2.makeColumnsEqualWidth=false;
		conditionGroup.setLayout(gridLayout2);
		conditionGroup.setLayoutData(gridData1);

		GridLayout gridLayout3 = new GridLayout();
		gridLayout3.numColumns = 3;
		gridLayout3.horizontalSpacing = 10;

		Group buttonGroup = new Group(shell, SWT.NONE); // 创建分组框

		buttonGroup.setLayout(gridLayout3);
		buttonGroup.setLayoutData(gridData1); // 设置按钮的布局数据

		Group listGroup = new Group(shell, SWT.NONE); // 创建分组框
		listGroup.setText("已设置条件列表"); // 设置分组框说明信息
		filtersList = new List(listGroup, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
		// filtersList.addSelectionListener(new SelectionAdapter(){
		// public void widgetSelected(SelectionEvent e){
		// filtersList.removeAll();
		// }
		// });
		GridData gridData3 = new GridData(GridData.FILL_BOTH
				| GridData.HORIZONTAL_ALIGN_CENTER);
		gridData3.grabExcessVerticalSpace = true; // 抢占垂直方向额外空间
		listGroup.setLayout(fillLayout);
		listGroup.setLayoutData(gridData3);

		Group logGroup = new Group(shell, SWT.NONE); // 创建分组框
		logGroup.setText("日志"); // 设置分组框说明信息
		logGroup.setLayoutData(gridData3);
		logGroup.setLayout(fillLayout);

		Label label = new Label(conditionGroup, SWT.None); // 在shell中创建Label对象
		label.setText("车型(关键词)");

		carType = new Text(conditionGroup, SWT.BORDER); // 在composite上创建button
														// B1
		// carType.setText("B1");
		carType.setLayoutData(gridData1);
		label = new Label(conditionGroup, SWT.None); // 在shell中创建Label对象
		label.setText("最高价格(万)");
		price = new Text(conditionGroup, SWT.BORDER); // B2设置同B1
		price.addVerifyListener(new TextVerifyListener(2));
		price.setLayoutData(gridData1);
		label = new Label(conditionGroup, SWT.None); // 在shell中创建Label对象
		label.setText("最大公里数(万)");
		miles = new Text(conditionGroup, SWT.BORDER); // B2设置同B1
		miles.addVerifyListener(new TextVerifyListener(2));
		miles.setLayoutData(gridData1);
		label = new Label(conditionGroup, SWT.None); // 在shell中创建Label对象
		label.setText("最早上牌年份");
		syear = new Text(conditionGroup, SWT.BORDER); // B2设置同B1
		syear.setLayoutData(gridData1);
		syear.setTextLimit(4);
		// 添加1-9的数字输入控制器
		syear.addVerifyListener(new TextVerifyListener(1));
		// final Text endYear = new Text(null, SWT.BORDER); // B2设置同B1
		// endYear.setLayoutData(gridData1);
		// endYear.setTextLimit(4);

		label = new Label(conditionGroup, SWT.None); // 在shell中创建Label对象
		label.setText("邮件列表");
		maillist = new Text(conditionGroup, SWT.BORDER); // B2设置同B1
		GridData gridData2 = new GridData(GridData.FILL_BOTH
				| GridData.HORIZONTAL_ALIGN_CENTER);
		gridData2.grabExcessVerticalSpace = false; // 抢占垂直方向额外空间
		gridData2.horizontalSpan = 3;
		maillist.setLayoutData(gridData2);

		GridData gridData4 = new GridData();
		gridData4.grabExcessVerticalSpace = false; // 抢占垂直方向额外空间
		gridData4.horizontalAlignment = GridData.HORIZONTAL_ALIGN_CENTER;
		gridData4.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
		Button add = new Button(buttonGroup, SWT.PUSH); // 在composite上创建button
														// B1
		add.setLayoutData(gridData4);
		add.setText(" 添   加 ");
		add.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if(checkInput()){
					double pp = 0;
					double mm = 0;
					int sy = 0;
					int ey = 0;
					if (price.getText().length() > 0)
						pp = Double.parseDouble(price.getText());
					if (miles.getText().length() > 0)
						pp = Double.parseDouble(miles.getText());
					if (syear.getText().length() > 0)
						sy = Integer.parseInt(syear.getText());
 
//					ToolsClient tl = new ToolsClient(carType.getText(), pp, mm,
//							sy, ey, maillist.getText());
//					if (control.clientList.contains(tl)) {
//						showMessageBox("搜索条件已存在");
//					} else {
//						filtersList.add(tl.clientName);
//						control.clientList.add(tl);
//					}
				}
			}

		});

		Button delete = new Button(buttonGroup, SWT.PUSH); // 在composite上创建button
															// B1
		delete.setText(" 删   除 ");
		delete.setLayoutData(gridData4);
		delete.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {

				if (filtersList.getSelectionCount() < 1) {
					showMessageBox("选择要删除的选项");
				} else {
					for (String str : filtersList.getSelection()) {
						filtersList.remove(str);
						//control.removeClient(str);
					}
				}
			}

		});

		final Button startButton = new Button(buttonGroup, SWT.PUSH); // 在composite上创建button
																		// B1
		startButton.setLayoutData(gridData4);
		startButton.setText("开始搜索");
		startButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (startButton.getText().equals("开始搜索")) {
					if(filtersList.getItemCount()<1){
						showMessageBox("至少添加一条搜索条件");
					}else{
						//control.start();
						startButton.setText("停止搜索");
					}
				} else if (startButton.getText().equals("停止搜索")) {
					//control.stop();
					startButton.setText("开始搜索");
				}
			}

		});

		MainApp.logText = new Text(logGroup, SWT.BORDER | SWT.MULTI|SWT.V_SCROLL); // 创建Text对象
		MainApp.logText.setText("");

		// shell.pack();
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		//control.stop();
		display.dispose();
	}

	public boolean checkInput() {
		// Logger.println(maillist.getTextChars().length);
		if (maillist.getText().length() < 1) {
			// 声明信息对话框对象,并在对话框中显示信息
			showMessageBox("邮件地址必须填写");
			return false;

		} else if (carType.getText().length() < 1
				&& price.getText().length() < 1 && miles.getText().length() < 1
				&& syear.getText().length() < 1) {
			showMessageBox("请至少填写一个搜索条件");
			return false;
		} else if (carType.getText().length() < 1
				&& price.getText().length() < 1 && miles.getText().length() < 1
				&& syear.getText().length() != 4) {
			showMessageBox("请正确填写年份");
			return false;
		} else { 
			
		}
		return true;
	}

	public void showMessageBox(String message) {
		// 声明信息对话框对象,并在对话框中显示信息
		MessageBox dialog = new MessageBox(shell, SWT.OK | SWT.ICON_INFORMATION);
		dialog.setText("提示");
		dialog.setMessage(message);
		dialog.open();
	}

	public static void print(final String str) {
		Display.getDefault().syncExec(new Runnable() {
			public void run() {
				MainApp.logText.append(str);
				MainApp.logText.append("\n");
			}
		});
	}

	public static void main(String[] args) {
		MainApp app = new MainApp();
		app.init();
	}
}



个人总结

Swt入门容易些,以前从没用过,根据一些例子我就能使用SWT开发界面了,界面的确反应迅速。但是使用中总觉着SWT各种不习惯,布局方式各种繁琐,因为是直接调用本地系统库的原因,界面上一旦有些异常,很容易整个界面直接挂掉,出现内存错误。跨平台没详细测试,调用不同系统上相应的lib库,我感觉问题应该不大。