星期五, 十二月 17, 2004

使用PHP开发qmail邮件服务器管理系统

电子邮件在网络中占有很重要的地位。目前,在企业中运行的邮件服务器均用各自独立的管理系统来实现账号创建、口令修改、邮箱扩容、删除邮箱等功能。当邮箱用户达到一定数量时,邮件管理员的日常维护工作显得极为繁重,这就需要将一部分管理任务(如账号申请)实现自动化处理;同时将一部分任务(如口令修改)由多个分组管理员来负责,从而使邮件管理员从繁琐的维护工作中解脱出来,真正对邮件服务器起到监管作用。

  邮件服务器及开发环境的选择

  目前很多邮件服务器不提供开发接口,因此在企业内部实现开发邮件管理系统的首要问题是,寻找一种能够与开发语言相结合的开放式邮件系统。

  由于对稳定性要求很高,因此大型电子邮件系统一般都使用Unix作为服务器的操作系统。例如,Hotmail使用的是FreeBSD和Solaris系统。

  Linux自带的邮件由于在系统结构上存在一定缺陷,难以承受大用户量的访问。qmail是GNU下一款著名的自由软件,是新一代Unix邮件系统,支持Maildir存储方式。它把每个邮件作为一个单独的文件保存在用户个人的邮件目录下。qmail支持虚拟域(Virtual Domain)和虚拟用户(Virtual User)。当前国内流行的免费电子邮件系统大都采用qmail作为基本服务器软件,提供多级目录以支持较大的用户数。

  从开发的角度看,PHP+Linux的开发模式已被许多开发人员采用。利用PHP来调用qmail提供的控制程序,实现对邮件系统的各种管理工作。为实现对大量用户的有效控制,还可引入数据库管理。本文将介绍一个PHP +Oracle+qmail+Linux的开发实例。

  总体设计

  整个系统分为邮箱管理和邮件收发两部分。申请邮箱时,先填写一些必要的信息,然后系统会自动地创建邮箱并允许用户立即使用。当用户忘记密码后,可采用目前互联网的通用做法,通过回答用户自定义的问题来修改邮箱密码。出于安全考虑,在用户三次回答错问题后,系统将该账号的“修复邮箱密码”功能锁定30分钟。

  邮件管理依据不同的需求,将用户权限分为以下3种级别:

  ◆ 普通用户 能够在浏览器中收发电子邮件、修改邮箱密码、修改自定义问题和答案,并进行邮箱的查询。

  ◆ 分组管理员 除拥有普通用户的功能外,可以修改本组内所有账号的密码,解除本科室账号的“修复邮箱密码”功能锁定。

  ◆ 邮箱管理员 可以修改全部邮箱口令、删除邮箱、修改邮箱容量、查看邮箱的申请情况,解除全部账号的“修复邮箱密码”功能锁定。

  邮件的收发采用PHP提供的标准POP3函数,可获得邮件清单、查看邮件的详细内容、发送带多个附件的邮件,并提供邮件删除、回复等功能。

  数据库主要由以下几个表组成:

  ◆ email_info 存放所有电子邮箱的相关信息,如账号、人员姓名、科室、联系电话、自定义问题、自定义问题的答案、锁定标记等。

  ◆ email_register_info 存放用户申请电子邮件时填写的信息,如账号、密码、申请时间、科室、申请的当前步骤(主要是为了防止用户恶意跳过某些步骤而设定的)。

  ◆ email_change_log 记录用户电子邮箱的变化情况,以备日后需要时检查。主要记录有邮件的申请时间、删除时间、邮箱账号、对邮箱操作的人员姓名、IP地址等信息。

  技术难点分析

  PHP调用qmail的控制程序

  在Linux环境中,每一个程序都有相应的用户和组的概念。PHP程序在服务器中执行时,默认的用户是nobody,没有权利执行qmail的控制程序。在Linux里面有个sudo命令,允许其它用户以root身份执行一些命令。修改/etc/sudoers文件,增加以下部分:


  nobody ALL=/var/vpopmail/bin/vadduser (增加用户)
  nobody ALL=/var/vpopmail/bin/vdeluser (删除用户)
  nobody ALL=/var/vpopmail/bin/vpasswd (修改口令)
  nobody ALL=/var/vpopmail/bin/vchkpw (检查用户口令是否正确)
  nobody ALL=/var/vpopmail/bin/vsetuserquota (修改邮箱最大容量)
  nobody ALL=/var/vpopmail/bin/vmoduser (修改用户信息)
  root ALL=(ALL) ALL



  在调用qmail控制程序时,需要用户手工输入一部分信息。如果要实现自动化,还需要使用Linux中的重定向技术,将用户预先输入的信息存放到文件中,使用重定向技术传递为Shell脚本。
  PHP提供执行外部命令的函数为system()、exec()。system()函数执行给定的命令、输出和返回结果。exec()函数与system()类似,但不输出结果。使用程序控制必须选用exec()函数,并根据执行后的状态来确定控制程序是否正确执行,如果出现错误需要向邮件管理员通告。下面代码以“增加用户”功能为例进行说明:


