第4章:基础控件 - 积木的初体验

第4章:基础控件 - 积木的初体验


作者:步子哥 (steper@foxmail.com)


4.1 标签(Label)

文本与图像的显示

Label textLabel = new Label(shell, SWT.NONE);
textLabel.setText("这是一个文本标签");
textLabel.setBounds(10, 10, 200, 30);

费曼解释:Label 是什么?

Label 就像"便利贴":
- 可以写字在上面(文本)
- 可以贴图片(图像)
- 用户只能看,不能改

类比:
Label = 警示牌
- 你看到警示牌上的文字
- 但不能修改警示牌

Label 的样式:

样式作用类比
SWT.NONE普通文本白纸黑字
SWT.SEPARATOR分隔线一道横线
SWT.HORIZONTAL水平分隔线横线
SWT.VERTICAL垂直分隔线竖线
SWT.CENTER文本居中居中书写
SWT.LEFT文本左对齐靠左书写
SWT.RIGHT文本右对齐靠右书写
SWT.WRAP文本自动换行自动折行

代码示例:各种 Label

public class LabelExamples {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("Label 示例");
        shell.setBounds(100, 100, 500, 400);
        
        // 普通文本标签
        Label textLabel = new Label(shell, SWT.NONE);
        textLabel.setText("普通文本标签");
        textLabel.setBounds(10, 10, 200, 30);
        
        // 居中文本标签
        Label centerLabel = new Label(shell, SWT.CENTER);
        centerLabel.setText("居中文本标签");
        centerLabel.setBounds(10, 50, 200, 30);
        
        // 右对齐文本标签
        Label rightLabel = new Label(shell, SWT.RIGHT);
        rightLabel.setText("右对齐文本标签");
        rightLabel.setBounds(10, 90, 200, 30);
        
        // 自动换行标签
        Label wrapLabel = new Label(shell, SWT.WRAP);
        wrapLabel.setText("这是一个自动换行的标签。文本很长时会自动换行显示。");
        wrapLabel.setBounds(10, 130, 300, 50);
        
        // 水平分隔线
        Label hSeparator = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
        hSeparator.setBounds(10, 190, 400, 20);
        
        // 垂直分隔线
        Label vSeparator = new Label(shell, SWT.SEPARATOR | SWT.VERTICAL);
        vSeparator.setBounds(10, 220, 20, 100);
        
        // 图像标签
        // 注意:需要先加载图像(第 11 章详解)
        // Image image = new Image(display, "path/to/image.png");
        // Label imageLabel = new Label(shell, SWT.NONE);
        // imageLabel.setImage(image);
        // imageLabel.setBounds(50, 220, 100, 100);
        
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        // image.dispose();  // 图像需要手动释放
        display.dispose();
    }
}

分隔线的妙用

费曼解释:分隔线的用途

分隔线就像"书签":
- 在长文中标记位置
- 让内容层次更清晰
- 帮助用户快速定位

类比:
分隔线 = 餐厅的菜单分隔
- 前菜、主菜、甜点
- 用横线分开
- 一目了然

代码示例:用分隔线组织界面

