微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在选项卡控制区域内添加控件?

如何解决如何在选项卡控制区域内添加控件?

如何获取选项卡控制区域坐标,然后在该区域添加按钮?我不知道我应该使用哪一个 TabCtrl_GetItemRect()GetWindowRect() 或其他东西,因为我似乎没有得到我想要的坐标,这是选项卡控制区域,我可以在那里把按钮。它目前位于远离选项卡控件白色区域的位置,我想将它们放置在那里,如下图所示。将它们放在此选项卡控件中的正确方法是什么?

处理这个的函数是这样的:

void CreateButtons(HWND hwnd)
{
    RECT rt = {0};
    //TabCtrl_GetItemRect(hTab,&rt);
    GetwindowRect(hTab,&rt);
    //GetClientRect(hTab,&rt);
    /*
    wchar_t buffer[256] = {0};
    wsprintf(buffer,L"top = %d,bottom = %d,left = %d,right = %d",rt.top,rt.bottom,rt.left,rt.right);
    MessageBox(NULL,buffer,L"",MB_OK);
    */
    int id = 4;
    static const wchar_t *title[] = { L"Button A",L"Button B",L"Button C",L"Button D",L"Button E",L"Button F",L"Button G",L"Button 001",L"Button 002",L"Button 003",L"Button 004" };
    const int nMaxButtonPerRow = 3;
    const int cx_margin = 10;
    const int cy_bottomMarge = 10;
    const int cy_breakSize = 25;
    int cx_initPos = (int)rt.left;
    int cx = cx_initPos;
    int cy = 50;
    const int width = 80;
    const int height = 25;
    for(int i = 0; i < sizeof(title)/sizeof(title[0]); ++i)
    {
        if(i != 0 && (i % nMaxButtonPerRow) == 0) {
            cy += cy_breakSize + cy_bottomMarge;
            cx = cx_initPos;
        }

        CreateWindow(L"button",title[i],WS_VISIBLE | WS_CHILD | WS_TABSTOP,cx,cy,width,height,hwnd,(HMENU) id++,NULL,NULL);
        cx += width + cx_margin;
    }
}

完整代码

#pragma comment(lib,"user32.lib")
#pragma comment(lib,"Comctl32.lib")
#pragma comment(lib,"Gdi32.lib")

#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE

#include <windows.h>
#include <Commctrl.h>
#include <crtdbg.h>
#include <strsafe.h>
#include <string.h>
#include <assert.h>

#ifdef UNICODE
#define STRSPLIT wcsrchr
#else
#define STRSPLIT strrchr
#endif

#define __FILENAME__ (STRSPLIT(TEXT(__FILE__),'/') ? STRSPLIT(TEXT(__FILE__),'/') + 1 : TEXT(__FILE__))

#define NAMEOF(s) TEXT(#s)

#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))

LRESULT CALLBACK WndProc(HWND,UINT,WParaM,LParaM);
LRESULT CALLBACK CreateTabProc(HWND,LParaM);
void ErrorExit(LPWSTR lpszFunction,int line,LPWSTR filename);
void InitComControls();
void ErrorExit(LPWSTR lpszFunction,LPWSTR filename);
DWORD ShowLastError(LPWSTR lpszFunction,LPWSTR filename);
void InitComControls();
void CreateTab(HWND hwnd);
void InsertTabItem(HWND tabHwnd,UINT id,LPWSTR text);
void CreateButtons(HWND hwnd);

HINSTANCE ghInstance;
HWND hTab;

