如何制作一个热点按钮 - 使用 Windows API 和 GDI+ 实现自定义按钮
要制作一个热点按钮并实现所描述的需求,你可以按照以下步骤进行操作:
-
准备资源文件:
- 在你的项目中添加两个图片资源,分别命名为 IDB_PNG1 和 IDB_PNG2,这两个资源分别对应普通情况下和热点效果下的按钮图片。
-
编写对话框模板:
- 在资源文件中,打开对话框资源(IDD_DIALOG1)并添加一个按钮控件(IDOK)。
- 将按钮控件的风格设置为 BS_OWNERDRAW,这样你可以自定义按钮的外观。
- 将按钮控件的 ID 设置为一个自定义的 ID,比如 IDC_HOTSPOT_BUTTON。
-
编写绘制按钮的函数:
- 在代码中,编写一个绘制按钮的函数,用于绘制按钮的外观,包括普通情况下和热点效果下的外观。
- 在函数中,使用 GDI+ 库加载并绘制两种不同状态下的按钮图片。
-
注册和处理按钮消息:
- 在 DialogProc 函数中,注册和处理按钮的消息。
- 在 WM_INITDIALOG 消息中,使用 GetDlgItem 获取按钮句柄,并使用 SetWindowLongPtr 设置按钮的风格为 BS_OWNERDRAW。
- 在 WM_DRAWITEM 消息中,根据绘制按钮的函数来绘制按钮的外观。
- 在 WM_COMMAND 消息中,根据按钮的 ID 来处理按钮的点击事件。
以下是一个示例代码,演示了如何制作热点按钮并实现所描述的需求:
#include <windows.h>
#include <windowsx.h>
#include <vector>
#include <gdiplus.h>
#include "resource.h"
#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;
HINSTANCE Hinstance;
// 存储按钮绘制效果所需的参数
struct CustomButtonData {
RECT rect;
bool isHot;
HBITMAP normalImage;
HBITMAP hotImage;
CustomButtonData(RECT r, HBITMAP normal, HBITMAP hot)
: rect(r), isHot(false), normalImage(normal), hotImage(hot) {}
};
// 全局变量,存储按钮的绘制效果数据
std::vector<CustomButtonData> buttonsData;
void DrawCustomButton(HDC hdc, const CustomButtonData& data) {
HBITMAP hBitmap = data.isHot ? data.hotImage : data.normalImage;
HDC hMemDC = CreateCompatibleDC(hdc);
HGDIOBJ hOldBitmap = SelectObject(hMemDC, hBitmap);
BitBlt(hdc, data.rect.left, data.rect.top, data.rect.right - data.rect.left,
data.rect.bottom - data.rect.top, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
}
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG: {
// 获取按钮句柄并存储绘制数据
HWND hButton = GetDlgItem(hwndDlg, IDC_HOTSPOT_BUTTON);
RECT rect;
GetClientRect(hButton, &rect);
HBITMAP normalImage = LoadBitmap(Hinstance, MAKEINTRESOURCE(IDB_PNG1));
HBITMAP hotImage = LoadBitmap(Hinstance, MAKEINTRESOURCE(IDB_PNG2));
CustomButtonData data(rect, normalImage, hotImage);
buttonsData.push_back(data);
// 设置按钮风格为 BS_OWNERDRAW
SetWindowLongPtr(hButton, GWL_STYLE, GetWindowLongPtr(hButton, GWL_STYLE) | BS_OWNERDRAW);
return TRUE;
}
case WM_DRAWITEM: {
// 绘制按钮
DRAWITEMSTRUCT* dis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
for (const auto& data : buttonsData) {
if (dis->CtlID == IDC_HOTSPOT_BUTTON && dis->hwndItem == GetDlgItem(hwndDlg, IDC_HOTSPOT_BUTTON)) {
data.isHot = (dis->itemState & ODS_SELECTED) || (dis->itemState & ODS_FOCUS);
DrawCustomButton(dis->hDC, data);
break;
}
}
return TRUE;
}
case WM_COMMAND: {
if (LOWORD(wParam) == IDC_HOTSPOT_BUTTON && HIWORD(wParam) == BN_CLICKED) {
// 点击了热点按钮,执行相应操作
MessageBox(hwndDlg, "Hotspot Button Clicked!", "Button Clicked", MB_OK);
return TRUE;
}
break;
}
case WM_CLOSE: {
EndDialog(hwndDlg, 0);
return TRUE;
}
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
Hinstance = hInstance;
// 初始化 GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// 创建并显示对话框
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);
// 释放 GDI+
GdiplusShutdown(gdiplusToken);
return 0;
}
请注意,上述示例代码中使用了 GDI+ 库来加载和绘制按钮的图片。确保你的项目正确地链接了 gdiplus.lib 库,并且在代码中包含了相关的头文件。
希望这可以帮助到你!如果你还有其他问题,请随时提问。
原文地址: https://www.cveoy.top/t/topic/VlY 著作权归作者所有。请勿转载和采集!