Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Winapi 如何获得窗口的确切大小';s区域,包括隐藏控件?_Winapi_Window_Height_Scrollbar - Fatal编程技术网

Winapi 如何获得窗口的确切大小';s区域,包括隐藏控件?

Winapi 如何获得窗口的确切大小';s区域,包括隐藏控件?,winapi,window,height,scrollbar,Winapi,Window,Height,Scrollbar,我需要得到整个窗口的显示区域大小,包括隐藏的控件。为了做到这一点,我从第一个窗口的顶部获取值,从最后一个控件获取底部的值。然而,我在显示区的末端发现了一个空白/白色区域。请参见下图。在看到编辑控件的边框之前,显示区域应一直显示。我错过了什么 我通过以下方式获得此尺寸: int scrollHeight(void) { int minTop = 0; int maxBottom = 0; RECT rt = {0}; if(allControls_indx ==

我需要得到整个窗口的显示区域大小,包括隐藏的控件。为了做到这一点,我从第一个窗口的顶部获取值,从最后一个控件获取底部的值。然而,我在显示区的末端发现了一个空白/白色区域。请参见下图。在看到编辑控件的边框之前,显示区域应一直显示。我错过了什么

我通过以下方式获得此尺寸:

int scrollHeight(void)
{
    int minTop = 0;
    int maxBottom = 0;
    RECT rt = {0};

    if(allControls_indx == 0) {
        return 0;
    }

#if 0
    assert(allControls[0] == hMainWindow);
    assert(allControls[allControls_indx - 1] == hEdit1);
#endif

    if(!GetWindowRect(allControls[0], &rt)) {
        ErrorExit(NAMEOF(scrollHeight), __LINE__, __FILENAME__);
    }

    minTop = rt.top;

    if(!GetWindowRect(allControls[allControls_indx - 1], &rt)) {
        ErrorExit(NAMEOF(scrollHeight), __LINE__, __FILENAME__);
    }

    maxBottom = rt.bottom;
    return maxBottom - minTop;
}
设置为滚动条的页面大小,如下所示:

    setUpScrollBar(hwnd, scrollHeight());
其中
setUpScrollBar
定义为:

void setUpScrollBar(HWND hwnd, int h)
{
    RECT rc = { 0 };
    GetClientRect(hwnd, &rc);
    SCROLLINFO si = { 0 };
    si.cbSize = sizeof(SCROLLINFO);
    si.fMask = SIF_ALL;
    si.nMin = 0;
    si.nMax = h;
    si.nPage = (rc.bottom - rc.top);
    si.nPos = 0;
    si.nTrackPos = 0;
    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}
完整代码:

#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, UINT, WPARAM, LPARAM);
void ErrorExit(LPWSTR lpszFunction, int line, LPWSTR filename);
void InitComControls();
void ErrorExit(LPWSTR lpszFunction, int line, LPWSTR filename);
DWORD ShowLastError(LPWSTR lpszFunction, int line, LPWSTR filename);
void InitComControls();
void CreateTab(HWND hwnd);
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text);
void CreateButtons(HWND hwnd);
RECT GetLocalCoordinates(HWND hWnd);
int scrollHeight(void);
int getHeight(HWND control);
void setUpScrollBar(HWND hwnd, int);
void pushControl(HWND);
int displayArea(void);
void setScrollBarSize(HWND hwnd, int s);
inline int my_max(int a, int b);
inline int my_min(int a, int b);
void displayText(HWND h);

HINSTANCE ghInstance;
HWND hTab;
HWND hLabel1, hLabel2;
HWND hEdit1;
HWND hRemoveButton;

enum
{
    IDBUTTON_REMOVE = 50
};

#define MAX_CONTROLS 8

static const wchar_t *title[] = { L"Button A1", L"Button B2", L"Button C3",
                                  L"Button D4", L"Button E5", L"Button F6",
                                  L"Button G" , L"Button 001", L"Button 002",
                                  L"Button 003", L"Button 004",
                                  L"Button 005", L"Button 006" };
