当前位置:C++技术网 > 精选软件 > 单选按钮控件的分组问题深度分析

单选按钮控件的分组问题深度分析

更新时间:2016-02-05 19:16:30浏览次数:1+次

    单选按钮控件,对于有编程经验的人,都已经太熟悉了。不过我还是要说说一些我们并不熟悉的细节。
    和复选框一样,单选按钮有自动切换状态的和非自动切换状态的。复选框控件的分析,请阅读《四种复选框控件的状态类型详细分析》。这样,单选按钮的状态切换问题,我就不重复了。
    对于单选按钮控件来说,分组是单选按钮的特色问题。这也是我们最关心的问题。很多时候,我们也在用,也似乎用的不错。然而到底单选按钮们是如何分组的,并不是所有人都说的清楚。到现在为止,我之前一直都是模模糊糊的,所以,在彻底掌握之后,我总结出来。希望你看到这篇文章之后,就不会再对单选按钮分组问题有任何的阴影或者模糊的地方了。
    单选按钮分组搞清楚了,单选按钮的使用也就没有大问题了。如果我们直接创建了很多个单选按钮,都放在一个窗口上。那么你会发现,所有的单选按钮只有一个能够选中。因为单选按钮的默认的相互排斥。在一个窗口中的多个单选按钮控件,都是这个窗口的子窗口。在默认情况下,所有的单选按钮就形成了一组,也就一次只能有一个单选按钮被选中。就算你将这些单选按钮放在窗口的不同的位置,看上去好像是几组,实际上通过位置是不能对单选按钮分组的。
    然后你会不会想到了分组框控件,会不会以为分组框中的几个单选按钮就是一组呢?其实这样是没有用的。
    要设置分组,就要用到WS_GROUP窗口风格。每一组的组长,需要拥有WS_GROUP窗口风格。然后跟着创建的单选按钮,都归这一组。在随后创建的单选按钮中,如果遇到一个单选按钮也有WS_GROUP窗口风格的,那么上一组就结束了。这个拥有WS_GROUP风格的单选按钮成为下一组的组长了。

    我们可以看到,单选按钮的分组,是通过WS_GROUP风格。组员就是在组长创建后创建的单选按钮。下面是我们实际的分组后的效果图:

单选按钮分组后的效果图

【单选按钮分组后的效果图】

    下面是单选按钮分组的原理示意图:

单选按钮分组的原理示意图

【单选按钮分组的原理示意图】
    如果在遇到WS_GROUP风格的单选按钮前,已经有了很多单选按钮,那么那些单选按钮也会默认构成一组。通过测试,前面的单选按钮和最后一组形成一组。
    单选按钮分组后,我们可以在每一组中互斥的选择,在一组中只能选择一个。每一组都可以选择一个。如果是在对话框中,我们通过确定Tab键顺序,来决定单选按钮控件的创建顺序,进而决定分组中拥有的组员。对于Tab键顺序的分析,请阅读《什么是Tab键顺序,Tab键顺序的本质含义是什么》。

    我们看下面这个Tab键顺序图:

Ctrl+D显示和修改Tab键顺序图

【Ctrl+D显示和修改Tab键顺序图】
    图中标注方框的单选按钮是一组,标注圆圈的单选按钮是一组。有WS_GROUP风格的单选按钮是组长。图中显示的数字是Tab键顺序,这个顺序决定了单选按钮的创建顺序。也就是说,标号为4的单选按钮,虽然在界面上在2之下,但是它是在3后面创建的,所以3自然而然是第一组的成员。然后4创建后,4成为了第二组的组长,因为它有WS_GROUP风格,后面创建的5和6也就成为了第二组成员。所以不要以为3是第二组的成员哦。

    所以在理解Tab键顺序是非常关键的。如果再复杂点,我们只要时刻知道Tab键顺序和WS_GROUP风格,就不会凌乱了。

    下面是完整的代码:


#include "windows.h"
#include <tchar.h>
// - 项目是Unicode字符集
TCHAR tip[]=_T("C++技术网http://www.cjjjs.com");
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    static HWND h1,h2,h3,h4,h5,h6,h7;
    switch (message)
    {
        case WM_CREATE:
            {
                h1 = CreateWindow(_T("button"),tip,WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON|WS_GROUP,0,0,250,20,hwnd,(HMENU)1,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
                h2 = CreateWindow(_T("button"),tip,WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON,0,20,250,20,hwnd,(HMENU)2,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
                h3 = CreateWindow(_T("button"),tip,WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON|WS_GROUP,100,40,250,20,hwnd,(HMENU)3,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
                h4 = CreateWindow(_T("button"),tip,WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON,0,60,250,20,hwnd,(HMENU)4,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
                h5 = CreateWindow(_T("button"),tip,WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON,200,80,250,20,hwnd,(HMENU)5,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
                h6 = CreateWindow(_T("button"),tip,WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON|WS_GROUP,0,100,250,20,hwnd,(HMENU)6,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
                h7 = CreateWindow(_T("button"),tip,WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON,0,120,250,20,hwnd,(HMENU)7,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
                SendMessage(h1,BM_SETCHECK,1,0);
                SendMessage(h3,BM_SETCHECK,1,0);
                SendMessage(h6,BM_SETCHECK,1,0);
                return 0;
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0); 
            return 0;
        default:
        break;//跳出到默认处理
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;

    if(!RegisterClass(&wndClass))return 0;
    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,10,100,600,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}