mirror of
https://github.com/VincentWei/minigui-docs.git
synced 2025-10-17 07:41:35 +08:00
update
This commit is contained in:
408
programming-guide-zh/MiniGUIProgGuidePart6Chapter02-zh.md
Normal file
408
programming-guide-zh/MiniGUIProgGuidePart6Chapter02-zh.md
Normal file
@@ -0,0 +1,408 @@
|
||||
# 按钮
|
||||
|
||||
|
||||
按钮是除静态框之外使用最为频繁的一种控件。按钮通常用来为用户提供开关选择。MiniGUI 的按钮可划分为普通按钮、复选框和单选钮等几种类型。用户可以通过键盘或者鼠标来选择或者切换按钮的状态。用户的输入将使按钮产生通知消息,应用程序也可以向按钮发送消息以改变按钮的状态。
|
||||
|
||||
以 `CTRL_BUTTON` 为控件类名调用 `CreateWindow` 函数,即可创建按钮控件。
|
||||
|
||||
## 1.1 按钮的类型和风格
|
||||
|
||||
### 1.1.1 普通按钮
|
||||
|
||||
普通按钮是一个矩形,其中显示了通过 `CreateWindow` 传递的窗口标题。该矩形占用了在 `CreateWindow` 调用中给出的全部高度和宽度,而文字位于矩形的中心。
|
||||
|
||||
按钮控件主要用来触发一个立即回应的动作,并且不会长久保持开关信息。这种形态的按钮控件有两种窗口风格,分别叫做 `BS_PUSHBUTTON` 和 `BS_DEFPUSHBUTTON`。`BS_DEFPUSHBUTTON` 中的 “DEF” 代表 “默认”。当用来设计对话框时,`BS_PUSHBUTTON` 风格和 `BS_DEFPUSHBUTTON` 风格的作用不同,具有 `BS_DEFPUSHBUTTON` 的按钮将是默认接收 `ENTER` 键输入的按钮,而不管当前的输入焦点处于哪个控件上。但是当用作普通主窗口的控件时,两种型态的按钮作用相同,只是具有 `BS_DEFPUSHBUTTON` 风格的按钮的边框要粗一些。
|
||||
|
||||
当鼠标光标处在按钮中时,按下鼠标左键将使按钮用三维阴影重画自己,就好像真的被按下一样。放开鼠标按键时,就恢复按钮的原貌,并产生 `BN_CLICKED` 通知,当按钮拥有输入焦点时,在文字的周围就有虚线,按下及释放空格键与按下及释放鼠标按键具有相同的效果。
|
||||
|
||||
>【提示】本指南对控件行为和表象的描述以默认的经典风格为准。
|
||||
|
||||
通常情况下,按钮文本会以单行的形式在垂直和水平方向居中显示,不会自动换行。不过,应用程序也可以通过指定 `BS_MULTLINE` 风格来指定显示多行文本。下面的程序段创建了两个普通按钮:
|
||||
|
||||
```c
|
||||
CreateWindow (CTRL_BUTTON,
|
||||
"Push Button",
|
||||
WS_CHILD | BS_PUSHBUTTON | BS_CHECKED | WS_VISIBLE,
|
||||
IDC_BUTTON,
|
||||
10, 10, 80, 30, hWnd, 0);
|
||||
|
||||
CreateWindow (CTRL_BUTTON,
|
||||
"Multiple Lines Push Button",
|
||||
WS_CHILD | BS_PUSHBUTTON | BS_MULTLINE | WS_VISIBLE,
|
||||
IDC_BUTTON + 1,
|
||||
100, 10, 80, 40, hWnd, 0);
|
||||
```
|
||||
|
||||
上述代码段建立的普通按钮的显示效果如__图 1.1__ 所示。注意在使用 `BS_MULTILINE` 风格之后,文本将垂直向上对齐。
|
||||
|
||||

|
||||
__图 1.1__ 普通按钮
|
||||
|
||||
|
||||
另外,也可以在普通按钮上显示位图或图标,这时要使用 `BS_BITMAP` 或者 `BS_ICON` 风格,并通过 `CreateWindow` 函数的 `dwAddData` 参数传递位图对象的指针或图标句柄。默认情况下位图或图标会缩放显示以充满整个按钮窗口范围,使用 `BS_REALSIZEIMAGE` 风格将使位图或图标显示在控件中部,不作任何缩放。下面的代码段建立了一个带位图的按钮,其效果见__图 1.2__。
|
||||
|
||||
```c
|
||||
hwnd = CreateWindow (CTRL_BUTTON,
|
||||
"Close",
|
||||
WS_CHILD | BS_PUSHBUTTON | BS_BITMAP |BS_REALSIZEIMAGE | BS_NOTIFY | WS_VISIBLE,
|
||||
IDC_BUTTON + 4,
|
||||
10, 300, 60, 30, hWnd, (DWORD) GetSystemBitmap (IDI_APPLICATION));
|
||||
```
|
||||
|
||||