public class SeparatorExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("分隔线示例");
        shell.setBounds(100, 100, 400, 500);
        
        // 第一部分:用户信息
        Label userLabel = new Label(shell, SWT.BOLD);
        userLabel.setText("用户信息");
        userLabel.setBounds(10, 10, 100, 30);
        
        Label nameInfo = new Label(shell, SWT.NONE);
        nameInfo.setText("姓名:张三");
        nameInfo.setBounds(10, 40, 200, 30);
        
        Label emailInfo = new Label(shell, SWT.NONE);
        emailInfo.setText("邮箱:zhangsan@example.com");
        emailInfo.setBounds(10, 70, 300, 30);
        
        // 分隔线
        Label separator1 = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
        separator1.setBounds(10, 110, 350, 20);
        
        // 第二部分:设置
        Label settingLabel = new Label(shell, SWT.BOLD);
        settingLabel.setText("设置");
        settingLabel.setBounds(10, 130, 100, 30);
        
        Label themeInfo = new Label(shell, SWT.NONE);
        themeInfo.setText("主题:深色");
        themeInfo.setBounds(10, 160, 200, 30);
        
        Label languageInfo = new Label(shell, SWT.NONE);
        languageInfo.setText("语言:中文");
        languageInfo.setBounds(10, 190, 200, 30);
        
        // 分隔线
        Label separator2 = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
        separator2.setBounds(10, 230, 350, 20);
        
        // 第三部分:操作按钮
        Button saveButton = new Button(shell, SWT.PUSH);
        saveButton.setText("保存");
        saveButton.setBounds(50, 260, 80, 30);
        
        Button cancelButton = new Button(shell, SWT.PUSH);
        cancelButton.setText("取消");
        cancelButton.setBounds(150, 260, 80, 30);
        
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

4.2 按钮(Button)

普通按钮、复选框、单选按钮

// 普通按钮
Button pushButton = new Button(shell, SWT.PUSH);
pushButton.setText("点击我");

// 复选框
Button checkBox = new Button(shell, SWT.CHECK);
checkBox.setText("记住密码");

// 单选按钮
Button radioButton = new Button(shell, SWT.RADIO);
radioButton.setText("选项 A");

费曼解释:三种按钮的区别

普通按钮 = 门铃
- 按一下就响
- 不保持状态
- 用法:确认、取消、打开等

复选框 = 多选题
- 可以多选
- 保存选中状态
- 用法:记住密码、启用功能等

单选按钮 = 单选题
- 只能选一个
- 组内互斥
- 用法:性别、主题等

Button 的样式:

样式作用类比
SWT.PUSH普通按钮门铃
SWT.CHECK复选框多选题
SWT.RADIO单选按钮单选题
SWT.TOGGLE切换按钮开关
SWT.ARROW箭头按钮方向键
SWT.FLAT扁平按钮无边框按钮
SWT.BORDER带边框有边框按钮
SWT.CENTER文本居中居中显示
SWT.LEFT文本左对齐靠左显示
SWT.RIGHT文本右对齐靠右显示

代码示例:各种按钮

public class ButtonExamples {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("Button 示例");
        shell.setBounds(100, 100, 500, 500);
        
        // 普通按钮
        Button pushButton = new Button(shell, SWT.PUSH);
        pushButton.setText("普通按钮");
        pushButton.setBounds(10, 10, 100, 30);
        pushButton.addListener(SWT.Selection, event -> {
            System.out.println("普通按钮被点击");
        });
        
        // 切换按钮
        Button toggleButton = new Button(shell, SWT.TOGGLE);
        toggleButton.setText("切换按钮");
        toggleButton.setBounds(120, 10, 100, 30);
        toggleButton.addListener(SWT.Selection, event -> {
            boolean selected = toggleButton.getSelection();
            System.out.println("切换按钮状态:" + selected);
        });
        
        // 箭头按钮
        Button arrowButton = new Button(shell, SWT.ARROW | SWT.LEFT);
        arrowButton.setBounds(230, 10, 30, 30);
        
        // 复选框
        Label checkboxLabel = new Label(shell, SWT.NONE);
        checkboxLabel.setText("复选框:");
        checkboxLabel.setBounds(10, 50, 60, 30);
        
        Button checkBox1 = new Button(shell, SWT.CHECK);
        checkBox1.setText("选项 1");
        checkBox1.setBounds(70, 50, 100, 30);
        checkBox1.addListener(SWT.Selection, event -> {
            System.out.println("选项 1:" + checkBox1.getSelection());
        });
        
        Button checkBox2 = new Button(shell, SWT.CHECK);
        checkBox2.setText("选项 2");
        checkBox2.setBounds(170, 50, 100, 30);
        checkBox2.addListener(SWT.Selection, event -> {
            System.out.println("选项 2:" + checkBox2.getSelection());
        });
        
