关于BS_OWNERDRAW的用法

BS_OWNERDRAW用于自绘按钮,通常与WM_CTLCOLORBTN消息连用,如下:

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND button0;

	switch (message)
	{
	case WM_CREATE:
		button0 = CreateWindow(L"button", NULL, WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 20, 20, 400, 200,
								hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);	
		return 0;

	case WM_CTLCOLORBTN:
		return (LRESULT)CreateSolidBrush(RGB(0, 255, 0));
			
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

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


 上述代码的结果会显示出一个绿色的按钮。

但如果想在按钮上显示一个位图或图标,则不能使用BS_OWNERDRAW,而要用BS_ICON或BS_BITMAP,并和SendMessage函数连用,如下:

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND button0;

	switch (message)
	{
	case WM_CREATE:
		button0 = CreateWindow(L"button", NULL, WS_CHILD | WS_VISIBLE | BS_ICON, 20, 20, 400, 200,
								hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);	
		SendMessage(button0, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(NULL, IDI_ERROR));
		return 0;

	case WM_CTLCOLORBTN:                                  //因为没有了BS_OWNERDRAW,所以被忽略了
		return (LRESULT)CreateSolidBrush(RGB(0, 255, 0)); //不起任何作用
			
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

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


 上述代码会显示出一个带有错误标记的按钮,而WM_CTLCOLORBTN的触发标志是按钮被重绘,因为没有了BS_OWNERDRAW,所以按钮不能被重绘,即WM_CTLCOLORBTN消息不会被触发。

但如果在上述代码中,再加入BS_OWNERDRAW,那么按钮会既有位图,又有自绘颜色吗?

即:

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND button0;

	switch (message)
	{
	case WM_CREATE:
		button0 = CreateWindow(L"button", NULL, WS_CHILD | WS_VISIBLE | BS_OWNERDRAW | BS_ICON, 20, 20, 400,
							   200, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);	
		SendMessage(button0, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(NULL, IDI_ERROR)); //因为有了BS_OWNERDRAW,导致不起作用
		return 0;

	case WM_CTLCOLORBTN:                                  //因为有了BS_OWNERDRAW,再次被触发
		return (LRESULT)CreateSolidBrush(RGB(0, 255, 0)); 

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

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


上述代码的结果是显示一绿色的按钮,而按钮上不见任何的位图。所以,如果在创建按钮的窗口句柄时,在CreateWindow中使用了BS_OWNERDRAW,那么就不能用SendMessage函数在按钮上载入位图或图标了,即使有BS_ICON也不能载入。
 

PS: 在WM_CTLCOLORBTN内所做的一切代码,只与设备环境句柄(HDC)有关,如果尝试通过窗口句柄(HWND)来更改什么,例如用SetWindowText(用到hwnd)来改变按钮内文字,都将无效陷入死循环

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 MFC 中,可以通过设置按钮的 `BS_OWNERDRAW` 样式来实现 `OwnerDraw`,然后在按钮的 `DrawItem` 函数中根据按钮的状态绘制不同的外观来实现按钮的选中状态。具体实现步骤如下: 1. 在对话框类中添加按钮的成员变量并添加 `ON_CONTROL` 消息映射,例如: ```cpp class CMyDialog : public CDialogEx { public: CMyDialog(CWnd* pParent = nullptr); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MYDIALOG }; #endif protected: HICON m_hIcon; CButton m_btnMyButton; // 添加按钮成员变量 afx_msg void OnMyButtonDrawItem(NMHDR* pNMHDR, LRESULT* pResult); // 添加按钮绘制消息处理函数 DECLARE_MESSAGE_MAP() }; ``` 在这个例子中,我们添加了一个名为 `m_btnMyButton` 的按钮成员变量,并添加了一个名为 `OnMyButtonDrawItem` 的按钮绘制消息处理函数。 2. 在对话框的 `OnInitDialog` 函数中设置按钮的 `BS_OWNERDRAW` 样式并添加绘制消息处理函数,例如: ```cpp BOOL CMyDialog::OnInitDialog() { CDialogEx::OnInitDialog(); // 将按钮的 BS_OWNERDRAW 样式设置为 OwnerDraw m_btnMyButton.ModifyStyle(0, BS_OWNERDRAW); // 添加按钮绘制消息处理函数 m_btnMyButton.SetOwner(this); m_btnMyButton.SetDlgCtrlID(IDC_MYBUTTON); m_btnMyButton.SubclassDlgItem(IDC_MYBUTTON, this); m_btnMyButton.SendMessage(WM_DRAWITEM); return TRUE; } ``` 在这个例子中,我们首先将按钮的 `BS_OWNERDRAW` 样式设置为 `OwnerDraw`,然后通过 `SetOwner`、`SetDlgCtrlID` 和 `SubclassDlgItem` 函数将按钮与消息处理函数关联起来,并发送 `WM_DRAWITEM` 消息触发按钮的绘制消息处理函数。 3. 在按钮的绘制消息处理函数 `OnMyButtonDrawItem` 中根据按钮的状态绘制不同的外观,例如: ```cpp void CMyDialog::OnMyButtonDrawItem(NMHDR* pNMHDR, LRESULT* pResult) { LPDRAWITEMSTRUCT lpDrawItemStruct = reinterpret_cast<LPDRAWITEMSTRUCT>(pNMHDR); CString strText; if (m_btnMyButton.GetCheck()) { // 按钮被选中 ::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_CHECKED); strText = "选中"; } else { // 按钮未选中 ::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH); strText = "未选中"; } // 绘制按钮文本 ::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &lpDrawItemStruct->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE); *pResult = TRUE; } ``` 在这个例子中,我们首先使用 `GetCheck` 函数获取按钮的状态,然后根据按钮的状态调用 `DrawFrameControl` 函数绘制按钮的外框,当按钮被选中时,我们通过设置 `DFCS_CHECKED` 标志来绘制选中状态的外观。最后使用 `DrawText` 函数绘制按钮的文本。 通过以上步骤,我们就可以在 MFC 中设置按钮的选中状态了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值