|
||||
__图 1.2__ 位图按钮
|
||||
|
||||
|
||||
### 1.1.2 复选框
|
||||
|
||||
复选框是一个文字方块,文字通常出现在复选框的右边(如果你在建立按钮时指定了 `BS_LEFTTEXT` 风格,那么文字会出现在左边)。复选框通常用于允许用户对选项进行选择的应用程序中。复选框的常用功能如同一个开关:单击一次将显示选中标记,再次单击则会清除选中标记。
|
||||
|
||||
复选框最常用的两种风格是 `BS_CHECKBOX` 和 `BS_AUTOCHECKBOX`。在使用 `BS_CHECKBOX` 时,应用程序需要自己向该控件发送消息来设定选中标记;而使用 `BS_AUTOCHECKBOX` 风格时,控件会自动在选中和非选中状态之间切换。
|
||||
|
||||
其余两种复选框风格是 `BS_3STATE` 和 `BS_AUTO3STATE`,正如它们名字所暗示的,这两种风格能显示第三种状态——复选框内是灰色的,这种状态表明该复选框不能被选择或者禁止使用。
|
||||
|
||||
`BS_3STATE` 和 `BS_AUTO3STATE` 风格之间的区别和上面一样:前者需要应用程序来操作其状态,而后者由控件负责状态的自动切换。
|
||||
|
||||
默认情况下,复选框沿矩形的左边框对齐,并位于控件窗口范围的顶边和底边之间(垂直居中),在该矩形内的任何地方按下鼠标都会产生通知消息。使用 `BS_LEFTTEXT` 风格将使复选框靠右对齐,并将文本置于复选框的左边。用于文本对齐的风格 `BS_LEFT`、`BS_CENTER`、`BS_RIGHT`、`BS_TOP`、`BS_VCENTER`、`BS_BOTTOM` 等可用于复选框。
|
||||
|
||||
另外,使用 `BS_PUSHLIKE` 风格将使复选框以普通按钮的形式显示:选中时显示为按下状态,未选中时显示为正常状态。
|
||||
|
||||
下面的程序段创建了两个复选框,其效果在__图 1.3__ 中。
|
||||
|
||||
```c
|
||||
CreateWindow (CTRL_BUTTON,
|
||||
"Auto 3-state check box",
|
||||
WS_CHILD | BS_AUTO3STATE | WS_VISIBLE,
|
||||
IDC_CHECKBOX,
|
||||
10, 60, 150, 30, hWnd, 0);
|
||||
|
||||
CreateWindow (CTRL_BUTTON,
|
||||
"Auto check box on left",
|
||||
WS_CHILD | BS_AUTOCHECKBOX | BS_LEFTTEXT | BS_RIGHT | WS_VISIBLE,
|
||||
IDC_CHECKBOX + 1,
|
||||
170, 60, 150, 30, hWnd, 0);
|
||||
```
|
||||
|
||||

|
||||
__图 1.3__ 复选框按钮
|
||||
|
||||
|
||||
### 1.1.3 单选钮
|
||||
|
||||
单选按钮就像收音机上选台按钮一样,每一个按钮都对应一个频道,而且一次只能有一个按钮被按下。在对话框中,单选按钮组常常用来表示相互排斥的选项。与复选框不同,单选按钮的工作方式不同于开关,也就是说,当第二次按单选按钮时,它的状态会保持不变。
|
||||
|
||||
单选按钮的形状是一个圆圈,而不是方框,除此之外,它的行为很像复选框。圆圈内的加重圆点表示该单选按钮已经被选中。单选按钮有风格 `BS_RADIOBUTTON` 或 `BS_AUTORADIOBUTTON` 两种,后者会自动显示用户的选择情况,而前者不会。
|
||||
|
||||
默认情况下,单选按钮沿控件窗口的左边框对齐,并位于控件窗口范围的顶边和底边之间(垂直居中),在该矩形内的任何地方按下鼠标都产生通知消息。使用 `BS_LEFTTEXT` 风格将使单选按钮靠右对齐,并将文本置于按钮的左边。用于文本对齐的风格 `BS_LEFT`、`BS_CENTER`、`BS_RIGHT`、`BS_TOP`、`BS_VCENTER`、`BS_BOTTOM` 等可用于单选按钮。
|
||||
|
||||
另外,使用 `BS_PUSHLIKE` 风格将使单选按钮以普通按钮的形式显示:选中时显示为按下状态,未选中时显示为正常状态。下面的程序段创建了两个单选按钮,其效果见__图 1.4__。
|
||||
|
||||
```c
|
||||
CreateWindow (CTRL_BUTTON,
|
||||
"Auto Radio Button 2",
|
||||
WS_CHILD | BS_AUTORADIOBUTTON | WS_VISIBLE,
|
||||
IDC_RADIOBUTTON + 1,
|
||||
20, 160, 130, 30, hWnd, 0);
|
||||
|
||||
CreateWindow (CTRL_BUTTON,
|
||||
"Auto Radio Button 2",
|
||||
WS_CHILD | BS_AUTORADIOBUTTON | BS_LEFTTEXT | BS_RIGHT | WS_VISIBLE,
|
||||
IDC_RADIOBUTTON + 4,
|
||||
180, 160, 140, 30, hWnd, 0);
|
||||
```
|
||||
|
||||

