以下是一个实现 x 坐标右对齐的 VC++ 代码示例:

#include <windows.h>
#include <string>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("RightAlignXAxis");
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName, TEXT("Right Align X Axis"), WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);

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

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static int cxClient, cyClient;
    static int cxChar, cyChar;
    static int cchMaxXAxisLabel;
    static std::wstring strXAxisLabel;
    static int iXAxisMin = 0, iXAxisMax = 100;
    static int iYAxisMin = 0, iYAxisMax = 100;
    static int iXScale = 10, iYScale = 10;
    static int iXAxisLabelStep = 10, iYAxisLabelStep = 10;
    static int iXAxisLabelOffset = 0, iYAxisLabelOffset = 0;

    HDC hdc;
    PAINTSTRUCT ps;
    int i, x, y;
    TCHAR szBuffer[10];

    switch (message)
    {
    case WM_CREATE:
        hdc = GetDC(hwnd);
        cxChar = LOWORD(GetDialogBaseUnits());
        cyChar = HIWORD(GetDialogBaseUnits());
        ReleaseDC(hwnd, hdc);

        cchMaxXAxisLabel = 10;
        strXAxisLabel.resize(cchMaxXAxisLabel, TEXT(' '));

        return 0;

    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);

        return 0;

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

        // Draw X and Y axes
        MoveToEx(hdc, 0, cyClient / 2, NULL);
        LineTo(hdc, cxClient, cyClient / 2);
        MoveToEx(hdc, cxClient / 2, 0, NULL);
        LineTo(hdc, cxClient / 2, cyClient);

        // Draw X axis labels
        SetTextAlign(hdc, TA_RIGHT | TA_TOP);
        for (i = iXAxisMin; i <= iXAxisMax; i += iXAxisLabelStep)
        {
            x = cxClient / 2 + i * cxChar * iXScale - iXAxisLabelOffset;
            if (x >= 0 && x <= cxClient)
            {
                wsprintf(szBuffer, TEXT("%d"), i);
                ExtTextOut(hdc, x, cyClient / 2 + cyChar / 2, ETO_OPAQUE, NULL, szBuffer, lstrlen(szBuffer), NULL);
            }
        }

        // Draw Y axis labels
        SetTextAlign(hdc, TA_RIGHT | TA_BOTTOM);
        for (i = iYAxisMin; i <= iYAxisMax; i += iYAxisLabelStep)
        {
            y = cyClient / 2 - i * cyChar * iYScale + iYAxisLabelOffset;
            if (y >= 0 && y <= cyClient)
            {
                wsprintf(szBuffer, TEXT("%d"), i);
                TextOut(hdc, cxClient / 2 - cxChar / 2, y, szBuffer, lstrlen(szBuffer));
            }
        }

        EndPaint(hwnd, &ps);

        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);

        return 0;

    case WM_CLIPBOARDUPDATE:
        if (IsClipboardFormatAvailable(CF_BITMAP))
        {
            OpenClipboard(hwnd);
            HBITMAP hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);
            CloseClipboard();

            if (hBitmap != NULL)
            {
                BITMAP bm;
                GetObject(hBitmap, sizeof(bm), &bm);

                int cxImage = bm.bmWidth;
                int cyImage = bm.bmHeight;

                // Calculate X axis label offset for right alignment
                int cxMaxXAxisLabel = 0;
                for (i = iXAxisMin; i <= iXAxisMax; i += iXAxisLabelStep)
                {
                    wsprintf(szBuffer, TEXT("%d"), i);
                    strXAxisLabel.replace(0, lstrlen(szBuffer), szBuffer);
                    int cxLabel = GetTextExtentPoint32(hdc, strXAxisLabel.c_str(), lstrlen(strXAxisLabel.c_str()), NULL).cx;
                    if (cxLabel > cxMaxXAxisLabel)
                    {
                        cxMaxXAxisLabel = cxLabel;
                    }
                }
                iXAxisLabelOffset = cxMaxXAxisLabel;

                // Draw image with right-aligned X axis labels
                hdc = CreateCompatibleDC(NULL);
                HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdc, hBitmap);
                SetTextAlign(hdc, TA_RIGHT | TA_TOP);
                for (i = iXAxisMin; i <= iXAxisMax; i += iXAxisLabelStep)
                {
                    x = cxImage / 2 + i * cxChar * iXScale - iXAxisLabelOffset;
                    if (x >= 0 && x <= cxImage)
                    {
                        wsprintf(szBuffer, TEXT("%d"), i);
                        ExtTextOut(hdc, x, cyImage / 2 + cyChar / 2, ETO_OPAQUE, NULL, szBuffer, lstrlen(szBuffer), NULL);
                    }
                }
                SelectObject(hdc, hOldBitmap);
                DeleteDC(hdc);
            }
        }

        return 0;

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

