使用Win 32 API设置窗口的最小尺寸以确保文本完全可见。

3
我目前是Win 32 API的初学者,正在制作一个示例程序。我遇到的问题是我找不到一种适当的方法来设置窗口的最小大小,以便在窗口达到最小值时能看到其中的文本(居中)。除了达到某个“临界”大小后,文本只部分可见或根本看不到外,在所有其他情况下文本都是完全可见的。
我找到了如何更改窗口的宽度和高度,如下所示:
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)        
{
    switch (message)                  
    {
        case WM_DESTROY:
            PostQuitMessage (0);      
            break;

        case WM_GETMINMAXINFO: 
            ((MINMAXINFO*)lParam)->ptMinTrackSize.x =100; //apply custom min width
            ((MINMAXINFO*)lParam)->ptMinTrackSize.y =100;  //apply custom min height
            break;

        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint (hwnd, &ps);

            GetClientRect(hwnd,&rc);

            DrawText (hdc, TEXT ("Sample text here"), -1, &rc,DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ;


            EndPaint (hwnd, &ps);
        }
        break;

        default:                      
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

我认为这些行需要改变,但我不知道需要做哪些改变。

((MINMAXINFO*)lParam)->ptMinTrackSize.x =100; //apply custom min width
((MINMAXINFO*)lParam)->ptMinTrackSize.y =100;  //apply custom min height

我的想法是,不要将明确的浮点值赋给 POINT 结构的 x 和 y 成员,而应该调用一个函数来确定文本的最小宽度和高度。

任何帮助都将不胜感激。

以下是此程序的完整代码。

#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif

#include <tchar.h>
#include <windows.h>
#include <stdio.h>


/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");
RECT rc;
int WINAPI WinMain (HINSTANCE hThisInstance,
                 HINSTANCE hPrevInstance,
                 LPSTR lpszArgument,
                 int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */

    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    if (!RegisterClassEx (&wincl))
        return 0;

    hwnd = CreateWindowEx (
       0,                   /* Extended possibilites for variation */
       szClassName,         /* Classname */
       _T("Code::Blocks Template Windows App"),
              /* Title Text */
       WS_OVERLAPPEDWINDOW, /* default window */
       CW_USEDEFAULT,       /* Windows decides the position */
       CW_USEDEFAULT,       /* where the window ends up on the screen */
       544,                 /* The programs width */
       375,                 /* and height in pixels */
       HWND_DESKTOP,        /* The window is a child-window to desktop */
       NULL,                /* No menu */
       hThisInstance,       /* Program Instance handler */
       NULL                 /* No Window Creation data */
       );

    ShowWindow (hwnd, nCmdShow);

    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }

    return messages.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  
    {
        case WM_DESTROY:
            PostQuitMessage (0);       
            break;

        case WM_GETMINMAXINFO:
            //window size/position is going to change
            //apply custom min width/height 350,50

            SIZE sz;
            HDC hdc = GetDC( hwnd );
            TCHAR* myString = TEXT("Sample Text!");
            HFONT oldFont, myFont; //create your own font
            //select your font into device context
            oldFont = (HFONT)SelectObject( hdc, myFont );
            //get font dimensions
            GetTextExtentPoint32( hdc, myString, _tcslen( myString ), &sz );

            ((MINMAXINFO*)lParam)->ptMinTrackSize.x = sz.cx;
            ((MINMAXINFO*)lParam)->ptMinTrackSize.y = sz.cy;

            //cleanup
            SelectObject( hdc, oldFont );
            DeleteObject( myFont );
            ReleaseDC( hwnd, hdc );
            break;

        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint (hwnd, &ps);
                GetClientRect(hwnd,&rc);
                DrawText (hdc, TEXT("Sample Text!"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_WORDBREAK ) ;
                EndPaint (hwnd, &ps);
            }
            break;

        default:                      
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

对于糟糕的缩进表示歉意。


是的,这就是正确的方法。100是任意的而且相当小。 - Hans Passant
我已经编辑了我的回答。尝试复制并粘贴代码-它应该可以工作。最好的问候。 - AlwaysLearningNewStuff
1个回答

0

我认为GetTextExtentPoint32是您想要的,这样您就可以计算文本的大小和长度。 这里 是使用它的示例。

以防您的文本尺寸超过屏幕,您可以添加DT_WORDBREAK 标志到您的DrawText 调用-请参阅文档。

您需要创建字体并在设备上下文中进行选择,CreateFontIndirect 可以帮助你-请注意LOGFONT 结构的成员, 以便您可以创建所需的字体。这里是一个示例。

试试像这样的东西:

case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint (hwnd, &ps);

        //create your own font
        HFONT oldFont, myFont; 
        // create logical font for menu
        LOGFONT lf = { sizeof(lf) };
        _tcscpy_s( lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Microsoft Sans Serif" );
        lf.lfHeight = -MulDiv( 12, GetDeviceCaps( hdc, LOGPIXELSY), 72);
        lf.lfWeight = FW_HEAVY;
        lf.lfItalic = FALSE;
        lf.lfUnderline = FALSE;

        myFont = CreateFontIndirect(&lf);

        //select your font into device context
        oldFont = (HFONT)SelectObject( hdc, myFont );

        GetClientRect(hwnd,&rc);
        DrawText (hdc, TEXT("Sample Text!"), -1, &rc, 
            DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_WORDBREAK ) ;

        //cleanup
        SelectObject( hdc, oldFont );
        DeleteObject( myFont );

        EndPaint (hwnd, &ps);
    }
    return 0L;

case WM_GETMINMAXINFO: 
    {
        SIZE sz;
        HDC hdc = GetDC( hwnd );
        LPTSTR myString = TEXT( "Sample text here" );

        //create your own font 
        HFONT oldFont, myFont; 

        // create logical font for menu
        LOGFONT lf = { sizeof(lf) };
        _tcscpy_s( lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Microsoft Sans Serif" );
        lf.lfHeight = -MulDiv( 12, GetDeviceCaps( hdc, LOGPIXELSY), 72);
        lf.lfWeight = FW_HEAVY;
        lf.lfItalic = FALSE;
        lf.lfUnderline = FALSE;

        myFont = CreateFontIndirect(&lf);

        //select your font into device context
        oldFont = (HFONT)SelectObject( hdc, myFont );

        //get font dimensions
        GetTextExtentPoint32( hdc, myString, _tcslen( myString ), &sz );

        ((MINMAXINFO*)lParam)->ptMinTrackSize.x = sz.cx; 
        ((MINMAXINFO*)lParam)->ptMinTrackSize.y = sz.cy; 

        //cleanup
        SelectObject( hdc, oldFont );
        DeleteObject( myFont );
        ReleaseDC( hwnd, hdc );
    }
break;

如果您有更多问题,请留言。

最好的问候。


非常感谢您提供的代码建议,但是当我尝试运行它时,编译器报告了以下错误:
  1. 'TCHAR* myString' 的初始化交叉
  2. 'HDC__* hdc' 的初始化交叉
我认为这是一个明显的错误,但是我似乎无法理解它的解决方法。
- v01d
我使用Code Blocks。我尝试将LPTSTR更改为TCHAR,但似乎没有帮助。我认为错误也存在于这里: HDC hdc = GetDC(hwnd);也许错误是因为我在WM_GETMINMAXINFO和WM_PAINT中重复了HDC和String声明,尽管我不确定。 无论如何,感谢您的答案,我会将其标记为有用! - v01d
我发布了程序的完整代码。我指定的错误是与此问题相关的唯一错误(另一个错误是错误:跳转到 case 标签)。 - v01d
你需要用括号 {} 包裹你的 WM_GETMINMAXINFO 处理程序-请看我的代码。最好的问候。 - AlwaysLearningNewStuff
谢谢您的见解!出错的原因很有趣,足以避免评论它。现在编译没有任何问题了。现在我猜又出现了一个小问题。当窗口达到最小调整框架时,它保持字符串的宽度(文本完全显示,但窗口的高度仍然非常小,文本看不到)。然而,当我修改((MINMAXINFO*)lParam)->ptMinTrackSize.y = sz.cy; 为 ((MINMAXINFO*)lParam)->ptMinTrackSize.y = sz.cy* (a value); 经过试验和错误,我找到了必要的高度。是否有更合理的方法来解决这个问题? - v01d
@v01d:我尝试过改变字体大小,但是还是找不到解决方案。我的建议是取消接受我的答案,这样其他人也可以帮助你。如果适合你的话,你随时可以再次接受它。这样别人就可以编辑我的答案或者提供解决方案来帮助你调整窗口高度。我会继续寻找解决方案,并在找到后更新我的答案。祝你好运,最好的问候。 - AlwaysLearningNewStuff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接