在窗口系統中,程序一般都是以事件驅動的。SWT的Control類實現了一些事件監聽的注冊方法,其子類都可以通過這些方法注冊鼠標和鍵盤的監聽器,通過實現這些監聽器的接口,窗口組件就能響應相應的鼠標和鍵盤事件。
Control類是窗口組件類的基類,它定義了基本的事件監聽方法,有如下一些:
addControlListener
addFocusListener
addHelpListener
addKeyListener
addMouseListener
addMouseTrackListener
addMouseMoveListener
addPaintListener
addTraverseListener
添加事件監聽器步驟如下:
1. 創建事件監聽器。例如:“new KeyListener()…”。
2. 通過Control類的子類添加事件監聽器。例如:“text.addKeyListener()”。
常用事件有鼠標事件、鍵盤事件、焦點事件、窗口控制事件和選擇事件,Control類的子類也可以定義添加相關的監聽方法。
在窗口系統中,鼠標基本上是必備的設備。一般來說,窗口中鼠標有鼠標單擊、鼠標雙擊、鼠標進入窗口、鼠標退出窗口及鼠標移動等事件。
在SWT中,事件的響應是通過相應接口實現的,每個組件可以添加相應的事件響應實例來監聽事件。例如“button.addMouseListener(listener)”,表示在button組件上添加鼠標的相應響應事件實例,其中,listener為實現監聽器對象,下面就具體的鼠標事件進行介紹。
MouseListener接口
在SWT中,通過實現MouseListener接口來響應鼠標的按下、松開及雙擊事件,MouseListener接口如例程1所示。
例程1 MouseListener.java
package org.eclipse.swt.events; import org.eclipse.swt.internal.SWTEventListener; public interface MouseListener extends SWTEventListener { public void mouseDoubleClick(MouseEvent e); public void mouseDown(MouseEvent e); public void mouseUp(MouseEvent e); }
其中,mouseDoubleClick表示鼠標雙擊事件響應方法,mouseDown表示鼠標鍵按下事件的響應方法,mouseUp表示鼠標鍵起來事件的響應方法,MouseEvent為系統傳入的鼠標事件的參數,MouseEvent中的button屬性表示鼠標的按鈕值,例如e.button等于1,表示鼠標左鍵按下,按鈕值對應鼠標按鈕如表1所示。
在程序中,開發人員可以根據e.button的值判斷當前用戶按的是哪一個鼠標鍵,從而確定采用什么操作。
MouseMoveListener接口
在SWT中,通過實現MouseMoveListener接口來響應鼠標的移動事件,MouseMoveListener接口如例程2所示。
例程2 MouseMoveListener.java
package org.eclipse.swt.events; import org.eclipse.swt.internal.SWTEventListener; public interface MouseMoveListener extends SWTEventListener { public void mouseMove(MouseEvent e); }
MouseMoveListener只有mouseMove方法,用來響應窗口中鼠標移動事件。
MouseTrackListener接口
在SWT中,通過實現MouseTrackListener接口來響應鼠標進入窗口、鼠標退出窗口和鼠標停放在窗口上的事件,MouseTrackListener接口如例程3所示。
例程3 MouseTrackListener.java
package org.eclipse.swt.events; import org.eclipse.swt.internal.SWTEventListener; public interface MouseTrackListener extends SWTEventListener { public void mouseEnter(MouseEvent e); public void mouseExit(MouseEvent e); public void mouseHover(MouseEvent e); }
其中,mouseEnter表示鼠標進入窗口事件的響應方法,mouseExit表示鼠標退出窗口事件的響應方法,mouseHover表示鼠標停放在窗口上事件的響應方法。
鼠標事件實例
為了更深入地理解鼠標事件,下面通過具體的實例演示如何響應鼠標事件。該程序只是當事件觸發時簡單地打印出相應信息,在具體的實例中,讀者可以根據需要進行修改,代碼如例程4所示。
例程4 MouseEventExample.java
/** * 為了節省篇幅,所有的import類已經被注釋 * 讀者可以通過ctrl+shift+o快捷鍵,自動引入所依賴的類 * 如果有問題可發郵件到ganshm@gmail.com * */ public class MouseEventExample implements MouseListener, MouseMoveListener, MouseTrackListener { //顯示信息的標簽 Label myLabel = null; Shell shell = null; public MouseEventExample() { } public void run() { Display display = new Display(); Shell shell = new Shell(display); shell.setLayout(new GridLayout()); shell.setSize(450, 200); shell.setText("Mouse Event Example"); myLabel = new Label(shell, SWT.BORDER); myLabel.setText("I ain't afraid of any old mouse"); //在當前窗口上添加鼠標響應事件 shell.addMouseListener(this); shell.addMouseMoveListener(this); shell.addMouseTrackListener(this); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } public static void main(String[] args) { new MouseEventExample().run(); } public void mouseDoubleClick(MouseEvent e) { myLabel.setText("Double Click " + e.button + " at: " + e.x + "," + e.y); System.out.println("Double Click " + e.button + " at: " + e.x + "," + e.y); } public void mouseDown(MouseEvent e) { myLabel.setText("Button " + e.button + " Down at: " + e.x + "," + e.y); System.out.println("Button " + e.button + " Down at: " + e.x + "," + e.y); } public void mouseUp(MouseEvent e) { myLabel.setText("Button " + e.button + " Up at: " + e.x + "," + e.y); System.out.println("Button " + e.button + " Up at: " + e.x + "," + e.y); } public void mouseMove(MouseEvent e) { myLabel.setText("Mouse Move at: " + e.x + "," + e.y); System.out.println("Mouse Move at: " + e.x + "," + e.y); } public void mouseEnter(MouseEvent e) { myLabel.setText("Mouse Enter at: " + e.x + "," + e.y); System.out.println("Mouse Enter at: " + e.x + "," + e.y); } public void mouseExit(MouseEvent e) { myLabel.setText("Mouse Exit at: " + e.x + "," + e.y); System.out.println("Mouse Exit at: " + e.x + "," + e.y); } public void mouseHover(MouseEvent e) { myLabel.setText("Mouse Hover at: " + e.x + "," + e.y); System.out.println("Mouse Hover at: " + e.x + "," + e.y); } }
MouseEventExample類實現了MouseListener、MouseMoveListener和MouseTrackListener 3個接口,并通過“shell.addMouseListener(this);”、“shell.addMouseMoveListener(this);”和“shell.addMouseTrackListener(this);”把自己作為監聽器添加到了窗口中,程序運行效果如圖1所示。
圖1 鼠標事件實例
package org.eclipse.swt.events; import org.eclipse.swt.internal.SWTEventListener; public interface FocusListener extends SWTEventListener { public void focusGained(FocusEvent e); public void focusLost(FocusEvent e); }
其中,focusGained表示組件獲得焦點事件的響應方法,focusLost表示組件失去焦點事件的響應方法,FocusEvent為系統傳入的焦點事件的參數,用戶可以通過FocusEvent參數找到相應的組件。
焦點事件實例
為了更深入地理解焦點事件,下面通過具體的實例演示如何響應焦點事件。該程序只是簡單地改變當前獲得焦點和失去焦點組件的顯示信息,在具體的實例中,讀者可以根據需要進行修改,代碼如例程8所示。
例程8 FocusListenerExample.java
public class FocusListenerExample { public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); shell.setLayout(new GridLayout(3, true)); shell.setText("One Potato, Two Potato"); //新建焦點監聽器 FocusListener listener = new FocusListener() { public void focusGained(FocusEvent event) { //獲得觸發事件的組件 Button button = (Button) event.getSource(); //焦點獲得時改變顯示文本 button.setText("I'm It!"); } public void focusLost(FocusEvent event) { //獲得觸發事件的組件 Button button = (Button) event.getSource(); //焦點獲得時改變顯示文本 button.setText("Pick Me!"); } }; for (int i = 0; i < 6; i++) { Button button = new Button(shell, SWT.PUSH); button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); button.setText("Pick Me!"); button.addFocusListener(listener); } shell.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }
程序中顯示了6個按鈕,并為按鈕添加上了焦點監聽器,程序運行效果如圖3所示。
圖3 焦點事件實例
窗口控制事件
在窗口系統中,當組件被移動或改變大小時將觸發相應的事件。SWT通過ControlListener監聽窗口控制事件。
ControlListener接口
在SWT中,通過實現ControlListener接口來響應組件被移動或改變大小的事件。ControlListener接口如例程9所示。
例程9 ControlListener.java
package org.eclipse.swt.events; import org.eclipse.swt.internal.SWTEventListener; public interface ControlListener extends SWTEventListener { public void controlMoved(ControlEvent e); public void controlResized(ControlEvent e); }
其中,controlMoved表示組件被移動事件的響應方法,controlResized表示組件被改變大小事件的響應方法,ControlEvent為系統傳入的窗口控制事件的參數,用戶可以通過ControlEvent參數找到相應的組件。
窗口控制事件實例
為了更深入地理解窗口控制事件,下面通過具體的實例演示如何響應窗口控制事件。該程序只是簡單地打印組件被移動或改變大小的信息,在具體的實例中,讀者可以根據需要進行修改,代碼如例程10所示。
例程10 ControlListenerExample.java
public class ControlListenerExample { public void run() { Display display = new Display(); Shell shell = new Shell(display); shell.addControlListener(new ControlListener() { public void controlMoved(ControlEvent e) { System.out.println("control move"); } public void controlResized(ControlEvent e) { System.out.println("control resize"); } } ); shell.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } public static void main(String[] args) { new ControlListenerExample().run(); } }
上例顯示的只是一個空白的窗口,當用戶移動窗口或改變窗口大小時,將會觸發監聽器所實現的事件。
SWT的很多組件都實現了選擇組件事件的監聽機制,例如按鈕、菜單項的選擇,當選擇了相關的菜單項或組件時,將觸發相應的事件。
SelectionListener接口
在SWT中,通過實現SelectionListener接口來響應選擇組件事件。SelectionListener接口如例程11所示。
例程11 SelectionListener.java
package org.eclipse.swt.events; import org.eclipse.swt.internal.SWTEventListener; public interface SelectionListener extends SWTEventListener { public void widgetSelected(SelectionEvent e); public void widgetDefaultSelected(SelectionEvent e); }
其中,widgetSelected表示組件被選擇事件的響應方法,widgetDefaultSelected表示組件默認選擇事件的響應方法,SelectionEvent為系統傳入的選擇事件的參數。
選擇組件事件實例
為了更深入地理解選擇組件事件,下面通過具體的實例演示如何響應選擇組件事件。該程序只是簡單地打印組件被移動或改變大小的信息,在具體的實例中,讀者可以根據需要進行修改,代碼如例程12所示。
例程12 SelectonListenerExample.java
public class SelectonListenerExample { public static void main(String[] args) { Display display = new Display(); final Shell mainShell = new Shell(display); Button button = new Button(mainShell, SWT.PUSH); button.setText("Close Me!"); button.setBounds(10, 10, 100, 30); // 添加選擇組件事件 button.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent event) { System.out.println("select button"); mainShell.close(); } public void widgetDefaultSelected(SelectionEvent e) { // 不執行任何操作 } }); mainShell.open(); while (!mainShell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }
上例中只是添加了一個按鈕,當選擇按鈕時關閉當前窗口。
其他常用事件
SWT中為了實現特定的功能,很多組件都提供了特定事件的響應,本節將通過實例介紹HelpListener、VerifyListener和ModifyListener 3個特定的事件監聽器。
HelpListener、VerifyListener和ModifyListener監聽器的功能
HelpListener監聽器通過helpRequested(HelpEvent e)方法響應用戶的幫助請求事件,當用戶在組件獲得焦點后按【F1】鍵將觸發此事件。
VerifyListener監聽器通過verifyText(VerifyEvent e)方法響應校驗輸入事件。此監聽器只對文本輸入校驗,當用戶輸入了數據后,verifyText方法將通過設置VerifyEvent中的doit屬性判斷輸入是否正確,從而確定修改是否有效。doit屬性為true時修改有效,即“e.doit = true;”。
ModifyListener監聽器通過modifyText(ModifyEvent e)方法響應文本被修改的事件。此監聽器只對文本輸入校驗。
提示:如果VerifyListener監聽器和ModifyListener監聽器同時存在的話,會先響應校驗輸入事件,如果校驗成功再響應修改事件。
HelpListener、VerifyListener和ModifyListener監聽器實例
在此實例中,用戶可以輸入華氏溫度和攝氏溫度,通過監聽器判斷輸入是否正確及計算相應的攝氏溫度和華氏溫度,另外,還可以按【F1】鍵獲得當前組件的信息,代碼如例程13所示。
例程13 MultipleListenersExample.java
public class MultipleListenersExample implements HelpListener, VerifyListener, ModifyListener { private static final double FIVE_NINTHS = 5.0 / 9.0; private static final double NINE_FIFTHS = 9.0 / 5.0; private Text fahrenheit; private Text celsius; private Label help; public void run() { Display display = new Display(); Shell shell = new Shell(display); shell.setText("Temperatures"); createContents(shell); shell.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } private void createContents(Shell shell) { shell.setLayout(new GridLayout(3, true)); new Label(shell, SWT.LEFT).setText("Fahrenheit:"); fahrenheit = new Text(shell, SWT.BORDER); GridData data = new GridData(GridData.FILL_HORIZONTAL); data.horizontalSpan = 2; fahrenheit.setLayoutData(data); fahrenheit.setData("Type a temperature in Fahrenheit"); // 為華氏溫度文本框添加監聽器 fahrenheit.addHelpListener(this); fahrenheit.addVerifyListener(this); fahrenheit.addModifyListener(this); new Label(shell, SWT.LEFT).setText("Celsius:"); celsius = new Text(shell, SWT.BORDER); data = new GridData(GridData.FILL_HORIZONTAL); data.horizontalSpan = 2; celsius.setLayoutData(data); celsius.setData("Type a temperature in Celsius"); //為攝氏溫度文本框添加監聽器 celsius.addHelpListener(this); celsius.addVerifyListener(this); celsius.addModifyListener(this); help = new Label(shell, SWT.LEFT | SWT.BORDER); data = new GridData(GridData.FILL_HORIZONTAL); data.horizontalSpan = 3; help.setLayoutData(data); } //響應幫助事件 public void helpRequested(HelpEvent event) { help.setText((String) event.widget.getData()); } //響應校驗事件 public void verifyText(VerifyEvent event) { event.doit = false; char myChar = event.character; String text = ((Text) event.widget).getText(); if (myChar == '-' && text.length() == 0) event.doit = true; if (Character.isDigit(myChar)) event.doit = true; if (myChar == '\b') event.doit = true; } //響應文本修改的事件 public void modifyText(ModifyEvent event) { // 刪除監聽器,從而在modifyText過程中不會觸發事件 celsius.removeVerifyListener(this); celsius.removeModifyListener(this); fahrenheit.removeVerifyListener(this); fahrenheit.removeModifyListener(this); Text text = (Text) event.widget; try { int temp = Integer.parseInt(text.getText()); if (text == fahrenheit) { celsius.setText(String.valueOf((int) (FIVE_NINTHS * (temp - 32)))); } else { fahrenheit.setText(String.valueOf((int) (NINE_FIFTHS * temp + 32))); } } catch (NumberFormatException e) { /* Ignore */ } //添加監聽器 celsius.addVerifyListener(this); celsius.addModifyListener(this); fahrenheit.addVerifyListener(this); fahrenheit.addModifyListener(this); } public static void main(String[] args) { new MultipleListenersExample().run(); } }
程序運行效果如圖4所示。
圖4 文本監聽器
提示:一般來說,監聽器都有一個抽象的Adaper類實現監聽器的方法,例如FocusAdapter實現了FocusListener的方法(方法為空)。如果讀者不想實現監聽器的全部方法則可以繼承監聽器的Adaper類,否則要實現監聽器接口的所有方法。