HWND hButton[sizeof(title)/sizeof(title[0])] = {0};
HWND allControls[MAX_CONTROLS];
HWND hMainWindow;
int allControls_indx = 0;

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/2; // half than the usual size, so that the scrollbar show up and we can test it
    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"main window",
                        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                        cx, cy, width, height, NULL, NULL, 
                        hInstance, NULL);
    ghInstance = hInstance;

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

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int g_scrollY;

  switch(msg)
  {
      case WM_CREATE:
        hMainWindow = hwnd;
        pushControl(hwnd); // push main window too

        hLabel1 = CreateWindowW(L"Static", L"This is label 1...",
          WS_VISIBLE | WS_CHILD | WS_TABSTOP,
          50, 10, 130, 25, hwnd, (HMENU) 18, NULL, NULL);
        pushControl(hLabel1);
        hLabel2 = CreateWindowW(L"Static", L"This is label 2...",
          WS_VISIBLE | WS_CHILD | WS_TABSTOP,
          50, 40, 130, 25, hwnd, (HMENU) 19, NULL, NULL);
        
        hRemoveButton = CreateWindow(L"Button", L"Remove",
                                     WS_VISIBLE | WS_CHILD | WS_TABSTOP,
                                     200, 40, 80, 25,
                                     hwnd,
                                     (HMENU) IDBUTTON_REMOVE,
                                     NULL,
                                     NULL);

        pushControl(hLabel2);
        CreateTab(hwnd);
        CreateButtons(hwnd);
        setUpScrollBar(hwnd, scrollHeight());
      break;

      case WM_VSCROLL:
      {
        int action = LOWORD(wParam);
        //HWND hScroll = (HWND)lParam;
        int pos = -1;
        if (action == SB_THUMBPOSITION || action == SB_THUMBTRACK) {
            pos = HIWORD(wParam);
        } else if (action == SB_LINEDOWN) {
            pos = g_scrollY + 30;
        } else if (action == SB_LINEUP) {
            pos = g_scrollY - 30;
        } 
        if (pos == -1)
            break;
        
        SCROLLINFO si = { 0 };
        si.cbSize = sizeof(SCROLLINFO);
        si.fMask = SIF_POS;
        si.nPos = pos;
        si.nTrackPos = 0;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
        GetScrollInfo(hwnd, SB_VERT, &si);
        pos = si.nPos;
        POINT pt;
        pt.x = 0;
        pt.y = pos - g_scrollY;
        HDC hdc = GetDC(hwnd);
        LPtoDP(hdc, &pt, 1);
        ReleaseDC(hwnd, hdc);
        ScrollWindow(hwnd, 0, -pt.y, NULL, NULL);
        g_scrollY = pos;
        return 0;
    }
      
    break;

    case WM_COMMAND:
    {
        switch(LOWORD(wParam))
        {
            case IDBUTTON_REMOVE:
                ShowWindow(hEdit1, SW_HIDE);
                SetScrollRange(hwnd, SB_VERT, 0, displayArea(), TRUE);
            break;
        }
    }
    break;

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

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

// this is like scrollHeight but control that are hidden
// aren't considered part of the display area.
int displayArea(void)
{
    int size = scrollHeight();

    // start i with 1 so we skip the mainwindow.
    // we are interested in the "children controls"
    for(int i = 1; i < MAX_CONTROLS && allControls[i]; i++)
    {
        HWND h = allControls[i];
        // if it not visible, remove it from display area
        if(!IsWindowVisible(h)) {
            size -= getHeight(h);
        }
    }

    return size;
}

void pushControl(HWND hwnd)
{
    if(allControls_indx > MAX_CONTROLS) {
        assert(!"no room for extra controls");
    }

    allControls[allControls_indx++] = hwnd;
}

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

    pushControl(hTab);
}

