The Goal
Keep walking…… |
當(dāng)一個(gè)GC方法在一個(gè)Drawabel對(duì)象上畫出一個(gè)圖案,它僅執(zhí)行這個(gè)painting過程一次。如果用戶改變對(duì)象尺寸或是用另一個(gè)窗口去覆蓋它,則圖形會(huì)被消除。因此,應(yīng)用程序能否在外界事件影響下維持其外觀這一點(diǎn)相當(dāng)重要。
這些外部事件被稱為PaintEvents,接收它們的程序接口是PaintListener。一個(gè)Control在任何時(shí)候當(dāng)其外觀被應(yīng)用程序或是外界活動(dòng)改變都會(huì)觸發(fā)一個(gè)PaintEvent。這些類對(duì)于事件和監(jiān)聽器的使用方式都和我們?cè)诘谒恼聝?nèi)提到的類似。由于PaintListener只有一個(gè)事件處理方法,所以不需要使用adapter類
Canvas canvas = new Canvas(shell, SWT.NONE);
canvas.setSize(150, 150);
canvas.setLocation(20, 20);
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent pe)
{
GC gc = pe.gc;//每一個(gè)PaintEvent對(duì)象都包含有其自己的GC
gc.drawPolyline(new int[] {10,120,70,100,100,130,130,75});
}
});
shell.open();
每一個(gè)PaintEvent對(duì)象都包含有其自己的GC,主要有2個(gè)原因:1.因?yàn)檫@個(gè)GC instance是由事件產(chǎn)生的,所以PaintEvent會(huì)負(fù)責(zé)釋放他。2.應(yīng)用程序可以在shell open之前創(chuàng)建GC,這樣可以使圖形在一個(gè)獨(dú)立的類中被創(chuàng)建。
SWT在PaintListener接口內(nèi)優(yōu)化painting過程,SWT的開發(fā)者強(qiáng)烈建議Control的painting僅對(duì)PaintEvent作出反應(yīng)。如果一個(gè)應(yīng)用程序因?yàn)槠渌虮仨毟缕鋱D形,則他們推薦使用control的redraw()方法,這會(huì)在隊(duì)列中加入一個(gè)paint請(qǐng)求。之后,你可以調(diào)用update()方法來(lái)處理所有的綁定于該對(duì)象的paint請(qǐng)求。
需要牢記的是,雖然對(duì)于Control對(duì)象推薦在一個(gè)PaintListener內(nèi)painting,但是由于Device和Image對(duì)象并不能在該接口內(nèi)使用。如果你需要在一個(gè)image或device內(nèi)生成圖形,你必須單獨(dú)地生成一個(gè)GC對(duì)象并在使用結(jié)束后將其銷毀。
要客制化layout,需要繼承抽象類Layout,需要寫2個(gè)方法——computeSize() 和layout().
computeSize()
protected Point computeSize(Composite composite,
int wHint, int hHint,
boolean flushCache)
{
Point maxDimensions =
calculateMaxDimensions(composite.getChildren());
int stepsPerHemisphere =
stepsPerHemisphere(composite.getChildren().length);
int maxWidth = maxDimensions.x;
int maxHeight = maxDimensions.y;
int dimensionMultiplier = (stepsPerHemisphere + 1);
int controlWidth = maxWidth * dimensionMultiplier;
int controlHeight = maxHeight * dimensionMultiplier;
int diameter = Math.max(controlWidth, controlHeight);
Point preferredSize = new Point(diameter,
diameter);
... // code to handle case when our calculations
// are too large
return preferredSize;
}
參數(shù):
1.composite--The object we’re going to populate. At the time this method is called, it has children, but neither the composite nor the children have been sized or positioned on the screen.
2.wHint and hHint--layout所需的最大長(zhǎng)寬。若帶有參數(shù)SWT.DEFAULT,表示此layout可以隨意使用use whatever sizes it decides it needs.
3.flushCache--作為flag,to tell the layout whether it’s safe to use any cached values that it may be maintaining.
computeSize()的目的主要在于計(jì)算我們要layout的composite有多大
layout()
……
與之前所述的layout不同,form layout不是基于行和列的,它是基于與其他control之間的相對(duì)位置的。
FormLayout十分簡(jiǎn)單,你只要:1.設(shè)定頁(yè)邊距(高,寬)屬性。 2.設(shè)定spacing屬性,即所有control間的距離(in pixels)
同樣可以使用FormData來(lái)配置單個(gè)的control。
FormData
如果一個(gè)control沒有一個(gè)FormData實(shí)例來(lái)描述它的話,就會(huì)默認(rèn)放在composite的右上角
width和height屬性指定了control的尺寸,in pixels.
top, bottom, right, 和left屬性,每一個(gè)都有一個(gè)FormAttachment實(shí)例,這些attachments描述了control與其他control之間的關(guān)系。
FormAttachment
有2個(gè)使用途徑:
1.通過使用percentage of the parent composite.
2.通過設(shè)定一個(gè)control和另一個(gè)control之間的相對(duì)位置?
《圖》
package com.swtjface.Ch6;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class Ch6FormLayoutComposite extends Composite {
public Ch6FormLayoutComposite(Composite parent) {
super(parent, SWT.NONE);
FormLayout layout = new FormLayout();
setLayout(layout);
Text t = new Text(this, SWT.MULTI);
FormData data = new FormData();
data.top = new FormAttachment(0, 0);
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100);
data.bottom = new FormAttachment(75);//確定text的位置,因?yàn)樽笊辖鞘亲鴺?biāo)原點(diǎn),所以right的百分?jǐn)?shù)為100。
t.setLayoutData(data);
Button ok = new Button(this, SWT.NONE);
ok.setText("Ok");
Button cancel = new Button(this, SWT.NONE);
cancel.setText("Cancel");
data = new FormData();
data.top = new FormAttachment(t);
data.right = new FormAttachment(cancel);//ok按鈕在text下面,cancel左邊
ok.setLayoutData(data);
data = new FormData();
data.top = new FormAttachment(t);
data.right = new FormAttachment(100);//cancel按鈕在text下面,在最右邊
cancel.setLayoutData(data);
}
}
最常用的一種layout.以row layout為基礎(chǔ)。
package com.swtjface.Ch6;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class Ch6GridLayoutComposite extends Composite {
public Ch6GridLayoutComposite(Composite parent) {
super(parent, SWT.NONE);
GridLayout layout = new GridLayout(4,false);//每一行有4個(gè)control,后一個(gè)參數(shù)是a
boolean to indicate whether the columns should take up an even amount of
space. By passing false, you tell the layout to only use the minimum amount of
space needed for each column.
setLayout(layout);
for (int i = 0; i < 16; ++i) {
Button button = new Button(this, SWT.NONE);
button.setText("Cell " + i);
}
}
}
Using GridData styles
十分類似于RowData對(duì)象。可通過其構(gòu)造函數(shù)來(lái)設(shè)定STYLE,這些STYLE可分為3類:FILL, HORIZONTAL_ALIGN, and VERTICAL_ALIGN.
1.FILL:此cell是否fill所有的availabe的空間。可用的值還包括FILL_HORIZONTAL(水平擴(kuò)張),FILL_VERTICAL(垂直擴(kuò)張),FILL_BOTH。
2.ALIGN,用來(lái)指定control在cell中的什么位置。值包括BEGINNING, END, CENTER和FILL。
具體參見下表
Using GridData size attributes
與RowData不同,GridData還有很多的public屬性。其中有些是布爾值類型的,一般會(huì)根據(jù)所設(shè)置的不同styles而自動(dòng)管理,所以無(wú)需對(duì)其直接操作。還有一些是integer值,用來(lái)確定單個(gè)cells的大小。具體件下表:
默認(rèn)為從左到右排放的,根據(jù)每個(gè)control實(shí)際所需的大小來(lái)分配空間,此composite中多于出來(lái)的空間,再平攤到每個(gè)control上。隨著composite的大小調(diào)整,control的大小也會(huì)跟著調(diào)整。
package com.swtjface.Ch6;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class Ch6FillLayoutComposite extends Composite {
public Ch6FillLayoutComposite(Composite parent) {
super(parent, SWT.NONE);
FillLayout layout = new FillLayout( SWT.VERTICAL); //默認(rèn)是SWT.HORIZONTAL
setLayout(layout);//為此Composite設(shè)定一個(gè)layout.如果漏了此語(yǔ)句,會(huì)顯示不出child control。
for (int i = 0; i < 8; ++i) {
Button button = new Button(this, SWT.NONE);
button.setText("Sample Text");
}
}
}
是JFace的類,繼承自ContributionManager,凡是繼承了IAction或IContribution接口的對(duì)象都可被加至ToolBarManager.你只要花時(shí)間為ToolBarManager添加Action,Toolbar和ToolItem實(shí)例會(huì)自動(dòng)產(chǎn)生。
你可通過調(diào)用ApplicationWindow的createToolBarManager()來(lái)為你的應(yīng)用程序添加一個(gè)toolbar。與MenuManager不同的是,createToolBarManager()需要一個(gè)style參數(shù),這個(gè)參數(shù)用來(lái)設(shè)定ToolBar所用的按鈕的風(fēng)格:flat或normal。
除了MenuManager所用的ContributionItems之外,還有一個(gè)新的ContributionItem,只能被ToolBarManager使用——ControlContribution。這個(gè)類可將任何能被用于toolbar的Control打包進(jìn)去。
要使用ControlContribution類,必須要實(shí)現(xiàn)抽象方法createControl().
toolBarManager.add(new ControlContribution("Custom") {
protected Control createControl(Composite parent) {
SashForm sf = new SashForm(parent, SWT.NONE);
Button b1 = new Button(sf, SWT.PUSH);
b1.setText("Hello");
Button b2 = new Button(sf, SWT.PUSH);
b2.setText("World");
b2.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
System.out.println("Selected:" + e);
}
});
return sf;
}
});
如果你希望有任何的事件發(fā)生,必須在你的controls上實(shí)現(xiàn)SelectionListeners
如果你不想ToolBarManager來(lái)創(chuàng)建toolbar的話,可以手動(dòng)創(chuàng)建,需要用到ToolBar和ToolItem類.
Toolbar
是一個(gè)composite control,包含多個(gè)ToolItems.Toolbar由多個(gè)小圖標(biāo)按鈕組成,一般是16-by-16bitmap圖片。每個(gè)按鈕都對(duì)應(yīng)一個(gè)ToolItem。Toolbar可以是水平的也可以是垂直的,默認(rèn)為水平
ToolItem
每一個(gè)ToolItem都有一個(gè)圖片,如果沒有,默認(rèn)為紅色方塊。When the user selects a ToolItem from the menu, it broadcasts the event to any registered SelectionListeners.Your application should register a listener with each ToolItem and use that listener to perform whatever logic corresponds to the menu item.
三種類型的Combo control:
1.Simple:默認(rèn)類型,一個(gè)可編輯的text field和一個(gè)供選擇的list
2.Drop-down:下拉列表,文本框可編輯
3.Read-only:文本框不可編輯的下拉列表,可用select( 0 )來(lái)將其默認(rèn)選中列表中的首項(xiàng)。
以上三種類型可在構(gòu)造函數(shù)中通過STYLE.*來(lái)設(shè)置。
先要將org.eclipse.text_x.y.z和org.eclipse.jface.text_x.y.z加到classpath
兩個(gè)重要的接口:IDocument和ITextViewer。JFace為其提供了默認(rèn)的實(shí)現(xiàn)。
一個(gè)IDocument的實(shí)例持有被編輯的真實(shí)的文本信息。它的主要實(shí)現(xiàn)是Document類。AbstractDocument提供了部分實(shí)現(xiàn),你可通過繼承它來(lái)添加自己的實(shí)現(xiàn)。IDocument允許通過IDocumentListener接口來(lái)獲取內(nèi)容編輯的通知。
IDocument還提供了以下功能
Positions
可以給每一個(gè)text區(qū)域分配一個(gè)記號(hào)來(lái)作為它的Position。當(dāng)被指定給某個(gè)ducument時(shí)一個(gè)Position對(duì)象有an offset and a length of text。如果document的text被更新的話,Position也會(huì)同步更新,所以他永遠(yuǎn)都是指向同一段文字。Position類本身提供了一些基本的功能,可通過繼承他來(lái)完善更多有用的功能。
Partition content types
每個(gè)document由一個(gè)或多個(gè)partitions組成,通過ITypedRegion接口來(lái)表現(xiàn)。每一個(gè)partition可以有各自的內(nèi)容類型,如plain text, rich text, or HTML。要使用它,你要?jiǎng)?chuàng)建一個(gè)IDocumentPartitioner然后assign給你的document,然后document的partitioner就會(huì)負(fù)責(zé)響應(yīng)對(duì)指定位置內(nèi)容類型的查詢,它必須通過實(shí)現(xiàn)computePartitioning()來(lái)返回包含此document中所有ITypedRegions的一個(gè)數(shù)組。不需要實(shí)現(xiàn)你自己的document partitioner。如果沒有創(chuàng)建,整個(gè)document就是一個(gè)區(qū)域,類型為IDocument.DEFAULT_CONTENT_TYPE。
Searching
IDocument通過search()提供了搜索的功能。不支持regular expressions or other patterns,但提供了search start location,direction, and case sensitivity and whether to match whole words only.
ITextViewer將一個(gè)標(biāo)準(zhǔn)的text widget轉(zhuǎn)換成一個(gè)基于document的text widget
ITextViewer的默認(rèn)實(shí)現(xiàn)是TextViewer,它使用StyledText來(lái)顯示數(shù)據(jù)。ITextViewer支持text modifications的listener,也支持visual events(如改變viewport,即text的當(dāng)前可視區(qū)域)的監(jiān)聽器。
雖然作為ITextViewer的默認(rèn)應(yīng)用,如果你想要修改顯示,TextViewer允許你直接accessStyledText,但建議你使用TextPresentation,因?yàn)樗梢允占撐臋n中帶有的各個(gè)不同的StyleRanges。
ITextViewer還支持很多不同類型的插件,可用來(lái)修改widget的行為。可以被customized的功能有:
1.通過IUndoManager來(lái)支持undo
2.通過ITextDoubleClickStrategy來(lái)支持對(duì)鼠標(biāo)雙擊的處理
3.通過IAutoIndentStrategy來(lái)支持文本的自動(dòng)縮進(jìn)
4.通過ITextHover來(lái)實(shí)現(xiàn),當(dāng)鼠標(biāo)停留在document的一個(gè)section上時(shí),顯示text.
要使用上述插件,你需要分配一個(gè)適當(dāng)?shù)慕涌趯?shí)例給text viewer,然后調(diào)用activatePlugins().
如下列出了org.eclipse.jface.text的子包及其作用
用于文本編輯的control有2個(gè):Text和StyledText.后者可以為文本和control本身設(shè)定顏色,格式等。這兩個(gè)control之間毫無(wú)關(guān)聯(lián),除了都是Composite的子類之外。
package com.swtjface.Ch5;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
public class Ch5Capitalizer extends Composite {
public Ch5Capitalizer(Composite parent) {
super(parent, SWT.NONE);
buildControls();
}
private void buildControls() {
this.setLayout(new FillLayout());
Text text = new Text(this, SWT.MULTI | SWT.V_SCROLL);
text.addVerifyListener(new VerifyListener() { //每當(dāng)text被改變,任何以注冊(cè)的VerifyListeners便會(huì)被調(diào)用。此處每按一次鍵盤,此方法就被調(diào)用。如果是同時(shí)輸入多個(gè)字符,也調(diào)用一次
public void verifyText(VerifyEvent e) {
if( e.text.startsWith("1") ) {
e.doit = false;
} //如果文本以1開頭,即不允許編輯
else {
e.text = e.text.toUpperCase();
}
}
});
}
}
Text的重要方法,見下圖
insert()--doesn’t allow you to insert text into the existing content.
StyledText包含了一系列的應(yīng)用到該小部件的預(yù)定義的動(dòng)作,這些是常規(guī)的東西如:剪切、粘貼、移動(dòng)至下一個(gè)詞、移動(dòng)至文末。代表這些動(dòng)作的常量在org.eclipse.swt.custom程序包中的ST類中有定義。這些常量在兩種情況下發(fā)揮功效:首先,你可以使用它們程序性地使用invokeAction()方法調(diào)用任一的這些方法;其次,你也可以使用setKeyBinding()方法來(lái)將它們綁定于鍵擊行為。setKeyBinding()選定一個(gè)鍵(可以通過諸如Shift或是Ctrl之類的編輯鍵來(lái)修改SWT常量之一)綁定于指定的動(dòng)作。如下的例子中組合鍵Ctrl-Q綁定于粘貼動(dòng)作。引起注意的是這并不意味著會(huì)將默認(rèn)鍵的綁定清除,該兩個(gè)綁定都會(huì)生效。
相對(duì)于Text而言,還添加了drawing line backgrounds and line styles的事件,可以通過此事件來(lái)改變整行的style或背景顏色。注意:如果使用了LineStyleListener,就不能在StyledText實(shí)例上調(diào)用get/setStyleRange(), 如果使用了LineBackgroundListener,那你就不能調(diào)用getLineBackground() or setLineBackground().
可以通過使用一個(gè)StyledText的StyleRanges來(lái)改變顯示的風(fēng)格
StyleRange
StyledText通過使用StyleRange類來(lái)管理當(dāng)前所顯示的不同styles。其所有的欄位都是public的可隨意修改,但是要一直到當(dāng)此StyledText實(shí)例的setStyleRange()被調(diào)用之后才會(huì)生效。
StyleRanges通過開始偏移量和長(zhǎng)度來(lái)設(shè)定text的區(qū)域范圍。
StyleRange可設(shè)定背景和前景色,默認(rèn)為null,還可設(shè)定字體,SWT.NORMAL 或者SWT.BOLD.
similarTo()可用來(lái)判斷兩個(gè)StyleRange實(shí)例是否有同樣的前景、背景和字體。
當(dāng)我們保存text之后,可通過styledText.getStyleRanges()來(lái)獲取style信息,此函數(shù)會(huì)返回an array of StyleRange
toggleBold()--將已輸入的文本在bold和normal之間切換,是被一個(gè)KeyListener調(diào)用的,此KeyListener會(huì)監(jiān)聽F1是否被按下
A StyledText example
復(fù)制、粘貼功能不需要通過代碼便可使用,是和platform的標(biāo)準(zhǔn)鍵盤快捷方式相關(guān)聯(lián)的
ExtendedModifyListener和ModifyListener不同,前者提供了關(guān)于what was done的event細(xì)節(jié),而后者只是當(dāng)編輯懂作產(chǎn)生時(shí)notify,不會(huì)去準(zhǔn)確的辨別到底何種修改發(fā)生了。
package com.swtjface.Ch5;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
public class Ch5Undoable extends Composite {
private static final int MAX_STACK_SIZE = 25;
private List undoStack;
private List redoStack;
private StyledText styledText;
public Ch5Undoable(Composite parent) {
super(parent, SWT.NONE);
undoStack = new LinkedList();
redoStack = new LinkedList();
buildControls();
}
private void buildControls() {
this.setLayout(new FillLayout());
styledText = new StyledText(this, SWT.MULTI | SWT.V_SCROLL);
styledText.addExtendedModifyListener(
new ExtendedModifyListener() { //每次text被編輯的時(shí)候,都會(huì)調(diào)用此listener
public void modifyText(ExtendedModifyEvent event) {
String currText = styledText.getText();
String newText = currText.substring(event.start,
event.start + event.length); //獲得新插入的文本
if( newText != null && newText.length() > 0 ) {
if( undoStack.size() == MAX_STACK_SIZE ) {
undoStack.remove( undoStack.size() - 1 );
}
undoStack.add(0, newText);//將新插入的文本保存到undoStack中
}
}
}); //關(guān)鍵部分
styledText.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
switch(e.keyCode) {
case SWT.F1:
undo(); break;
case SWT.F2:
redo(); break;
default: //ignore everything else
}
}
});
}
private void undo() {
if( undoStack.size() > 0 ) {
String lastEdit = (String)undoStack.remove(0);//得到要undo的字符
int editLength = lastEdit.length();
String currText = styledText.getText();
int startReplaceIndex = currText.length() - editLength;
styledText.replaceTextRange(startReplaceIndex, editLength, ""); //將最后輸入的字符替換成空
redoStack.add(0, lastEdit);//把最后的這個(gè)undo的字符加到redoStack中
}
}
private void redo() {
if( redoStack.size() > 0 ) {
String text = (String)redoStack.remove(0);//得到要恢復(fù)的字符
moveCursorToEnd();
styledText.append(text);//將要恢復(fù)的字符加至文本的最后
moveCursorToEnd();
}
}
private void moveCursorToEnd() {
styledText.setCaretOffset(styledText.getText().length());
}
}
ActionContributionItem--combines the function of a GUI widget and its attached listener class.
Action--處理事件
與SWT的listener/event模式很類似,但是其class更抽象,更易于使用,scope更窄。
Action--可以簡(jiǎn)單的理解成一個(gè)命令,可以關(guān)聯(lián)到菜單,工具條,以及按鈕
Contribution--在JFace里面,一個(gè)Action可以對(duì)應(yīng)多個(gè)GUI對(duì)象,這些對(duì)象就是所謂的Contribution Item. 有兩個(gè)主要的Contribution類:ContributionItem和ContributionManager,它們都是抽象類,靠其子類來(lái)實(shí)現(xiàn)事件的處理。繼承關(guān)系見下圖
ContributionItem--引發(fā)事件的單獨(dú)GUI組件
ContributionManager--產(chǎn)生包含ContributionItems的對(duì)象
ActionContributionItem--最重要,在ApplicationWindow中創(chuàng)建和實(shí)施,來(lái)將一個(gè)action連接至此GUI,它雖沒有設(shè)定好的外觀,但是依賴于你使用的fill()方法,卻可以幫助一個(gè)按鈕、菜單欄和工具欄的成形
另一個(gè)與Contribution協(xié)作的方法是通過ContributionManager,它的子類類似于ContributionItem的container。其中MenuManager將ContributionItems組合在窗口最高層菜單, ToolBarManager則將這些對(duì)象放在僅在菜單之下的toolbar中。
Action是抽象類。
package com.swtjface.Ch4;
import org.eclipse.jface.action.*;
import org.eclipse.jface.resource.*;
public class Ch4_StatusAction extends Action
{
StatusLineManager statman;
short triggercount = 0;
public Ch4_StatusAction(StatusLineManager sm)
{
super("&Trigger@Ctrl+T",
AS_PUSH_BUTTON);//在T字母之前的&符號(hào)意味著這個(gè)字母將作為該動(dòng)作的快捷鍵。而在TEXT領(lǐng)域內(nèi)的“Ctrl+T”確保了當(dāng)用戶在同時(shí)按下Ctrl鍵和T鍵時(shí)該動(dòng)作就會(huì)被激發(fā)。
statman = sm;
setToolTipText("Trigger the Action");
setImageDescriptor(ImageDescriptor.createFromFile
(this.getClass(),"eclipse.gif"));
}
public void run() //每次當(dāng)Ch4_StatusAction被生成,run()方法就被調(diào)用
{
triggercount++;
statman.setMessage("The status action has fired. Count: " +
triggercount);
}
package com.swtjface.Ch4;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.jface.window.*;
import org.eclipse.jface.action.*;
public class Ch4_Contributions extends ApplicationWindow {
StatusLineManager slm = new StatusLineManager();
Ch4_StatusAction status_action = new Ch4_StatusAction(slm); //用StatusLineManager的對(duì)象作參數(shù),創(chuàng)建了一個(gè)Ch4_StatusAction的實(shí)例
ActionContributionItem aci = new ActionContributionItem(status_action); //用Ch4_StatusAction的對(duì)象作參數(shù),創(chuàng)建了ActionContributionItem對(duì)象
public Ch4_Contributions() {
super(null); // 創(chuàng)建了 ApplicationWindow對(duì)象
addStatusLine();
addMenuBar();
addToolBar(SWT.FLAT | SWT.WRAP); //在窗口上添加了status line, menu, toolbar
}
protected Control createContents(Composite parent) {
getShell().setText("Action/Contribution Example");
parent.setSize(290,150); //設(shè)置了窗口的title和size
aci.fill(parent); // 將ActionContributionItem放在GUI中。因?yàn)檫@里的參數(shù)是Composite對(duì)象,所以根據(jù)Action的STYLE屬性來(lái)確定。此處是Button,因?yàn)?font color="#0000ff">Ch4_StatusAction 的STYLE屬性是AS_PUSH_BUTTON;
return parent;
}
public static void main(String[] args) {
Ch4_Contributions swin = new Ch4_Contributions();
swin.setBlockOnOpen(true);
swin.open();
Display.getCurrent().dispose();
}
protected MenuManager createMenuManager() {
MenuManager main_menu = new MenuManager(null);
MenuManager action_menu = new MenuManager("Menu");
main_menu.add(action_menu);
action_menu.add(status_action); //關(guān)聯(lián)status_action.created and added to the menu in the form of a menu item
return main_menu;
}
protected ToolBarManager createToolBarManager(int style) {
ToolBarManager tool_bar_manager = new ToolBarManager(style);
tool_bar_manager.add(status_action); //關(guān)聯(lián)status_action。created and added to the toolbar as a toolbar item.
return tool_bar_manager;
}
protected StatusLineManager createStatusLineManager() {
return slm;
}
}
兩個(gè)途徑來(lái)將ActionContributionItem添加到GUI:
1. 通過ContributionManager子類的add()方法。
(1)可接受Action對(duì)象的參數(shù),從而間接的將ContributionItem和ContributionManager關(guān)聯(lián)。可多次執(zhí)行
(2)可直接接受ActionContributionItem對(duì)象的參數(shù)。只可執(zhí)行一次
2.通過ActionContributionItem類的fill()方法。根據(jù)其參數(shù)的不同,所先是的組件也不同,具體見下表:
Important methods of the Action class
Property methods for the Action class
DESCRIPTION--written to a status line to provide additional help.
Style methods for the Action class
如果ENABLED是FALSE,則變灰。CHECKED主要用于radio和checkbox
Accelerator key / keyboard methods for the Action class
Accelerator keys--鼠標(biāo)點(diǎn)擊的鍵盤塊捷方式
Listener methods for the Action class
雖然JFace使用action代替了SWT的listener/event機(jī)制,但是Actiono類仍然可以和listener協(xié)作來(lái)處理特定需求的事件。
IPropertyChangeListener接口關(guān)注客戶自定義的PropertyChangeEvents,當(dāng)所給的對(duì)象按照你所給的方式變成另一個(gè)對(duì)象時(shí),此事件被觸發(fā)。
Miscellaneous methods of the Action class
1. Once an SWT application begins running, its Display class sorts through this queue using its readAndDispatch() method and msg field, which acts as a handle to the underlying OS message queue.
2. If it finds anything relevant, it sends the event to its top-level Shell object, which determines which widget should receive the event.
3. The Shell then sends the event to the widget that the user acted on, which transfers this information to an associated interface called a listener.
4. One of the listener’s methods performs the necessary processing or invokes another method to handle the user’s action, called an event handler.
所在包:org.eclipse.swt.events
??
typed listeners--只對(duì)某一類的用戶事件起作用,繼承TypedListener類
typed events--與此類特定動(dòng)作相關(guān)的事件,繼承TypedEvent類
可通過add...Listener()method with the typed listener as the argument來(lái)將listener附加到widget。
完整的typed events和listeners列表,如下:?
TypedEvent類包含了一些member field,他們提供與事件發(fā)生相關(guān)的一些信息,這些信息可以在event handler中使用來(lái)獲得與環(huán)境相關(guān)的信息。下圖為繼承自TypedEvent及EventObject類的fields:
除此之外,很多的event類還有其他用來(lái)提供更多用戶動(dòng)作信息的fields,如MouseEvent類的button field
要將listener加入到code中,有兩個(gè)主要的方法:
第一個(gè)是在component的add...Listener()中創(chuàng)建一個(gè)匿名接口,這樣可以使listener的作用域僅限于此component,示例代碼如下:
Button button = new Button(shell, SWT.PUSH | SWT.CENTER);//創(chuàng)建了一個(gè)button,并將其加入到shell中
button.addMouseListener(new MouseListener() //創(chuàng)建了一個(gè)匿名MouseListener接口,并將其與button關(guān)聯(lián)
{
public void mouseDown(MouseEvent e)
{
clkdwnEventHandler();
}
public void mouseUp(MouseEvent e)
{
clkupEventHandler();
}
public void mouseDoubleClick(MouseEvent e)
{
dblclkEventHandler(); //此接口中必須被實(shí)現(xiàn)的三個(gè)方法。一旦鼠標(biāo)按下,放開或雙擊,就會(huì)有一個(gè)MouseEvent被發(fā)送到這三個(gè)方法中的一個(gè),然后,此方法再調(diào)用相關(guān)聯(lián)的event-handling方法(即下文中的三個(gè))。
}
});
static void dblclkEventHandler()
{
System.out.println("Double click.");
}
static void clkdwnEventHandler()
{
System.out.println("Click - down.");
}
static void clkupEventHandler()
{
System.out.println("Click - up.");//event-handlers通過發(fā)送message到console來(lái)完成事件處理
}
上一類方法的缺點(diǎn)是此listener僅限于此component內(nèi),而第二種方法便可解決這種問題--獨(dú)立的聲明一個(gè)繼承MouseListener的接口,示例代碼如下:
Button button = new Button(shell, SWT.PUSH | SWT.CENTER);
button.addMouseListener(ExampleMouseListener);
MouseListener ExampleMouseListener = new MouseListener()
{
public void mouseDoubleClick(MouseEvent e)
{
System.out.println("Double click.");
}
public void mouseDown(MouseEvent e)
{
System.out.println("Click - down.");
}
public void mouseUp(MouseEvent e)
{
System.out.println("Click - up.");
}
};
使用MouseListener的缺點(diǎn)就是哪怕你只關(guān)心鼠標(biāo)雙擊事件,卻仍要聲明其接口中所包含的所有方法。?
Adapter是繼承了Listener接口并提供了所有required方法的實(shí)現(xiàn)的abstract類。也就是說如果你使用adapter而不是listener的話,你只需要寫你感興趣的方法
只有那些listener有多個(gè)成員方法的event才有adapter,其完整列表見下圖:
adapter同樣是通過add...Listener()方法來(lái)創(chuàng)建的,與listener類似,同樣也可通過匿名類和本地類兩種方法,下例為匿名類方法:
button.addMouseListener(new MouseAdapter()
{
public void mouseDoubleClick(MouseEvent e)
{
dblclkEventHandler();
}
)};
static void dblclkEventHandler()
{
System.out.println("Double click.");
}
任何時(shí)候只要key被按下,就會(huì)創(chuàng)建KeyEvent,它有兩個(gè)子類:TraverseEvent 和VerifyEvent.
TraverseEvent--當(dāng)按下arrow key或tab key來(lái)focus on text widget時(shí)
VerifyEvent--fires when the user enters text that the program needs to check before taking further action.
除了繼承自TypedEvent和EventObject的field,KeyEvent還包括三個(gè)member field來(lái)提供那些與觸發(fā)事件的key相關(guān)的信息,具體如下:
character--代表被按下key的char
stateMask--Returns an integer representing the state of the keyboard modifier keys.By examining this integer, a program can determine whether any of the Alt, Ctrl, Shift, and Command keys are currently pressed.
keyCode--Provides the SWT public constant corresponding to the typed key. KeyCode列表,見下圖:
TraverseEvent中有兩個(gè)fields:
1. doit--返回布爾值,若為真則允許在各個(gè)component間切換focus,若為假則不允許切換focus
2. detail--It’s an integer that represents the identity of the key that caused the event. For example, if the user presses the Tab key to switch to a new component, the detail field will contain the SWT constant TRAVERSE_TAB_NEXT.
每個(gè)類型的Control對(duì)于所給的traversal key都有不同的默認(rèn)behavior,如果設(shè)doit為true,則override了其默認(rèn)的設(shè)置。
VerifyEvent的field:
1.start和end--設(shè)定了輸入的范圍
2.text--contains the input String under examination.
3.doit--Having looked at the user’s text, you set the boolean doit field to allow (TRUE) or disallow (FALSE) the action.
更靈活,但不安全,不推薦使用。
當(dāng)一個(gè)代表著非類型化監(jiān)聽器的監(jiān)聽器類和GUI的某一組件相聯(lián)系時(shí),它就能接受該組件所能發(fā)送的任一類事件。因此,你需要操控這由Event類代表的捕獲的全部事件,決定用戶執(zhí)行的那個(gè)動(dòng)作。然后,正確的事件處理方法就被調(diào)用。
不是被包含在org.eclipse.swt.events包中,而是被包含在org.eclipse.swt.widgets包中。
代碼示例如下:
Listener listener = new Listener ()
{
public void handleEvent (Event event)
{
switch (event.type)
{
case SWT.KeyDown:
if (event.character == 'b')
System.out.println("Key"+event.character);
break;
case SWT.MouseDown:
if (event.button == 3)
System.out.println("Right click");
break;
case SWT.MouseDoubleClick:
System.out.println("Double click");
break;
}
}
};
Button button = new Button(shell, SWT.CENTER);
button.addListener(SWT.KeyDown, listener);
button.addListener(SWT.MouseDown, listener);
button.addListener(SWT.MouseDoubleClick, listener);
Event類包含了所有typed event中的所有field,此外還有一個(gè)type field,其所有的值列表如下:
getChildren()
lists the children of a Composite as an array of Control objects.
getLayout()、setLayout(Layout)
處理layout對(duì)象
getTabList()、setTabList(Control[])
指定widgets在Composite中的Tab順序(按鍵盤tab鍵的切換順序)
Composite類是Scrollable類的直接子類,這就是說SWT/JFace中的所有Composite對(duì)象都有Scrollbars.所有的Scrollable對(duì)象都可使用如下方法:
getClientArea()、 computeTrim(int, int,int, int)
trim--Composite的不可編輯區(qū)域,如title bars, scrollbars, 或status bars等.
client area--那些可編輯,使用的區(qū)域
getClientArea()--Returns the available display area of a Scrollable object
computeTrim(int,int,int,int)--Returns the necessary dimensions of the Composite for the desired client area
getHorizontalBar()、getVerticalBar()
Returns the horizontal/vertical ScrollBar object
Control, Scrollable, and Composite的關(guān)系,如下圖??
Composite子類中最簡(jiǎn)單的一個(gè),自身不執(zhí)行任何動(dòng)作,僅僅是將一組子widgets用矩形邊框起來(lái),此邊框類似于之前提到的分隔符,同樣也提供SWT.SHADOW_IN, SWT.SHADOW_OUT, SWT.SHADOW_NONE風(fēng)格,還可以通過選擇SWT.SHADOW_ETCHED_IN or SWT.SHADOW_ETCHED_OUT來(lái)客制化陰影效果。
可以通過setText()方法來(lái)設(shè)定它的label
與許多Widgets子類一樣,Group類不可被繼承。
可以在子widgets之間創(chuàng)建可移動(dòng)的分界,此分界稱為Sash.Sash類可以在org.eclipse.swt.widgets包中找到,而SashForms卻存在于org.eclipse.swt.custom包中。
SWT.HORIZONTAL和SWT.VERTICAL--用來(lái)設(shè)定Sash的方向
setOrientation()--用來(lái)設(shè)定Sash的方向
getMaximizedControl()--returns the Control object that has been expanded the most.
getWeights()--returns an int array containing the weight of each of the SashForm’s children.uses an int array to specify weights for each of the widgets in the Composite.
creating and populating a TabFolder的四個(gè)步驟:
1.?創(chuàng)建一個(gè)TabFolder實(shí)例
2. 為每個(gè)頁(yè)面構(gòu)建一個(gè)TabItem對(duì)象
3. 用setText()方法來(lái)設(shè)定tab的label
4. setControl()--關(guān)聯(lián)一個(gè)control,當(dāng)它的tab被選中時(shí),顯示此control
TabFolder類提供了一些用來(lái)獲得TabItems信息的方法,如下:
getItemCount()
返回此TabFolder所包含的TabItems數(shù)
getItems()
返回TabItems對(duì)象的數(shù)組
getSelection()
確定user選擇了哪個(gè)TabItem
setSelection()
Makes this decision from within the application
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
26 | 27 | 28 | 1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 | |||
12 | 13 | 14 | 15 | 16 | 17 | 18 | |||
19 | 20 | 21 | 22 | 23 | 24 | 25 | |||
26 | 27 | 28 | 29 | 30 | 31 | 1 | |||
2 | 3 | 4 | 5 | 6 | 7 | 8 |