        // 单选按钮
        Label radioLabel = new Label(shell, SWT.NONE);
        radioLabel.setText("单选按钮:");
        radioLabel.setBounds(10, 90, 70, 30);
        
        Button radio1 = new Button(shell, SWT.RADIO);
        radio1.setText("选项 A");
        radio1.setBounds(80, 90, 100, 30);
        
        Button radio2 = new Button(shell, SWT.RADIO);
        radio2.setText("选项 B");
        radio2.setBounds(180, 90, 100, 30);
        
        Button radio3 = new Button(shell, SWT.RADIO);
        radio3.setText("选项 C");
        radio3.setBounds(280, 90, 100, 30);
        
        // 默认选中第一个
        radio1.setSelection(true);
        
        // 扁平按钮
        Button flatButton = new Button(shell, SWT.FLAT);
        flatButton.setText("扁平按钮");
        flatButton.setBounds(10, 130, 100, 30);
        
        // 带边框按钮
        Button borderButton = new Button(shell, SWT.BORDER);
        borderButton.setText("带边框按钮");
        borderButton.setBounds(120, 130, 100, 30);
        
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

按钮的样式组合

// 组合多个样式
Button button = new Button(shell, SWT.PUSH | SWT.CENTER | SWT.BORDER);
button.setText("组合样式");

常用组合:

组合效果
`SWT.PUSHSWT.CENTER`居中的普通按钮
`SWT.PUSHSWT.BORDER`带边框的普通按钮
`SWT.PUSHSWT.FLAT`扁平按钮
`SWT.TOGGLESWT.BORDER`带边框的切换按钮
`SWT.ARROWSWT.LEFT`左箭头按钮
`SWT.ARROWSWT.RIGHT`右箭头按钮
`SWT.ARROWSWT.UP`上箭头按钮
`SWT.ARROWSWT.DOWN`下箭头按钮

图标按钮的制作

注意:需要先加载图像(Image)

public class ImageButtonExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("图标按钮示例");
        shell.setBounds(100, 100, 400, 300);
        
        // 创建图像(实际应用中应该从文件加载)
        // Image image = new Image(display, "icon.png");
        
        // 创建带图像的按钮
        Button imageButton = new Button(shell, SWT.PUSH);
        imageButton.setText("图标按钮");
        // imageButton.setImage(image);  // 设置图像
        imageButton.setBounds(50, 50, 150, 50);
        
        // 创建只有图像的按钮(无文本)
        Button iconOnlyButton = new Button(shell, SWT.PUSH);
        // iconOnlyButton.setImage(image);
        iconOnlyButton.setBounds(50, 120, 50, 50);
        
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        // image.dispose();  // 图像需要手动释放
        display.dispose();
    }
}

费曼解释:为什么需要手动释放图像?

SWT 资源 = 操作系统资源
- Image 映射到操作系统的图像对象
- Java 的 GC 不会自动释放
- 必须手动 dispose()

类比:
Image = 借书
- 你从图书馆借了一本书(创建 Image)
- 看完后要还书(dispose)
- 不还书 = 图书馆的书越来越少

4.3 文本输入(Text)

单行与多行

// 单行文本
Text singleLineText = new Text(shell, SWT.BORDER | SWT.SINGLE);
singleLineText.setText("单行文本");