void CreateButtons(HWND hwnd)
{
    RECT rt = GetLocalCoordinates(hTab);
    TabCtrl_AdjustRect(hTab, FALSE, &rt);


    RECT rt2 = {0};
    GetWindowRect(hTab, &rt2);
    int tab_width = rt2.right - rt2.left;
    int tab_height = rt2.bottom - rt2.top;
    
    int id = 4;

    const int cy_breakSize = 25;
    int cx_initPos = rt.left;
    int cy_initPos = rt.top;
    int cx = cx_initPos;
    int cy = cy_initPos;
    const int button_width = 80;
    const int button_height = 25;
    const int cx_margin = 10;
    int nMaxButtonPerRow = tab_width / (button_width + cx_margin);

    for(int i = 0; i < sizeof(title)/sizeof(title[0]); ++i)
    {
        if(i != 0 && (i % nMaxButtonPerRow) == 0) {
            cy += cy_breakSize;
            cx = cx_initPos;
        }

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

    const int edit_width = 180;
    const int edit_height = 25;
    hEdit1 = CreateWindow(L"Edit", L"Hello, world!",
                          WS_VISIBLE | WS_CHILD | WS_BORDER,
                          cx,
                          // put below tab control's display area
                          getHeight(hTab) + cx,
                          edit_width,
                          edit_height,
                          hwnd,
                          (HMENU) id++,
                          NULL, NULL);
    pushControl(hEdit1);
    cx += edit_width;
}

void setUpScrollBar(HWND hwnd, int h)
{
    RECT rc = { 0 };
    GetClientRect(hwnd, &rc);
    SCROLLINFO si = { 0 };
    si.cbSize = sizeof(SCROLLINFO);
    si.fMask = SIF_ALL;
    si.nMin = 0;
    si.nMax = h;
    si.nPage = (rc.bottom - rc.top);
    si.nPos = 0;
    si.nTrackPos = 0;
    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}

void setScrollBarSize(HWND hwnd, int s)
{
    SCROLLINFO si = { 0 };
    si.cbSize = sizeof(SCROLLINFO);
    si.fMask = SIF_RANGE;
    si.nMin = 0;
    si.nMax = s;
    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}

int getHeight(HWND control)
{
    RECT rt;

    if(!GetWindowRect(control, &rt)) {
        ErrorExit(NAMEOF(getHeight), __LINE__, __FILENAME__);
    }

    return rt.bottom - rt.top;
}

void displayText(HWND h)
{
    int len = GetWindowTextLength(h);
    
    if(len == 0) {
        return;
    }

    wchar_t buffer[len + 1];
    memset(buffer, 0, sizeof(buffer));
    GetWindowText(h, buffer, len+1);
    MessageBox(NULL, buffer, L"control text = ", MB_OK);
}

int scrollHeight(void)
{
    int minTop = 0;
    int maxBottom = 0;
    RECT rt = {0};

    if(allControls_indx == 0) {
        return 0;
    }

#if 0
    assert(allControls[0] == hMainWindow);
    assert(allControls[allControls_indx - 1] == hEdit1);
#endif

    if(!GetWindowRect(allControls[0], &rt)) {
        ErrorExit(NAMEOF(scrollHeight), __LINE__, __FILENAME__);
    }

    minTop = rt.top;

    if(!GetWindowRect(allControls[allControls_indx - 1], &rt)) {
        ErrorExit(NAMEOF(scrollHeight), __LINE__, __FILENAME__);
    }

    maxBottom = rt.bottom;
    return maxBottom - minTop;
}

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

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

void InitComControls()
{
    INITCOMMONCONTROLSEX icex;
    /* initialize this component is required to use tab control,
        it seems.
    */
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_TAB_CLASSES;
    InitCommonControlsEx(&icex);
}

// display the error message from last error seen then
// exit the application, with that last error code seen.
// to test function, do something like:
//       if(!GetProcessId(NULL))
//          errorExit(TEXT("GetProcessId"));
// not quite a unittest but yeah.
void ErrorExit(LPWSTR lpszFunction, int line, LPWSTR filename)
{
    DWORD dw = ShowLastError(lpszFunction, line, filename);
    ExitProcess(dw);
}

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

   /* 
    * NOTE!!: calling GetLastError() must be done before calling
    * any other function, that would reset the GetLastError(), making
    * this function report error about the wrong function.
    */
    DWORD dw = GetLastError();
    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0,
        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, dw, lpMsgBuf
    );
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    return dw;
}
#pragma注释(lib,“user32.lib”)
#pragma注释(lib,“Comctl32.lib”)
#pragma注释(lib,“Gdi32.lib”)
#定义WIN32_精益_和_平均值
#定义UNICODE
#定义UNICODE
#包括
#包括
#包括
#包括
#包括
#包括
#ifdef UNICODE
#定义STRSPLIT wcsrchr
#否则
#定义STRSPLIT strrchr
#恩迪夫
#定义uuu文件名uuuu(STRSPLIT(TEXT(uuuu文件),“/”)?STRSPLIT(TEXT(uuu文件),“/”)+1:TEXT(uu文件))
#定义文本的名称(#s)
#定义(a)(sizeof(a)/sizeof(a[0])的计数
LRESULT回调WndProc(HWND、UINT、WPARAM、LPARAM);
LRESULT回调CreateTabProc(HWND、UINT、WPARAM、LPARAM);
void ErrorExit(LPWSTR lpszFunction,int行,LPWSTR文件名);
void InitComControls();
void ErrorExit(LPWSTR lpszFunction,int行,LPWSTR文件名);
DWORD ShowLastError(LPWSTR LPSZ函数,int行,LPWSTR文件名);
void InitComControls();
void CreateTab(HWND-HWND);
void InsertTabItem(HWND tabHwnd、UINT id、LPWSTR text);
无效创建按钮(HWND HWND);
RECT GetLocalCoordinates(HWND-HWND);
内部滚动高度(无效);
int getHeight(HWND控制);
无效设置滚动条(HWND HWND,int);
无效推力控制(HWND);
int显示区域(无效);
无效设置CrollBarSize(HWND HWND,int s);
内联int my_max(int a,int b);
内联int my_min(int a,int b);
无效显示文本(HWND h);
例如,HINSTANCE;
HWND-hTab;
HWND hLabel1,hLabel2;
HWND-hEdit1;
HWND-hremove按钮;
枚举
{
IDBUTTON_REMOVE=50
};
#定义MAX_控件8
静态常量wchar_t*标题[]={L“按钮A1”、L“按钮B2”、L“按钮C3”,
L“按钮D4”,L“按钮E5”,L“按钮F6”,
L“按钮G”,L“按钮001”,L“按钮002”,
L“按钮003”,L“按钮004”,
L“按钮005”,L“按钮006”};
HWND hButton[sizeof(title)/sizeof(title[0])]={0};
HWND allControls[最大控制];
主窗口;
int-allControls_indx=0;
int WINAPI wWinMain(HINSTANCE HINSTANCE、HINSTANCE hPrevInstance、,
PWSTR pCmdLine,int nCmdShow)
{
MSG={0};
HWND-HWND;
WNDCLASSW wc={0};
wc.lpszClassName=L“窗口”;
wc.hInstance=hInstance;
wc.hbrBackground=GetSysColorBrush(颜色面);
wc.lpfnWndProc=WndProc;
wc.hCursor=加载光标(0,IDC_箭头);
InitComControls();
如果(!注册表类(&wc)){
ErrorExit(注册表类的名称),\uuuuu行\uuuuuuuuuuuuu文件名\uuuuuuuuu);
}
整数宽度=500;
int height=350/2;//比通常大小的一半,这样滚动条就会显示出来,我们可以测试它
int screenWidth=GetSystemMetrics(SM_CXSCREEN);
int screenHeight=GetSystemMetrics(SM_CYSCREEN);
int cx=(屏幕宽度-宽度)/2;
int cy=(屏幕高度-高度)/2;
hwnd=CreateWindowW(wc.lpszClassName,L“主窗口”,
WS|U重叠窗口| WS|U可见,
cx、cy、宽度、高度、NULL、NULL、,
hInstance,NULL);
ghInstance=hInstance;
while(GetMessage(&msg,NULL,0,0))
{
如果(!IsDialogMessage(hwnd和msg))
{
翻译信息(&msg);
发送消息(&msg);
}
}
返回(int)msg.wParam;
}
LRESULT回调WndProc(HWND HWND,UINT msg,WPARAM WPARAM,LPARAM LPARAM)
{
静态int g_滚动;
开关(msg)
{
案例WM_创建:
hMainWindow=hwnd;
pushControl(hwnd);//也按主窗口
hLabel1=CreateWindowW(L“静态”,L“这是标签1…”,
WS|u可见| WS|u儿童| WS|u禁忌,
50,10,130,25,hwnd,(HMENU)18,NULL,NULL);
推送控制(hLabel1);
hLabel2=CreateWindowW(L“静态”,L“这是标签2…”,
WS|u可见| WS|u儿童| WS|u禁忌,
50,40,130,25,hwnd,(HMENU)19,空,空);
hRemoveButton=CreateWindow(L“按钮”,L“删除”,
WS|u可见| WS|u儿童| WS|u禁忌,
200, 40, 80, 25,
hwnd,
(笑)我的按钮被移除,
无效的
无效);
pushControl(hLabel2);
CreateTab(hwnd);
创建按钮(hwnd);
设置滚动条(hwnd,scrollHeight());
打破
案例WM_VSCROLL:
{
int action=LOWORD(wParam);
//HWND hScroll=(HWND)lParam;
int pos=-1;
如果(动作==SB|U拇指位置|动作==SB|U拇指轨迹){
pos=HIWORD(wParam);
}else if(action==SB\u LINEDOWN){
位置=g_滚动+30;
}否则如果(动作==SB\U阵容){
位置=g_滚动-30;
} 
如果(位置==-1)
打破
SCROLLINFO si={0};
si.cbSize=sizeof(SCROLLINFO);
si.fMask=SIF_POS;
si.nPos=pos;
si.nTrackPos=0;
SetScrolInfo(hwnd、SB_VERT和si、TRUE);
获取滚动信息(hwnd、SB_VERT和si);
pos=si.nPos;
点pt;
pt.x=0;
pt.y=位置-g_滚动;
HDC HDC=GetDC(hwnd);
LPtoDP(hdc和pt,1);
释放DC(hwnd、hdc);
滚动窗口(hwnd,0,-pt.y,NULL,NULL);
g_scrollY=pos;
返回0;
}
打破
case WM_命令:
{
开关(LOWORD
if (!GetWindowRect(allControls[1], &rt)) {
    ErrorExit((LPWSTR)NAMEOF(scrollHeight), __LINE__, (LPWSTR)__FILENAME__);
}
minTop = rt.top;
return maxBottom - minTop + y; //The y size of the topmost control.