2006年12月4日
以前只知道alt+/調(diào)出assist,后來(lái)發(fā)現(xiàn)可以所有字母都激活content assist(方法百度上都有,就不在這寫了).用起來(lái)果然很爽.但是eclipse還是有些默認(rèn)的設(shè)置不是很好,比如空格鍵和=號(hào)會(huì)把第一行的內(nèi)容自動(dòng)上屏,其實(shí)很多時(shí)候我就是想輸一個(gè)空格或=號(hào)而已.這個(gè)在設(shè)置里面沒(méi)辦法設(shè)置.幸好eclipse是有插件機(jī)制的,可以通過(guò)修改插件的源碼,然后導(dǎo)出成插件,再替換掉原來(lái)的插件來(lái)處理
1.先找到相關(guān)的插件
打開Plug-ins View找到插件org.eclipse.jface.text,右鍵點(diǎn)擊,選擇import as Source Project,導(dǎo)入完成后,在你的workspace就可以看到這個(gè)project了
2.修改代碼
在
src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java文件中,找到這樣一行代碼
char triggers = t.getTriggerCharacter();
if(contains(triggers,key))
在那行if判斷里面,eclipse會(huì)判斷key(就是你按下的鍵)是否在triggers中,如果是,那就觸發(fā)下面的第一行提示上屏的代碼.所以我們要做的就是把空格和=號(hào)排除就可以了:
if(key!='='&&key!=0x20&&contains(triggers,key))
3.把修改好的org.eclipse.jface.text導(dǎo)出
右鍵點(diǎn)擊你的workspace里的org.eclipse.jface.text,選擇export-->Deployable plugins and fragments, next,destination 選擇archive file,然后finish.你就可以在zip文件里看到生成好的jar ,用它替換掉eclipse/plugins里面的同名jar包,就可以了
Visio的圖標(biāo)很多,但是用來(lái)設(shè)計(jì)web程序的基本沒(méi)有,在網(wǎng)上找到了這個(gè),覺(jué)得還蠻好用的,共享一下
/Files/yes1983/GUUUI_Web_Prototyping_Tool_3.zip
摘要: 本文分析了Eclipse中多線程程序的實(shí)現(xiàn),討論了在Eclipse客戶端程序開發(fā)中應(yīng)用多線程的方法和要注意的問(wèn)題,同時(shí)也討論了多線程程序的一些調(diào)試和問(wèn)題解決的方法。
閱讀全文
轉(zhuǎn)載自http://blog.csdn.net/shangboerds/archive/2010/01/27/5260783.aspx
CTE:
說(shuō)起WITH 語(yǔ)句,除了那些第一次聽說(shuō)WITH語(yǔ)句的人,大部分人都覺(jué)得它是用來(lái)做遞歸查詢的。其實(shí)那只是它的一個(gè)用途而已,它的本名正如我們標(biāo)題寫的那樣,叫做:公共表表達(dá)式(Common Table Expression),從字面理解,大家覺(jué)得它是用來(lái)干嘛的呢?其實(shí),它是用來(lái)定義臨時(shí)集合的。?。縑ALUES語(yǔ)句不是用來(lái)定義臨時(shí)集合的嗎?怎么WITH語(yǔ)句也用來(lái)定義臨時(shí)集合呢?它們有什么區(qū)別呢?
VALUES語(yǔ)句是用明確的值來(lái)定義臨時(shí)集合的,如下:
VALUES (1,2), (1,3),(2,1)
WITH語(yǔ)句是用查詢(也就是select語(yǔ)句)來(lái)定義臨時(shí)集合的,從這個(gè)角度講,有點(diǎn)像視圖,不過(guò)不是視圖,大家千萬(wàn)別誤解。如下:
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--語(yǔ)句1
)
SELECT NAME_TEST FROM TEST WHERE BDAY_TEST='1949-10-1';--語(yǔ)句2
下面我們來(lái)解釋一下,首先語(yǔ)句1執(zhí)行,它會(huì)產(chǎn)生一個(gè)有兩列(NAME,BIRTHDAY)的結(jié)果集;接著,我們將這個(gè)結(jié)果集命名為test,并且將列名重命名為NAME_TEST, BDAY_TEST;最后我們執(zhí)行語(yǔ)句2,從這個(gè)臨時(shí)集合中找到生日是1949-10-1,也就是共和國(guó)的同齡人。
怎么樣?如果你感覺(jué)不好理解,請(qǐng)仔細(xì)的分析一下上面的語(yǔ)句。下面我們舉個(gè)VALUES語(yǔ)句和WITH語(yǔ)句結(jié)合使用的例子,如下:
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語(yǔ)句不為大多數(shù)人所熟悉可以猜測(cè),WITH語(yǔ)句是為復(fù)雜的查詢?yōu)樵O(shè)計(jì)的,的確是這樣的,下面我們舉個(gè)復(fù)雜的例子,想提高技術(shù)的朋友可千萬(wàn)不能錯(cuò)過(guò)??紤]下面的情況:
CREATE TABLE USER
(
NAME VARCHAR(20) NOT NULL,--姓名
DEGREE INTEGER NOT NULL,--學(xué)歷(1、???2、本科 3、碩士 4、博士)
STARTWORKDATE date NOT NULL,--入職時(shí)間
SALARY1 FLOAT NOT NULL,--基本工資
SALARY2 FLOAT NOT NULL--獎(jiǎng)金
);
假設(shè)現(xiàn)在讓你查詢一下那些 1、學(xué)歷是碩士或博士 2、學(xué)歷相同,入職年份也相同,但是工資(基本工資+獎(jiǎng)金)卻比相同條件員工的平均工資低的員工。(哈哈,可能是要漲工資),不知道你聽明白問(wèn)題沒(méi)有?該怎么查詢呢?我們是這樣想的:
1、查詢學(xué)歷是碩士或博士的那些員工得到結(jié)果集1,如下:
SELECT NAME,DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, SALARY1+SALARY2 AS SALARY FROM USER WHERE DEGREE IN (3,4);
2、根據(jù)學(xué)歷和入職年份分組,求平均工資 得到結(jié)果集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、以學(xué)歷和入職年份為條件 聯(lián)合兩個(gè)結(jié)果集,查找工資<平均工資 的員工,以下是完整的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;
查詢結(jié)果完全正確,但我們還有改善的空間,在查詢結(jié)果集2的時(shí)候,我們是從user表中取得數(shù)據(jù)的。其實(shí)此時(shí)結(jié)果集1已經(jīng)查詢出來(lái)了,我們完全可以從結(jié)果集1中通過(guò)分組得到結(jié)果集2,而不用從uer表中得到結(jié)果集2,比較上面和下面的語(yǔ)句你就可以知道我說(shuō)的是什么意思了!
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;
可能有些朋友會(huì)說(shuō),我不用WITH語(yǔ)句也可以查出來(lái),的確是這樣,如下:
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,這兩種寫法有什么區(qū)別呢?一般情況下這兩種寫法在性能上不會(huì)有太大差異,但是,
1、當(dāng)USER表的記錄很多
2、碩士或博士(DEGREE IN (3,4))在USER表中的比例很少
當(dāng)滿足以上條件時(shí),這兩種寫法在性能的差異將會(huì)顯現(xiàn)出來(lái),為什么呢?因?yàn)椴皇褂肳ITH寫法的語(yǔ)句訪問(wèn)了2次USER表,如果DEGREE 字段又沒(méi)有索引,性能差異將會(huì)非常明顯。
當(dāng)你看到這時(shí),如果很好的理解了上面的內(nèi)容,我相信你會(huì)對(duì)WITH語(yǔ)句有了一定的體會(huì)。然而WITH語(yǔ)句能做的還不止這些,下面給大家介紹一下,如何用WITH語(yǔ)句做遞歸查詢。遞歸查詢的一個(gè)典型的例子是對(duì)樹狀結(jié)構(gòu)的表進(jìn)行查詢,考慮如下的情況:
論壇首頁(yè)
--數(shù)據(jù)庫(kù)開發(fā)
----DB2
------DB2 文章1
--------DB2 文章1 的評(píng)論1
--------DB2 文章1 的評(píng)論2
------DB2 文章2
----Oracle
--Java技術(shù)
以上是一個(gè)論壇的典型例子,下面我們新建一個(gè)表來(lái)存儲(chǔ)以上信息。
CREATE TABLE BBS
(
PARENTID INTEGER NOT NULL,
ID INTEGER NOT NULL,
NAME VARCHAR(200) NOT NULL---板塊、文章、評(píng)論等。
);
insert into bbs (PARENTID,ID,NAME) values
(0,0,'論壇首頁(yè)'),
(0,1,'數(shù)據(jù)庫(kù)開發(fā)'),
(1,11,'DB2'),
(11,111,'DB2 文章1'),
(111,1111,'DB2 文章1 的評(píng)論1'),
(111,1112,'DB2 文章1 的評(píng)論2'),
(11,112,'DB2 文章2'),
(1,12,'Oracle'),
(0,2,'Java技術(shù)');
現(xiàn)在萬(wàn)事兼?zhèn)淞?,我們開始查詢吧。假設(shè)現(xiàn)在讓你查詢一下‘DB2 文章1’的所有評(píng)論,有人說(shuō),這還不簡(jiǎn)單,如下這樣就可以了。
SELECT * FROM BBS WHERE PARENTID=(SELECT ID FROM BBS WHERE NAME='DB2');
答案完全正確。那么,現(xiàn)在讓你查詢一下DB2的所有文章及評(píng)論,怎么辦?傳統(tǒng)的方法就很難查詢了,這時(shí)候遞歸查詢就派上用場(chǎng)了,如下:
WITH TEMP(PARENTID,ID,NAME) AS
(
SELECT PARENTID,ID,NAME FROM BBS WHERE NAME='DB2'---語(yǔ)句1
UNION ALL---語(yǔ)句2
SELECT B.PARENTID,B.ID,B.NAME FROM BBS AS B, TEMP AS T WHERE B.PARENTID=T.ID---語(yǔ)句3
)
SELECT NAME FROM TEMP;---語(yǔ)句4
運(yùn)行后,我們發(fā)現(xiàn),結(jié)果完全正確,那它到底是怎么運(yùn)行的呢?下面我們?cè)敿?xì)講解一下。
1、首先,語(yǔ)句1將會(huì)執(zhí)行,它只執(zhí)行一次,作為循環(huán)的起點(diǎn)。得到結(jié)果集:DB2
2、接著,將循環(huán)執(zhí)行語(yǔ)句3,這里我們有必要詳細(xì)介紹一下。
首先語(yǔ)句3的意圖是什么呢?說(shuō)白了,它就是查找語(yǔ)句1產(chǎn)生結(jié)果集(DB2)的下一級(jí),那么在目錄樹中DB2的下一級(jí)是什么呢?是‘DB2 文章1’和‘DB2 文章2’,并且把查詢到的結(jié)果集作為下一次循環(huán)的起點(diǎn),然后查詢它們的下一級(jí),直到?jīng)]有下一級(jí)為止。
怎么樣?還沒(méi)明白?哈哈,不要緊,我們一步一步來(lái):
首先,語(yǔ)句1產(chǎn)生結(jié)果集:DB2,作為循環(huán)的起點(diǎn),把它和BBS表關(guān)聯(lián)來(lái)查找它的下一級(jí),查詢后的結(jié)果為:‘DB2 文章1’和‘DB2 文章2’
接著,把上次的查詢結(jié)果(也就是‘DB2 文章1’和‘DB2 文章2’)和BBS表關(guān)聯(lián)來(lái)查找它們的下一級(jí),查詢后的結(jié)果為:‘DB2 文章1 的評(píng)論1’ 和 ‘DB2 文章1 的評(píng)論2’。
然后,在把上次的查詢結(jié)果(也就是‘DB2 文章1 的評(píng)論1’ 和 ‘DB2 文章1 的評(píng)論2’)和BBS表關(guān)聯(lián)來(lái)查找它們的下一級(jí),此時(shí),沒(méi)有結(jié)果返回,循環(huán)結(jié)束。
3、第三,將執(zhí)行語(yǔ)句2,將所有的結(jié)果集放在一起,最終得到temp結(jié)果集。
4、最后,我們通過(guò)語(yǔ)句4 從temp臨時(shí)集合中得到我們期望的查詢結(jié)果。
怎么樣,這回理解了吧,如果還沒(méi)有理解,那么我也無(wú)能為力了。需要特別提醒的是
1、一定要注意語(yǔ)句3的關(guān)聯(lián)條件,否則很容易就寫成死循環(huán)了。
2、語(yǔ)句2必須是UNION ALL
最后請(qǐng)大家猜想一下,把語(yǔ)句1的where子句去掉,將會(huì)產(chǎn)生什么樣的結(jié)果呢?
NTE:
SELECT * FROM <TABLE-NAME>;
看到上面的語(yǔ)句了嗎?這是我們?cè)谑煜げ贿^(guò)的一條語(yǔ)句,我們中的大多人學(xué)習(xí)SQL正是從這條語(yǔ)句開始的。所以大多數(shù)人認(rèn)為FROM語(yǔ)句后只能接一個(gè)表或視圖(或者壓根就沒(méi)多想),有這種想法的人我非常能理解,因?yàn)槲以?jīng)也是這其中的一員。其實(shí)FROM后面可以接任何集合(表)。說(shuō)到這,關(guān)于集合和表,我特別想多少幾句。SQL的理論基礎(chǔ)是數(shù)學(xué)中的集合理論,所以SQL關(guān)注的就是如何對(duì)集合進(jìn)行操作,基于以上原因,我特別喜歡名詞 集合,而不喜歡說(shuō)表。不過(guò),大家如果不習(xí)慣,也可以把集合和表當(dāng)一個(gè)意思來(lái)理解,因?yàn)槲覀儾皇歉憷碚撗芯抗ぷ鞯?,沒(méi)必要深究他們之間的細(xì)微差別。說(shuō)了這么多,我們還是趕快來(lái)看個(gè)例子吧。
---建表
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--關(guān)聯(lián)兩個(gè)集合
看到上面的例子5了嗎?我們可以給臨時(shí)集合命名,還可以給重命名臨時(shí)集合的列名,還可以關(guān)聯(lián)兩個(gè)臨時(shí)集合,總之,操作臨時(shí)集合和操作表沒(méi)有區(qū)別。
Temporary table
臨時(shí)表(TEMPORARY TABLE)通常應(yīng)用在需要定義臨時(shí)集合的場(chǎng)合。但是,在大部分需要臨時(shí)集合的時(shí)候,我們根本就不需要定義臨時(shí)表。當(dāng)我們?cè)谝粭lSQL語(yǔ)句中只使用一次臨時(shí)集合時(shí),我們可以使用嵌套表表達(dá)式來(lái)定義臨時(shí)集合;當(dāng)我們?cè)谝粭lSQL語(yǔ)句中需要多次使用同一臨時(shí)集合時(shí),我們可以使用公共表表達(dá)式;只有當(dāng)我們?cè)谝粋€(gè)工作單元中的多條SQL語(yǔ)句中使用同一臨時(shí)集合時(shí),我們才需要定義臨時(shí)表。
可以通過(guò)以下三種方式定義臨時(shí)表:
方法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;
定義了臨時(shí)表后,我們可以像使用普通表一樣使用臨時(shí)表。臨時(shí)表只對(duì)定義它的用戶有效,不同用戶可以在同一時(shí)間定義同名的臨時(shí)表,他們之間互不影響。臨時(shí)表的生命周期是SESSION,當(dāng)SESSION關(guān)閉時(shí),臨時(shí)表將自動(dòng)刪除,這也是臨時(shí)表的模式名只能為SESSION的原因。此外,我們還可以給臨時(shí)表定義索引。更多細(xì)節(jié)請(qǐng)參考DB2 信息中心。
Eclipse的擴(kuò)展機(jī)制是其一個(gè)重要特色,但隨著Eclipse功能越做越強(qiáng),插件越來(lái)越多,你會(huì)發(fā)現(xiàn)GUI上的圖標(biāo)越來(lái)越多,Menu,toolbar,context menu都被占滿了,其實(shí)很多item并不是我們需要的,但是contribute這些item的插件我們是需要的,那怎么去掉它們擴(kuò)展的那些菜單項(xiàng)呢?
1.在Plugin.xml中定制
這是最簡(jiǎn)單的辦法,很多時(shí)候我們自己想寫代碼來(lái)去掉一些菜單項(xiàng),但效果并不好.所以能在Plugin.xml中定制的,我們就 盡量寫在plugin.xml里面.下面舉一個(gè)右鍵菜單的例子:
擴(kuò)展右鍵菜單需要擴(kuò)展org.eclipse.ui.popupMenus擴(kuò)展點(diǎn),我們一般都在它下面new一個(gè)action,但這個(gè)action擴(kuò)展之后不管在 任何界面都會(huì)出現(xiàn),如果我們想在某些條件下隱藏掉它該怎么辦?仔細(xì)觀察下org.eclipse.ui.popupMenus擴(kuò)展點(diǎn),其實(shí)我們還可以新建objectContribution擴(kuò)展
<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里面也包含一個(gè)action,但這個(gè)action在popupmenu里出現(xiàn)是有條件的:我們給它定義了一個(gè)nameFilter, 只有當(dāng)selection()的path中包含了"example"才會(huì)顯示,否則這個(gè)action是不會(huì)出現(xiàn)在 popupmenu里的.這里的selection假設(shè)選中的是一個(gè)File,如果選中的是你自己寫的類,那namefilter會(huì)在你的類的toString方法里面找keyword.
2.使用Eclipse的Activities擴(kuò)展
plugin.xml并不能解決所有問(wèn)題,當(dāng)我們實(shí)在沒(méi)有辦法在plugin.xml中限制某些extension的出現(xiàn)的時(shí)候,可以考慮使用Eclipse的Activities.Activities的官方定義大家可以google一下eclipse的help.我個(gè)人的理解就是它可以和perspective一樣控制UI的顯示,但是Perspective設(shè)計(jì)的太易于擴(kuò)展了,假如Plugin A在perspective上擴(kuò)展了一個(gè)UI,那么Plugin B在每次進(jìn)入這個(gè)perspective的時(shí)候就一定可以看得見(jiàn)它,而且在Eclipse的擴(kuò)展機(jī)制下,Plugin B是沒(méi)有權(quán)利去刪了Plugin A的contribution的(Eclipse的ExtensionRegistry倒是提供了一個(gè)removeExtension方法,但運(yùn)行的時(shí)候會(huì)報(bào)錯(cuò)).在這樣的情況下,Activities的價(jià)值就體現(xiàn)出來(lái)了,你只要給它一個(gè)Extension的id,它就可以幫你把這個(gè)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中擴(kuò)展了 org.eclipse.ui.newWizards,id是mywizard,那么上面這個(gè)activityPatternBinding就會(huì)disable掉my.example的mywizard擴(kuò)展,你在 GUI中就看不見(jiàn)這個(gè)wizard了.pattern是支持正則表達(dá)式的,所以如果有"."的話需要用轉(zhuǎn)義字符\.注意,這里的disable的意思并不是說(shuō)我把mywizard這個(gè)擴(kuò)展刪掉了,而是屏蔽了它,mywizard仍然在 ExtensionRegistry中.
3.用代碼來(lái)動(dòng)態(tài)控制UI
方法2只是隱藏掉一些擴(kuò)展,但是有一些需求并不是簡(jiǎn)單的隱藏就可以了,我最近碰到的一個(gè)需求就是:有一個(gè)flag,只有當(dāng)flag==1的時(shí)候擴(kuò)展是可見(jiàn)的,否則是不可見(jiàn)的,需要disable這個(gè)擴(kuò)展.這時(shí)就必須要加一些代碼才能實(shí)現(xiàn)了,還是以方法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的,當(dāng)你在plugin.xml中定義好了一個(gè)Activity,缺省它是disable的,就是說(shuō)activityPatternBinding 匹配的擴(kuò)展是會(huì)被disable的,但你也可以把Activities設(shè)成enable的(在plugin.xml或者用代碼都可以設(shè)置),它匹配的擴(kuò)展是可以正常使用的.
在上面的code sample中,我們通過(guò)activityManager.getEnabledActivityIds()得到所有enable的Activities.如果flag==1,那my.example.activity 也應(yīng)該被加入到enable Activities中,這樣mywizard就可以顯示在界面上,反之,就要在enable Activities中remove掉my.example.activity,它就變成
disable,會(huì)把mywizard隱藏.
摘要: Access Path
1.并不是用index就一定快.有時(shí)候一個(gè)表只有很少的records,那么你直接scan這個(gè)表,比你先讀index,再訪問(wèn)表要快.
2.不過(guò)大多數(shù)情況下還是用index快一些(要不然這個(gè)技術(shù)就沒(méi)有意義了).DB2中index的應(yīng)用需要兩個(gè)前提條件:
閱讀全文
TreeViewer的setSelection方法使用后,會(huì)在樹上選中并展開方法參數(shù)中對(duì)應(yīng)的節(jié)點(diǎn).但是有時(shí)候你發(fā)現(xiàn)它只能選中第一級(jí)節(jié)點(diǎn),下面的子節(jié)點(diǎn)沒(méi)有辦法選中.其實(shí)這個(gè)方法是沒(méi)有問(wèn)題的,它的大概實(shí)現(xiàn)算法是:先找到某一個(gè)子節(jié)點(diǎn),然后找到它的父節(jié)點(diǎn),把父節(jié)點(diǎn)展開,然后又找父節(jié)點(diǎn)的父節(jié)點(diǎn),做同樣的操作,直到根節(jié)點(diǎn)為止,這樣你才能看到選中的子節(jié)點(diǎn).所以父節(jié)點(diǎn)如果為null,那肯定你是看不到子節(jié)點(diǎn)了.而我們很多人在實(shí)現(xiàn)ITreeContentProvide的接口的時(shí)候,是不實(shí)現(xiàn)getParent方法的,因?yàn)橹灰獙?shí)現(xiàn)了getChildren方法就可以看見(jiàn)一棵樹了.包括陳剛的<Eclipse從入門到精通>也是這樣.所以在實(shí)現(xiàn)treeViewer的時(shí)候,最好還是實(shí)現(xiàn)getparent方法.其實(shí)也不麻煩,在添加一個(gè)child的時(shí)候,加一句setparent(this)就可以了
最初java是不支持對(duì)文本文件的處理的,為了彌補(bǔ)這個(gè)缺憾而引入了Reader和Writer兩個(gè)類,這兩個(gè)類都是抽象類,Writer中 write(char[] ch,int off,int
length),flush()和close()方法為抽象方法,Reader中read(char[] ch,int off,int length)和close()方法是抽象方法。子類應(yīng)該分別實(shí)現(xiàn)他們。
當(dāng)我們讀寫文本文件的時(shí)候,采用Reader是非常方便的,比如FileReader,InputStreamReader和BufferedReader。其中最重要的類是InputStreamReader,
它是字節(jié)轉(zhuǎn)換為字符的橋梁。你可以在構(gòu)造器重指定編碼的方式,如果不指定的話將采用底層操作系統(tǒng)的默認(rèn)編碼方式,例如GBK等。當(dāng)使用FileReader讀取文件
的時(shí)候。
FileReader fr = new FileReader("ming.txt");
int ch = 0;
while((ch = fr.read())!=-1 )
{
System.out.print((char)ch);
}
其中read()方法返回的是讀取得下個(gè)字符。當(dāng)然你也可以使用read(char[] ch,int off,int length)這和處理二進(jìn)制文件的時(shí)候類似,不多說(shuō)了。如果使用
InputStreamReader來(lái)讀取文件的時(shí)候
while((ch = isr.read())!=-1)
{
System.out.print((char)ch);
}
這和FileReader并沒(méi)有什么區(qū)別,事實(shí)上在FileReader中的方法都是從InputStreamReader中繼承過(guò)來(lái)的。read()方法是比較好費(fèi)時(shí)間的,如果為了提高效率
我們可以使用BufferedReader對(duì)Reader進(jìn)行包裝,這樣可以提高讀取得速度,我們可以一行一行的讀取文本,使用readLine()方法。
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("ming.txt")));
String data = null;
while((data = br.readLine())!=null)
{
System.out.println(data);
}
當(dāng)你明白了如何用Reader來(lái)讀取文本文件的時(shí)候那么用Writer寫文件同樣非常簡(jiǎn)單。有一點(diǎn)需要注意,當(dāng)你寫文件的時(shí)候,為了提高效率,寫入的數(shù)據(jù)會(huì)先
放入緩沖區(qū),然后寫入文件。因此有時(shí)候你需要主動(dòng)調(diào)用flush()方法。與上面對(duì)應(yīng)的寫文件的方法為:
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);
不要忘記用完后關(guān)閉流!下面是個(gè)小例子,幫助新手理解。其實(shí)有的時(shí)候java的IO系統(tǒng)是需要我們多記記的,不然哪天就生疏了。
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中多種方式讀文件
一、多種方式讀文件內(nèi)容。
1、按字節(jié)讀取文件內(nèi)容
2、按字符讀取文件內(nèi)容
3、按行讀取文件內(nèi)容
4、隨機(jī)讀取文件內(nèi)容
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 {
/**
* 以字節(jié)為單位讀取文件,常用于讀二進(jìn)制文件,如圖片、聲音、影像等文件。
* @param fileName 文件的名
*/
public static void readFileByBytes(String fileName){
File file = new File(fileName);
InputStream in = null;
try {
System.out.println("以字節(jié)為單位讀取文件內(nèi)容,一次讀一個(gè)字節(jié):");
// 一次讀一個(gè)字節(jié)
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("以字節(jié)為單位讀取文件內(nèi)容,一次讀多個(gè)字節(jié):");
//一次讀多個(gè)字節(jié)
byte[] tempbytes = new byte[100];
int byteread = 0;
in = new FileInputStream(fileName);
ReadFromFile.showAvailableBytes(in);
//讀入多個(gè)字節(jié)到字節(jié)數(shù)組中,byteread為一次讀入的字節(jié)數(shù)
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) {
}
}
}
}
/**
* 以字符為單位讀取文件,常用于讀文本,數(shù)字等類型的文件
* @param fileName 文件名
*/
public static void readFileByChars(String fileName){
File file = new File(fileName);
Reader reader = null;
try {
System.out.println("以字符為單位讀取文件內(nèi)容,一次讀一個(gè)字節(jié):");
// 一次讀一個(gè)字符
reader = new InputStreamReader(new FileInputStream(file));
int tempchar;
while ((tempchar = reader.read()) != -1){
//對(duì)于windows下,rn這兩個(gè)字符在一起時(shí),表示一個(gè)換行。
//但如果這兩個(gè)字符分開顯示時(shí),會(huì)換兩次行。
//因此,屏蔽掉r,或者屏蔽n。否則,將會(huì)多出很多空行。
if (((char)tempchar) != 'r'){
System.out.print((char)tempchar);
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println("以字符為單位讀取文件內(nèi)容,一次讀多個(gè)字節(jié):");
//一次讀多個(gè)字符
char[] tempchars = new char[30];
int charread = 0;
reader = new InputStreamReader(new FileInputStream(fileName));
//讀入多個(gè)字符到字符數(shù)組中,charread為一次讀取字符數(shù)
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("以行為單位讀取文件內(nèi)容,一次讀一整行:");
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 1;
//一次讀入一行,直到讀入null為文件結(jié)束
while ((tempString = reader.readLine()) != null){
//顯示行號(hào)
System.out.println("line " + line + ": " + tempString);
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null){
try {
reader.close();
} catch (IOException e1) {
}
}
}
}
/**
* 隨機(jī)讀取文件內(nèi)容
* @param fileName 文件名
*/
public static void readFileByRandomAccess(String fileName){
RandomAccessFile randomFile = null;
try {
System.out.println("隨機(jī)讀取一段文件內(nèi)容:");
// 打開一個(gè)隨機(jī)訪問(wèn)文件流,按只讀方式
randomFile = new RandomAccessFile(fileName, "r");
// 文件長(zhǎng)度,字節(jié)數(shù)
long fileLength = randomFile.length();
// 讀文件的起始位置
int beginIndex = (fileLength > 4) ? 4 : 0;
//將讀文件的開始位置移到beginIndex位置。
randomFile.seek(beginIndex);
byte[] bytes = new byte[10];
int byteread = 0;
//一次讀10個(gè)字節(jié),如果文件內(nèi)容不足10個(gè)字節(jié),則讀剩下的字節(jié)。
//將一次讀取的字節(jié)數(shù)賦給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) {
}
}
}
}
/**
* 顯示輸入流中還剩的字節(jié)數(shù)
* @param in
*/
private static void showAvailableBytes(InputStream in){
try {
System.out.println("當(dāng)前字節(jié)輸入流中的字節(jié)數(shù)為:" + 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);
}
}
二、將內(nèi)容追加到文件尾部
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* 將內(nèi)容追加到文件尾部
*/
public class AppendToFile {
/**
* A方法追加文件:使用RandomAccessFile
* @param fileName 文件名
* @param content 追加的內(nèi)容
*/
public static void appendMethodA(String fileName,
String content){
try {
// 打開一個(gè)隨機(jī)訪問(wèn)文件流,按讀寫方式
RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
// 文件長(zhǎng)度,字節(jié)數(shù)
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 {
//打開一個(gè)寫文件器,構(gòu)造函數(shù)中的第二個(gè)參數(shù)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");
//顯示文件內(nèi)容
ReadFromFile.readFileByLines(fileName);
//按方法B追加文件
AppendToFile.appendMethodB(fileName, content);
AppendToFile.appendMethodB(fileName, "append end. n");
//顯示文件內(nèi)容
ReadFromFile.readFileByLines(fileName);
}
}
1.有的時(shí)候在project的java build path中定義好了一些jar包依賴,但是project在運(yùn)行的時(shí)候仍然報(bào)NoClassDef的錯(cuò)誤.這是因?yàn)閜roject的MANIFEST.MF文件沒(méi)有更新.手動(dòng)在MANIFEST.MF加上那些jar包就可以了.
2.Plugin A 依賴 Plugin B.B也把相應(yīng)的package export出來(lái)了,但是A還是找不到B里面定義的類.修改A的MANIFEST.MF文件,在dependence tab里去掉Plugin B,再添加B.此時(shí)發(fā)現(xiàn)有5,6個(gè)同樣的Plugin B出現(xiàn)在選擇plugin的list中.cancel 掉該對(duì)話框,然后重啟eclipse,在A的dependence里面重新加上B,問(wèn)題解決.
3.當(dāng)我們通過(guò)在plugin.xml中用extension的方式定義action的時(shí)候,你會(huì)發(fā)現(xiàn)你定義的actionset和action在GUI出現(xiàn)的順序不是你可以控制的,就是說(shuō)同一個(gè)actionset下的多個(gè)action不是按你定義的先后順序出現(xiàn)在程序的界面上的,這樣對(duì)action進(jìn)行排序呢?其實(shí)仔細(xì)觀察一下,你會(huì)發(fā)現(xiàn)action在GUI出現(xiàn)的順序是和你定義action的順序相反的,比如你先后定義了3個(gè)action A,B,C,那么你就會(huì)在GUI上看見(jiàn)action的順序是C,B,A.如果你定義了多個(gè)actionset,你會(huì)發(fā)現(xiàn)這個(gè)規(guī)律不適用與actionset,actionset在界面上出現(xiàn)的順序其實(shí)是和它的id的排序相反的.比如你定義了三個(gè)actionset,它們的id分別是:seta,setb,setc,你會(huì)發(fā)現(xiàn)GUI上出現(xiàn)的順序是setc,setb,seta
4.雙擊激活TreeViewer的celleditor
JFace的Viewer都有單元格編輯功能,但是celleditor默認(rèn)的實(shí)現(xiàn)是單擊激活editor,雙擊選中item.如果需要改成單擊選中item,雙擊激活editor呢?Eclipse的官網(wǎng)上好像也有人問(wèn)到這個(gè)問(wèn)題,不過(guò)目前好像是開了一個(gè)bug,期待eclipse的下個(gè)版本解決這個(gè)問(wèn)題.但最近找到了一個(gè)用SWT來(lái)解決這個(gè)問(wèn)題的方法:
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的易擴(kuò)展性,理論上可以有無(wú)數(shù)個(gè)Action運(yùn)行在一個(gè)RCP 程序中,但是快捷鍵是有限的,尤其是一些常用的,像Ctrl+C,Ctrl+S之類的普通用戶能記得住的就那么幾個(gè),萬(wàn)一你自定義的Action的快捷鍵和Eclipse默認(rèn)的發(fā)生了沖突怎么辦?比如Eclipse默認(rèn)Ctrl+S是Save的快捷鍵,但是你又自定義了一個(gè)SaveAction,希望用戶按下Ctrl+S之后執(zhí)行的是自己的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>
這樣的方法一般是不會(huì)有沖突的,但是像我們上面提到的情況,如果你自定義一個(gè)binding,它的key sequence是Ctrl+S,那就會(huì)有問(wèn)題.由于org.eclipse.ui插件已經(jīng)提供了一個(gè)Ctrl+S的快捷鍵,所以系統(tǒng)中會(huì)有兩個(gè)Ctrl+S,這樣Eclipse會(huì)在右下角pop up一個(gè)assist dialog,讓你從兩個(gè)Action中選擇一個(gè),這樣可能會(huì)造成一些用戶使用上的不習(xí)慣.
解決辦法:
1.直接改快捷鍵.
這個(gè)最簡(jiǎn)單了,比如把你自己的save定義成Alt+S.但是這個(gè)方法也是最不好的方法,因?yàn)楹芏嘤脩舨⒉恢繟lt+S在你的程序里面就是save.
2.修改自定義action的definition id
我們剛才說(shuō)過(guò),action的definition id綁定著一個(gè)command,而command又對(duì)應(yīng)著一個(gè)binding,Eclipse通過(guò)這樣的方式實(shí)現(xiàn)action和快捷鍵的綁定.我們?cè)賮?lái)看看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進(jìn)行了綁定,而這個(gè)command對(duì)應(yīng)的key就是"M1+S"(Ctrl + S),這樣就實(shí)現(xiàn)了快捷鍵綁定.如果我們也把自定義的Save Action的definition id指定為org.eclipse.ui.file.save,是不是就可以達(dá)到目的呢?答案是肯定的.
Eclipse中的Action存在著一個(gè)類似"優(yōu)先級(jí)"的概念(具體實(shí)現(xiàn)是通過(guò)action handler).越"具體"的action,優(yōu)先級(jí)越高.Eclipse的Save Action明顯是一個(gè)global的action,(同樣的global action還有copy, cut,undo,redo等等).而我們自定義的action一般是實(shí)現(xiàn)了IWorkbenchWindowActionDelegate接口的,就是說(shuō),它是contribute to workbench window的,它是一個(gè)workbench action,它的優(yōu)先級(jí)就高于任何global action.同理,如果你定義一個(gè)editor action或者view action,由于它比workbench還"具體"(workbench可以包含多個(gè)editor或view,workbench action對(duì)這些editor或view都是有效的;而editor action只對(duì)某個(gè)具體的editor有效),所以editor action的優(yōu)先級(jí)就高于workbench action.這樣,如果自定義的action和eclipse缺省的action都綁定到同一個(gè)command,那么eclipse runtim最后會(huì)選擇自定義的action來(lái)執(zhí)行.
3.終極解決大法:自定義schema
Eclipse 有一個(gè)default的快捷鍵schema文件:org.eclipse.ui.defaultAcceleratorConfiguration.它存儲(chǔ)著Eclipse所有的快捷鍵.如果你自定義一個(gè)自己的schema文件,并把它設(shè)成當(dāng)前使用的schema文件,那么Eclipse就會(huì)調(diào)用自定義的schema文件.(新的schema文件可以在org.eclipse.ui.bindings擴(kuò)展點(diǎn)中定義,請(qǐng)注意,在定義新schema的時(shí)候由一個(gè)parentID屬性,如果你定義了它,新的schema會(huì)像類繼承一樣把parent schema里面的key binding全繼承下來(lái).如果不定義,則是一個(gè)全新的schema)
假定我們已經(jīng)有了一個(gè)新的schema文件,id是myplugin.schema.然后我們?cè)趏rg.eclipse.ui.bindings下定義一個(gè)key:
<key
commandId="myplugin.actions.save"
contextId="org.eclipse.ui.contexts.window"
schemaId="myplugin.schema"
sequence="CTRL+S">
</key>
我們已經(jīng)把schemaId換成了myplugin.schema,表示我們把CTRL+S加到了myplugin.schema中,然后把新建的schema文件在product配置文件plugin_customization.ini中設(shè)置成當(dāng)前的key schema文件:
org.eclipse.ui/KEY_CONFIGURATION_ID=myplugin.schema
這種方法雖然麻煩了一點(diǎn),但卻可以治標(biāo)又治本.而且由于可以指定parent schema,我們完全可以把org.eclipse.ui.defaultAcceleratorConfiguration作為parent schema,繼承它全部的快捷鍵配置,只定制幾個(gè)會(huì)產(chǎn)生沖突的快捷鍵即可
gef中經(jīng)常會(huì)有很多連線,這些連線如何和每個(gè)node連接,允不允許交叉等等都是用router來(lái)控制的.網(wǎng)上有篇文章對(duì)這個(gè)做了一些介紹:
http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-gef/part2/
我現(xiàn)在做的這個(gè)項(xiàng)目需要在兩個(gè)node之間同時(shí)存在多根線,如果不使用router的話就只能看見(jiàn)一根,在diagram的 figure里面set一個(gè)FanRouter作為缺省的router就可以解決這個(gè)問(wèn)題.兩個(gè)node之間如果存在多根連線的話,FanRouter會(huì)把它們分布成扇形,每根連線都可以看見(jiàn).但是FanRouter好像只能在diagram的figure里面設(shè)置,如果每根connection你都設(shè)置成FanRouter,反而不會(huì)啟效果,這可能跟它的handlecollision方法的算法有關(guān).
但是設(shè)置成FanRouter之后有一個(gè)問(wèn)題:我的項(xiàng)目中還有那種自連接的connection(該connection的source和target是同一個(gè)node),原先我是把這種connection的router設(shè)置為bendconnectionrouter,但是后來(lái)設(shè)置了FanRouter之后BendConnectionRouter好像就失效了,不管你的connection上面有多少個(gè)bendpoint都看不出來(lái)效果.
后來(lái)終于找到了讓這兩張router和平共處的辦法,只要加一行:fanRouter.setNextRouter(new BendPointConnectionRouter());setNextRouter這個(gè)方法有點(diǎn)怪,按照字面的理解,應(yīng)該是fanrouter的下一個(gè)router,按理說(shuō)應(yīng)該是先用fanrouter來(lái)layout 連線,然后再使用BendPointConnectionRouter來(lái)layout 連線,但是它實(shí)際上是先用BendPointConnectionRouter來(lái)layout 連線,然后再使用fanRouter.
GEF中自帶有Directeditrequest,所以實(shí)現(xiàn)Directedit還是比較容易的,八進(jìn)制的gef例子里面就有實(shí)現(xiàn).但我在給directedit加上content assist的時(shí)候卻發(fā)現(xiàn)由一個(gè)小bug不太好弄,費(fèi)了兩天才搞定,現(xiàn)在先記下來(lái),以供參考
directedit是通過(guò)一個(gè)text celleditor來(lái)實(shí)現(xiàn)編輯功能的,所以可以在directeditmanager類里面的initCellEditor方法里面加上ContentAssistHandler來(lái)實(shí)現(xiàn)auto complete.但是加上去之后卻發(fā)現(xiàn)有一個(gè)問(wèn)題:不支持用鼠標(biāo)來(lái)選擇proposal.只能用鍵盤上的上下箭頭來(lái)選擇.雖然也可以用,但是終究不是那么的人性化.
為了修復(fù)這個(gè)bug,走了不少的彎路,一開始以為是contentassist的問(wèn)題,因?yàn)樗莇eprecated,所以換了3.3里面的assist api,發(fā)現(xiàn)還是不行.后來(lái)才知道是因?yàn)閏elleditor有一個(gè)focus listener,當(dāng)用戶點(diǎn)擊proposals 來(lái)選擇一行的時(shí)候,celleditor的focus就lost了,就會(huì)調(diào)用focusLost方法,導(dǎo)致directedit編輯失敗.所以我重寫了celleditor的focusLost方法,把它設(shè)成當(dāng)focus在contentassist的popup dialog就什么都不干,否則調(diào)用父類的focusLost方法.理論上是一個(gè)好的解決方法,但是contentassist的hasPopupFocus居然一直都返回false,這個(gè)方法也失敗了.
最后,在bug.eclipse.org上面有人提到GMF里面的TextDirectEditManager是可以做到用鼠標(biāo)選擇proposal的,于是又去看gmf的這個(gè)類,它也是繼承自DirectEditManager,不過(guò)它消除這個(gè)bug不是在listener上作文章,而是在commit方法里面,在這個(gè)方法里面判斷popup dialog是否是active的,如果是的話則給celleditor加上deactive lock,不允許它deactive,這樣來(lái)實(shí)現(xiàn)用鼠標(biāo)選擇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里面對(duì)于deactive lock的應(yīng)用,MyTextCellEditor的deactive之前會(huì)判斷一下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文件,其格式都是沒(méi)有縮進(jìn)的,每個(gè)element都是頂?shù)阶钋懊?今天終于找到了比較好的處理方法,趕緊記下來(lái).
使用Java標(biāo)準(zhǔn)的JAXP來(lái)輸出可以使用:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(document), new StreamResult(outputFile));
中間的紅色代碼是用于設(shè)置縮進(jìn)的,比較遺憾的是JAXP只抽象出是否設(shè)置縮進(jìn)(indent: yes|no),但并沒(méi)有抽象出設(shè)置縮進(jìn)量長(zhǎng)度的常量(indent-number),所以默認(rèn)的縮進(jìn)量長(zhǎng)度為0。如果有下面這樣一個(gè)xml文檔:<root><a><b>c</b></a></root>會(huì)被格式化為:
<root>
<a>
<b>c</b>
</a>
</root>
由于JAXP只是一個(gè)Java一個(gè)處理XML的框架,根據(jù)實(shí)現(xiàn)的不一樣,可以傳入實(shí)現(xiàn)特定的某個(gè)Key來(lái)設(shè)置縮進(jìn)量。比如在Java 1.4下面,可以通過(guò)下面語(yǔ)句將縮進(jìn)量設(shè)為2:
ransformer.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount", "2");
或
transformer.setOutputProperty(
"{http://xml.apache.org/xalan}indent-amount", "2");
上面兩句不同之處僅在于命名空間。
而在Java 1.5下面,情況就有些復(fù)雜了。Java 1.5集成了JXAP 1.3(Java 1.4集成的是JXAP 1.1,不同之處參見(jiàn)http://java.sun.com/j2se/1.5.0/docs/guide/xml/jaxp/JAXP-Compatibility_150.html),實(shí)現(xiàn)基于Xerces類庫(kù)。由于內(nèi)部實(shí)現(xiàn)上的Bug,導(dǎo)致了設(shè)置縮進(jìn)的不同:
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)))));
注意紅色代碼的不同之處。第一句設(shè)置TransformerFactory的indent-number屬性,在Java 1.4下面運(yùn)行會(huì)拋出異常,因?yàn)槠洳恢С衷搶傩?,而在Java 1.5中卻只能通過(guò)該屬性來(lái)設(shè)置縮進(jìn)。后面標(biāo)為紅色的代碼則是由于Sun實(shí)現(xiàn)上的Bug,只有通過(guò)StreamResult(Writer)構(gòu)造函數(shù)生成才能正確設(shè)置縮進(jìn)(通過(guò)OutputStream或者File生成的StreamResult是無(wú)法設(shè)置縮進(jìn)的,其實(shí)現(xiàn)上會(huì)忽略任何非正式的屬性,而僅僅采用rt.jar下面com\sun\org\apache\xml\internal\serializer\output_xml.properties中的配置。詳細(xì)可以在com.sun.org.apache.xml.internal.serializer.ToStream類的setOutputStream方法中加斷點(diǎn)進(jìn)行分析)
?
如果忽略掉可移植性,確認(rèn)綁定在Sun的JRE實(shí)現(xiàn)上面,則可以通過(guò)如下代碼來(lái)更好的實(shí)現(xiàn):
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包下。
如果應(yīng)用對(duì)增加一個(gè)300K左右的jar包不敏感的話,我還是強(qiáng)烈推薦用dom4j來(lái)處理xml,其API設(shè)計(jì)的非常易用,寫出來(lái)的代碼比用JXAP寫出來(lái)的代碼漂亮多了,也容易維護(hù),也不會(huì)出現(xiàn)上面那種兩個(gè)Java版本不兼容的問(wèn)題。
Java 對(duì)文件進(jìn)行讀寫操作的例子很多,讓初學(xué)者感到十分困惑,我覺(jué)得有必要將各種方法進(jìn)行
一次分析,歸類,理清不同方法之間的異同點(diǎn)。
一.在 JDK 1.0 中,通常是用 InputStream & OutputStream 這兩個(gè)基類來(lái)進(jìn)行讀寫操作的。
InputStream 中的 FileInputStream 類似一個(gè)文件句柄,通過(guò)它來(lái)對(duì)文件進(jìn)行操作,類似的,在
OutputStream 中我們有 FileOutputStream 這個(gè)對(duì)象。
用FileInputStream 來(lái)讀取數(shù)據(jù)的常用方法是:
FileInputStream fstream = new FileInputStream(args[0]);
DataInputStream in = new DataInputStream(fstream);
用 in.readLine() 來(lái)得到數(shù)據(jù),然后用 in.close() 關(guān)閉輸入流。
完整代碼見(jiàn) Example 1。
用FileOutputStream 來(lái)寫入數(shù)據(jù)的常用方法是:
FileOutputStream out out = new FileOutputStream("myfile.txt");
PrintStream p = new PrintStream( out );
用 p.println() 來(lái)寫入數(shù)據(jù),然后用 p.close() 關(guān)閉輸入。
完整代碼見(jiàn) Example 2。
二.在 JDK 1.1中,支持兩個(gè)新的對(duì)象 Reader & Writer, 它們只能用來(lái)對(duì)文本文件進(jìn)行操作,而
JDK1.1中的 InputStream & OutputStream 可以對(duì)文本文件或二進(jìn)制文件進(jìn)行操作。
用FileReader 來(lái)讀取文件的常用方法是:
FileReader fr = new FileReader("mydata.txt");
BufferedReader br = new BufferedReader(fr);
用 br.readLing() 來(lái)讀出數(shù)據(jù),然后用br.close() 關(guān)閉緩存,用fr.close() 關(guān)閉文件。
完整代碼見(jiàn) Example 3。
用 FileWriter 來(lái)寫入文件的常用方法是:
FileWriter fw = new FileWriter("mydata.txt");
PrintWriter out = new PrintWriter(fw);
在用out.print 或 out.println 來(lái)往文件中寫入數(shù)據(jù),out.print 和 out.println的唯一區(qū)別是后者寫
入數(shù)據(jù)或會(huì)自動(dòng)開一新行。寫完后要記得 用out.close() 關(guān)閉輸出,用fw.close() 關(guān)閉文件。
完整代碼見(jiàn) 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中導(dǎo)出一種DIM file,然后在
IA的organization-->DIM Reference-->add DIM Reference中使用它。ISMP 11 sp1之前的版本IA不再兼容
11)installer運(yùn)行時(shí)參數(shù)
你可以在installer運(yùn)行的時(shí)候添加一些參數(shù),比如
installer.exe -i console //在console模式下運(yùn)行
//在silent模式下運(yùn)行,由于silent模式不會(huì)有任何界面,所以你可以
//設(shè)置一些安裝的屬性,格式如下:
installer.exe -i silent <propertyname>=<value>
//具體實(shí)例:
installer.exe -i silent USER_INSTALL_DIR=C:\Mydirectory
//如果你屬性很多,你可以都寫在一個(gè)文件中,然后引用就可以了
installer.exe -i silent -f <path to the properties file>
12)用代碼啟動(dòng)IA的build
稍微復(fù)雜一點(diǎn)的java項(xiàng)目在編譯打包的時(shí)候都少不了要用到ant。如果我們要在ant中啟動(dòng)IA來(lái)制作安裝程序該怎么做呢
IA的安裝目錄下有一個(gè)build.exe,用它就可以了。
build.exe <path to IA project file>
13)source path
在Edit菜單里面可以設(shè)置source path。感覺(jué)它跟ISMP的alias是一樣的。無(wú)非就是讓你設(shè)置IA_HOME,PROJECT_HOME等等。
和alias不同的是,source path都是global,沒(méi)有project類型的。source path存放在C:\Documents and Settings\Administrator\InstallAnywhere\80\Enterprise\preferences中
14)merge modules
當(dāng)我們需要有一個(gè)project包含其他project的時(shí)候,就要用到merge modules。最典型的例子就是office包含word,powerpoint
,excel等。merge modules最少要有兩個(gè)project,一個(gè)parent project,若干個(gè)child project。merge modules主要有以下幾種:
i. design time merge module
這種merge module直接把child project拷貝到了parent project中,child project中的panel和action都會(huì)在parent project
的安裝過(guò)程中出現(xiàn),并且你可以在parent project中修改它們。如果原來(lái)的child project做了某些變化,parent project中的child project不會(huì)有任何變化。
這種merge module只生成一個(gè)uninstaller,它會(huì)卸載掉整個(gè)軟件產(chǎn)品。如果要只卸載child project,好像可以通過(guò)把child project
設(shè)成feature來(lái)實(shí)現(xiàn),但我目前還沒(méi)有實(shí)驗(yàn)過(guò)。
ii. dynamic time merge module
這種merge module不拷貝child project到parent project中,它只鏈接到child project。所以child project的任何變化都會(huì)反映到
parent project中。但是你不能在parent project中修改child project的panel和action,因?yàn)槟阒皇擎溄拥絚hild project。
這種merge module會(huì)生成多個(gè)uninstaller,分別用來(lái)卸載parent project 和child projects。
iii. build time merge module
和dynamic time merge module類似,不同的是build time merge module不會(huì)出現(xiàn)child project的panel。換句話說(shuō),child project是以silent模式安裝的。
怎么在具體的項(xiàng)目中用merge module呢?首先,你需要把child project build成merge module,會(huì)生成一個(gè)文件。然后在parent project的
orgnization-->Modules 導(dǎo)入就可以了
15)Custom Code
IA的advanced designer已經(jīng)可以滿足大部分用戶的需要了,如果你所要的功能advanced designer還無(wú)法實(shí)現(xiàn),你可以自己編寫Custom Code來(lái)實(shí)現(xiàn)??梢哉f(shuō)
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的安裝目錄下有一個(gè)javadoc目錄,里面有IA提供的api的文檔,跟java的api的文檔的使用方法是一樣的。IA為以上四種Custom Code提供了四個(gè)
缺省的類來(lái)實(shí)現(xiàn),分別是CustomCodeAction,CustomCodePanel,CustomCodeConsoleAction,CustomCodeRule,你可以去繼承它們并添加你需要的
功能。
代碼寫好了之后不能直接用于IA中,還需要編譯,打包。打包有兩種方法
一)打包成類的JAR包
先寫好代碼,然后用javac命令編譯(當(dāng)然你也可以用eclipse,netbean來(lái)得到class文件),最后把class file壓成jar包。
點(diǎn)擊Add Action-->Execute Custom Code,指定你的jar包的位置,如果用到了第三方的jar包,記得把它們添加到“Dependencies”中
ps:點(diǎn)擊Add Action,你會(huì)看到有四個(gè)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,不能通過(guò)Add Action添加,你需要點(diǎn)擊Add Rule-->evaluate custom code
來(lái)執(zhí)行
二)打包成plugin
先寫好代碼,然后用javac命令編譯(當(dāng)然你也可以用eclipse,netbean來(lái)得到class文件)。
創(chuàng)建一個(gè)properties文件,然后把這個(gè)properties文件打包成一個(gè)jar包??梢?jiàn)與第一種方法的區(qū)別就是多了一個(gè)屬性文件
舉一個(gè)屬性文件的例子:
plguin.name=my custom action
plugin.main.class=MySampleAction
plugin.type=action
//如果你寫了preinstall,那在preinstall view中Add Action-->Plugin里面可以看見(jiàn)這個(gè)plugin,否則是看不見(jiàn)的。
plugin.available=preinstall,install,postinstall
//property.myproperty=this value
property.database=localhost
打包完成后,把jar包拷貝到IA安裝目錄下的plugins文件夾,然后重啟IA(eclipse的用戶肯定很熟悉這個(gè)操作吧,呵呵)
然后你就可以在Add Action-->Plug-Ins里面發(fā)現(xiàn)你自己寫的plugin了。
最后列一下IA提供的api中比較重要的方法(IA提供了一個(gè)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可以到
它的網(wǎng)站上查詢。
最后,引用training teacher的一句話作為本文的結(jié)尾“不管你的產(chǎn)品有多好,用戶第一印象是看你的安裝程序,如果你的安裝程序不夠人性化,甚至安裝失敗了,那用戶對(duì)它的評(píng)價(jià)就不會(huì)高”
不知道你是否注意過(guò),當(dāng)你安裝java jdk的時(shí)候,當(dāng)你安裝微軟office的時(shí)候,當(dāng)你裝db2的時(shí)候,你都會(huì)看到一個(gè)熟悉的標(biāo)記---installshield。installshield可以說(shuō)是當(dāng)今安裝程序解決方案的巨無(wú)霸了,功能十分強(qiáng)大,你可以用它制作出你想要的安裝程序。但是功能的強(qiáng)大也帶來(lái)一個(gè)壞處,就是要上手非常難。所以公司特意請(qǐng)macrovision(就是制作installshield的公司)的人給我們進(jìn)行了一個(gè)training,感覺(jué)收獲還是很大的,所以把我認(rèn)為重要的地方紀(jì)錄下來(lái),一方面萬(wàn)一自己忘了可以查一查,另一方面說(shuō)不定對(duì)別人也有幫助。
先從版本說(shuō)起。installshield有專門用于制作java安裝程序的產(chǎn)品,由于java是跨平臺(tái)的語(yǔ)言,所以installshield對(duì)應(yīng)的產(chǎn)品就叫installshield multiple platform,簡(jiǎn)稱ismp。我接觸的最早版本是ismp 5.0,后來(lái)又出了ismp 11.5,再后來(lái)ismp改名字叫Install Anywhere(以下簡(jiǎn)稱IA)。目前我們training用的版本是IA 8.0,相信應(yīng)該是最新的版本了。IA是共享軟件,不注冊(cè)的話有21天的試用期。
安裝程序是一個(gè)可定制性非常強(qiáng)的東西,每個(gè)軟件作者的需求都不一樣。有的推崇簡(jiǎn)單就是美,一般只需要用戶選擇安裝的目錄,然后就一路next就裝完了;但有的軟件非常復(fù)雜,比如需要設(shè)置參數(shù),需要選擇安裝哪些部分,甚至需要啟動(dòng)windows的系統(tǒng)服務(wù)。這時(shí)候就需要比較復(fù)雜的配置了。installshield針對(duì)兩種用戶設(shè)計(jì)了不同的開發(fā)環(huán)境:一種是common designer,另一種是Advanced Designer。當(dāng)你第一次打開IA的時(shí)候,缺省的是common designer,你只需要做一些簡(jiǎn)單的配置,比如產(chǎn)品的名稱,需要安裝的文件,要不要綁定虛擬機(jī)等等,然后就可以build出一個(gè)安裝程序了。Advanced Designer是為高級(jí)用戶設(shè)置的,提供了更多,更豐富的功能,你可以用它來(lái)打造你所需要的安裝程序。本文主要是針對(duì)Advanced Designer進(jìn)行一些說(shuō)明。
1)安裝模式(install modes)
gui:這是最常用的一種模式,在安裝過(guò)程中會(huì)彈出若干個(gè)panel,比如welcome panel,license panel,destination panel等等。
console:用這種模式安裝程序時(shí),不會(huì)出現(xiàn)panel。它的所有信息都在控制臺(tái)中出現(xiàn)。說(shuō)的再通俗一點(diǎn),就是整個(gè)安裝過(guò)程只有一個(gè)dos窗口,這個(gè)窗口先會(huì)顯示一行信息歡迎你安裝本軟件,然后是讓你選擇destination,再安裝,最后會(huì)顯示一行安裝成功的信息
silent:顧名思義,這種模式在安裝的時(shí)候不會(huì)彈出任何窗口,它會(huì)安靜地裝上軟件,所以用戶也不能自己設(shè)定安裝目錄,一般都市由安裝程序安裝到固定的目錄上
2)install sets
很多安裝程序都有完全安裝,最小安裝,自定義安裝等選項(xiàng),這一般是用features來(lái)實(shí)現(xiàn)的。你可以把你的產(chǎn)品分成幾個(gè)features,然后由用戶來(lái)選擇一部分進(jìn)行安裝。
3)actions
IA中很多操作被稱為actions,常見(jiàn)的有copy files,delete files,modifying registry, creating service, modifying configurations files等
4)variable
IA中很重要的一個(gè)概念,你可以用variable來(lái)存放屬性信息,比如安裝目錄,用戶名等等。比如
安裝目錄可能會(huì)在很多地方都用到,如果你安裝目錄是硬編碼的,萬(wàn)一將來(lái)要修改就要改
很多地方,容易出錯(cuò);如果用variable來(lái)保存的話,只要修改變量值就可以了。注意一點(diǎn):variable
的值基本上都是string類型的
5)magic folders
IA里面獨(dú)有的概念,但感覺(jué)沒(méi)什么新意,就是variables的一種,專門用于定義folder的
variable而已
6)InstallAnywhere registry
不同于windows的registry,這是InstallAnywhere自己的registry。每個(gè)用IA制作的安裝程序,在安裝的過(guò)程中
都會(huì)把自己注冊(cè)到這個(gè)InstallAnywhere registry(注意:你只能在InstallAnywhere registry找到安裝的
component,找不到product)。它的一個(gè)典型應(yīng)用就是當(dāng)你需要檢查這個(gè)機(jī)器上是否安裝過(guò)某個(gè)軟件的時(shí)候,就可以
用search這個(gè)IA registry。不過(guò)如果你是用其他工具制作的安裝程序,IA registry就不會(huì)有記錄了。
7)execute command&execute script
execute command是用來(lái)執(zhí)行command,常用的dos命令(copy,cd等)你都可以寫在這里。execute script其實(shí)就是
execute command的加強(qiáng)版:如果你有多個(gè)命令,不需要建多個(gè)execute command,把它們寫在execute script就好了
8)計(jì)算所需空間
在IA中,默認(rèn)的空間大小是用byte來(lái)計(jì)算的,所以如果你的軟件比較大的話,那一長(zhǎng)串的阿拉伯?dāng)?shù)字會(huì)把用戶嚇倒的
解決方法是,在pre-install summary panel的配置項(xiàng)中,有一個(gè)是Edit Custom Field。在那里新建一個(gè)field。Variable
name是顯示給用戶看的內(nèi)容,比如你可以寫disk space。variable value是你的軟件所需的硬盤大小。你可以先算出來(lái)
,存在一個(gè)變量中,然后讓variable value等于這個(gè)變量就可以了。
9)results variable
用來(lái)存放用戶的選擇。比如在show message dialog中,有一個(gè)results variable是$CHOSEN_DIALOG_BUTTON$
它用來(lái)存放用戶按的是OK 還是Cancel
摘要: How to understand and use Eclipse Production Configuration
...
閱讀全文
摘要: 1.在tabbedProperties(eclipse3.2以上支持)中,如果要建立一個(gè)treeview,且想要click任何一列都可以實(shí)現(xiàn)celledit,需要在創(chuàng)建treeview的時(shí)候加上style: SWT.FULL_SELECTION
2.tabbedProperties中section的大小現(xiàn)在無(wú)法做到根據(jù)widget的大小自動(dòng)調(diào)整,目前只能用getMinimumHeight()返回一個(gè)固定值
閱讀全文
很多人在開發(fā)RCP時(shí),發(fā)現(xiàn)開發(fā)時(shí)都沒(méi)問(wèn)題,但導(dǎo)出成包時(shí)卻報(bào)找不到第三方庫(kù)中類的錯(cuò)誤。主要原因就是沒(méi)有將第三方庫(kù)配置好?,F(xiàn)在我給出一個(gè)實(shí)現(xiàn)項(xiàng)目的配置為示例,以供參考?!≡某鎏?http://www.eclipseworld.org/bbs/read.php?tid=1133 環(huán)境:Eclipse3.2M3 一個(gè)RCP的實(shí)際項(xiàng)目
一、
最關(guān)鍵的就是plugin.xml和MANIFEST.MF 所有界面上的最后操作,結(jié)果都是保存在這兩個(gè)文件中。注意:“.classpath”文件只是開發(fā)時(shí)對(duì)引用第三庫(kù)有用,打包發(fā)行之后它的作用就沒(méi)有了,還得靠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="事件細(xì)節(jié)"
??????????? 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="事件統(tǒng)計(jì)"
??????????? 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定義了項(xiàng)目依賴的插件。
(2)Bundle-ClassPath定義了引用的第三方庫(kù),別忘了把AdminConolse項(xiàng)目自己console.jar加進(jìn)去,否則連自己項(xiàng)目里的類都會(huì)找不到。
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文件。
這個(gè)文件主要是用Eclipse導(dǎo)出包的時(shí)候用。
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,這個(gè)放一些上面幾個(gè)文件用到的變量。
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?二、圖形方式 有時(shí)直接編輯plugin.xml等文件容易出錯(cuò)(全角空格什么的),那么可以用圖形編輯方式來(lái),不過(guò)最后結(jié)果還是反映到plugin.xml等文件中的。我把plugin.xml打開,然后一個(gè)項(xiàng)一個(gè)項(xiàng)的把圖截下來(lái),以供大家參考。
作者:hopeshared
引用地址:http://m.tkk7.com/hopeshared/archive/2005/12/20/24798.html
最近社區(qū)里問(wèn)這個(gè)問(wèn)題的人特別多,所以在這里將自己用到的幾個(gè)方法寫出來(lái)。假如以后還有其他的方法,會(huì)進(jìn)行更新。
從插件中獲得絕對(duì)路徑:
AaaaPlugin.getDefault().getStateLocation().makeAbsolute().toFile().getAbsolutePath());
通過(guò)文件得到Project:
IProject project = ((IFile)o).getProject();
通過(guò)文件得到全路徑:
String path = ((IFile)o).getLocation().makeAbsolute().toFile().getAbsolutePath();
得到整個(gè)Workspace的根:
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
從根來(lái)查找資源:
IResource resource = root.findMember(new Path(containerName));
從Bundle來(lái)查找資源:
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();
從編輯器來(lái)獲得編輯文件:
IEditorPart editor = ((DefaultEditDomain)(parent.getViewer().getEditDomain())).getEditorPart();
IEditorInput input = editor.getEditorInput();
if(input instanceof IFileEditorInput){
IFile file = ((IFileEditorInput)input).getFile();
}
在<<Eclipse從入門到精通>>里提到了一些獲取ImageDescriptor的方法,其中獲取本地圖片文件是用createfromurl來(lái)實(shí)現(xiàn)的,但我用這個(gè)方法總是無(wú)法成功,后來(lái)在網(wǎng)上找到了這個(gè)方法,比較管用:
AbstractUIPlugin.imageDescriptorFromPlugin(plugin的id, "icons/save.gif")