我用纯C语言写了一个简单的win32图形用户界面应用程序,包括按钮和其他控件,没有MFC。我想让那些不能使用鼠标的人更容易使用它。
首先,我的示例代码不能响应 Tab
键将焦点从一个按钮移动到另一个按钮。我可以用鼠标按下UI按钮,然后它就会变成焦点,我可以使用 Space-bar
但我不能使用以下方法将焦点移动到其他按钮上 Tab
或 Shift+Tab
. 如何解决这个问题?
我想给按钮分配键盘提示(小下划线),这样用户就可以使用键盘快捷键来激活按钮。
我有谷歌周围,但答案是很难谷歌,所以我需要有人指出我的一些文档。一个小的代码将是非常有用的。
下面是我的代码。我用WINE + TinyCC在Linux上编译和运行。
#include <stdio.h>
#include <windows.h>
/* Yeres distributed forums node v0001 */
/* compile: wine tcc_win/tcc/tcc.exe win_yeres */
HWND status_text_hwnd = NULL;
HWND shutdown_hs_button_hwnd = NULL;
unsigned int button_height = 26;
unsigned int window_length = 400;
#define V_BUTTON_PADDING 2
int tor_running = 0;
int select_running = 0;
#include "yeres_bind.c"
#include "win_yeres_w1_proc.c"
int APIENTRY WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
) {
MSG msg;
WNDCLASS wc;
HWND hwnd;
printf("\n ** YERES v0001 **\n\n");
// Fill in window class structure with parameters that describe
// the main window.
ZeroMemory(&wc, sizeof wc);
wc.hInstance = hInstance;
wc.lpszClassName = "yeres_wcl";
wc.lpfnWndProc = (WNDPROC)w1_proc;
wc.style = CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 0);
wc.hIcon = LoadIcon(NULL, IDI_EXCLAMATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
if (FALSE == RegisterClass(&wc)) return 0;
RECT client_rect;
client_rect.left = 0;
client_rect.top = 0;
client_rect.right = window_length;
client_rect.bottom = 500;
/* calculate window size from known client area size */
if (0 == AdjustWindowRect(&client_rect, wc.style, 0)) return 0;
// create main window
hwnd = CreateWindow(
"yeres_wcl",
"YERES control panel",
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
30,
30,
client_rect.right, //CW_USEDEFAULT
client_rect.bottom,
0,
0,
hInstance,
0);
if (NULL == hwnd) return 0;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
#define ID_TOR_CONTROL_PORT 1
#define ID_BIND 2
#define ID_UNBIND 3
#define ID_TOR_SHUTDOWN_HS 4
#define ID_PORT_NUM 5
#define ID_QUIT 6
LRESULT CALLBACK w1_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
int y = 4;
int x;
RECT rc;
switch (message) {
case WM_CREATE:
ZeroMemory(&rc, sizeof(rc));
GetClientRect(hwnd, &rc);
if (rc.right) window_length = rc.right - rc.left;
status_text_hwnd = CreateWindow("Static",
"** YERES v0001 **\n\nPress 'Bind to localhost'..",
WS_CHILD | WS_VISIBLE | SS_CENTER,
3, y, window_length, (button_height * 3),
hwnd, (HMENU) 1, NULL, NULL);
y += button_height * 3;
x = 2;
CreateWindow("Static", "Port:",
WS_CHILD | WS_VISIBLE | SS_CENTER,
x, y, 60, button_height,
hwnd, (HMENU) 1, NULL, NULL);
x += 60;
/* editable field here */
CreateWindow("Edit", "19407",
WS_CHILD | WS_VISIBLE | WS_BORDER,
x, y, 90, button_height, hwnd, (HMENU) ID_PORT_NUM,
NULL, NULL);
x += 120;
CreateWindow("Button", "Bind to localhost",
WS_VISIBLE | WS_CHILD ,
x, y, 140, button_height,
hwnd, (HMENU) ID_BIND, NULL, NULL);
x += 140;
CreateWindow("Button", "Unbind",
WS_VISIBLE | WS_CHILD ,
x, y, window_length - 2 - x, button_height,
hwnd, (HMENU) ID_UNBIND, NULL, NULL);
y += button_height + V_BUTTON_PADDING;
CreateWindow("Button", "Use tor control port to start HiddenService",
WS_VISIBLE | WS_CHILD ,
2, y, window_length - 4, button_height,
hwnd, (HMENU) ID_TOR_CONTROL_PORT, NULL, NULL);
y += button_height + V_BUTTON_PADDING;
shutdown_hs_button_hwnd = CreateWindow("Button", "Shutdown HiddenService",
WS_VISIBLE | WS_CHILD ,
2, y, window_length - 4, button_height,
hwnd, (HMENU) ID_TOR_SHUTDOWN_HS, NULL, NULL);
EnableWindow(shutdown_hs_button_hwnd, 0); /* inactive button */
y += button_height + V_BUTTON_PADDING;
CreateWindow("Button", "Shutdown EVERYTHING and QUIT",
WS_VISIBLE | WS_CHILD ,
2, y, window_length - 4, button_height,
hwnd, (HMENU) ID_QUIT, NULL, NULL);
y += button_height + V_BUTTON_PADDING;
break;
case WM_DESTROY:
if (!tor_running && !select_running) PostQuitMessage(0);
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case ID_BIND:
yeres_bind();
break;
case ID_QUIT:
PostQuitMessage(0);
break;
default: DefWindowProc(hwnd, message, wParam, lParam);
}
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
};
return 0;
};
P.S. Sorry my bad English :)
这很简单。在主消息处理循环中,我调用 IsDialogMessage()
适当 HWND
. 然后,如果这个函数返回0,我就调用正常的TranslateMessage和DispatchMessage函数。下面是代码。
while(GetMessage(&msg, NULL, 0, 0) > 0) {
if(!IsDialogMessage(hwnd, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
};
yeres_select(); /* scan incoming connections on sockets using select(), activated by timer and/or other messages */
}
窗口中的每个按钮都有位 WS_TABSTOP
设置,所以当我按 Tab
, IsDialogMessage()
会捕捉到信息并将焦点移到下一个按钮。可编辑也可以这样选择。
WS_GROUP
对我来说没有用。理论上它应该允许我使用方向键导航。我已经把 WS_GROUP
位在第一个按钮上。
CreateWindow("Button", "&Bind to localhost",
WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP,
x, y, 140, button_height,
hwnd, (HMENU) ID_BIND, NULL, NULL);
安培符号即使在不使用 TranslateAccelerator()
调用,只需将其放入标签文本中 "&Bind to localhost"
激活按钮,可以使用 Alt+B
左右。它是不区分大小写的。
我没有在Windows上检查它,但我想如果它在WINE中工作的话,应该是可以的。