|
||||
__图 1.4__ 单选按钮
|
||||
|
||||
|
||||
单选按钮通常成组使用,同一组单选按钮每一刻只能有一个被选中。在创建一组单选按钮时,我们需要设定它们的状态是互斥的,因此,要在创建第一个单选按钮时使用 `WS_GROUP` 风格,以将其设置为该组单选按钮的“打头按钮”。
|
||||
|
||||
## 1.2 按钮消息
|
||||
|
||||
应用程序通过给按钮发送消息来实现如下目的:
|
||||
|
||||
- 查询/设置复选框或者单选钮的选中状态:`BM_GETCHECK`、`BM_SETCHECK`
|
||||
- 查询/设置普通按钮或者复选框的按下或释放状态:`BM_GETSTATE`、`BM_SETSTATE`
|
||||
- 获取/设置位图按钮上的位图或者图标:`BM_GETIMAGE`、`BM_SETIMAGE`
|
||||
- 发送 `BM_CLICK` 模拟用户鼠标的单击操作
|
||||
|
||||
应用程序向复选框或者单选钮发送 `wParam` 等于 `BST_CHECKED` 的 `BM_SETCHECK` 消息来显示其处于选中状态:
|
||||
|
||||
```c
|
||||
SendMessage (hwndButton, BM_SETCHECK, BST_CHECKED, 0);
|
||||
```
|
||||
|
||||
其实 `wParam` 可取的值一共有三个,见__表 1.1__。这些值也是通过 `BM_GETCHECK` 消息返回的选中状态值。
|
||||
|
||||
__表 1.1__ 复选框和单选钮的选中状态
|
||||
|
||||
| 状态标识符 | 含义 |
|
||||
|:----------------------|:-------|
|
||||
|`BST_UNCHECKED`(0) |未选中 |
|
||||
|`BST_CHECKED`(1) |已选中 |
|
||||
|`BST_INDETERMINATE`(2) |不可用状态|
|
||||
|
||||
|
||||
我们可以通过给窗口发送 `BM_SETSTATE` 消息来模拟按钮闪动。以下的操作将导致按钮被按下:
|
||||
|
||||
```c
|
||||
SendMessage (hwndButton, BM_SETSTATE, BST_PUSHED, 0) ;
|
||||
```
|
||||
|
||||
下面的调用使按钮恢复正常:
|
||||
|
||||
```c
|
||||
SendMessage (hwndButton, BM_SETSTATE, 0, 0) ;
|
||||
```
|
||||
|
||||
对位图按钮,可使用 `BM_GETIMAGE` 和 `BM_SETIMAGE` 消息获取或设置位图对象或图标句柄:
|
||||
|
||||
```c
|
||||
int image_type;
|
||||
PBITMAP btn_bmp;
|
||||
HICON btn_icon;
|
||||
|
||||
int ret_val = SendMessage (hwndButton, BM_GETIMAGE, (WPARAM)&image_type, 0) ;
|
||||
|
||||
if (image_type == BM_IMAGE_BITMAP) {
|
||||
/* 该按钮使用的是位图对象 */
|
||||
btn_bmp = (PBITMAP) ret_val;
|
||||
}
|
||||
else {
|
||||
/* 该按钮使用的是图标对象 */
|
||||
btn_icon = (HICON) ret_val;
|
||||
}
|
||||
|
||||
/* 将按钮图象设置为位图对象 */
|
||||
SendMessage (hwndButton, BM_SETIMAGE, BM_IMAGE_BITMAP, btn_bmp) ;
|
||||
|
||||
/* 将按钮图象设置为图标对象 */
|
||||
SendMessage (hwndButton, BM_SETIMAGE, BM_IMAGE_ICON, btn_icon) ;
|
||||
```
|
||||
|
||||
另外,我们在应用程序中也可以通过向按钮发送 `BM_CLICK` 消息来模拟用户在按钮上的单击操作。
|
||||
|
||||
## 1.3 按钮通知码
|
||||
|
||||
具有 `BS_NOTIFY` 风格的按钮可产生的通知码主要有:
|
||||
|
||||
- `BN_CLICKED`:表明用户单击此按钮。该通知码的值为 0,因此,如果要在按钮的父窗口中处理该按钮发送过来的 `BN_CLICKED` 通知消息,只需判断 `MSG_COMMAND` 消息的 `wParam` 参数是否等于按钮的标识符即可。该通知的产生是默认的,将忽略按钮控件的 `BS_NOTIFY` 风格。
|
||||
- `BN_PUSHED`:表明用户将此按钮按下。
|
||||
- `BN_UNPUSHED`:表明用户将此按钮释放。
|
||||
- `BN_DBLCLK`:表明用户在此按钮上进行了鼠标左键的双击操作。
|
||||
- `BN_SETFOCUS`:表明按钮获得了输入焦点。
|
||||
- `BN_KILLFOCUS`:表明按钮失去了输入焦点。
|
||||
|
||||
## 1.4 编程实例
|
||||
|
||||
通常,应用程序只需处理 `BN_CLICKED` 通知码,对复选框和单选钮,一般设置为自动状态,并在需要时发送 `BM_GETCHECK` 消息来获得选中状态。在对话框中,应用程序还可以使用__表 1.2__ 中的函数来快速获得按钮控件的状态信息。
|
||||
|
||||
__表 1.2__ 对话框为处理按钮控件而提供的便利函数
|
||||
|
||||
| 函数名 | 用途 | 备注 |
|
||||
|:--------------------|:---------------------------------|:----------|
|
||||
|`CheckDlgButton` |通过按钮标识符来改变按钮的选中状态 | |
|
||||
|`CheckRadioButton` |通过按钮标识符来改变一组单选钮的选中状态 |确保互斥选中 |
|
||||
|`IsDlgButtonChecked `|通过标识符判断按钮是否选中 | |
|
||||
|
||||
|
||||
__清单 1.1__ 所示的程序代码,给出了一个按钮控件的综合性使用范例。该程序使用一个对话框来询问用户的口味,通过分组单选框来选择喜欢的小吃类型,并通过复选框来选择用户的一些特殊口味。该程序的完整源代码请见本指南示例程序包 `mg-samples` 中的 `button.c` 文件,其运行效果见__图 1.5__。
|
||||
|
||||
__清单 1.1__ 按钮控件的使用范例
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <minigui/common.h>
|
||||
#include <minigui/minigui.h>
|
||||
#include <minigui/gdi.h>
|
||||
#include <minigui/window.h>
|
||||
#include <minigui/control.h>
|
||||
|
||||
#define IDC_LAMIAN 101
|
||||
#define IDC_CHOUDOUFU 102
|
||||
#define IDC_JIANBING 103
|
||||
#define IDC_MAHUA 104
|
||||
#define IDC_SHUIJIAO 105
|
||||
|
||||
#define IDC_XIAN 110
|
||||
#define IDC_LA 111
|
||||
|
||||
#define IDC_PROMPT 200
|
||||
|
||||
static DLGTEMPLATE DlgYourTaste =
|
||||
{
|
||||
WS_BORDER | WS_CAPTION,
|
||||
WS_EX_NONE,
|
||||
120, 100, 300, 280,
|
||||
"你喜欢吃哪种风味的小吃",
|
||||
0, 0,
|
||||
12, NULL,
|
||||
0
|
||||
};
|
||||
|
||||
static CTRLDATA CtrlYourTaste[] =
|
||||
{
|
||||
{
|
||||
"static",
|
||||
WS_VISIBLE | SS_GROUPBOX,
|
||||
16, 10, 130, 160,
|
||||
IDC_STATIC,
|
||||
"可选小吃",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
/* 使用 BS_CHECKED,初始时使其选中 */
|
||||
WS_VISIBLE | BS_AUTORADIOBUTTON | BS_CHECKED | WS_TABSTOP | WS_GROUP,
|
||||
36, 38, 88, 20,
|
||||
IDC_LAMIAN,
|
||||
"西北拉面",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
WS_VISIBLE | BS_AUTORADIOBUTTON,
|
||||
36, 64, 88, 20,
|
||||
IDC_CHOUDOUFU,
|
||||
"长沙臭豆腐",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
WS_VISIBLE | BS_AUTORADIOBUTTON,
|
||||
36, 90, 88, 20,
|
||||
IDC_JIANBING,
|
||||
"山东煎饼",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
WS_VISIBLE | BS_AUTORADIOBUTTON,
|
||||
36, 116, 88, 20,
|
||||
IDC_MAHUA,
|
||||
"天津麻花",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
WS_VISIBLE | BS_AUTORADIOBUTTON,
|
||||
36, 142, 100, 20,
|
||||
IDC_SHUIJIAO,
|
||||
"成都红油水饺",
|
||||
0
|
||||
},
|
||||
{
|
||||
"static",
|
||||
WS_VISIBLE | SS_GROUPBOX | WS_GROUP,
|
||||
160, 10, 124, 160,
|
||||
IDC_STATIC,
|
||||
"口味",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
WS_VISIBLE | BS_AUTOCHECKBOX,
|
||||
170, 38, 88, 20,
|
||||
IDC_XIAN,
|
||||
"偏咸",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
/* 使用 BS_CHECKED,初始时使其选中 */
|
||||
WS_VISIBLE | BS_AUTOCHECKBOX | BS_CHECKED,
|
||||
170, 64, 88, 20,
|
||||
IDC_LA,
|
||||
"偏辣",
|
||||
0
|
||||
},
|
||||
{
|
||||
"static",
|
||||
WS_VISIBLE | SS_LEFT | WS_GROUP,
|
||||
16, 180, 360, 20,
|
||||
IDC_PROMPT,
|
||||
"西北拉面是面食中的精品,但街上的兰州拉面除外!",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_GROUP,
|
||||
80, 220, 95, 28,
|
||||
IDOK,
|
||||
"确定",
|
||||
0
|
||||
},
|
||||
{
|
||||
"button",
|
||||
WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
|
||||
185, 220, 95, 28,
|
||||
IDCANCEL,
|
||||
"取消",
|
||||
0
|
||||
},
|
||||
};
|
||||
|
||||
static char* prompts [] = {
|
||||
"西北拉面是面食中的精品,但街上的兰州拉面除外!",
|
||||
"长沙臭豆腐口味很独特,一般人适应不了。",
|
||||
"山东煎饼很难嚼 :(",
|
||||
"天津麻花很脆,很香!",
|
||||
"成都的红油水饺可真好吃啊!想起来就流口水。",
|
||||
};
|
||||
|
||||
static void my_notif_proc (HWND hwnd, int id, int nc, DWORD add_data)
|
||||
{
|
||||
/* 用户选择不同的小吃时,在下面的静态框中显示针对这种小吃的提示信息 */
|
||||
if (nc == BN_CLICKED) {
|
||||
SetWindowText (GetDlgItem (GetParent (hwnd), IDC_PROMPT), prompts [id - IDC_LAMIAN]);
|
||||
}
|
||||
}
|
||||
|
||||
static int DialogBoxProc2 (HWND hDlg, int message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message) {
|
||||
case MSG_INITDIALOG:
|
||||
{
|
||||
int i;
|
||||
/* 为小吃单选钮设定通知回调函数 */
|
||||
for (i = IDC_LAMIAN; i <= IDC_SHUIJIAO; i++)
|
||||
SetNotificationCallback (GetDlgItem (hDlg, i), my_notif_proc);
|
||||
}
|
||||
return 1;
|
||||
|
||||
case MSG_COMMAND:
|
||||
switch (wParam) {
|
||||
case IDOK:
|
||||
case IDCANCEL:
|
||||
EndDialog (hDlg, wParam);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return DefaultDialogProc (hDlg, message, wParam, lParam);
|
||||
}
|
||||
|
||||
int MiniGUIMain (int argc, const char* argv[])
|
||||
{
|
||||
#ifdef _MGRM_PROCESSES
|
||||
JoinLayer(NAME_DEF_LAYER , "button" , 0 , 0);
|
||||
#endif
|
||||
|
||||
DlgYourTaste.controls = CtrlYourTaste;
|
||||
|
||||
DialogBoxIndirectParam (&DlgYourTaste, HWND_DESKTOP, DialogBoxProc2, 0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef _MGRM_PROCESSES
|
||||
#include <minigui/dti.c>
|
||||
#endif
|
||||
```
|
||||
|
||||

|
||||
__图 1.5__ 按钮控件的使用范例
|
Reference in New Issue
Block a user