2006年11月22日
以前只知道alt+/调出assist,后来发现可以所有字母都激活content assist(方法百度上都有,就不在这写了).用起来果然很爽.但是eclipse还是有些默认的设置不是很好,比如空格键和=号会把第一行的内容自动上屏,其实很多时候我就是想输一个空格或=号而已.这个在设置里面没办法设置.幸好eclipse是有插件机制的,可以通过修改插件的源码,然后导出成插件,再替换掉原来的插件来处理
1.先找到相关的插件
打开Plug-ins View找到插件org.eclipse.jface.text,右键点击,选择import as Source Project,导入完成后,在你的workspace就可以看到这个project了
2.修改代码
在
src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java文件中,找到这样一行代码
char triggers = t.getTriggerCharacter();
if(contains(triggers,key))
在那行if判断里面,eclipse会判断key(就是你按下的键)是否在triggers中,如果是,那就触发下面的第一行提示上屏的代码.所以我们要做的就是把空格和=号排除就可以了:
if(key!='='&&key!=0x20&&contains(triggers,key))
3.把修改好的org.eclipse.jface.text导出
右键点击你的workspace里的org.eclipse.jface.text,选择export-->Deployable plugins and fragments, next,destination 选择archive file,然后finish.你就可以在zip文件里看到生成好的jar ,用它替换掉eclipse/plugins里面的同名jar包,就可以了
Visio的图标很多,但是用来设计web程序的基本没有,在网上找到了这个,觉得还蛮好用的,共享一下
/Files/yes1983/GUUUI_Web_Prototyping_Tool_3.zip
摘要: 本文分析了Eclipse中多线程程序的实现,讨论了在Eclipse客户端程序开发中应用多线程的方法和要注意的问题,同时也讨论了多线程程序的一些调试和问题解决的方法。
阅读全文
转载自http://blog.csdn.net/shangboerds/archive/2010/01/27/5260783.aspx
CTE:
说起WITH 语句,除了那些第一次听说WITH语句的人,大部分人都觉得它是用来做递归查询的。其实那只是它的一个用途而已,它的本名正如我们标题写的那样,叫做:公共表表达式(Common Table Expression),从字面理解,大家觉得它是用来干嘛的呢?其实,它是用来定义临时集合的。啊?VALUES语句不是用来定义临时集合的吗?怎么WITH语句也用来定义临时集合呢?它们有什么区别呢?
VALUES语句是用明确的值来定义临时集合的,如下:
VALUES (1,2), (1,3),(2,1)
WITH语句是用查询(也就是select语句)来定义临时集合的,从这个角度讲,有点像视图,不过不是视图,大家千万别误解。如下:
CREATE TABLE USER (
NAME VARCHAR(20) NOT NULL,---姓名
SEX INTEGER,---性别(1、男 2、女)
BIRTHDAY DATE---生日
);
WITH TEST(NAME_TEST, BDAY_TEST) AS
(
SELECT NAME,BIRTHDAY FROM USER--语句1
)
SELECT NAME_TEST FROM TEST WHERE BDAY_TEST='1949-10-1';--语句2
下面我们来解释一下,首先语句1执行,它会产生一个有两列(NAME,BIRTHDAY)的结果集;接着,我们将这个结果集命名为test,并且将列名重命名为NAME_TEST, BDAY_TEST;最后我们执行语句2,从这个临时集合中找到生日是1949-10-1,也就是共和国的同龄人。
怎么样?如果你感觉不好理解,请仔细的分析一下上面的语句。下面我们举个VALUES语句和WITH语句结合使用的例子,如下:
WITH TEST(NAME_TEST, BDAY_TEST) AS
(
VALUES ('张三','1997-7-1'),('李四','1949-10-1')
)
SELECT NAME_TEST FROM TEST WHERE BDAY_TEST='1949-10-1'
从上面的介绍和WITH语句不为大多数人所熟悉可以猜测,WITH语句是为复杂的查询为设计的,的确是这样的,下面我们举个复杂的例子,想提高技术的朋友可千万不能错过。考虑下面的情况:
CREATE TABLE USER
(
NAME VARCHAR(20) NOT NULL,--姓名
DEGREE INTEGER NOT NULL,--学历(1、专科 2、本科 3、硕士 4、博士)
STARTWORKDATE date NOT NULL,--入职时间
SALARY1 FLOAT NOT NULL,--基本工资
SALARY2 FLOAT NOT NULL--奖金
);
假设现在让你查询一下那些 1、学历是硕士或博士 2、学历相同,入职年份也相同,但是工资(基本工资+奖金)却比相同条件员工的平均工资低的员工。(哈哈,可能是要涨工资),不知道你听明白问题没有?该怎么查询呢?我们是这样想的:
1、查询学历是硕士或博士的那些员工得到结果集1,如下:
SELECT NAME,DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, SALARY1+SALARY2 AS SALARY FROM USER WHERE DEGREE IN (3,4);
2、根据学历和入职年份分组,求平均工资 得到结果集2,如下:
SELECT DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, AVG(SALARY1+SALARY2) AS AVG_SALARY
FROM USER WHERE DEGREE IN (3,4)
GROUP BY DEGREE,YEAR(STARTWORKDATE)
3、以学历和入职年份为条件 联合两个结果集,查找工资<平均工资 的员工,以下是完整的SQL:
WITH TEMP1(NAME,DEGREE,WORDDATE,SALARY) AS
(
SELECT NAME,DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, SALARY1+SALARY2 AS SALARY FROM USER WHERE DEGREE IN (3,4)
),
TEMP2 (DEGREE,WORDDATE,AVG_SALARY) AS
(
SELECT DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, AVG(SALARY1+SALARY2) AS AVG_SALARY
FROM USER WHERE DEGREE IN (3,4)
GROUP BY DEGREE,YEAR(STARTWORKDATE)
)
SELECT NAME FROM TEMP1, TEMP2 WHERE
TEMP1.DEGREE=TEMP2.DEGREE
AND TEMP1.WORDDATE=TEMP2.WORDDATE
AND SALARY<AVG_SALARY;
查询结果完全正确,但我们还有改善的空间,在查询结果集2的时候,我们是从user表中取得数据的。其实此时结果集1已经查询出来了,我们完全可以从结果集1中通过分组得到结果集2,而不用从uer表中得到结果集2,比较上面和下面的语句你就可以知道我说的是什么意思了!
WITH TEMP1(NAME,DEGREE,WORDDATE,SALARY) AS
(
SELECT NAME,DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, SALARY1+SALARY2 AS SALARY FROM USER WHERE DEGREE IN (3,4)
),
TEMP2 (DEGREE,WORDDATE,AVG_SALARY) AS
(
SELECT DEGREE,WORDDATE, AVG(SALARY) AS AVG_SALARY
FROM TEMP1
GROUP BY DEGREE,WORDDATE
)
SELECT NAME FROM TEMP1, TEMP2 WHERE
TEMP1.DEGREE=TEMP2.DEGREE
AND TEMP1.WORDDATE=TEMP2.WORDDATE
AND SALARY<AVG_SALARY;
可能有些朋友会说,我不用WITH语句也可以查出来,的确是这样,如下:
SELECT U.NAME FROM USER AS U,
(
SELECT DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, AVG(SALARY1+SALARY2) AS AVG_SALARY
FROM USER WHERE DEGREE IN (3,4)
GROUP BY DEGREE,YEAR(STARTWORKDATE)
) AS G
WHERE U.DEGREE=G.DEGREE
AND YEAR(U.STARTWORKDATE)=G.WORDDATE
AND (SALARY1+SALARY2)<G.AVG_SALARY;
那使用WITH 和不使用 WITH,这两种写法有什么区别呢?一般情况下这两种写法在性能上不会有太大差异,但是,
1、当USER表的记录很多
2、硕士或博士(DEGREE IN (3,4))在USER表中的比例很少
当满足以上条件时,这两种写法在性能的差异将会显现出来,为什么呢?因为不使用WITH写法的语句访问了2次USER表,如果DEGREE 字段又没有索引,性能差异将会非常明显。
当你看到这时,如果很好的理解了上面的内容,我相信你会对WITH语句有了一定的体会。然而WITH语句能做的还不止这些,下面给大家介绍一下,如何用WITH语句做递归查询。递归查询的一个典型的例子是对树状结构的表进行查询,考虑如下的情况:
论坛首页
--数据库开发
----DB2
------DB2 文章1
--------DB2 文章1 的评论1
--------DB2 文章1 的评论2
------DB2 文章2
----Oracle
--Java技术
以上是一个论坛的典型例子,下面我们新建一个表来存储以上信息。
CREATE TABLE BBS
(
PARENTID INTEGER NOT NULL,
ID INTEGER NOT NULL,
NAME VARCHAR(200) NOT NULL---板块、文章、评论等。
);
insert into bbs (PARENTID,ID,NAME) values
(0,0,'论坛首页'),
(0,1,'数据库开发'),
(1,11,'DB2'),
(11,111,'DB2 文章1'),
(111,1111,'DB2 文章1 的评论1'),
(111,1112,'DB2 文章1 的评论2'),
(11,112,'DB2 文章2'),
(1,12,'Oracle'),
(0,2,'Java技术');
现在万事兼备了,我们开始查询吧。假设现在让你查询一下‘DB2 文章1’的所有评论,有人说,这还不简单,如下这样就可以了。
SELECT * FROM BBS WHERE PARENTID=(SELECT ID FROM BBS WHERE NAME='DB2');
答案完全正确。那么,现在让你查询一下DB2的所有文章及评论,怎么办?传统的方法就很难查询了,这时候递归查询就派上用场了,如下:
WITH TEMP(PARENTID,ID,NAME) AS
(
SELECT PARENTID,ID,NAME FROM BBS WHERE NAME='DB2'---语句1
UNION ALL---语句2
SELECT B.PARENTID,B.ID,B.NAME FROM BBS AS B, TEMP AS T WHERE B.PARENTID=T.ID---语句3
)
SELECT NAME FROM TEMP;---语句4
运行后,我们发现,结果完全正确,那它到底是怎么运行的呢?下面我们详细讲解一下。
1、首先,语句1将会执行,它只执行一次,作为循环的起点。得到结果集:DB2
2、接着,将循环执行语句3,这里我们有必要详细介绍一下。
首先语句3的意图是什么呢?说白了,它就是查找语句1产生结果集(DB2)的下一级,那么在目录树中DB2的下一级是什么呢?是‘DB2 文章1’和‘DB2 文章2’,并且把查询到的结果集作为下一次循环的起点,然后查询它们的下一级,直到没有下一级为止。
怎么样?还没明白?哈哈,不要紧,我们一步一步来:
首先,语句1产生结果集:DB2,作为循环的起点,把它和BBS表关联来查找它的下一级,查询后的结果为:‘DB2 文章1’和‘DB2 文章2’
接着,把上次的查询结果(也就是‘DB2 文章1’和‘DB2 文章2’)和BBS表关联来查找它们的下一级,查询后的结果为:‘DB2 文章1 的评论1’ 和 ‘DB2 文章1 的评论2’。
然后,在把上次的查询结果(也就是‘DB2 文章1 的评论1’ 和 ‘DB2 文章1 的评论2’)和BBS表关联来查找它们的下一级,此时,没有结果返回,循环结束。
3、第三,将执行语句2,将所有的结果集放在一起,最终得到temp结果集。
4、最后,我们通过语句4 从temp临时集合中得到我们期望的查询结果。
怎么样,这回理解了吧,如果还没有理解,那么我也无能为力了。需要特别提醒的是
1、一定要注意语句3的关联条件,否则很容易就写成死循环了。
2、语句2必须是UNION ALL
最后请大家猜想一下,把语句1的where子句去掉,将会产生什么样的结果呢?
NTE:
SELECT * FROM <TABLE-NAME>;
看到上面的语句了吗?这是我们在熟悉不过的一条语句,我们中的大多人学习SQL正是从这条语句开始的。所以大多数人认为FROM语句后只能接一个表或视图(或者压根就没多想),有这种想法的人我非常能理解,因为我曾经也是这其中的一员。其实FROM后面可以接任何集合(表)。说到这,关于集合和表,我特别想多少几句。SQL的理论基础是数学中的集合理论,所以SQL关注的就是如何对集合进行操作,基于以上原因,我特别喜欢名词 集合,而不喜欢说表。不过,大家如果不习惯,也可以把集合和表当一个意思来理解,因为我们不是搞理论研究工作的,没必要深究他们之间的细微差别。说了这么多,我们还是赶快来看个例子吧。
---建表
CREATE TABLE USER
(
NAME VARCHAR(20) NOT NULL,---姓名
BIRTHDAY DATE---生日
);
---例子1
SELECT * FROM
(
SELECT * FROM USER
) AS TEMP1;
---例子2
SELECT NAME,BIRTHDAY FROM
(
SELECT NAME,BIRTHDAY FROM USER
) AS TEMP1;
---例子3
SELECT TEMP1.NAME,TEMP1.BIRTHDAY FROM
(
SELECT NAME,BIRTHDAY FROM USER
) AS TEMP1;
---例子4
SELECT N,B FROM
(
SELECT NAME,BIRTHDAY FROM USER
) AS TEMP1(N,B);
---例子5
SELECT AAA.A,AAA.B,XXX.X,XXX.Y FROM
(
SELECT NAME,BIRTHDAY FROM USER
) AS AAA(A,B),--集合1
(
SELECT NAME,BIRTHDAY FROM USER
) AS XXX(X,Y)--集合2
WHERE AAA.A=XXX.X AND AAA.B=XXX.Y--关联两个集合
看到上面的例子5了吗?我们可以给临时集合命名,还可以给重命名临时集合的列名,还可以关联两个临时集合,总之,操作临时集合和操作表没有区别。
Temporary table
临时表(TEMPORARY TABLE)通常应用在需要定义临时集合的场合。但是,在大部分需要临时集合的时候,我们根本就不需要定义临时表。当我们在一条SQL语句中只使用一次临时集合时,我们可以使用嵌套表表达式来定义临时集合;当我们在一条SQL语句中需要多次使用同一临时集合时,我们可以使用公共表表达式;只有当我们在一个工作单元中的多条SQL语句中使用同一临时集合时,我们才需要定义临时表。
可以通过以下三种方式定义临时表:
方法1:
DECLARE GLOBAL TEMPORARY TABLE SESSION.EMP
(
NAME VARCHAR(10),---姓名
DEPT SMALLINT,---部门
SALARY DEC(7,2)---工资
)
ON COMMIT DELETE ROWS;
方法2:
DECLARE GLOBAL TEMPORARY TABLE session.emp
LIKE staff INCLUDING COLUMN DEFAULTS
WITH REPLACE
ON COMMIT PRESERVE ROWS;
方法3:
DECLARE GLOBAL TEMPORARY TABLE session.emp AS
(
SELECT * FROM staff WHERE <condition>
)
DEFINITION ONLY
WITH REPLACE;
定义了临时表后,我们可以像使用普通表一样使用临时表。临时表只对定义它的用户有效,不同用户可以在同一时间定义同名的临时表,他们之间互不影响。临时表的生命周期是SESSION,当SESSION关闭时,临时表将自动删除,这也是临时表的模式名只能为SESSION的原因。此外,我们还可以给临时表定义索引。更多细节请参考DB2 信息中心。
Eclipse的扩展机制是其一个重要特色,但随着Eclipse功能越做越强,插件越来越多,你会发现GUI上的图标越来越多,Menu,toolbar,context menu都被占满了,其实很多item并不是我们需要的,但是contribute这些item的插件我们是需要的,那怎么去掉它们扩展的那些菜单项呢?
1.在Plugin.xml中定制
这是最简单的办法,很多时候我们自己想写代码来去掉一些菜单项,但效果并不好.所以能在Plugin.xml中定制的,我们就 尽量写在plugin.xml里面.下面举一个右键菜单的例子:
扩展右键菜单需要扩展org.eclipse.ui.popupMenus扩展点,我们一般都在它下面new一个action,但这个action扩展之后不管在 任何界面都会出现,如果我们想在某些条件下隐藏掉它该怎么办?仔细观察下org.eclipse.ui.popupMenus扩展点,其实我们还可以新建objectContribution扩展
<extension
point="org.eclipse.ui.popupMenus">
<objectContribution
id="my.example.objectContribution"
nameFilter="*example*"
objectClass="java.io.File">
<action
class="my.example.MyAction"
id="my.example.MyAction"
label="Exe"
menubarPath="additional">
</action>
</objectContribution>
</extension>
objectContribution里面也包含一个action,但这个action在popupmenu里出现是有条件的:我们给它定义了一个nameFilter, 只有当selection()的path中包含了"example"才会显示,否则这个action是不会出现在 popupmenu里的.这里的selection假设选中的是一个File,如果选中的是你自己写的类,那namefilter会在你的类的toString方法里面找keyword.
2.使用Eclipse的Activities扩展
plugin.xml并不能解决所有问题,当我们实在没有办法在plugin.xml中限制某些extension的出现的时候,可以考虑使用Eclipse的Activities.Activities的官方定义大家可以google一下eclipse的help.我个人的理解就是它可以和perspective一样控制UI的显示,但是Perspective设计的太易于扩展了,假如Plugin A在perspective上扩展了一个UI,那么Plugin B在每次进入这个perspective的时候就一定可以看得见它,而且在Eclipse的扩展机制下,Plugin B是没有权利去删了Plugin A的contribution的(Eclipse的ExtensionRegistry倒是提供了一个removeExtension方法,但运行的时候会报错).在这样的情况下,Activities的价值就体现出来了,你只要给它一个Extension的id,它就可以帮你把这个Extension disable掉.例如:
<extension
point="org.eclipse.ui.activities">
<activity
id="my.example.activity"
name="WizardActivity">
</activity>
<activityPatternBinding
activityId="my.example.activity"
pattern="my\.example/mywizard">
</activityPatternBinding>
</extension>
比较重要的是activityPatternBinding中的pattern属性,它是由plugin id + "/" + local-id组成.比如在插件my.example中扩展了 org.eclipse.ui.newWizards,id是mywizard,那么上面这个activityPatternBinding就会disable掉my.example的mywizard扩展,你在 GUI中就看不见这个wizard了.pattern是支持正则表达式的,所以如果有"."的话需要用转义字符\.注意,这里的disable的意思并不是说我把mywizard这个扩展删掉了,而是屏蔽了它,mywizard仍然在 ExtensionRegistry中.
3.用代码来动态控制UI
方法2只是隐藏掉一些扩展,但是有一些需求并不是简单的隐藏就可以了,我最近碰到的一个需求就是:有一个flag,只有当flag==1的时候扩展是可见的,否则是不可见的,需要disable这个扩展.这时就必须要加一些代码才能实现了,还是以方法2中的mywizard为例:
IWorkbenchActivitySupport workbenchActivitySupport = PlatformUI.getWorkbench().getActivitySupport();
IActivityManager activityManager = workbenchActivitySupport.getActivityManager();
Set enabledActivityIds = new HashSet(activityManager.getEnabledActivityIds());
if(flag==1)
{
if (enabledActivityIds.add("my.example.activity"))
workbenchActivitySupport.setEnabledActivityIds(enabledActivityIds);
}
else{
if(enabledActivityIds.remove("my.example.activity"))
workbenchActivitySupport.setEnabledActivityIds(enabledActivityIds);
}
Activities可以是enable或者disable的,当你在plugin.xml中定义好了一个Activity,缺省它是disable的,就是说activityPatternBinding 匹配的扩展是会被disable的,但你也可以把Activities设成enable的(在plugin.xml或者用代码都可以设置),它匹配的扩展是可以正常使用的.
在上面的code sample中,我们通过activityManager.getEnabledActivityIds()得到所有enable的Activities.如果flag==1,那my.example.activity 也应该被加入到enable Activities中,这样mywizard就可以显示在界面上,反之,就要在enable Activities中remove掉my.example.activity,它就变成
disable,会把mywizard隐藏.
摘要: Access Path
1.并不是用index就一定快.有时候一个表只有很少的records,那么你直接scan这个表,比你先读index,再访问表要快.
2.不过大多数情况下还是用index快一些(要不然这个技术就没有意义了).DB2中index的应用需要两个前提条件:
阅读全文
TreeViewer的setSelection方法使用后,会在树上选中并展开方法参数中对应的节点.但是有时候你发现它只能选中第一级节点,下面的子节点没有办法选中.其实这个方法是没有问题的,它的大概实现算法是:先找到某一个子节点,然后找到它的父节点,把父节点展开,然后又找父节点的父节点,做同样的操作,直到根节点为止,这样你才能看到选中的子节点.所以父节点如果为null,那肯定你是看不到子节点了.而我们很多人在实现ITreeContentProvide的接口的时候,是不实现getParent方法的,因为只要实现了getChildren方法就可以看见一棵树了.包括陈刚的<Eclipse从入门到精通>也是这样.所以在实现treeViewer的时候,最好还是实现getparent方法.其实也不麻烦,在添加一个child的时候,加一句setparent(this)就可以了
最初java是不支持对文本文件的处理的,为了弥补这个缺憾而引入了Reader和Writer两个类,这两个类都是抽象类,Writer中 write(char[] ch,int off,int
length),flush()和close()方法为抽象方法,Reader中read(char[] ch,int off,int length)和close()方法是抽象方法。子类应该分别实现他们。
当我们读写文本文件的时候,采用Reader是非常方便的,比如FileReader,InputStreamReader和BufferedReader。其中最重要的类是InputStreamReader,
它是字节转换为字符的桥梁。你可以在构造器重指定编码的方式,如果不指定的话将采用底层操作系统的默认编码方式,例如GBK等。当使用FileReader读取文件
的时候。
FileReader fr = new FileReader("ming.txt");
int ch = 0;
while((ch = fr.read())!=-1 )
{
System.out.print((char)ch);
}
其中read()方法返回的是读取得下个字符。当然你也可以使用read(char[] ch,int off,int length)这和处理二进制文件的时候类似,不多说了。如果使用
InputStreamReader来读取文件的时候
while((ch = isr.read())!=-1)
{
System.out.print((char)ch);
}
这和FileReader并没有什么区别,事实上在FileReader中的方法都是从InputStreamReader中继承过来的。read()方法是比较好费时间的,如果为了提高效率
我们可以使用BufferedReader对Reader进行包装,这样可以提高读取得速度,我们可以一行一行的读取文本,使用readLine()方法。
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("ming.txt")));
String data = null;
while((data = br.readLine())!=null)
{
System.out.println(data);
}
当你明白了如何用Reader来读取文本文件的时候那么用Writer写文件同样非常简单。有一点需要注意,当你写文件的时候,为了提高效率,写入的数据会先
放入缓冲区,然后写入文件。因此有时候你需要主动调用flush()方法。与上面对应的写文件的方法为:
FileWriter fw = new FileWriter("hello.txt");
String s = "hello world";
fw.write(s,0,s.length());
fw.flush();
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("hello2.txt"));
osw.write(s,0,s.length());
osw.flush();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("hello3.txt")),true);
pw.println(s);
不要忘记用完后关闭流!下面是个小例子,帮助新手理解。其实有的时候java的IO系统是需要我们多记记的,不然哪天就生疏了。
import java.io.*;
public class TestFile2
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("ming.txt");
char[] buffer = new char[1024];
int ch = 0;
while((ch = fr.read())!=-1 )
{
System.out.print((char)ch);
}
InputStreamReader isr = new InputStreamReader(new FileInputStream("ming.txt"));
while((ch = isr.read())!=-1)
{
System.out.print((char)ch);
}
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("ming.txt")));
String data = null;
while((data = br.readLine())!=null)
{
System.out.println(data);
}
FileWriter fw = new FileWriter("hello.txt");
String s = "hello world";
fw.write(s,0,s.length());
fw.flush();
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("hello2.txt"));
osw.write(s,0,s.length());
osw.flush();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("hello3.txt")),true);
pw.println(s);
fr.close();
isr.close();
br.close();
fw.close();
osw.close();
pw.close();
}
}
java中多种方式读文件
一、多种方式读文件内容。
1、按字节读取文件内容
2、按字符读取文件内容
3、按行读取文件内容
4、随机读取文件内容
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
public class ReadFromFile {
/**
* 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。
* @param fileName 文件的名
*/
public static void readFileByBytes(String fileName){
File file = new File(fileName);
InputStream in = null;
try {
System.out.println("以字节为单位读取文件内容,一次读一个字节:");
// 一次读一个字节
in = new FileInputStream(file);
int tempbyte;
while((tempbyte=in.read()) != -1){
System.out.write(tempbyte);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
try {
System.out.println("以字节为单位读取文件内容,一次读多个字节:");
//一次读多个字节
byte[] tempbytes = new byte[100];
int byteread = 0;
in = new FileInputStream(fileName);
ReadFromFile.showAvailableBytes(in);
//读入多个字节到字节数组中,byteread为一次读入的字节数
while ((byteread = in.read(tempbytes)) != -1){
System.out.write(tempbytes, 0, byteread);
}
} catch (Exception e1) {
e1.printStackTrace();
} finally {
if (in != null){
try {
in.close();
} catch (IOException e1) {
}
}
}
}
/**
* 以字符为单位读取文件,常用于读文本,数字等类型的文件
* @param fileName 文件名
*/
public static void readFileByChars(String fileName){
File file = new File(fileName);
Reader reader = null;
try {
System.out.println("以字符为单位读取文件内容,一次读一个字节:");
// 一次读一个字符
reader = new InputStreamReader(new FileInputStream(file));
int tempchar;
while ((tempchar = reader.read()) != -1){
//对于windows下,rn这两个字符在一起时,表示一个换行。
//但如果这两个字符分开显示时,会换两次行。
//因此,屏蔽掉r,或者屏蔽n。否则,将会多出很多空行。
if (((char)tempchar) != 'r'){
System.out.print((char)tempchar);
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println("以字符为单位读取文件内容,一次读多个字节:");
//一次读多个字符
char[] tempchars = new char[30];
int charread = 0;
reader = new InputStreamReader(new FileInputStream(fileName));
//读入多个字符到字符数组中,charread为一次读取字符数
while ((charread = reader.read(tempchars))!=-1){
//同样屏蔽掉r不显示
if ((charread == tempchars.length)&&(tempchars[tempchars.length-1] != 'r')){
System.out.print(tempchars);
}else{
for (int i=0; i<charread; i++){
if(tempchars[i] == 'r'){
continue;
}else{
System.out.print(tempchars[i]);
}
}
}
}
} catch (Exception e1) {
e1.printStackTrace();
}finally {
if (reader != null){
try {
reader.close();
} catch (IOException e1) {
}
}
}
}
/**
* 以行为单位读取文件,常用于读面向行的格式化文件
* @param fileName 文件名
*/
public static void readFileByLines(String fileName){
File file = new File(fileName);
BufferedReader reader = null;
try {
System.out.println("以行为单位读取文件内容,一次读一整行:");
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 1;
//一次读入一行,直到读入null为文件结束
while ((tempString = reader.readLine()) != null){
//显示行号
System.out.println("line " + line + ": " + tempString);
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null){
try {
reader.close();
} catch (IOException e1) {
}
}
}
}
/**
* 随机读取文件内容
* @param fileName 文件名
*/
public static void readFileByRandomAccess(String fileName){
RandomAccessFile randomFile = null;
try {
System.out.println("随机读取一段文件内容:");
// 打开一个随机访问文件流,按只读方式
randomFile = new RandomAccessFile(fileName, "r");
// 文件长度,字节数
long fileLength = randomFile.length();
// 读文件的起始位置
int beginIndex = (fileLength > 4) ? 4 : 0;
//将读文件的开始位置移到beginIndex位置。
randomFile.seek(beginIndex);
byte[] bytes = new byte[10];
int byteread = 0;
//一次读10个字节,如果文件内容不足10个字节,则读剩下的字节。
//将一次读取的字节数赋给byteread
while ((byteread = randomFile.read(bytes)) != -1){
System.out.write(bytes, 0, byteread);
}
} catch (IOException e){
e.printStackTrace();
} finally {
if (randomFile != null){
try {
randomFile.close();
} catch (IOException e1) {
}
}
}
}
/**
* 显示输入流中还剩的字节数
* @param in
*/
private static void showAvailableBytes(InputStream in){
try {
System.out.println("当前字节输入流中的字节数为:" + in.available());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String fileName = "C:/temp/newTemp.txt";
ReadFromFile.readFileByBytes(fileName);
ReadFromFile.readFileByChars(fileName);
ReadFromFile.readFileByLines(fileName);
ReadFromFile.readFileByRandomAccess(fileName);
}
}
二、将内容追加到文件尾部
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* 将内容追加到文件尾部
*/
public class AppendToFile {
/**
* A方法追加文件:使用RandomAccessFile
* @param fileName 文件名
* @param content 追加的内容
*/
public static void appendMethodA(String fileName,
String content){
try {
// 打开一个随机访问文件流,按读写方式
RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
// 文件长度,字节数
long fileLength = randomFile.length();
//将写文件指针移到文件尾。
randomFile.seek(fileLength);
randomFile.writeBytes(content);
randomFile.close();
} catch (IOException e){
e.printStackTrace();
}
}
/**
* B方法追加文件:使用FileWriter
* @param fileName
* @param content
*/
public static void appendMethodB(String fileName, String content){
try {
//打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件
FileWriter writer = new FileWriter(fileName, true);
writer.write(content);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String fileName = "C:/temp/newTemp.txt";
String content = "new append!";
//按方法A追加文件
AppendToFile.appendMethodA(fileName, content);
AppendToFile.appendMethodA(fileName, "append end. n");
//显示文件内容
ReadFromFile.readFileByLines(fileName);
//按方法B追加文件
AppendToFile.appendMethodB(fileName, content);
AppendToFile.appendMethodB(fileName, "append end. n");
//显示文件内容
ReadFromFile.readFileByLines(fileName);
}
}
1.有的时候在project的java build path中定义好了一些jar包依赖,但是project在运行的时候仍然报NoClassDef的错误.这是因为project的MANIFEST.MF文件没有更新.手动在MANIFEST.MF加上那些jar包就可以了.
2.Plugin A 依赖 Plugin B.B也把相应的package export出来了,但是A还是找不到B里面定义的类.修改A的MANIFEST.MF文件,在dependence tab里去掉Plugin B,再添加B.此时发现有5,6个同样的Plugin B出现在选择plugin的list中.cancel 掉该对话框,然后重启eclipse,在A的dependence里面重新加上B,问题解决.
3.当我们通过在plugin.xml中用extension的方式定义action的时候,你会发现你定义的actionset和action在GUI出现的顺序不是你可以控制的,就是说同一个actionset下的多个action不是按你定义的先后顺序出现在程序的界面上的,这样对action进行排序呢?其实仔细观察一下,你会发现action在GUI出现的顺序是和你定义action的顺序相反的,比如你先后定义了3个action A,B,C,那么你就会在GUI上看见action的顺序是C,B,A.如果你定义了多个actionset,你会发现这个规律不适用与actionset,actionset在界面上出现的顺序其实是和它的id的排序相反的.比如你定义了三个actionset,它们的id分别是:seta,setb,setc,你会发现GUI上出现的顺序是setc,setb,seta
4.双击激活TreeViewer的celleditor
JFace的Viewer都有单元格编辑功能,但是celleditor默认的实现是单击激活editor,双击选中item.如果需要改成单击选中item,双击激活editor呢?Eclipse的官网上好像也有人问到这个问题,不过目前好像是开了一个bug,期待eclipse的下个版本解决这个问题.但最近找到了一个用SWT来解决这个问题的方法:
Tree tree=treeViewer.getTree();
final TreeEditor editor = new TreeEditor(tree);
editor.horizontalAlignment = SWT.LEFT;
editor.grabHorizontal = true;
// Use a mouse listener, not a selection listener, because you're
// interested
// in the selected column as well as row
tree.addMouseListener(new MouseAdapter() {
public void mouseDoubleClick(MouseEvent event) {
final TreeItem item = tree.getSelection()[0];
// Create a text field to do the editing
final Text text = new Text(tree, SWT.NONE);
text.setText(item.getText());
text.selectAll();
text.setFocus();
text.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent event) {
text.dispose();
}
});
// Set the text field into the editor
editor.setEditor(text, item);
}
});
由于Eclipse的易扩展性,理论上可以有无数个Action运行在一个RCP 程序中,但是快捷键是有限的,尤其是一些常用的,像Ctrl+C,Ctrl+S之类的普通用户能记得住的就那么几个,万一你自定义的Action的快捷键和Eclipse默认的发生了冲突怎么办?比如Eclipse默认Ctrl+S是Save的快捷键,但是你又自定义了一个SaveAction,希望用户按下Ctrl+S之后执行的是自己的SaveAction的run方法.
一般给Action绑定快捷键的方法是自定义binding和command,然后在action中指定definition id为command的id.如下:
<extension
point="org.eclipse.ui.bindings">
<key
commandId="myplugin.actions.save"
contextId="org.eclipse.ui.contexts.window"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="CTRL+S">
</key>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
id="myplugin.actions.save"
name="Save">
</command>
</extension>
这样的方法一般是不会有冲突的,但是像我们上面提到的情况,如果你自定义一个binding,它的key sequence是Ctrl+S,那就会有问题.由于org.eclipse.ui插件已经提供了一个Ctrl+S的快捷键,所以系统中会有两个Ctrl+S,这样Eclipse会在右下角pop up一个assist dialog,让你从两个Action中选择一个,这样可能会造成一些用户使用上的不习惯.
解决办法:
1.直接改快捷键.
这个最简单了,比如把你自己的save定义成Alt+S.但是这个方法也是最不好的方法,因为很多用户并不知道Alt+S在你的程序里面就是save.
2.修改自定义action的definition id
我们刚才说过,action的definition id绑定着一个command,而command又对应着一个binding,Eclipse通过这样的方式实现action和快捷键的绑定.我们再来看看Eclipse定义的command和key binding(摘自org.eclipse.ui的plugin.xml):
<command
name="%command.save.name"
description="%command.save.description"
categoryId="org.eclipse.ui.category.file"
id="org.eclipse.ui.file.save" />
<key
commandId="org.eclipse.ui.file.save"
sequence="M1+S"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" />
<key
Eclipse的Save Action把definition id指定为org.eclipse.ui.file.save,然后它就和上面的command进行了绑定,而这个command对应的key就是"M1+S"(Ctrl + S),这样就实现了快捷键绑定.如果我们也把自定义的Save Action的definition id指定为org.eclipse.ui.file.save,是不是就可以达到目的呢?答案是肯定的.
Eclipse中的Action存在着一个类似"优先级"的概念(具体实现是通过action handler).越"具体"的action,优先级越高.Eclipse的Save Action明显是一个global的action,(同样的global action还有copy, cut,undo,redo等等).而我们自定义的action一般是实现了IWorkbenchWindowActionDelegate接口的,就是说,它是contribute to workbench window的,它是一个workbench action,它的优先级就高于任何global action.同理,如果你定义一个editor action或者view action,由于它比workbench还"具体"(workbench可以包含多个editor或view,workbench action对这些editor或view都是有效的;而editor action只对某个具体的editor有效),所以editor action的优先级就高于workbench action.这样,如果自定义的action和eclipse缺省的action都绑定到同一个command,那么eclipse runtim最后会选择自定义的action来执行.
3.终极解决大法:自定义schema
Eclipse 有一个default的快捷键schema文件:org.eclipse.ui.defaultAcceleratorConfiguration.它存储着Eclipse所有的快捷键.如果你自定义一个自己的schema文件,并把它设成当前使用的schema文件,那么Eclipse就会调用自定义的schema文件.(新的schema文件可以在org.eclipse.ui.bindings扩展点中定义,请注意,在定义新schema的时候由一个parentID属性,如果你定义了它,新的schema会像类继承一样把parent schema里面的key binding全继承下来.如果不定义,则是一个全新的schema)
假定我们已经有了一个新的schema文件,id是myplugin.schema.然后我们在org.eclipse.ui.bindings下定义一个key:
<key
commandId="myplugin.actions.save"
contextId="org.eclipse.ui.contexts.window"
schemaId="myplugin.schema"
sequence="CTRL+S">
</key>
我们已经把schemaId换成了myplugin.schema,表示我们把CTRL+S加到了myplugin.schema中,然后把新建的schema文件在product配置文件plugin_customization.ini中设置成当前的key schema文件:
org.eclipse.ui/KEY_CONFIGURATION_ID=myplugin.schema
这种方法虽然麻烦了一点,但却可以治标又治本.而且由于可以指定parent schema,我们完全可以把org.eclipse.ui.defaultAcceleratorConfiguration作为parent schema,继承它全部的快捷键配置,只定制几个会产生冲突的快捷键即可
gef中经常会有很多连线,这些连线如何和每个node连接,允不允许交叉等等都是用router来控制的.网上有篇文章对这个做了一些介绍:
http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-gef/part2/
我现在做的这个项目需要在两个node之间同时存在多根线,如果不使用router的话就只能看见一根,在diagram的 figure里面set一个FanRouter作为缺省的router就可以解决这个问题.两个node之间如果存在多根连线的话,FanRouter会把它们分布成扇形,每根连线都可以看见.但是FanRouter好像只能在diagram的figure里面设置,如果每根connection你都设置成FanRouter,反而不会启效果,这可能跟它的handlecollision方法的算法有关.
但是设置成FanRouter之后有一个问题:我的项目中还有那种自连接的connection(该connection的source和target是同一个node),原先我是把这种connection的router设置为bendconnectionrouter,但是后来设置了FanRouter之后BendConnectionRouter好像就失效了,不管你的connection上面有多少个bendpoint都看不出来效果.
后来终于找到了让这两张router和平共处的办法,只要加一行:fanRouter.setNextRouter(new BendPointConnectionRouter());setNextRouter这个方法有点怪,按照字面的理解,应该是fanrouter的下一个router,按理说应该是先用fanrouter来layout 连线,然后再使用BendPointConnectionRouter来layout 连线,但是它实际上是先用BendPointConnectionRouter来layout 连线,然后再使用fanRouter.
GEF中自带有Directeditrequest,所以实现Directedit还是比较容易的,八进制的gef例子里面就有实现.但我在给directedit加上content assist的时候却发现由一个小bug不太好弄,费了两天才搞定,现在先记下来,以供参考
directedit是通过一个text celleditor来实现编辑功能的,所以可以在directeditmanager类里面的initCellEditor方法里面加上ContentAssistHandler来实现auto complete.但是加上去之后却发现有一个问题:不支持用鼠标来选择proposal.只能用键盘上的上下箭头来选择.虽然也可以用,但是终究不是那么的人性化.
为了修复这个bug,走了不少的弯路,一开始以为是contentassist的问题,因为它是deprecated,所以换了3.3里面的assist api,发现还是不行.后来才知道是因为celleditor有一个focus listener,当用户点击proposals 来选择一行的时候,celleditor的focus就lost了,就会调用focusLost方法,导致directedit编辑失败.所以我重写了celleditor的focusLost方法,把它设成当focus在contentassist的popup dialog就什么都不干,否则调用父类的focusLost方法.理论上是一个好的解决方法,但是contentassist的hasPopupFocus居然一直都返回false,这个方法也失败了.
最后,在bug.eclipse.org上面有人提到GMF里面的TextDirectEditManager是可以做到用鼠标选择proposal的,于是又去看gmf的这个类,它也是继承自DirectEditManager,不过它消除这个bug不是在listener上作文章,而是在commit方法里面,在这个方法里面判断popup dialog是否是active的,如果是的话则给celleditor加上deactive lock,不允许它deactive,这样来实现用鼠标选择proposal.
下面是TextDirectEditManager的方法commit里面的部分代码:
Shell activeShell = Display.getCurrent().getActiveShell();
if (activeShell != null
&& getCellEditor().getControl().getShell().equals(
activeShell.getParent())) {
Control[] children = activeShell.getChildren();
if (children.length == 1 && children[0] instanceof Table) {
/*
* CONTENT ASSIST: focus is lost to the content assist pop up -
* stay in focus
*/
getCellEditor().getControl().setVisible(true);
((MyTextCellEditor) getCellEditor()).setDeactivationLock(true);
return;
}
}
下面是MyTextCellEditor里面对于deactive lock的应用,MyTextCellEditor的deactive之前会判断一下deactive lock是否为true:
public boolean isDeactivationLocked() {
return deactivationLock;
}
public void deactivate() {
if (! isDeactivationLocked())
super.deactivate();
setDeactivationLock(false);
}
public void setDeactivationLock(boolean deactivationLock) {
this.deactivationLock = deactivationLock;
}
使用java自带的xml api生成的xml文件,其格式都是没有缩进的,每个element都是顶到最前面,今天终于找到了比较好的处理方法,赶紧记下来.
使用Java标准的JAXP来输出可以使用:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(document), new StreamResult(outputFile));
中间的红色代码是用于设置缩进的,比较遗憾的是JAXP只抽象出是否设置缩进(indent: yes|no),但并没有抽象出设置缩进量长度的常量(indent-number),所以默认的缩进量长度为0。如果有下面这样一个xml文档:<root><a><b>c</b></a></root>会被格式化为:
<root>
<a>
<b>c</b>
</a>
</root>
由于JAXP只是一个Java一个处理XML的框架,根据实现的不一样,可以传入实现特定的某个Key来设置缩进量。比如在Java 1.4下面,可以通过下面语句将缩进量设为2:
ransformer.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount", "2");
或
transformer.setOutputProperty(
"{http://xml.apache.org/xalan}indent-amount", "2");
上面两句不同之处仅在于命名空间。
而在Java 1.5下面,情况就有些复杂了。Java 1.5集成了JXAP 1.3(Java 1.4集成的是JXAP 1.1,不同之处参见http://java.sun.com/j2se/1.5.0/docs/guide/xml/jaxp/JAXP-Compatibility_150.html),实现基于Xerces类库。由于内部实现上的Bug,导致了设置缩进的不同:
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(document), new StreamResult(new?BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile)))));
注意红色代码的不同之处。第一句设置TransformerFactory的indent-number属性,在Java 1.4下面运行会抛出异常,因为其不支持该属性,而在Java 1.5中却只能通过该属性来设置缩进。后面标为红色的代码则是由于Sun实现上的Bug,只有通过StreamResult(Writer)构造函数生成才能正确设置缩进(通过OutputStream或者File生成的StreamResult是无法设置缩进的,其实现上会忽略任何非正式的属性,而仅仅采用rt.jar下面com\sun\org\apache\xml\internal\serializer\output_xml.properties中的配置。详细可以在com.sun.org.apache.xml.internal.serializer.ToStream类的setOutputStream方法中加断点进行分析)
?
如果忽略掉可移植性,确认绑定在Sun的JRE实现上面,则可以通过如下代码来更好的实现:
OutputFormat format = new OutputFormat(document);
format.setIndenting(true);
format.setIndent(2);
Writer output = new BufferedWriter( new FileWriter(outputFile) );
XMLSerializer serializer = new XMLSerializer(output, format);
serializer.serialize(document);
但是OutputFormat类和XMLSerializer类都是位于com.sun.org.apache.xml.internal.serialize包下。
如果应用对增加一个300K左右的jar包不敏感的话,我还是强烈推荐用dom4j来处理xml,其API设计的非常易用,写出来的代码比用JXAP写出来的代码漂亮多了,也容易维护,也不会出现上面那种两个Java版本不兼容的问题。
Java 对文件进行读写操作的例子很多,让初学者感到十分困惑,我觉得有必要将各种方法进行
一次分析,归类,理清不同方法之间的异同点。
一.在 JDK 1.0 中,通常是用 InputStream & OutputStream 这两个基类来进行读写操作的。
InputStream 中的 FileInputStream 类似一个文件句柄,通过它来对文件进行操作,类似的,在
OutputStream 中我们有 FileOutputStream 这个对象。
用FileInputStream 来读取数据的常用方法是:
FileInputStream fstream = new FileInputStream(args[0]);
DataInputStream in = new DataInputStream(fstream);
用 in.readLine() 来得到数据,然后用 in.close() 关闭输入流。
完整代码见 Example 1。
用FileOutputStream 来写入数据的常用方法是:
FileOutputStream out out = new FileOutputStream("myfile.txt");
PrintStream p = new PrintStream( out );
用 p.println() 来写入数据,然后用 p.close() 关闭输入。
完整代码见 Example 2。
二.在 JDK 1.1中,支持两个新的对象 Reader & Writer, 它们只能用来对文本文件进行操作,而
JDK1.1中的 InputStream & OutputStream 可以对文本文件或二进制文件进行操作。
用FileReader 来读取文件的常用方法是:
FileReader fr = new FileReader("mydata.txt");
BufferedReader br = new BufferedReader(fr);
用 br.readLing() 来读出数据,然后用br.close() 关闭缓存,用fr.close() 关闭文件。
完整代码见 Example 3。
用 FileWriter 来写入文件的常用方法是:
FileWriter fw = new FileWriter("mydata.txt");
PrintWriter out = new PrintWriter(fw);
在用out.print 或 out.println 来往文件中写入数据,out.print 和 out.println的唯一区别是后者写
入数据或会自动开一新行。写完后要记得 用out.close() 关闭输出,用fw.close() 关闭文件。
完整代码见 Example 4。
-------------------------------------------------------------- following is the source code of examples------------------------------------------------------
Example 1:
// FileInputDemo
// Demonstrates FileInputStream and DataInputStream
import java.io.*;
class FileInputDemo {
public static void main(String args[]) {
// args.length is equivalent to argc in C
if (args.length == 1) {
try {
// Open the file that is the first command line parameter
FileInputStream fstream = new FileInputStream(args[0]);
// Convert our input stream to a DataInputStream
DataInputStream in = new DataInputStream(fstream);
// Continue to read lines while there are still some left to read
while (in.available() !=0) {
// Print file line to screen
System.out.println (in.readLine());
}
in.close();
} catch (Exception e) {
System.err.println("File input error");
}
}
else
System.out.println("Invalid parameters");
}
}
Example 2:
// FileOutputDemo
// Demonstration of FileOutputStream and PrintStream classes
import java.io.*;
class FileOutputDemo
{
public static void main(String args[]) {
FileOutputStream out; // declare a file output object
PrintStream p; // declare a print stream object
try {
// connected to "myfile.txt"
out = new FileOutputStream("myfile.txt");
// Connect print stream to the output stream
p = new PrintStream( out );
p.println ("This is written to a file");
p.close();
} catch (Exception e) {
System.err.println ("Error writing to file");
}
}
}
Example 3:
// FileReadTest.java
// User FileReader in JDK1.1 to read a file
import java.io.*;
class FileReadTest {
public static void main (String[] args) {
FileReadTest t = new FileReadTest();
t.readMyFile();
}
void readMyFile() {
String record = null;
int recCount = 0;
try {
FileReader fr = new FileReader("mydata.txt");
BufferedReader br = new BufferedReader(fr);
record = new String();
while ((record = br.readLine()) != null) {
recCount++;
System.out.println(recCount + ": " + record);
}
br.close();
fr.close();
} catch (IOException e) {
System.out.println("Uh oh, got an IOException error!");
e.printStackTrace();
}
}
}
Example 4:
// FileWriteTest.java
// User FileWriter in JDK1.1 to writer a file
import java.io.*;
class FileWriteTest {
public static void main (String[] args) {
FileWriteTest t = new FileWriteTest();
t.WriteMyFile();
}
void WriteMyFile() {
try {
FileWriter fw = new FileWriter("mydata.txt");
PrintWriter out = new PrintWriter(fw);
out.print(“hi,this will be wirte into the file!”);
out.close();
fw.close();
} catch (IOException e) {
System.out.println("Uh oh, got an IOException error!");
e.printStackTrace();
}
}
}
10)使用ISMP 11.5的project file
ISMP 11.5的project file是uip格式的,IA不能直接打开它。我们可以在ISMP 11.5中导出一种DIM file,然后在
IA的organization-->DIM Reference-->add DIM Reference中使用它。ISMP 11 sp1之前的版本IA不再兼容
11)installer运行时参数
你可以在installer运行的时候添加一些参数,比如
installer.exe -i console //在console模式下运行
//在silent模式下运行,由于silent模式不会有任何界面,所以你可以
//设置一些安装的属性,格式如下:
installer.exe -i silent <propertyname>=<value>
//具体实例:
installer.exe -i silent USER_INSTALL_DIR=C:\Mydirectory
//如果你属性很多,你可以都写在一个文件中,然后引用就可以了
installer.exe -i silent -f <path to the properties file>
12)用代码启动IA的build
稍微复杂一点的java项目在编译打包的时候都少不了要用到ant。如果我们要在ant中启动IA来制作安装程序该怎么做呢
IA的安装目录下有一个build.exe,用它就可以了。
build.exe <path to IA project file>
13)source path
在Edit菜单里面可以设置source path。感觉它跟ISMP的alias是一样的。无非就是让你设置IA_HOME,PROJECT_HOME等等。
和alias不同的是,source path都是global,没有project类型的。source path存放在C:\Documents and Settings\Administrator\InstallAnywhere\80\Enterprise\preferences中
14)merge modules
当我们需要有一个project包含其他project的时候,就要用到merge modules。最典型的例子就是office包含word,powerpoint
,excel等。merge modules最少要有两个project,一个parent project,若干个child project。merge modules主要有以下几种:
i. design time merge module
这种merge module直接把child project拷贝到了parent project中,child project中的panel和action都会在parent project
的安装过程中出现,并且你可以在parent project中修改它们。如果原来的child project做了某些变化,parent project中的child project不会有任何变化。
这种merge module只生成一个uninstaller,它会卸载掉整个软件产品。如果要只卸载child project,好像可以通过把child project
设成feature来实现,但我目前还没有实验过。
ii. dynamic time merge module
这种merge module不拷贝child project到parent project中,它只链接到child project。所以child project的任何变化都会反映到
parent project中。但是你不能在parent project中修改child project的panel和action,因为你只是链接到child project。
这种merge module会生成多个uninstaller,分别用来卸载parent project 和child projects。
iii. build time merge module
和dynamic time merge module类似,不同的是build time merge module不会出现child project的panel。换句话说,child project是以silent模式安装的。
怎么在具体的项目中用merge module呢?首先,你需要把child project build成merge module,会生成一个文件。然后在parent project的
orgnization-->Modules 导入就可以了
15)Custom Code
IA的advanced designer已经可以满足大部分用户的需要了,如果你所要的功能advanced designer还无法实现,你可以自己编写Custom Code来实现。可以说
Custom Code是IA的more advanced designer。
Custom Code分成以下几种:
i.custom code actions
ii.custom code panels
iii.custom code consoles
iv.custom code rules
在IA的安装目录下有一个javadoc目录,里面有IA提供的api的文档,跟java的api的文档的使用方法是一样的。IA为以上四种Custom Code提供了四个
缺省的类来实现,分别是CustomCodeAction,CustomCodePanel,CustomCodeConsoleAction,CustomCodeRule,你可以去继承它们并添加你需要的
功能。
代码写好了之后不能直接用于IA中,还需要编译,打包。打包有两种方法
一)打包成类的JAR包
先写好代码,然后用javac命令编译(当然你也可以用eclipse,netbean来得到class文件),最后把class file压成jar包。
点击Add Action-->Execute Custom Code,指定你的jar包的位置,如果用到了第三方的jar包,记得把它们添加到“Dependencies”中
ps:点击Add Action,你会看到有四个tab:General,Panels,Consoles,Plug-ins。如果你是Custom Code Action,要选择General里面的
Execute Custom Code,如果你是custom code panels,你要选择Panels里面的Execute Custom Code,如果是custom code consoles,
要选择Consoles里面的Execute Custom Code,如果是custom code rules,不能通过Add Action添加,你需要点击Add Rule-->evaluate custom code
来执行
二)打包成plugin
先写好代码,然后用javac命令编译(当然你也可以用eclipse,netbean来得到class文件)。
创建一个properties文件,然后把这个properties文件打包成一个jar包。可见与第一种方法的区别就是多了一个属性文件
举一个属性文件的例子:
plguin.name=my custom action
plugin.main.class=MySampleAction
plugin.type=action
//如果你写了preinstall,那在preinstall view中Add Action-->Plugin里面可以看见这个plugin,否则是看不见的。
plugin.available=preinstall,install,postinstall
//property.myproperty=this value
property.database=localhost
打包完成后,把jar包拷贝到IA安装目录下的plugins文件夹,然后重启IA(eclipse的用户肯定很熟悉这个操作吧,呵呵)
然后你就可以在Add Action-->Plug-Ins里面发现你自己写的plugin了。
最后列一下IA提供的api中比较重要的方法(IA提供了一个zip包IAClasses.zip在IA安装目录下)
public class MySampleAction extends CustomCodeAction
{
public void install(InstallerProxy ip)
{
}
}
subsititue(String var)-recursively gets the variable value
getVariable(String var)- jaut gets the variable value
for example:
database_name=$user_install_dir$/mydir
subsititue(String var) C:\pf\macrovision\mydir
getVariable(String var)
$user_install_dir$/mydir
public class MyCustom Panel extend CustomCodePanel{
public boolean setupUI(CustomCodePanelProxy ccpp){
//execute some condition or logic
return true or false;//if true ,display,or don't display
public voidpanelIsDisplayed()
{//you will put controls and logic for displaying the panel
//this is where you will use java's swing classes to display controls on your dialogs
//just for text area,if you wanna add a button to the bottom,then you need
//to create a new dialog by swing ,
}
public boolean okToContinue()
{
}
}
}
public class MyCustomConsole extend CustomCodeConsoleAction{
public boolean setup(CustomCodePanelProxy ccpp){
//any validation you want to execute before displaying this console panel
you will put here
}
}
}
public class MyCustomRule extends CustomCodeRule{
public void evaluateRule()
{
//in this method,you can put the logic to evaulate this custom rule
//return true or false
}
}
}
在IA安装目录下的Custom Code文件夹,你可以找到一些sample code,更多的sample code可以到
它的网站上查询。
最后,引用training teacher的一句话作为本文的结尾“不管你的产品有多好,用户第一印象是看你的安装程序,如果你的安装程序不够人性化,甚至安装失败了,那用户对它的评价就不会高”
不知道你是否注意过,当你安装java jdk的时候,当你安装微软office的时候,当你装db2的时候,你都会看到一个熟悉的标记---installshield。installshield可以说是当今安装程序解决方案的巨无霸了,功能十分强大,你可以用它制作出你想要的安装程序。但是功能的强大也带来一个坏处,就是要上手非常难。所以公司特意请macrovision(就是制作installshield的公司)的人给我们进行了一个training,感觉收获还是很大的,所以把我认为重要的地方纪录下来,一方面万一自己忘了可以查一查,另一方面说不定对别人也有帮助。
先从版本说起。installshield有专门用于制作java安装程序的产品,由于java是跨平台的语言,所以installshield对应的产品就叫installshield multiple platform,简称ismp。我接触的最早版本是ismp 5.0,后来又出了ismp 11.5,再后来ismp改名字叫Install Anywhere(以下简称IA)。目前我们training用的版本是IA 8.0,相信应该是最新的版本了。IA是共享软件,不注册的话有21天的试用期。
安装程序是一个可定制性非常强的东西,每个软件作者的需求都不一样。有的推崇简单就是美,一般只需要用户选择安装的目录,然后就一路next就装完了;但有的软件非常复杂,比如需要设置参数,需要选择安装哪些部分,甚至需要启动windows的系统服务。这时候就需要比较复杂的配置了。installshield针对两种用户设计了不同的开发环境:一种是common designer,另一种是Advanced Designer。当你第一次打开IA的时候,缺省的是common designer,你只需要做一些简单的配置,比如产品的名称,需要安装的文件,要不要绑定虚拟机等等,然后就可以build出一个安装程序了。Advanced Designer是为高级用户设置的,提供了更多,更丰富的功能,你可以用它来打造你所需要的安装程序。本文主要是针对Advanced Designer进行一些说明。
1)安装模式(install modes)
gui:这是最常用的一种模式,在安装过程中会弹出若干个panel,比如welcome panel,license panel,destination panel等等。
console:用这种模式安装程序时,不会出现panel。它的所有信息都在控制台中出现。说的再通俗一点,就是整个安装过程只有一个dos窗口,这个窗口先会显示一行信息欢迎你安装本软件,然后是让你选择destination,再安装,最后会显示一行安装成功的信息
silent:顾名思义,这种模式在安装的时候不会弹出任何窗口,它会安静地装上软件,所以用户也不能自己设定安装目录,一般都市由安装程序安装到固定的目录上
2)install sets
很多安装程序都有完全安装,最小安装,自定义安装等选项,这一般是用features来实现的。你可以把你的产品分成几个features,然后由用户来选择一部分进行安装。
3)actions
IA中很多操作被称为actions,常见的有copy files,delete files,modifying registry, creating service, modifying configurations files等
4)variable
IA中很重要的一个概念,你可以用variable来存放属性信息,比如安装目录,用户名等等。比如
安装目录可能会在很多地方都用到,如果你安装目录是硬编码的,万一将来要修改就要改
很多地方,容易出错;如果用variable来保存的话,只要修改变量值就可以了。注意一点:variable
的值基本上都是string类型的
5)magic folders
IA里面独有的概念,但感觉没什么新意,就是variables的一种,专门用于定义folder的
variable而已
6)InstallAnywhere registry
不同于windows的registry,这是InstallAnywhere自己的registry。每个用IA制作的安装程序,在安装的过程中
都会把自己注册到这个InstallAnywhere registry(注意:你只能在InstallAnywhere registry找到安装的
component,找不到product)。它的一个典型应用就是当你需要检查这个机器上是否安装过某个软件的时候,就可以
用search这个IA registry。不过如果你是用其他工具制作的安装程序,IA registry就不会有记录了。
7)execute command&execute script
execute command是用来执行command,常用的dos命令(copy,cd等)你都可以写在这里。execute script其实就是
execute command的加强版:如果你有多个命令,不需要建多个execute command,把它们写在execute script就好了
8)计算所需空间
在IA中,默认的空间大小是用byte来计算的,所以如果你的软件比较大的话,那一长串的阿拉伯数字会把用户吓倒的
解决方法是,在pre-install summary panel的配置项中,有一个是Edit Custom Field。在那里新建一个field。Variable
name是显示给用户看的内容,比如你可以写disk space。variable value是你的软件所需的硬盘大小。你可以先算出来
,存在一个变量中,然后让variable value等于这个变量就可以了。
9)results variable
用来存放用户的选择。比如在show message dialog中,有一个results variable是$CHOSEN_DIALOG_BUTTON$
它用来存放用户按的是OK 还是Cancel
摘要: How to understand and use Eclipse Production Configuration
...
阅读全文
摘要: 1.在tabbedProperties(eclipse3.2以上支持)中,如果要建立一个treeview,且想要click任何一列都可以实现celledit,需要在创建treeview的时候加上style: SWT.FULL_SELECTION
2.tabbedProperties中section的大小现在无法做到根据widget的大小自动调整,目前只能用getMinimumHeight()返回一个固定值
阅读全文
很多人在开发RCP时,发现开发时都没问题,但导出成包时却报找不到第三方库中类的错误。主要原因就是没有将第三方库配置好。现在我给出一个实现项目的配置为示例,以供参考。 原文出处:http://www.eclipseworld.org/bbs/read.php?tid=1133 环境:Eclipse3.2M3 一个RCP的实际项目
一、
最关键的就是plugin.xml和MANIFEST.MF 所有界面上的最后操作,结果都是保存在这两个文件中。注意:“.classpath”文件只是开发时对引用第三库有用,打包发行之后它的作用就没有了,还得靠plugin.xml和MANIFEST.MF。
1、plugin.xml文件
<?xml version="1.0" encoding="GB2312"?>
<?eclipse version="3.0"?>
<plugin>
<extension
id="AdminConsole"
point="org.eclipse.core.runtime.applications">
<application>
<run class="com.wxxr.management.admin.console.AdminConsole"/>
</application>
</extension>
<extension id="AdminConsole" point="org.eclipse.core.runtime.products">
<product name="%productName" application="com.wxxr.management.admin.console.AdminConsole">
<property name="appName" value="%swtAppName"/>
<property name="windowImages" value="icons/eclipse.gif,icons/eclipse32.gif"/>
<property name="aboutText" value="%aboutText"/>
<property name="aboutImage" value="icons/eclipse_lg.gif"/>
<property name="windowImages" value="icons/alt16.gif,icons/eclipse.gif"/>
</product>
</extension>
<extension
point="org.eclipse.ui.perspectives">
<perspective
class="com.wxxr.management.admin.console.monitor.MonitorPerspective"
name="%perspectiveName"
id="com.wxxr.management.admin.console.monitor.MonitorPerspective"/>
<perspective
class="com.wxxr.management.admin.console.configure.ConfigurePerspective"
name="%configurePerspectiveName"
id="com.wxxr.management.admin.console.configure.ConfigurePerspective"/>
<perspective
class="com.wxxr.management.admin.console.jmx.JMXPerspective"
name="%jmxPerspectiveName"
id="com.wxxr.management.admin.console.jmx.JMXPerspective"/>
</extension>
<extension
point="org.eclipse.ui.editors">
<editor
name="事件列表"
icon="icons/alt16.gif"
class="com.wxxr.management.admin.console.log.ui.LogEditor"
id="com.wxxr.management.admin.console.log.ui.LogEditor">
</editor>
<editor
name="地图"
icon="icons/map_view.gif"
class="com.wxxr.management.admin.console.map.MapEditor"
id="com.wxxr.management.admin.console.map.MapEditor">
</editor>
</extension>
<extension
point="org.eclipse.ui.views">
<category
id="com.wxxr.management.admin.console.monitor.view"
name="%views.category.name"/>
<view
id="com.wxxr.management.admin.console.navigator.ui.StationExploreView"
name="工作站"
icon="icons/eclipse.gif"
class="com.wxxr.management.admin.console.navigator.ui.StationExploreView"
category="com.wxxr.management.admin.console.monitor.view"/>
<view
name="事件细节"
icon="icons/eclipse.gif"
category="com.wxxr.management.admin.console.monitor.view"
class="com.wxxr.management.admin.console.monitor.eventview.EventDetailView"
id="com.wxxr.management.admin.console.monitor.eventview.EventDetailView" />
<view
name="事件统计"
icon="icons/eclipse.gif"
category="com.wxxr.management.admin.console.monitor.view"
class="com.wxxr.management.admin.console.monitor.view.SystemEventStatisticsView"
id="com.wxxr.management.admin.console.monitor.view.SystemEventStatisticsView" />
<view
name="紧急事件处理"
icon="icons/eclipse.gif"
category="com.wxxr.management.admin.console.monitor.view"
class="com.wxxr.management.admin.console.emergency.ui.EmergencyEventReceiverView"
id="com.wxxr.management.admin.console.emergency.ui.EmergencyEventReceiverView" />
<category
id="com.wxxr.management.admin.console.jmx.view"
name="%views.category.name"/>
<view
name="JMX Connections"
icon="icons/eclipse.gif"
category="com.wxxr.management.admin.console.jmx.view"
class="com.wxxr.management.admin.console.jmx.ui.JMXExploreView"
id="com.wxxr.management.admin.console.jmx.ui.JMXExploreView" />
<view
name="JMX Attributes View"
icon="icons/eclipse.gif"
category="com.wxxr.management.admin.console.jmx.view"
class="com.wxxr.management.admin.console.jmx.ui.AttributesView"
id="com.wxxr.management.admin.console.jmx.ui.AttributesView" />
<view
name="JMX Operations View"
icon="icons/eclipse.gif"
category="com.wxxr.management.admin.console.jmx.view"
class="com.wxxr.management.admin.console.jmx.ui.OperationsView"
id="com.wxxr.management.admin.console.jmx.ui.OperationsView" />
<view
name="JMX MBean View"
icon="icons/eclipse.gif"
category="com.wxxr.management.admin.console.jmx.view"
class="com.wxxr.management.admin.console.jmx.ui.MBeanView"
id="com.wxxr.management.admin.console.jmx.ui.MBeanView" />
</extension>
<extension
id="AdminConsole"
point="org.eclipse.core.runtime.products">
<product
application="com.wxxr.management.admin.console.AdminConsole"
name="AdminConsole"/>
</extension>
</plugin>
2、
META-INF\MANIFEST.MF文件
注意:(1)这里require-bundle定义了项目依赖的插件。
(2)Bundle-ClassPath定义了引用的第三方库,别忘了把AdminConolse项目自己console.jar加进去,否则连自己项目里的类都会找不到。
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: com.wxxr.management.admin.console; singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: com.wxxr.management.admin.console.AdminConsolePlugin
Bundle-Localization: plugin
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.core.resources,
org.eclipse.gef,
org.eclipse.ui.forms,
org.eclipse.ui.console
Eclipse-AutoStart: true
Bundle-Vendor: %providerName
Bundle-ClassPath: console.jar,
lib/commons-codec-1.3.jar,
lib/jboss.jar,
lib/jbossall-client.jar,
lib/jboss-jmx.jar,
lib/jboss-system.jar,
lib/log4j-1.2.8.jar,
lib/wxxr-common-1.0-b1.jar,
lib/wxxr-common-jboss-1.0-b1.jar,
lib/wxxr-db-persistence-1.0-b1.jar,
lib/wxxr-jboss-controller-1.0-b1.jar,
lib/wxxr-jboss-workstation-1.0-b1.jar,
lib/wxxr-remoting-1.0-b1.jar,
lib/wxxr-security-1.0-b1.jar,
lib/xerces-2.6.2.jar,
lib/xmlParserAPIs-2.2.1.jar,
lib/xmlrpc-2.0.jar
3、build.properties文件。
这个文件主要是用Eclipse导出包的时候用。
source.console.jar = src/
output.console.jar = bin/
bin.includes = plugin.xml,\
*.jar,\
console.jar, \
plugin.properties
pluginName = Admin Console Plug-in
providerName = WXXR.com.cn
perspectiveName = Admin Console
configurePerspectiveName= Configure
jmxPerspectiveName= JMX Console
jars.extra.classpath = lib/commons-codec-1.3.jar,\
lib/jboss.jar,\
lib/jbossall-client.jar,\
lib/jboss-jmx.jar,\
lib/jboss-system.jar,\
lib/log4j-1.2.8.jar,\
lib/wxxr-common-1.0-b1.jar,\
lib/wxxr-common-jboss-1.0-b1.jar,\
lib/wxxr-db-persistence-1.0-b1.jar,\
lib/wxxr-jboss-controller-1.0-b1.jar,\
lib/wxxr-jboss-workstation-1.0-b1.jar,\
lib/wxxr-security-1.0-b1.jar,\
lib/wxxr-remoting-1.0-b1.jar,\
lib/xerces-2.6.2.jar,\
lib/xmlParserAPIs-2.2.1.jar,\
lib/xmlrpc-2.0.jar
4、plugin.properties,这个放一些上面几个文件用到的变量。
pluginName= WXXR Admin Console
providerName= wxxr.com.cn
productName= WXXR SMS Operation Platform
appName= WXXR Admin Console
perspectives.browser.name= WXXR Admin Console
views.category.name= WXXR Admin Console
views.browser.name= Browser
views.history.name= History
views.stationexplore.name= Stations
views.tasklist.name= Task List
views.loglist.name= Workstation Monitor
monitor.message.detail=Monitor Message Detail
monitor.message.statistics=????
swtAppName= AdminConsole
aboutText= WXXR Admin Console \n\n\
(c) Copyright WXXR Ltd. and others 2003, 2004. All rights reserved.\n\
Visit
http://www.wxxr.com.cn 二、图形方式 有时直接编辑plugin.xml等文件容易出错(全角空格什么的),那么可以用图形编辑方式来,不过最后结果还是反映到plugin.xml等文件中的。我把plugin.xml打开,然后一个项一个项的把图截下来,以供大家参考。
作者:hopeshared
引用地址:http://www.blogjava.net/hopeshared/archive/2005/12/20/24798.html
最近社区里问这个问题的人特别多,所以在这里将自己用到的几个方法写出来。假如以后还有其他的方法,会进行更新。
从插件中获得绝对路径:
AaaaPlugin.getDefault().getStateLocation().makeAbsolute().toFile().getAbsolutePath());
通过文件得到Project:
IProject project = ((IFile)o).getProject();
通过文件得到全路径:
String path = ((IFile)o).getLocation().makeAbsolute().toFile().getAbsolutePath();
得到整个Workspace的根:
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
从根来查找资源:
IResource resource = root.findMember(new Path(containerName));
从Bundle来查找资源:
Bundle bundle = Platform.getBundle(pluginId);
URL fullPathString = BundleUtility.find(bundle, filePath);
得到Appliaction workspace:
Platform.asLocalURL(PRODUCT_BUNDLE.getEntry("")).getPath()).getAbsolutePath();
得到runtimeworkspace:
Platform.getInstanceLocation().getURL().getPath();
从编辑器来获得编辑文件:
IEditorPart editor = ((DefaultEditDomain)(parent.getViewer().getEditDomain())).getEditorPart();
IEditorInput input = editor.getEditorInput();
if(input instanceof IFileEditorInput){
IFile file = ((IFileEditorInput)input).getFile();
}
在<<Eclipse从入门到精通>>里提到了一些获取ImageDescriptor的方法,其中获取本地图片文件是用createfromurl来实现的,但我用这个方法总是无法成功,后来在网上找到了这个方法,比较管用:
AbstractUIPlugin.imageDescriptorFromPlugin(plugin的id, "icons/save.gif")
首先讲一下eclipse中给Action中添加快捷键的一般方法
要添加快捷键,必须要扩展eclipse的org.eclipse.ui.command和org.eclipse.ui.binding这两个extension.然后Action和command关联,command又和一个binding关联起来,这样就间接的使action和binding有了关联.有人会问,这样做是不是太麻烦了,我直接把action和binding关联起来不就行了?最好是有个方法,比如action.setKeybind("Ctrl+A").其实eclipse这样做是涉及到设计模式的问题.如果用这种"简单"方法,你以后如果想要改actioon的快捷键就要去改action的源码了,是一种紧耦合的关系.而eclipse的处理方式削弱了这种耦合,你如果要改快捷键,改binding就可以了,你还可以让一个action在不同的perspective,甚至是不同的view中使用不同的快捷键.让一个action对应多个快捷键等等.
command和binding的关联在你扩展这两个extension的时候就可以建立了,下面看看怎么让一个action对应一个command
在你的插件中添加Action有两种方法:1.通过plugin.xml扩展extension.2.直接在代码中code. 如果是用第一种方法,在Action的设置中会有definitionId这一项,你把它填上你自己写的command的Id就好了;如果是第二种方法,那需要在你的定义action的代码中加上两句:
yourAction.setActionDefinitionId("commandId");
getViewSite().getKeyBindingService().registerAction(yourAction);
这两种方法是等效的
但要给viewaction添加快捷键以上两种方法都有点问题.viewaction在plugin.xml文件中是没有definitionId这一项的,所以你没办法设置;如果你是program方法,由于viewaction不是继承自Action类的,所以你也不能用setActionDefinitionId这个方法.聪明的你可能会想到了,那我让viewaction继承Action不就行了:
public class ViewAction
extends Action implements IViewActionDelegate //红色部分是自己添加的extends
{ ...
public void init(IViewPart view) {
this.view=view;
this.setActionDefinitionId("ViewAction.command1");
view.getViewSite().getKeyBindingService().registerAction(this);
}
}
这个方法理论上可以,但可惜也仅仅是理论上行得通而已.具体是为什么我也不知道,如果有大牛告知小弟不胜感激.我后来的解决办法是这样的:在viewaction的init方法中加入以下代码段
this.view=view;
IContributionItem item= view.getViewSite().getActionBars().getToolBarManager().find("ViewAction.action1");
IAction action=((ActionContributionItem)item).getAction();
action.setActionDefinitionId("ViewAction.command1");
view.getSite().getKeyBindingService().registerAction(action);
这样就可以给viewaction添加快捷键了
hotmail
邮箱
无法登录的解决办法
最近,很多网友反映无法登录自己的 hotmail 邮箱。我自己也碰到了同样的问题,我的 msn messenger 里显示有6封未读邮件,就是无法登录查看,真是着急!
在网上搜了一下,一些热心的网友提供了一些解决办法,我统统试了,发现只有一种方法很有效,这就是:
访问 http://mobile.msn.com/hm/folder.aspx
这样就绕过了Live.com,而直接登录.net passport,就可以了。不过,这时看到了信件都是文本形式的,不是html的。可以解燃眉之急。
等我找到更好的方法,再和大家分享。