require("/home/httpd/phplib/qmail.inc");
$qmail_date = "v1";
$qmail_email = new register_email ;
$sql = "select pw_name from ".$qmail_date;
$qmail_email->query($sql);
while ($qmail_email->next_record())
{
$qmail_user = $qmail_email->f("pw_name");
$passwd = "12345";
$str_command = "sudo /var/vpopmail/bin/vadduser " .$qmail_user.;
$str_command = $str_command."@mail.com".$passwd." -q 10000000 < /home/n";
@exec($str_command,$str,&$result);
if ($result != 0 )
{
echo "command string is :".$str_command." , command is failed!!!
";
$error_info = "在执行vadduser命令时失败";
$address = "From: computer@mail.com\nReply-To: computer@mail.com\n" ;
mail("webmaster@mail.com", $error_info , $message,$address );
}
}
$qmail_email->free();


  其它功能如修改口令、修改邮箱容量、删除邮箱等,在程序实现上非常类似,不做过多阐述。

  E-mail中附件的上传及下载

  PHP本身提供上载功能,但根据实际情况,可以相应做一些配置和错误处理。用户可以通过修改php.ini文件来扩大上载文件的最大容量。同时,可以通过在网页的Form中增加[i]的方法,将单个附件的大小限制在5MB以内。如果网络速度比较慢,则需要设置网页的timeout变量,否则上载时会因为时间太长而超时。在服务器端的处理程序部分代码如下:


if (!file_exists($mail_att)) //判断文件是否上载成功
{ //错误处理及显示
 break ;
}
copy ($mail_att, $mail_att.".att") ; //将附件重新改名并拷贝到指定位置。
for ($i = 1; $i <= $num_attach; $i++)
{
 $file_name = "send_att".$i; //得到上传文件的原始名称
 $file_tmp = "send_att_tmp".$i; //得到上传文件在服务器中的临时文件名称
 $file_size = "send_att_size".$i; //得到上传文件的大小
 $file_mime = "send_att_mime".$i; //得到上传文件的类型
}



在提供附件下载时,这里没有采用常用做法,即给用户提供文件的URL。因为这种做法理论上并不安全,用户有可能通过链接直接下载到该文件。相反,从浏览器无法访问到的目录下读出文件提供给用户下载,就不会遇到类似安全问题。程序核心代码如下:


if (file_exists($attach_filepos)) //判断文件是否存在
{
 $size = filesize($attach_filepos); //得到文件的大小
 //将用户原始文件名提供给用户下载。
 header("Content-Disposition: attachment; filename=".$attach_filename);
 header("Content-length: ".$size);
 header("Content-type: application/x-zip-compressed");
 readfile($attach_filepos); //将下载文件读出,提供给用户下载。
}



  结束语

  该系统在技术上很完美地将PHP与Oracle数据库结合起来,实现对qmail用户的管理及日常邮箱服务器的维护。目前该系统已在我公司内部使用了一年多,效果很好。它一方面减轻了邮件管理员的日常维护工作;另一方面为不太熟悉邮件配置的用户提供网上收发邮件。此系统还有认证、分组管理及邮件收发、汉字编码等方面的功能,由于篇幅有限就不一一阐述。

星期六, 十二月 11, 2004

(转)Eclipse插件开发指南(基于Eclipse3.0的系列文章)

Eclipse插件开发指南(基于Eclipse3.0的系列文章)
第1章 Eclipse概述.PDF
1.1 Eclipse简介
  1.1.1 Eclipse的历史
  1.1.2 Eclipse的技术特征与优势
1.2 安装Eclipse及其中文语言包
1.3 第三方插件SWT Designer的下载与安装
Eclipse插件开发系列6.TableViewer的使用(1)让数据显示出来
前言:
  本章本来是计划周五帖的,昨晚才赶出来,渐愧。说实在话,写这样的教程实在是很无味的一件事,本来是自己已经知道的东西,但为了易懂,还得慢条斯理的详细写出来。但想着Eclipse插件在国内还是阳春白雪的新鲜东东,自己能做一些别人没做过的推广工作,还是蛮有意义的。
  前次有个MSN上的同行问我做JAVA什么方面的,我说JAVA Application,他说:“你别骗我了.....”。现在已是B/S泛滥成灾的时代,而Appliction的胖客端早已被大多数人遗忘了。但事物的发展都是螺旋上升的,.net时代到来和下一代windows操作系统即将来临,新型的胖客端模式就要抬头了。我已过了那种计较Java和c++或C#谁好,b/s和c/s谁优的阶段,现在我更关注问题的解决方案和其中优雅的设计,以及在开发阶段的过程控制和管理中的技巧,(关注的东西似乎多了些,呵)。来北京快一年了,在IBM我在设计方面学到了很多,而软件工程和管理方面我认为很难向别人学到些什么,中国的软件业界在这方面是如此的虚弱不堪和模糊不清,要在这方面有所得,必须还得靠自己摸索总结,这也是我来北京一年来学习所得出的结论。
=============================================================================
  在swt中用的是表格控件table,SWT Desiger插件里也只提供了table。但我们最常用的是一个在table基础上扩展而来的Jface控件TableViewer。
  在下面的实例中演示了如何将数据用TableViewer显示出来的方法,它一般包含如下几个步骤(同时也是要点):
1. new一个TableViewer对象。在new 的时候通过参数可以定义它的一些属性(如下例),属性英文单词的 比较明显示,不再说明。
2. 对其布局(这和其它控件没什么区别)。
3. 建立表格中的列。
4. 设定内容器。一般写成内部类,但内容器基本一样,你可以单独拿出来写成一个类,让整个系统共用。
5. 设定标签器。这个比较重要和复杂一些。
6. 用setInput输入数据。以后这些数据会根据列设置、内容器、标签器的设定将自己显示在TableViewer的表格中。
  另注:这个例子是一个Application(应用程序),在运行时请加上“VM自变量”,否则会出错并无法运行,怎么加请参照本系列前几面几章,有详细说明。这个例子中还有一个实体类,相当于数据库中的一条记录。例子加有详细注释,如有不明请在帖后回复说明,我将随时跟帖答复。
运行效果图:


代码:
package net.yeah.glchengang.tableviewer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
public class App1 {
public static void main(String[] args) {
App1 window = new App1();
window.open();
}
public void open() {
final Display display = new Display();
final Shell shell = new Shell();
shell.setLayout(new FillLayout());
shell.setText("SWT Application");
{
TableViewer tv = new TableViewer(shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
/*
* TableViewer是通过Table来布局的
*/
Table table = tv.getTable();
//table.setLayoutData(new GridData(GridData.FILL_BOTH));
table.setHeaderVisible(true); //表头显示
table.setLinesVisible(true); //表格线显示
/*
* 建立表格中的列
*/
TableLayout tLayout = new TableLayout();
table.setLayout(tLayout);
tLayout.addColumnData(new ColumnWeightData(10)); //10个单位的宽度
new TableColumn(table, SWT.NONE).setText("ID号");
tLayout.addColumnData(new ColumnWeightData(40));
new TableColumn(table, SWT.NONE).setText("姓名");
tLayout.addColumnData(new ColumnWeightData(20));
new TableColumn(table, SWT.NONE).setText("年龄");
tLayout.addColumnData(new ColumnWeightData(60));
new TableColumn(table, SWT.NONE).setText("记录建立时间");
/*
* 当People的记录集输入的tv中,注意setInput的参数是Object也就是说它可以接受任何参数,
* 不过它最常接受的还是Java的Collection(集合,这里为List)或者数组,
* 那么tv是怎么知道如何来显示这么输入格式千差万别的数据的呢?就是依靠内容器和标签器(这里它两是一个内部类)
*/
tv.setContentProvider(new MyContentProvider()); //内容器
tv.setLabelProvider(new MyLabelProvider()); //标签器
tv.setInput(getPeoples());
}
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
/**
* PeopleEntity对象的生成工厂,生成三个PeopleEntry对象,并放到一个List中
* 在实现应用中这个方法可改为从数据库中取数据,然后将数据包装成一个个实体类,并将这些实体类装在List集合中返回
* @return
*/
private List getPeoples() {
List peoples = new ArrayList();
{ //第1个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(1));
p.setName("陈刚");
p.setAge(28);
p.setCreateDate(new Date()); //当前日期
peoples.add(p);
}
{ //第2个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(2));
p.setName("韩立新");
p.setAge(29);
p.setCreateDate(new Date());
peoples.add(p);
}
{ //第3个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(3));
p.setName("陈常恩");
p.setAge(27);
p.setCreateDate(new Date());
peoples.add(p);
}
return peoples;
}
/**
* 内容器(写成了一个内部类). 在这里对所有记录集中的记录进行处理
*/
private static final class MyContentProvider implements IStructuredContentProvider {
public Object[] getElements(Object element) {
if (element instanceof List)
return ((List) element).toArray();//将List转化为数组
else
return new Object[0];//否则,返回一个空数组
}
public void dispose() {}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
}
/**
* 标签器(写成了一个内部类).在这里对单条记录进行处理
*/
private static final class MyLabelProvider implements ITableLabelProvider {
/**
* 这个方法返回的是各列的记录的文字
* 参数1:输入的对象
* 参数2:列号
* 返回值:注意一定要避免Null值,否则出错
*/
public String getColumnText(Object element, int col) {
PeopleEntity o = (PeopleEntity) element; //转换一下类型
if (col == 0)
return o.getId().toString();
if (col == 1)
return o.getName();
if (col == 2)
return "" + o.getAge();//加个""是为了将int型转为String型
if (col == 3)
return o.getCreateDate().toString();
return "";
}
/**
* 返回每条记录前面的图标
*/
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
//-------------以下方法用处不大,暂时不管它-----------------
public void addListener(ILabelProviderListener listener) {}
public void dispose() {}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {}
}
}
以下是实体类PeopleEntity :
package net.yeah.glchengang.tableviewer;
import java.util.Date;
/**
* 这是一个实体类,相当于数据库中的一条记录。
* 具体为一个人的记录,象征性的包含四个不同数据类型的字段。
* 这些字段都是private的,然后以其相应的set/get方法来访问
*/
public class PeopleEntity {
private Long id; //唯一识别码,在数据库里为自动递增的ID列
private String name; //姓名
private int age; //年龄
private Date createDate; //记录的建立日期
public Long getId() {
return id;
}
public void setId(Long long1) {
id = long1;
}
public String getName() {
return name;
}
public void setName(String string) {
name = string;
}
public int getAge() {
return age;
}
public void setAge(int i) {
age = i;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date date) {
createDate = date;
}
}

如果想让tableViewer响应鼠标的双击或单周事件,在上面代码的tv.setInput()后加入如下代码。
/*
* tv的鼠标双击事件监听
*/
tv.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
PeopleEntity obj = (PeopleEntity) selection.getFirstElement();
MessageDialog.openInformation(null, "提示", "你双击了--" + obj.getName()); //一个弹出提示框
}
});
/*
* tv的选择事件监听
*/
tv.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
//-------事件处理代码。。。。。
}
});

Eclipse插件开发系列6.TableViewer的使用(2)加上右键菜单
前言:
  今天组里买了一大堆小吃,边干边吃感觉真不错,于是继续再发一篇。
  在我Blog上好好的文章,被CSDN转到文档中心后图片就不见了,不知道他们的技术人员发现这个BUG了吗?说到软件系统的测试,我们项目的测试已经足足有三个月了,从项目完了三分之二时起就有一男一女两个人加入了项目组,一个做功能测试,一个做系统测试。系统完成后,又有一个多月是在改BUG和根据需求的变更改程序,还好系统设计和代码写得都很干净,改动不成问题,不过还是从中体会到需求的重要性。用一个小时来做需求,五个小时写代码,十个小时改程序还是用三个小时来做需求,五个小时写代码,一个小时改代码?那个更合算?所以确定的需求将节省几何数量级的后期修改程序和维护的时间。
====================================================================================

  这一节主讲如何给TableViewer加上右键菜单。
1、效果图如下:


2、将以下代码加入到上一节的程序代码的最后面(但最后还有一个括号括着),这一段代码是三个内部部,当然你也可以将它们分离出来单独成类,之前所以写成内部类一是因为方便,二是这些类仅本文件用。Action代表一种动作,在这里是右键菜单的动作,以后我们还能看到它可以同时是下拉菜单的动作、工具栏按钮的动作,这样Action中的代码就可以很好的共用了。
/**
* ActionGroup类,将所有action集中在这个类里管理,它不是必须的。
*/
private final class MyActionGroup extends ActionGroup {
private TableViewer tv;
private OpenAction openAction;
private RefreshAction refreshAction;
public MyActionGroup(TableViewer v) {
this.tv = v;
openAction = new OpenAction(v);
refreshAction = new RefreshAction(v);
}
/**
* 菜单的生成
*/
public void fillContextMenu(IMenuManager mgr) {
/*
* 下面两句代码,eclipse用到了"乒乓模式".menu和tv两个对象互为参数
*/
Menu menu = ((MenuManager) mgr).createContextMenu(tv.getTable()); //通过菜单管理器在tv上得到一个菜单对象
tv.getTable().setMenu(menu); //把这个菜单赋给tv
mgr.add(openAction);
mgr.add(refreshAction);
}
}
/**
* 删除的Action类
*/
private final class OpenAction extends Action {
private TableViewer tv;
public OpenAction(TableViewer v) {
this.tv = v;
setText("打开");
}
public void run() {
IStructuredSelection selection = (IStructuredSelection) tv.getSelection();
PeopleEntity obj = (PeopleEntity) (selection.getFirstElement());
if (obj == null)
MessageDialog.openInformation(null, null, "必须选择一条记录");
else
MessageDialog.openInformation(null, null, "打开记录" + obj.getName());
}
}
/**
* 刷新的Action类
*/
private final class RefreshAction extends Action {
private TableViewer tv;
public RefreshAction(TableViewer tv) {
this.tv = tv;
setText("刷新");
}
public void run() {
tv.refresh();
}
}

3、然后将以下代码加入到第一节代码中open()方法的最后位置。
/*
* 加上菜单
*/
MyActionGroup actionGroup = new MyActionGroup(tv); //生成一个Action组对象
actionGroup.fillContextMenu(new MenuManager()); //生成一个菜单管理器对象做参数

4、然后再给出完整的源代码如下:
package net.yeah.glchengang.tableviewer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.actions.ActionGroup;
public class App3 {
public static void main(String[] args) {
App3 window = new App3();
window.open();
}
public void open() {
final Display display = new Display();
final Shell shell = new Shell();
shell.setLayout(new FillLayout());
shell.setText("SWT Application");
{
TableViewer tv = new TableViewer(shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
/*
* TableViewer是通过Table来布局的
*/
Table table = tv.getTable();
//table.setLayoutData(new GridData(GridData.FILL_BOTH));
table.setHeaderVisible(true); //表头显示
table.setLinesVisible(true); //表格线显示
/*
* 建立表格中的列
*/
TableLayout tLayout = new TableLayout();
table.setLayout(tLayout);
tLayout.addColumnData(new ColumnWeightData(10));
new TableColumn(table, SWT.NONE).setText("ID号");
tLayout.addColumnData(new ColumnWeightData(40));
new TableColumn(table, SWT.NONE).setText("姓名");
tLayout.addColumnData(new ColumnWeightData(20));
new TableColumn(table, SWT.NONE).setText("年龄");
tLayout.addColumnData(new ColumnWeightData(60));
new TableColumn(table, SWT.NONE).setText("记录建立时间");
/*
* 当People的记录集输入的tv中,注意setInput的参数是Object也就是说它可以接受任何参数,
* 不过它最常接受的还是Java的Collection(集合,这里为List)或者数组,
* 那么tv是怎么知道如何来显示这么输入格式千差万别的数据的呢?就是依靠内容器和标签器(这里它两是一个内部类)
*/
tv.setContentProvider(new MyContentProvider()); //内容器
tv.setLabelProvider(new MyLabelProvider()); //标签器
tv.setInput(getPeoples());
/*
* tv的鼠标双击事件监听
*/
tv.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
PeopleEntity obj = (PeopleEntity) selection.getFirstElement();
MessageDialog.openInformation(null, "提示", "你双击了--" + obj.getName());
}
});
/*
* tv的选择事件监听
*/
tv.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
//-------事件处理代码。。。。。
}
});
/*
* 加上菜单
*/
MyActionGroup actionGroup = new MyActionGroup(tv); //生成一个Action组对象
actionGroup.fillContextMenu(new MenuManager()); //生成一个菜单管理器对象做参数
}
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
/**
* PeopleEntity对象的生成工厂,生成三个PeopleEntry对象,并放到一个List中
* 在实现应用中这个方法可改为从数据库中取数据,然后将数据包装成一个个实体类,并将这些实体类装在List集合中返回
* @return
*/
private List getPeoples() {
List peoples = new ArrayList();
{ //第1个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(1));
p.setName("陈刚");
p.setAge(28);
p.setCreateDate(new Date()); //当前日期
peoples.add(p);
}
{ //第2个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(2));
p.setName("韩立新");
p.setAge(29);
p.setCreateDate(new Date());
peoples.add(p);
}
{ //第3个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(3));
p.setName("陈常恩");
p.setAge(27);
p.setCreateDate(new Date());
peoples.add(p);
}
return peoples;
}
/**
* 内容器(写成了一个内部类). 在这里对所有记录集中的记录进行处理
*/
private static final class MyContentProvider implements IStructuredContentProvider {
public Object[] getElements(Object element) {
if (element instanceof List)
return ((List) element).toArray(); //将List转化为数组
else
return new Object[0]; //否则,返回一个空数组
}
public void dispose() {}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
}
/**
* 标签器(写成了一个内部类).在这里对单条记录进行处理
*/
private static final class MyLabelProvider implements ITableLabelProvider {
/**
* 这个方法返回的是各列的记录的文字
* 参数1:输入的对象
* 参数2:列号
* 返回值:注意一定要避免Null值,否则出错
*/
public String getColumnText(Object element, int col) {
PeopleEntity o = (PeopleEntity) element; //转换一下类型
if (col == 0)
return o.getId().toString();
if (col == 1)
return o.getName();
if (col == 2)
return "" + o.getAge(); //加个""是为了将int型转为String型
if (col == 3)
return o.getCreateDate().toString();
return "";
}
/**
* 返回每条记录前面的图标
*/
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
//-------------以下方法用处不大,暂时不管它-----------------
public void addListener(ILabelProviderListener listener) {}
public void dispose() {}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {}
}
/**
* ActionGroup类,将所有action集中在这个类里管理,它不是必须的。
*/
private final class MyActionGroup extends ActionGroup {
private TableViewer tv;
private OpenAction openAction;
private RefreshAction refreshAction;
public MyActionGroup(TableViewer v) {
this.tv = v;
openAction = new OpenAction(v);
refreshAction = new RefreshAction(v);
}
/**
* 菜单的生成
*/
public void fillContextMenu(IMenuManager mgr) {
/*
* 下面两句代码,eclipse用到了"乒乓模式".menu和tv两个对象互为参数
*/
Menu menu = ((MenuManager) mgr).createContextMenu(tv.getTable()); //通过菜单管理器在tv上得到一个菜单对象
tv.getTable().setMenu(menu); //把这个菜单赋给tv
mgr.add(openAction);
mgr.add(refreshAction);
}
}
/**
* 删除的Action类
*/
private final class OpenAction extends Action {
private TableViewer tv;
public OpenAction(TableViewer v) {
this.tv = v;
setText("打开");
}
public void run() {
IStructuredSelection selection = (IStructuredSelection) tv.getSelection();
PeopleEntity obj = (PeopleEntity) (selection.getFirstElement());
if (obj == null)
MessageDialog.openInformation(null, null, "必须选择一条记录");
else
MessageDialog.openInformation(null, null, "打开记录" + obj.getName());
}
}
/**
* 刷新的Action类
*/
private final class RefreshAction extends Action {
private TableViewer tv;
public RefreshAction(TableViewer tv) {
this.tv = tv;
setText("刷新");
}
public void run() {
tv.refresh();
}
}
}
  这一章关于TableViewer的使用就完了,以后将改变一下形式,因为这样一章章的写下去,实在是无趣且缓慢。我的想法是这样的,以一个现实项目的开发为主线,将Eclipse插件开发、Hibernate的使用及一些设计方面的体会融合在其中。这种风格有这样几个特点:(1)代码注释详细(2)每一个版的源代码都可以下载(3)每一个版本配以简单的指导性的文档以辅助阅读代码了解系统结构。不过文章方面的易读性和详细性会差很多,这需要想学Eclipse的朋友自己看源代码了。希望大家能喜欢这样的形式风格。
