Java - Implement SWT Text Input selection by "mouseDoubleClick event"

在這邊將探討如何在SWT Text輸入元件下,自行定義selection的行為在mouse double click的情況之下,因為Text在double click內容時,預設的行為會是整段資料做全選的動作!

相關程式碼如下:
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class TextInputSelection {

 public static void main(String[] args) {
        // TODO Auto-generated method stub
        Display display = new Display();

        Shell shell = new Shell(display);
        shell.setText("Text Selection");
        shell.setLayout(new GridLayout(1, false));
        shell.setSize(400, 300);
        
        Text input = new Text(shell, SWT.BORDER);
        input.setText("00:00:00");
        input.setDoubleClickEnabled(false);
        GridData grid = new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1);
        grid.widthHint = 100;
        grid.heightHint = 30;
        input.setLayoutData(grid);
        
        FontData fontData = input.getFont().getFontData()[0];
        fontData.setHeight(16);
        Font font = new Font(display, new FontData(fontData.getName(), fontData.getHeight(), SWT.NONE));
        input.setFont(font);
        
        input.setForeground(display.getSystemColor(SWT.COLOR_GRAY));
        input.addMouseListener(new MouseAdapter() {
        public void mouseDoubleClick(MouseEvent e) {
          Text input = (Text) e.widget;
          String text = input.getText();
          int curPos = input.getCaretPosition();
          if(curPos == text.length()) {
             return;
          }
          int start = text.lastIndexOf(":", curPos);
          int end = text.indexOf(":", curPos);
          
          start = (start == -1) ? 0 : start + 1;
          end = (end == -1) ? text.length() : end;
          System.out.println("mouseDoubleClick..."+start+", "+end);
          input.setSelection(start, end);
         }
        });
        
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        font.dispose();
        display.dispose();
 }

}

在此將說明的是,為何需要呼叫setDoubleClickEnabled且指定為false
查了一下Text的source code,若設定該method為false,在Text內doubleClick全域變數set為false,如此一來method WM_LBUTTONDBLCLK內原本預設的double click行為將被disable,看這樣子Text double click會全選的行為似乎是windows本身定義好的!
相關註解如下,詳見org.eclipse.swt.widgets.Text:
/*
* Prevent Windows from processing WM_LBUTTONDBLCLK
* when double clicking behavior is disabled by not
* calling the window proc.
*/

因此若我們沒有setDoubleClickEnabled為flase,如此一來我們定義的event mouseDoubleClick在呼叫getCaretPosition時,不管是在哪個cursor position做click的動作,最後它都會跳到尾端且進行全選的動作,如此一來在計算start and end就會得到錯誤的值!

相反地,若setDoubleClickEnabled為false,則getCaretPosition就會回傳當下我click的cursor position位置!

最後DEMO如下:
當我選起00:00:00,只要我的cursor在00的左側及中間點擊都會選擇起來,而若是右側的話則會選起其右側的冒號!

補充一下:
1. 如何將Text輸入框設大一點
可以調整其LayoutData的widthHint and heightHint,在此是Grid Layout
2. 如何將Text text size設大一點
需要new Font來進行重畫的動作

留言