int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PWSTR pCmdLine,int nCmdshow)
{

    MSG  msg = {0};
    HWND hwnd;
    WNDCLASSW wc = {0};

    wc.lpszClassName = L"Window";
    wc.hInstance     = hInstance;
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpfnWndProc   = WndProc;
    wc.hCursor = LoadCursor(0,IDC_ARROW);
    
    InitComControls();
    if(!RegisterClass(&wc)) {
        ErrorExit(NAMEOF(RegisterClass),__LINE__,__FILENAME__);
    }

    int width = 500;
    int height = 350;
    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight = GetSystemMetrics(SM_CYSCREEN);
    int cx = (screenWidth - width) / 2;
    int cy = (screenHeight - height) / 2;
    hwnd = CreateWindowW(wc.lpszClassName,L"Window",WS_OVERLAPPEDWINDOW | WS_VISIBLE,hInstance,NULL);
    ghInstance = hInstance;

    while (GetMessage(&msg,0))
    {
        if (!IsDialogMessage(hwnd,&msg))
        {
            TranslateMessage(&msg);
            dispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WParaM wParam,LParaM lParam)
{

  switch(msg)
  {
      case WM_CREATE:
        CreateWindowW(L"Static",L"This is label 1...",50,10,130,25,(HMENU) 18,NULL);
        CreateWindowW(L"Static",L"This is label 2...",40,(HMENU) 19,NULL);
          CreateTab(hwnd);
          CreateButtons(hwnd);
          //ChangetoDefaultFont(hwnd);
      break;

      case WM_DESTROY:
          PostQuitMessage(0);
          return 0;
  }

  return DefWindowProc(hwnd,msg,wParam,lParam);
}

void CreateTab(HWND hwnd)
{
  hTab =
   CreateWindow(WC_TABCONTROLW,WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP | WS_EX_CONTROLPARENT,80,400,250,(HMENU) 1,NULL);
    InsertTabItem(hTab,2,L"Tab 1");
    InsertTabItem(hTab,3,L"Tab b");
}

void CreateButtons(HWND hwnd)
{
    RECT rt = {0};
    //TabCtrl_GetItemRect(hTab,NULL);
        cx += width + cx_margin;
    }
}

void InsertTabItem(HWND tabHwnd,LPWSTR text)
{
    TCITEMW tci = {0};
    tci.mask = TCIF_TEXT;
    tci.pszText = text;
    tci.cchTextMax = lstrlenW(text);
    SendMessage(tabHwnd,TCM_INSERTITEMW,id,(LParaM) &tci);
}

void InitComControls()
{
    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_TAB_CLASSES;
    InitCommonControlsEx(&icex);
}

void ErrorExit(LPWSTR lpszFunction,LPWSTR filename)
{
    DWORD dw = ShowLastError(lpszFunction,line,filename);
    ExitProcess(dw);
}

DWORD ShowLastError(LPWSTR lpszFunction,LPWSTR filename)
{
    #define MAX_DIGITS 16

    DWORD dw = GetLastError();
    LPVOID lpMsgBuf;
    LPVOID lpdisplayBuf;
    
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYstem |
        FORMAT_MESSAGE_IGnorE_INSERTS,dw,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR) &lpMsgBuf,NULL
    );

    lpdisplayBuf = (LPVOID) LocalAlloc(LMEM_ZEROINIT,(lstrlen((LPCTSTR)lpMsgBuf) +
            lstrlen((LPCTSTR)lpszFunction) + 40 +
            (line > 0 ? MAX_DIGITS : 0) +
            (filename != NULL ? lstrlen(filename) : 0)) *
            sizeof(TCHAR)
    );
    StringCchPrintf((LPTSTR)lpdisplayBuf,LocalSize(lpdisplayBuf) / sizeof(TCHAR),TEXT("%s Failed with %d: %s"),lpszFunction,lpMsgBuf
    );
    MessageBox(NULL,(LPCTSTR)lpdisplayBuf,TEXT("Error"),MB_OK);
    LocalFree(lpMsgBuf);
    LocalFree(lpdisplayBuf);
    return dw;
}

enter image description here

更新 1: 使用 GetwindowRect()MapWindowPoints() 设法做到了这一点。我错过了前一个。见 this 帖子。它获得了正确的选项卡控件坐标,但还没有获得控件应该打开的显示区域(白色区域)。我怎样才能得到这个白色区域的坐标?如果我设法获得选项卡按钮(由 TCM_INSERTITEM 消息插入的按钮)所在的窗口区域大小,也可以工作(不确定是否非常优雅)在设置 cx_initPos 时会跳过它们价值。

最新代码

void CreateButtons(HWND hwnd)
{
    RECT rt = GetLocalCoordinates(hTab);

    int id = 4;
    static const wchar_t *title[] = { L"Button A",L"Button 004" };
    const int nMaxButtonPerRow = 3;
    const int cx_margin = 10;
    const int cy_bottomMarge = 10;
    const int cy_breakSize = 25;
    int cx_initPos = rt.left;
    int cx = cx_initPos;
    int cy = rt.top;
    const int width = 80;
    const int height = 25;
    for(int i = 0; i < sizeof(title)/sizeof(title[0]); ++i)
    {
        if(i != 0 && (i % nMaxButtonPerRow) == 0) {
            cy += cy_breakSize + cy_bottomMarge;
            cx = cx_initPos;
        }

        CreateWindow(L"button",NULL);
        cx += width + cx_margin;
    }
}

RECT GetLocalCoordinates(HWND hWnd)
{
    RECT Rect;
    GetwindowRect(hWnd,&Rect);
    MapWindowPoints(HWND_DESKTOP,GetParent(hWnd),(LPPOINT) &Rect,2);
    return Rect;
}

现在的样子:

enter image description here

解决方法

如果需要在tab控件中添加按钮,应该传递hTab作为按钮的父类:

CreateButtons(hTab);

根据documentation

x

类型:整数

窗口的初始水平位置。对于重叠或 弹出窗口,x参数是初始x坐标 窗口的左上角,以屏幕坐标表示。对于子窗口, x 是相对窗口左上角的 x 坐标 到父窗口客户区的左上角。如果这 参数设置为CW_USEDEFAULT,系统选择默认 窗口左上角的位置并忽略 y 范围。 CW_USEDEFAULT 仅对重叠窗口有效;如果它 为弹出窗口或子窗口指定,x 和 y 参数是 设置为零。

所以设置的坐标是相对于父窗口的左上角。不需要通过hTab获取GetWindowRect的位置信息,而是应该像下面的代码一样传递相对tab控件的位置:

int cx_initPos = 10;
int cx = cx_initPos;

它对我有用:

enter image description here

补充:如果需要针对不同的标签页进行调整,可以参考这个thread

编辑:

您可以尝试在 TabCtrl_AdjustRect(hTab,FALSE,&rt); 后添加 RECT rt = GetLocalCoordinates(hTab);

RECT rt;
rt = GetLocalCoordinates(hTab);
TabCtrl_AdjustRect(hTab,&rt);

这是你想要的结果吗:

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。