评论
# 回复:Eclipse插件开发系列6.TableViewer的使用(2)加上右键菜单 2004-07-19 10:55 AM 贺伟
想请教你一个问题,就是如何调整org.eclipse.swt.widgets.Text这个Text的宽度。谢谢


# 回复:Eclipse插件开发系列6.TableViewer的使用(2)加上右键菜单 2004-07-19 11:00 AM 陈刚
代码如下:
//生成一个装text的面板
Composite c = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(num, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
c.setLayout(layout);
//用GridData和widthHint 属性
Text text = new Text(c, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
GridData gd = new GridData();
gd.widthHint = 30; //30就是text框的长度
text.setLayoutData(gd);



# 回复:Eclipse插件开发系列6.TableViewer的使用(2)加上右键菜单 2004-08-10 12:36 PM 肖振春
陈刚:
您好!
在您的网站看了Eclipse插件开发系列文章以后,感觉很有收获。
在看到“TableViewer的使用(2)加上右键菜单”的时候,我这里却出现了如附件中的错误,即“extends ActionGroup”不能被认出来。请问这是什么原因呢?万分感谢!
另外,我这里有这样一个问题:我的界面中有一个Tree,我想在这个Tree的区域内鼠标右键,然后弹出菜单,这个时候我右键的位置如果刚好在某个节点(TreeItem)上,那么弹出菜单的菜单选项的名称就是该TreeItem的名称。我花了很长时间,然后就是仔细研究您的“TableViewer的使用(2)加上右键菜单”这篇文章,但是现在还是没有做出来。
万分感谢!


# 回复:Eclipse插件开发系列6.TableViewer的使用(2)加上右键菜单 2004-08-10 12:37 PM 陈刚
TO:肖振春

第一个问题:“ActionGroup”不能被认出来
  我看了你的截图,你是用Eclipse3.0的,我的例子是用eclipse2.1.3的。于是我装了一个Eclipse3.0并将原例子复制(没有做任何修改)运行了一次,成功,没有问题。所以我判断是你的项目里的类路径(相当于classpath)没有设置好,所以系统找不到ActionGroup所在的包(org.eclipse.ui)。具体设置方法请参考我前面几章关于新建插件项目的文章。

第二个问题:本来要专门写一个TreeViewer文章的,先给你一个双击响应的例子吧。

   tv1.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
Object obj = ((IStructuredSelection) event.getSelection()).getFirstElement();
       。。。
}
});