在上面的代码中,我们在窗口的WM_PAINT消息处理程序中使用SetTextAlign函数设置了文本对齐方式为右对齐,并使用ExtTextOut函数绘制 X 轴标签。为了实现右对齐,我们需要在 X 轴标签的位置上减去标签字符串的长度,这里使用了GetTextExtentPoint32函数来获取标签字符串的长度。

在窗口的WM_CLIPBOARDUPDATE消息处理程序中,我们首先检查剪贴板中是否有位图格式的数据。如果有,我们使用GetClipboardData函数获取位图句柄,然后使用GetObject函数获取位图的信息,包括宽度和高度。接着,我们计算出 X 轴标签的最大长度,并将其保存在变量iXAxisLabelOffset中。最后,我们使用ExtTextOut函数绘制右对齐的 X 轴标签,并将位图复制到剪贴板中。

需要注意的是,在窗口的WM_CREATE消息处理程序中,我们使用GetDialogBaseUnits函数获取对话框基本单元的宽度和高度,用于计算字符宽度和高度。在窗口的WM_SIZE消息处理程序中,我们保存窗口的客户区宽度和高度,用于绘制 X 和 Y 轴。在窗口的WM_DESTROY消息处理程序中,我们调用PostQuitMessage函数退出程序。

解决方案:

在复制到剪贴板后,我们创建了一个兼容的设备上下文(DC),并使用 SelectObject 将位图选择到该 DC 中。然后,我们再次使用 GetTextExtentPoint32 函数获取每个标签字符串的长度,并使用 ExtTextOut 函数在位图上绘制标签。最后,我们释放 DC 和选择对象。

修改后的代码:

// ... (其他代码)

case WM_CLIPBOARDUPDATE:
    if (IsClipboardFormatAvailable(CF_BITMAP))
    {
        OpenClipboard(hwnd);
        HBITMAP hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);
        CloseClipboard();

        if (hBitmap != NULL)
        {
            // ... (获取位图信息)

            // Calculate X axis label offset for right alignment
            int cxMaxXAxisLabel = 0;
            for (i = iXAxisMin; i <= iXAxisMax; i += iXAxisLabelStep)
            {
                wsprintf(szBuffer, TEXT("%d"), i);
                strXAxisLabel.replace(0, lstrlen(szBuffer), szBuffer);
                // Use GetTextExtentPoint32 on compatible DC
                int cxLabel = GetTextExtentPoint32(hdc, strXAxisLabel.c_str(), lstrlen(strXAxisLabel.c_str()), NULL).cx;
                if (cxLabel > cxMaxXAxisLabel)
                {
                    cxMaxXAxisLabel = cxLabel;
                }
            }
            iXAxisLabelOffset = cxMaxXAxisLabel;

            // Draw image with right-aligned X axis labels
            hdc = CreateCompatibleDC(NULL);
            HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdc, hBitmap);
            SetTextAlign(hdc, TA_RIGHT | TA_TOP);
            for (i = iXAxisMin; i <= iXAxisMax; i += iXAxisLabelStep)
            {
                x = cxImage / 2 + i * cxChar * iXScale - iXAxisLabelOffset;
                if (x >= 0 && x <= cxImage)
                {
                    wsprintf(szBuffer, TEXT("%d"), i);
                    ExtTextOut(hdc, x, cyImage / 2 + cyChar / 2, ETO_OPAQUE, NULL, szBuffer, lstrlen(szBuffer), NULL);
                }
            }
            SelectObject(hdc, hOldBitmap);
            DeleteDC(hdc);
        }
    }

    return 0;

// ... (其他代码)

通过使用兼容的 DC 来获取标签字符串的长度,我们解决了剪贴板问题,并确保在复制到剪贴板时 X 轴标签可以正确地右对齐。

VC++ 画图:使用 GetTextExtent 函数实现 X 坐标右对齐(剪贴板问题解决方案)

原文地址: https://www.cveoy.top/t/topic/gEnW 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录