You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows平台GUI创建及Windows Forms未知按钮识别咨询

解决方案:定制非原生Windows 10风格GUI + 目标控件识别

一、C++实现定制风格GUI的模板框架

Windows Samples里的示例默认都是原生Win10风格(Modern UI/WinUI或经典Win32原生控件),如果你想要和附图一致的自定义风格GUI,这里提供两个主流方向的C++模板:

1. C++/CLI + Windows Forms 自定义控件模板

Windows Forms本身是原生风格,但可以通过重写OnPaint方法完全自定义控件外观,适配你想要的样式。下面是基础框架示例:

#include <windows.h>
#using <System.dll>
#using <System.Windows.Forms.dll>
#using <System.Drawing.dll>

using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;

// 自定义风格按钮控件
ref class CustomStyledButton : public Button
{
protected:
    virtual void OnPaint(PaintEventArgs^ e) override
    {
        Graphics^ g = e->Graphics;
        Rectangle btnRect = this->ClientRectangle;

        // 绘制自定义背景(示例为渐变圆角)
        Brush^ bgBrush = gcnew LinearGradientBrush(btnRect, Color::LightSkyBlue, Color::DeepSkyBlue, LinearGradientMode::Vertical);
        g->FillRoundedRectangle(bgBrush, btnRect, 8); // 圆角半径8

        // 绘制居中文本
        StringFormat^ sf = gcnew StringFormat();
        sf->Alignment = StringAlignment::Center;
        sf->LineAlignment = StringAlignment::Center;
        g->DrawString(this->Text, this->Font, Brushes::White, btnRect, sf);

        // 可选:绘制下拉箭头(对应带菜单的按钮)
        if (this->Tag != nullptr && this->Tag->ToString() == "DropDown")
        {
            Point arrowPos = Point(btnRect.Right - 20, btnRect.Top + btnRect.Height / 2 - 5);
            Pen^ arrowPen = gcnew Pen(Color::White);
            g->DrawLine(arrowPen, arrowPos, Point(arrowPos.X + 8, arrowPos.Y + 5));
            g->DrawLine(arrowPen, arrowPos, Point(arrowPos.X - 8, arrowPos.Y + 5));
        }
    }
};

// 主窗口
ref class CustomGUIForm : public Form
{
public:
    CustomGUIForm()
    {
        this->Text = "自定义风格GUI";
        this->Size = Drawing::Size(400, 300);
        this->BackColor = Color::WhiteSmoke;

        // 添加普通自定义按钮
        CustomStyledButton^ normalBtn = gcnew CustomStyledButton();
        normalBtn->Text = "操作按钮";
        normalBtn->Size = Drawing::Size(150, 40);
        normalBtn->Location = Point(120, 80);
        this->Controls->Add(normalBtn);

        // 添加带下拉菜单的自定义按钮
        CustomStyledButton^ dropdownBtn = gcnew CustomStyledButton();
        dropdownBtn->Text = "下拉选项";
        dropdownBtn->Size = Drawing::Size(150, 40);
        dropdownBtn->Location = Point(120, 150);
        dropdownBtn->Tag = "DropDown";
        // 绑定下拉菜单
        ContextMenuStrip^ menu = gcnew ContextMenuStrip();
        menu->Items->Add("选项A");
        menu->Items->Add("选项B");
        dropdownBtn->ContextMenuStrip = menu;
        this->Controls->Add(dropdownBtn);
    }
};

[STAThreadAttribute]
int main(array<String^>^ args)
{
    Application::EnableVisualStyles();
    Application::SetCompatibleTextRenderingDefault(false);
    Application::Run(gcnew CustomGUIForm());
    return 0;
}

2. 纯Win32 API 自定义绘制模板

如果不想依赖.NET,纯原生C++可以通过自定义窗口过程(WndProc)实现:

#include <windows.h>
#include <gdiplus.h>
using namespace Gdiplus;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
VOID DrawCustomButton(HDC hdc, RECT rect, BOOL isPressed, LPCWSTR text);

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

    // 初始化GDI+
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    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("该程序需要Windows NT环境!"), szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName, TEXT("自定义Win32 GUI"), WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
        NULL, NULL, hInstance, NULL);

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

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

    GdiplusShutdown(gdiplusToken);
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static RECT btnRect = {120, 80, 270, 120};
    static BOOL btnPressed = FALSE;
    HDC hdc;
    PAINTSTRUCT ps;

    switch (message)
    {
        case WM_LBUTTONDOWN:
            if (PtInRect(&btnRect, LOWORD(lParam), HIWORD(lParam)))
            {
                btnPressed = TRUE;
                InvalidateRect(hwnd, &btnRect, TRUE);
            }
            return 0;

        case WM_LBUTTONUP:
            if (btnPressed)
            {
                btnPressed = FALSE;
                InvalidateRect(hwnd, &btnRect, TRUE);
                MessageBox(hwnd, TEXT("按钮触发!"), TEXT("提示"), MB_OK);
            }
            return 0;

        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            DrawCustomButton(hdc, btnRect, btnPressed, TEXT("自定义按钮"));
            EndPaint(hwnd, &ps);
            return 0;

        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

VOID DrawCustomButton(HDC hdc, RECT rect, BOOL isPressed, LPCWSTR text)
{
    Graphics graphics(hdc);
    RectF rectF(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);

    // 绘制渐变背景
    LinearGradientBrush brush(rectF, isPressed ? Color(255, 30, 144, 255) : Color(255, 173, 216, 230), 
                              isPressed ? Color(255, 173, 216, 230) : Color(255, 30, 144, 255), 
                              LinearGradientModeVertical);
    graphics.FillRoundedRectangle(&brush, rectF, 8.0f);

    // 绘制边框
    Pen pen(Color(255, 0, 0, 128), 2);
    graphics.DrawRoundedRectangle(&pen, rectF, 8.0f);

    // 绘制文本
    Font font(L"微软雅黑", 12, FontStyleBold);
    SolidBrush textBrush(Color(255, 255, 255, 255));
    StringFormat format;
    format.SetAlignment(StringAlignmentCenter);
    format.SetLineAlignment(StringAlignmentCenter);
    graphics.DrawString(text, -1, &font, rectF, &format, &textBrush);
}

二、附图标记按钮对应的Windows Forms控件

虽然看不到你的附图,但根据常见的特殊按钮场景,你要找的大概率是以下两种:

  • ToolStripSplitButton:如果按钮放在工具栏(ToolStrip)中,这个控件支持左侧点击执行主命令、右侧箭头弹出下拉菜单;
  • SplitButton:如果是独立在窗体上的拆分按钮,Windows Forms原生库没有直接提供,但可以通过两种方式实现:
    1. 用普通Button配合ContextMenuStrip,再自定义绘制添加下拉箭头(如上面C++/CLI示例);
    2. 引用Microsoft.VisualBasic.PowerPacks组件,里面包含原生SplitButton控件。

如果你的按钮是展开/折叠功能的,也可能是Expander控件,但拆分按钮是最常见的匹配场景。

内容的提问来源于stack exchange,提问作者firefly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:58:45