就一句话,得到是一个Object,它就是你点击的结点对象,你要用它还需要做一个简单的类型转换就可以了
Eclipse插件开发系列7.TreeViewer的使用(1)一个简单例子
=====================================================================================
/*
* @author 陈刚 ,2004-8-21 0:54:20
* Email: glchengang@yeah.net
* Blog : glchengang.yeah.net
*/
package book.c3.e1;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class S3_1 {
public static void main(String[] args) {
S3_1 window = new S3_1();
window.open();
}
public void open() {
final Display display = new Display();
final Shell shell = new Shell();
shell.setLayout(new FillLayout());
ui(shell);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
private void ui(Shell shell) {
Composite c = new Composite(shell, SWT.NONE);
c.setLayout(new FillLayout());
TreeViewer tv = new TreeViewer(c, SWT.BORDER);
tv.setContentProvider(new MyContentProvider());
tv.setLabelProvider(new MyLableProvider());
tv.setInput(new Object());//设置输入对象的方法与前面相同
}
/**
* 内容提供器。由它决定那些对象应该输出在TreeViewer里显示
*/
private static final class MyContentProvider implements ITreeContentProvider {
/**
* 由这个方法决定树的顶级显示那些对象。在此方法里生成了三个Country对象
* @param inputElement 用tv.setInput()方法输入的那个对象,在这里没有使用这个对象
*/
public Object[] getElements(Object inputElement) {
String[] obj = new String[3];
obj[0] = "中国";
obj[1] = "美国";
obj[2] = "英国";
return obj;
}
/**
* 由这个方法决定结点应该显示那些子结点。在这里也不管父结点是什么,每个结点都统一有三个字结点
* @param parentElement 被点击的结点(父结点)
*/
public Object[] getChildren(Object parentElement) {
String[] obj = new String[4];
obj[0] = "桂林";
obj[1] = "北京";
obj[2] = "纽约";
obj[3] = "伦敦";
return obj;
}
/**
* 判断某结点是否有子结点。在这里不管3721,全返回真,即都有子结点。这时结点前都有一个“+”号图标
* @param element 需要判断是否有子的结点
*/
public boolean hasChildren(Object element) {
return true;
}
/**
* 取得某结点的父结点。极少需要实现此方法
*/
public Object getParent(Object element) {
return null;
}
/**
* 当TreeViewer被销毁时将执行这个方法。极少需要实现此方法
*/
public void dispose() {}
/**
* 当tv.setInput()发生变化时调用此方法。极少需要实现此方法
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
}
/**
* 标签提供器。主要负责每一单个对象在TreeViewer中的显示(文字、图象)
*/
private static final class MyLableProvider implements ILabelProvider {
/**
* 显示什么图片
* @param 结点
* @return 可以为null值
*/
public Image getImage(Object element) {
// ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
// return sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK);
return null;
}
/**
* 显示什么文字
* @param 结点
* @return 不能为null值
*/
public String getText(Object element) {
return (String) element;
}
public void addListener(ILabelProviderListener listener) {}
public void dispose() {}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {}
}
/**
* 标签提供器。如果你赚上面的MyLableProvider那些没用的方法碍眼,
* Eclipse中有一个ILabelProvider的缺省实现LabelProvider,继承它也行
*/
// private static final class MyLableProvider extends LabelProvider {
// public String getText(Object element) {
// return (String)element;
// }
// }
}


  在这里面“标签器”比较简单,甚至可以不要(可以将实体类的toString方法改写,这样不要标签器则TreeViewer会自动调用实体类的toString方法)。“内容器”是理解TreeViewer的关键,程序里已有详细注释了,在这里再给出TreeVeiwer启动、点击结点、关闭三种操作时“内容器”里几个方法的时序图。

评论
# 回复:Eclipse插件开发系列7.TreeViewer的使用(1)一个简单例子 2004-11-04 12:07 AM Haulon
java.lang.NoClassDefFoundError: org/eclipse/core/internal/boot/DelegatingURLClassLoader
at org.eclipse.core.runtime.Platform.run(Platform.java:413)
at org.eclipse.jface.viewers.StructuredViewer.updateItem(StructuredViewer.java:1271)
at org.eclipse.jface.viewers.AbstractTreeViewer.createTreeItem(AbstractTreeViewer.java:320)
at org.eclipse.jface.viewers.AbstractTreeViewer$1.run(AbstractTreeViewer.java:303)
at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:69)
at org.eclipse.jface.viewers.AbstractTreeViewer.createChildren(AbstractTreeViewer.java:289)
at org.eclipse.jface.viewers.AbstractTreeViewer$5.run(AbstractTreeViewer.java:729)
at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(StructuredViewer.java:801)
at org.eclipse.jface.viewers.AbstractTreeViewer.inputChanged(AbstractTreeViewer.java:721)
at org.eclipse.jface.viewers.ContentViewer.setInput(ContentViewer.java:238)
at org.eclipse.jface.viewers.StructuredViewer.setInput(StructuredViewer.java:991)
at comtest.S3_1.ui(S3_1.java:59)
at comtest.S3_1.open(S3_1.java:44)
at comtest.S3_1.main(S3_1.java:37)
Exception in thread "main"

我在XP下试了下,老是出现以上问题,不过只要我屏蔽setInput函数就可以,但是什么都看不到了?
Eclipse插件开发系列7.TreeViewer的使用(2)一个更接近实际应用的例子
=====================================================================================
上面的例子很简单,主要让大家明白几个关键Provider类的方法的使用。下面一个例子更接近于实际项目一些。这个例子有三个实体类:国家、城市、人,它们都实现了TreeEntry接口,这三个实体是有层级关系的。另外还写了一个工厂类来生成TreeViewer.setInput所需要的参数。
  这个例子比较长,为了大家阅读方便,在此说明一下:实体类可以看做JAVA类对数据库表的一个一一映射,类的属性就相当于表的一个字段。按照JAVA的通常规范写法实体类中每一个属性都附加了set/get方法,所以代码看起来很长,实际的内容却没多少,大家可以看看实体的UML图就应该对三个实体类的关系很清楚了。
====================================================================================
package book.c3.e2;
/**
?* 树的Entry的接口
?*/
public interface TreeEntry {
??? public String getName();
??? public void setName(String name);
}
?
/*
?* @author 陈刚 ,2004-8-21 15:32:15
?* Email: glchengang@yeah.net
?* Blog : glchengang.yeah.net
?*/
package book.c3.e2;
import java.util.List;
/**
?* 国家实体类
?*/
public class Country implements TreeEntry{
??? private String name; //国家名
??? private List cities; //此国家所包含的的城市的集合,集合元素为City对象
??? public Country() {}
??? public Country(String name) {
??????? this.name = name;
??? }
??? public String getName() {
??????? return name;
??? }
??? public void setName(String name) {
??????? this.name = name;
??? }
??? public List getCities() {
??????? return cities;
??? }
??? public void setCities(List cities) {
??????? this.cities = cities;
??? }
}
?
/*
?* @author 陈刚 ,2004-8-21 15:33:17
?* Email: glchengang@yeah.net
?* Blog : glchengang.yeah.net
?*/
package book.c3.e2;
import java.util.List;
/**
?* 城市的实体类
?*/
public class City implements TreeEntry{
??? private String name;//城市名
??? private List peoples;
??? public City() {}
??? public City(String name) {
??????? this.name = name;
??? }
??? public String getName() {
??????? return name;
??? }
??? public void setName(String name) {
??????? this.name = name;
??? }
??? public List getPeoples() {
??????? return peoples;
??? }
??? public void setPeoples(List peoples) {
??????? this.peoples = peoples;
??? }
}
?
/*
?* @author 陈刚 ,2004-8-21 18:15:53
?* Email: glchengang@yeah.net
?* Blog : glchengang.yeah.net
?*/
package book.c3.e2;
/**
?* 人的实体类
?*/
public class People implements TreeEntry{
??? private String name;
??? public People() {}
??? public People(String name) {
??????? this.name = name;
??? }
??? public String getName() {
??????? return name;
??? }
??? public void setName(String name) {
??????? this.name = name;
??? }
}
?

package book.c3.e2;
import java.util.ArrayList;
import java.util.List;
/**
?* 此类负责生成TreeViewer的方法setInput所需要的参数
?*/
public class TvInputFactory {
??? public Object build() {
??????? /*
???????? * 生成顶级的三个对象
???????? */
??????? Country[] countryArray = new Country[3];
??????? countryArray[0] = new Country("中国");
??????? countryArray[1] = new Country("美国");
??????? countryArray[2] = new Country("英国");
??????? /*
???????? * 生成中国的三个城市
???????? */
??????? List chinaList = new ArrayList();
??????? chinaList.add(new City("北京"));
??????? City glCity = new City("桂林");
??????? chinaList.add(glCity);
??????? City nnCity = new City("南宁");
??????? chinaList.add(nnCity);
??????? countryArray[0].setCities(chinaList);
??????? /*
???????? * 生成美国的两个城市
???????? */
??????? List usaList = new ArrayList();
??????? usaList.add(new City("纽约"));
??????? usaList.add(new City("芝加哥"));
??????? countryArray[1].setCities(usaList);
??????? /*
???????? * 生成城市里的人
???????? */
??????? {
??????????? List list = new ArrayList();
??????????? list.add(new People("陈刚"));
??????????? list.add(new People("陈知行"));
??????????? list.add(new People("韩立新"));
??????????? glCity.setPeoples(list);
??????? }
??????? {
??????????? List list = new ArrayList();
??????????? list.add(new People("桃子"));
??????????? list.add(new People("林雅仕"));
??????????? list.add(new People("陈常恩"));
??????????? nnCity.setPeoples(list);
??????? }
??????? return countryArray;
??? }
}
?
?
/*
?* @author 陈刚 ,2004-8-21 0:54:20
?* Email: glchengang@yeah.net
?* Blog : glchengang.yeah.net
?*/
package book.c3.e2;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import java.util.List;
public class S3_1 {
??? public static void main(String[] args) {
??????? S3_1 window = new S3_1();
??????? window.open();
??? }
??? public void open() {
??????? final Display display = new Display();
??????? final Shell shell = new Shell();
??????? shell.setLayout(new FillLayout());
??????? ui(shell);
??????? shell.open();
??????? while (!shell.isDisposed()) {
??????????? if (!display.readAndDispatch())
??????????????? display.sleep();
??????? }
??? }
??? private void ui(Shell shell) {
??????? Composite c = new Composite(shell, SWT.NONE);
??????? c.setLayout(new FillLayout());
??????? TreeViewer tv = new TreeViewer(c, SWT.BORDER);
??????? tv.setContentProvider(new MyContentProvider());
??????? tv.setLabelProvider(new MyLableProvider());
??????? tv.setInput(new TvInputFactory().build());//设置输入对象的方法与前面相同
??? }
??? /**
???? * 内容提供器。由它决定那些对象应该输出在TreeViewer里显示
???? */
??? private static final class MyContentProvider implements ITreeContentProvider {
??????? /**
???????? * 由这个方法决定树的顶级显示那些对象。在此方法里生成了三个Country对象
???????? * @param inputElement? 用tv.setInput()方法输入的那个对象,在这里没有使用这个对象
???????? */
??????? public Object[] getElements(Object inputElement) {
??????????? if (inputElement instanceof Country[])
??????????????? return (Country[]) inputElement;
??????????? return new Object[0]; //生成一个空数组
??????? }
??????? /**
???????? * 由这个方法决定结点应该显示那些子结点。在这里也不管父结点是什么,每个结点都统一有三个字结点
???????? * @param parentElement 被点击的结点(父结点)
???????? */
??????? public Object[] getChildren(Object parentElement) {
??????????? if (parentElement instanceof Country)
??????????????? return ((Country) parentElement).getCities().toArray();
??????????? else if (parentElement instanceof City)
??????????????? return ((City) parentElement).getPeoples().toArray();
??????????? return new Object[0];
??????? }
??????? /**
???????? * 判断某结点是否有子结点。在这里不管3721,全返回真,即都有子结点。这时结点前都有一个“+”号图标
???????? * @param element 需要判断是否有子的结点
???????? */
??????? public boolean hasChildren(Object element) {
??????????? //People没有结点,Country和City才可能有子结点
??????????? if (element instanceof People) {
??????????????? return false;
??????????? } else if (element instanceof Country) {
??????????????? List list = ((Country) element).getCities();
??????????????? //其子的集合不为空
??????????????? if (list != null && !list.isEmpty())
??????????????????? return true;
??????????? } else if (element instanceof City) {
??????????????? List list = ((City) element).getPeoples();
??????????????? if (list != null && !list.isEmpty())
??????????????????? return true;
??????????? }
??????????? return false;
??????? }
??????? public Object getParent(Object element) {
??????????? return null;
??????? }
??????? public void dispose() {}
??????? public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
??? }
??? /**
???? * 标签提供器。
???? */
??? private static final class MyLableProvider extends LabelProvider {
//??????? /**
//???????? * 显示什么图片
//???????? * @param 结点
//???????? * @return 可以为null值
//???????? */
//??????? public Image getImage(Object element) {
//??????????? //??????????? ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
//??????????? //??????????? return sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK);
//??????????? return null;
//??????? }
??????? public String getText(Object element) {
??????????? if (element instanceof TreeEntry)
??????????????? return ((TreeEntry) element).getName();
??????????? return "";
??????? }
??? }
}


版权声明:CSDN是本Blog托管服务提供商。如本文牵涉版权问题,CSDN不承担相关责任,请版权拥有者直接与文章作者联系解决。
发表于 2004年08月25日 6:37 PM

评论
# 回复:Eclipse插件开发系列7.TreeViewer的使用(2)一个更接近实际应用的例子 2004-08-26 1:32 PM bluexiaopang
支持!学习!


# 回复:Eclipse插件开发系列7.TreeViewer的使用(2)一个更接近实际应用的例子 2004-08-26 3:59 PM hru
good


# 回复:Eclipse插件开发系列7.TreeViewer的使用(2)一个更接近实际应用的例子 2004-08-26 8:12 PM lintower
陈先生,我觉得在TreeEntry接口中加入Object[] getChildren()方法,Country、City、People根据自己数据结构实现该方法,那么在Provider中的getElements()和getChildren()就不用类型检查,效果应该好些。请指正


# 打扰一下:为何屏幕上显示的内容和text.getText()的内容比不一致呢 2004-08-27 4:56 PM wxb
import java.util.StringTokenizer;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class TestText {

private Shell shell;

/**
* @param parentShell
*/
public TestText(Shell aShell) {
shell = aShell;
shell.setText("test");
shell.setLayout(new GridLayout(1,true));
shell.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
shell.setVisible(false);
}

public void start(){
showLogContent("start");
}

private void showLogContent(String str){
createContent(str);
createButtons();

shell.setSize(400,250);
shell.setVisible(true);
}

private void createContent(String str){
Label label = null;
Text text = null;
label = new Label(shell,SWT.NONE | SWT.WRAP);
label.setText("No: ");
text = new Text(shell,SWT.BORDER);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
text.setEditable(true);
text.setText(str);
text.update();
System.out.println("input parameter is "+str+" source is "+text.getText());
}

private void createButtons(){
Button preBtn = new Button(shell,SWT.PUSH);
preBtn.setText("test");
preBtn.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
preBtn.addSelectionListener(new SelectionListener(){

public void widgetSelected(SelectionEvent e) {
showLogContent("runtime");
}

public void widgetDefaultSelected(SelectionEvent e) {

}
});
}

public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
TestText win = new TestText(shell);
win.start();
while (! shell.isDisposed()) {
if (! display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}
评论# 打扰一下:为何屏幕上显示的内容和text.getText()的内容比不一致呢 2004-08-27 4:56 PM wxb
import java.util.StringTokenizer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class TestText {

private Shell shell;

/**
* @param parentShell
*/
public TestText(Shell aShell) {
shell = aShell;
shell.setText("test");
shell.setLayout(new GridLayout(1,true));
shell.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
shell.setVisible(false);
}

public void start(){
showLogContent("start");
}

private void showLogContent(String str){
createContent(str);
createButtons();

shell.setSize(400,250);
shell.setVisible(true);
}

private void createContent(String str){
Label label = null;
Text text = null;
label = new Label(shell,SWT.NONE | SWT.WRAP);
label.setText("No: ");
text = new Text(shell,SWT.BORDER);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
text.setEditable(true);
text.setText(str);
text.update();
System.out.println("input parameter is "+str+" source is "+text.getText());
}

private void createButtons(){
Button preBtn = new Button(shell,SWT.PUSH);
preBtn.setText("test");
preBtn.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
preBtn.addSelectionListener(new SelectionListener(){

public void widgetSelected(SelectionEvent e) {
showLogContent("runtime");
}

public void widgetDefaultSelected(SelectionEvent e) {

}
});
}

public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
TestText win = new TestText(shell);
win.start();
while (! shell.isDisposed()) {
if (! display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}


星期一, 十二月 06, 2004

我的第一篇Blog

因为我在申请blog时,老是遇到问题,在申请时有时会遇到一些错误。今天好不容易在blogger.com上建立了属于自己的blog
,我希望能够通过它结识更多的朋友,能使我学到更多的知识。