// 多行文本
Text multiLineText = new Text(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
multiLineText.setText("第一行\n第二行\n第三行");

费曼解释:单行 vs 多行

单行文本 = 名片
- 只能写一行
- 适合输入姓名、邮箱等

多行文本 = 笔记本
- 可以写多行
- 适合输入文章、备注等

Text 的样式:

样式作用类比
SWT.SINGLE单行文本名片
SWT.MULTI多行文本笔记本
SWT.BORDER带边框有边框
SWT.V_SCROLL垂直滚动条上下滚动
SWT.H_SCROLL水平滚动条左右滚动
SWT.READ_ONLY只读只能看不能改
SWT.PASSWORD密码框输入显示星号
SWT.CENTER文本居中居中显示
SWT.LEFT文本左对齐靠左显示
SWT.RIGHT文本右对齐靠右显示
SWT.WRAP自动换行自动折行

密码框、只读框

// 密码框
Text passwordText = new Text(shell, SWT.BORDER | SWT.PASSWORD);
passwordText.setMessage("请输入密码");  // 提示文本

// 只读框
Text readOnlyText = new Text(shell, SWT.BORDER | SWT.READ_ONLY | SWT.MULTI);
readOnlyText.setText("这是只读文本,不能修改");

费曼解释:密码框的原理

密码框 = 戴面具
- 你输入的是密码
- 但显示的是星号(*)
- 就像戴着面具,别人看不清你的脸

类比:
密码输入 = 在 ATM 输密码
- 你按了数字
- 屏幕显示星号
- 防止别人偷看

文本选择与光标控制

Text text = new Text(shell, SWT.BORDER | SWT.MULTI);
text.setBounds(10, 10, 300, 200);

// 获取文本
String content = text.getText();
System.out.println("文本内容:" + content);

// 设置文本
text.setText("新文本");

// 获取选中的文本
String selection = text.getSelectionText();
System.out.println("选中的文本:" + selection);

// 设置选中的范围(从索引 2 到 6)
text.setSelection(2, 6);

// 获取光标位置
int caretPosition = text.getCaretPosition();
System.out.println("光标位置:" + caretPosition);

// 设置光标位置
text.setCaretPosition(5);

// 获取选中的范围
Point selectionRange = text.getSelection();
System.out.println("选中的范围:" + selectionRange.x + " - " + selectionRange.y);

// 获取行数
int lineCount = text.getLineCount();
System.out.println("行数:" + lineCount);

// 获取第 2 行的文本(从 0 开始计数)
String lineText = text.getLine(1);
System.out.println("第 2 行:" + lineText);

// 获取第 5 个字符的行号
int lineAtOffset = text.getLineAtOffset(5);
System.out.println("第 5 个字符在第 " + lineAtOffset + " 行");

// 插入文本
text.insert("插入的文本");

// 追加文本
text.append("\n追加的文本");

// 清除文本
text.setText("");

代码示例:文本操作工具

public class TextOperationsExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("文本操作示例");
        shell.setBounds(100, 100, 500, 400);
        
        // 文本框
        Text text = new Text(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
        text.setBounds(10, 10, 300, 200);
        text.setText("这是一段示例文本。\n包含多行内容。\n你可以尝试选择文本。");
        
        // 按钮:获取文本
        Button getTextButton = new Button(shell, SWT.PUSH);
        getTextButton.setText("获取文本");
        getTextButton.setBounds(10, 230, 80, 30);
        getTextButton.addListener(SWT.Selection, event -> {
            System.out.println("文本内容:" + text.getText());
        });
        
        // 按钮:获取选中的文本
        Button getSelectionButton = new Button(shell, SWT.PUSH);
        getSelectionButton.setText("获取选中");
        getSelectionButton.setBounds(100, 230, 80, 30);
        getSelectionButton.addListener(SWT.Selection, event -> {
            System.out.println("选中的文本:" + text.getSelectionText());
        });
        
        // 按钮:获取行数
        Button getLineCountButton = new Button(shell, SWT.PUSH);
        getLineCountButton.setText("获取行数");
        getLineCountButton.setBounds(190, 230, 80, 30);
        getLineCountButton.addListener(SWT.Selection, event -> {
            System.out.println("行数:" + text.getLineCount());
        });
        
        // 按钮:获取光标位置
        Button getCaretButton = new Button(shell, SWT.PUSH);
        getCaretButton.setText("光标位置");
        getCaretButton.setBounds(10, 270, 80, 30);
        getCaretButton.addListener(SWT.Selection, event -> {
            System.out.println("光标位置:" + text.getCaretPosition());
        });
        
        // 按钮:追加文本
        Button appendButton = new Button(shell, SWT.PUSH);
        appendButton.setText("追加文本");
        appendButton.setBounds(100, 270, 80, 30);
        appendButton.addListener(SWT.Selection, event -> {
            text.append("\n追加的文本 " + System.currentTimeMillis());
        });
        
        // 按钮:清空文本
        Button clearButton = new Button(shell, SWT.PUSH);
        clearButton.setText("清空");
        clearButton.setBounds(190, 270, 80, 30);
        clearButton.addListener(SWT.Selection, event -> {
            text.setText("");
        });
        
        // 单行文本框
        Text singleLineText = new Text(shell, SWT.BORDER | SWT.SINGLE);
        singleLineText.setMessage("请输入单行文本");
        singleLineText.setBounds(10, 320, 300, 30);
        
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

4.4 列表(List)

添加、删除、选择

List list = new List(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL);
list.setBounds(10, 10, 200, 200);

// 添加项
list.add("选项 1");
list.add("选项 2");
list.add("选项 3");

// 在指定位置添加
list.add("插入的选项", 1);

// 删除指定项
list.remove(2);  // 删除索引为 2 的项

// 删除所有项
list.removeAll();

// 获取选中项的索引
int[] selectionIndices = list.getSelectionIndices();

// 获取选中项的文本
String[] selectionItems = list.getSelection();

// 设置选中项
list.setSelection(0, 2);  // 选中索引 0 到 2 的项

// 获取项的数量
int itemCount = list.getItemCount();

// 获取指定索引的项
String item = list.getItem(0);

// 获取所有项
String[] items = list.getItems();

费曼解释:List 是什么?

List 就像"菜单":
- 列出所有选项
- 可以多选或单选
- 适合让用户从选项中选择

类比:
List = 餐厅菜单
- 列出所有菜品
- 你可以多选(几个菜)
- 也可以单选(一个菜)

List 的样式:

样式作用类比
SWT.SINGLE单选只能选一个
SWT.MULTI多选可以选多个
SWT.BORDER带边框有边框
SWT.V_SCROLL垂直滚动条上下滚动
SWT.H_SCROLL水平滚动条左右滚动

代码示例:列表操作

public class ListExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("List 示例");
        shell.setBounds(100, 100, 500, 400);
        
        // 单选列表
        Label singleListLabel = new Label(shell, SWT.NONE);
        singleListLabel.setText("单选列表:");
        singleListLabel.setBounds(10, 10, 100, 30);
        
        List singleList = new List(shell, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL);
        singleList.setBounds(10, 40, 200, 100);
        singleList.add("选项 A");
        singleList.add("选项 B");
        singleList.add("选项 C");
        singleList.add("选项 D");
        singleList.add("选项 E");
        singleList.setSelection(0);  // 默认选中第一个
        
        singleList.addListener(SWT.Selection, event -> {
            String selected = singleList.getSelection()[0];
            System.out.println("单选列表选中:" + selected);
        });
        
        // 多选列表
        Label multiListLabel = new Label(shell, SWT.NONE);
        multiListLabel.setText("多选列表:");
        multiListLabel.setBounds(10, 150, 100, 30);
        
        List multiList = new List(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL);
        multiList.setBounds(10, 180, 200, 100);
        multiList.add("苹果");
        multiList.add("香蕉");
        multiList.add("橙子");
        multiList.add("葡萄");
        multiList.add("草莓");
        
        multiList.addListener(SWT.Selection, event -> {
            String[] selectedItems = multiList.getSelection();
            System.out.println("多选列表选中:" + String.join(", ", selectedItems));
        });
        
        // 操作按钮
        Button addButton = new Button(shell, SWT.PUSH);
        addButton.setText("添加");
        addButton.setBounds(250, 40, 80, 30);
        addButton.addListener(SWT.Selection, event -> {
            multiList.add("新选项 " + (multiList.getItemCount() + 1));
        });
        
        Button removeButton = new Button(shell, SWT.PUSH);
        removeButton.setText("删除选中");
        removeButton.setBounds(250, 80, 80, 30);
        removeButton.addListener(SWT.Selection, event -> {
            int[] indices = multiList.getSelectionIndices();
            // 从后往前删除,避免索引变化
            for (int i = indices.length - 1; i >= 0; i--) {
                multiList.remove(indices[i]);
            }
        });
        
        Button clearButton = new Button(shell, SWT.PUSH);
        clearButton.setText("清空");
        clearButton.setBounds(250, 120, 80, 30);
        clearButton.addListener(SWT.Selection, event -> {
            multiList.removeAll();
        });
        
        Button showSelectedButton = new Button(shell, SWT.PUSH);
        showSelectedButton.setText("显示选中");
        showSelectedButton.setBounds(250, 180, 80, 30);
        showSelectedButton.addListener(SWT.Selection, event -> {
            String[] selectedItems = multiList.getSelection();
            for (String item : selectedItems) {
                System.out.println("选中:" + item);
            }
        });
        
        Button showAllButton = new Button(shell, SWT.PUSH);
        showAllButton.setText("显示全部");
        showAllButton.setBounds(250, 220, 80, 30);
        showAllButton.addListener(SWT.Selection, event -> {
            String[] items = multiList.getItems();
            for (String item : items) {
                System.out.println("项:" + item);
            }
        });
        
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

4.5 组合框(Combo)

下拉列表的本质

Combo combo = new Combo(shell, SWT.DROP_DOWN | SWT.READ_ONLY);
combo.setBounds(10, 10, 200, 30);

// 添加项
combo.add("选项 1");
combo.add("选项 2");
combo.add("选项 3");

// 设置选中项
combo.select(1);  // 选中索引为 1 的项

// 获取选中项
int selectedIndex = combo.getSelectionIndex();
String selectedText = combo.getText();

// 设置文本(可编辑模式)
combo.setText("自定义文本");

费曼解释:Combo 是什么?

Combo 就像"自动售货机":
- 列出所有商品(选项)
- 你可以点击选择(下拉)
- 也可以手动输入(可编辑)

类比:
Combo = 浏览器的地址栏
- 你可以点击历史记录(下拉选择)
- 也可以手动输入网址(可编辑)

Combo 的样式:

样式作用类比
SWT.DROP_DOWN下拉列表可以点击展开
SWT.SIMPLE简单列表一直展开
SWT.READ_ONLY只读只能选,不能改
SWT.BORDER带边框有边框

代码示例:各种 Combo

public class ComboExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("Combo 示例");
        shell.setBounds(100, 100, 400, 300);
        
        // 下拉列表(只读)
        Label dropDownLabel = new Label(shell, SWT.NONE);
        dropDownLabel.setText("下拉列表(只读):");
        dropDownLabel.setBounds(10, 10, 150, 30);
        
        Combo dropDownCombo = new Combo(shell, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER);
        dropDownCombo.setBounds(10, 40, 200, 30);
        dropDownCombo.add("选项 1");
        dropDownCombo.add("选项 2");
        dropDownCombo.add("选项 3");
        dropDownCombo.add("选项 4");
        dropDownCombo.select(0);  // 默认选中第一个
        
        dropDownCombo.addListener(SWT.Selection, event -> {
            String selected = dropDownCombo.getText();
            System.out.println("下拉列表选中:" + selected);
        });
        
        // 可编辑的下拉列表
        Label editableLabel = new Label(shell, SWT.NONE);
        editableLabel.setText("可编辑下拉列表:");
        editableLabel.setBounds(10, 80, 150, 30);
        
        Combo editableCombo = new Combo(shell, SWT.DROP_DOWN | SWT.BORDER);
        editableCombo.setBounds(10, 110, 200, 30);
        editableCombo.add("苹果");
        editableCombo.add("香蕉");
        editableCombo.add("橙子");
        editableCombo.setMessage("请输入或选择");
        
        editableCombo.addListener(SWT.Selection, event -> {
            System.out.println("选择:" + editableCombo.getText());
        });
        
        editableCombo.addListener(SWT.Modify, event -> {
            System.out.println("文本改变:" + editableCombo.getText());
        });
        
        // 简单列表(一直展开)
        Label simpleLabel = new Label(shell, SWT.NONE);
        simpleLabel.setText("简单列表:");
        simpleLabel.setBounds(10, 150, 100, 30);
        
        Combo simpleCombo = new Combo(shell, SWT.SIMPLE | SWT.BORDER);
        simpleCombo.setBounds(10, 180, 200, 80);
        simpleCombo.add("A");
        simpleCombo.add("B");
        simpleCombo.add("C");
        simpleCombo.add("D");
        
        // 操作按钮
        Button showSelectedButton = new Button(shell, SWT.PUSH);
        showSelectedButton.setText("显示选中");
        showSelectedButton.setBounds(10, 270, 80, 30);
        showSelectedButton.addListener(SWT.Selection, event -> {
            int index = dropDownCombo.getSelectionIndex();
            String text = dropDownCombo.getText();
            System.out.println("下拉列表:索引=" + index + ", 文本=" + text);
            
            index = editableCombo.getSelectionIndex();
            text = editableCombo.getText();
            System.out.println("可编辑列表:索引=" + index + ", 文本=" + text);
        });
        
        Button addButton = new Button(shell, SWT.PUSH);
        addButton.setText("添加");
        addButton.setBounds(100, 270, 80, 30);
        addButton.addListener(SWT.Selection, event -> {
            editableCombo.add("新选项 " + (editableCombo.getItemCount() + 1));
        });
        
        Button removeButton = new Button(shell, SWT.PUSH);
        removeButton.setText("删除选中");
        removeButton.setBounds(190, 270, 80, 30);
        removeButton.addListener(SWT.Selection, event -> {
            editableCombo.remove(editableCombo.getSelectionIndex());
        });
        
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

4.6 本章小结

基础控件总结

控件用途类比
Label显示文本和图像便利贴
Button触发操作门铃
Text输入和编辑文本笔记本
List从列表中选择菜单
Combo下拉列表自动售货机

费曼测试:你能解释清楚吗?

  1. Label、Text、Combo 的区别?

- Label:只能看,不能改(便利贴) - Text:可以看,可以改(笔记本) - Combo:可以选择,可以输入(自动售货机)

  1. 单选按钮和复选框的区别?

- 单选:组内互斥,只能选一个(单选题) - 复选:可以多选(多选题)

  1. SWT.READ_ONLY 的作用?

- 文本变成只读(只能看,不能改)

  1. 如何获取 Combo 的选中项?

- combo.getSelectionIndex() 获取索引 - combo.getText() 获取文本

下一章预告

现在你已经认识了基础控件,
但你还不知道:
- 如何让控件自动排列?(布局管理器)
- 如何让界面适应不同屏幕?(响应式布局)
- 如何避免手写坐标的痛苦?(布局的优势)

下一章,我们将学习布局管理器,
让界面自动排列,省心省力。

练习题:

  1. 创建一个登录界面,包含:用户名(Text)、密码(Text + SWT.PASSWORD)、登录按钮(Button)。
  2. 创建一个表单,包含:姓名、性别(单选按钮)、爱好(复选框)、城市(Combo)。
  3. 创建一个列表操作工具,可以添加、删除、清空列表项。

(提示:复选框要放在同一个父容器中才能组成一组,单选按钮同理)

← 返回目录