高分急求:VC中鼠标移到按钮上后,更改按钮图片的实现代码

是这样的,我想做一个用9个按钮组成的所谓“工具栏”,这样,便于我做更换皮肤的功能。因为VC中工具栏只支持16色图,达不到我的要求。碰到了这样的问题:怎样判断鼠标移到了按钮... 是这样的,我想做一个用 9 个按钮组成的所谓“工具栏”,这样,便于我做更换皮肤的功能。因为VC中工具栏只支持16色图,达不到我的要求。

碰到了这样的问题:怎样判断鼠标移到了按钮上?

当然,网上一搜,建议用WM_MOUSEMOVE的方法居多。然而,我取的按钮的坐标总是不对,无论是ClientToScreen()还是ScreenToClient(),总是坐标有误,往往,鼠标移出了按钮,才做了我要做的事。

比如,在对话框上,有一个按钮,ID号为:IDC_BUTTON1,为这个对话框添加WM_MOUSEMOVE后,编写:

CRect lpRec;
GetDlgItem(IDC_BUTTON1)->GetWindowRect(&lpRec);
ScreenToClient(&lpRec);

if(point.x > lpRec.left
&& point.x < lpRec.right
&& point.y > lpRec.top
&& point .y < lpRec.bottom)
MessageBox(L"移到了 按钮1 上");
结果,移到按钮1上时,不弹出MessageBox,移出按钮1,又弹出了。

然后,我又试了第二种方法,派生一个CButton的类,叫CMyButton,然后将IDC_BUTTON1添加成员变量时,基类修改为CMyButton,再为CMyButton添加WM_MOUSEMOVE消息,通过GetWindowText()获得按钮上的文本的方法,分别实现我要做的事。这样,可以成功根据不同的按钮弹出相应的MessageBox,但是却怎么也不改变按钮的图片。
按钮的bitmap属性已经改为TRUE。
为按钮贴图所需要的资源我是通过以下方法实现的:
HBITMAP hBtnBmp = LoadBitmap(::AfxGetInstanceHandle(),MAKEINTRESOURCE(1001));
m_btn1.SetBitmap(hBtnBmp);

那么,第三种方法就是通过CBitmapButton类来实现,但是,四种状态中,居然没有鼠标悬停的效果。

各位前辈、高手,有办法实现我要的功能吗?就是:鼠标移动到按钮上,改变其贴图,移出按钮,恢复原图,即实现工具栏的效果。

或者,有这样的别人做好的类吗?

我要的是代码,不要过多的注释和说明。我不想看理论方面的文字,实现机制我应该是看得懂的,但是如果是添加消息或者函数、变量,请您说明添加的位置、所属基类等。

或者,将您的完整工程发到我的邮箱:yvhpfiipfi@163.com,您自己做的工程或者别人写的类都行。

分不是问题,实现了我要的功能的,我将分加到最高!
在线急等各位前辈的指导!
展开
 我来答
silvergingko
2011-03-21 · TA获得超过5945个赞
知道小有建树答主
回答量:688
采纳率:0%
帮助的人:864万
展开全部
楼主无法解决该问题,从解决问题的能力上有两点不足:
1)不会使用 MSDN,一定要多参考MSDN。
2)楼主对WINDOWS编程不熟悉,MFC不是用来学习的,MFC是让职业程序员在做开发时,
对于原来大量需要调用的API调用和一些基本功能模块进行了包装,简化程序员的编码,提高工作效率。学习的话,只能从最底层的API调用开始学习。这个是VC程序员的悲哀,VB,C#不需要关注太多WINDOWS编程的底层细节,VC.NET同样也不需要关注太多。只有用MFC的程序员,必须了解所有底层的机制。

这里,我自己写了一个针对楼主帖子的代码示例,是WIN32的,没有使用MFC,其中用编号给出的注释,是要实现位图加文本按钮的必须步骤,否则程序无法获得需要的效果。在最后,我指出楼主MFC中的一个问题,可能是这个原因,当然,任何其它情况都会阻碍程序的实现。楼主没有代码,我不知道楼主是否还有其它问题。

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

class IconButton {
public:
IconButton(HWND hParent, LPRECT prcPos) {
// 按钮在不同状态下显示的文本
m_pszHover = _T("hover");
m_pszLeave = _T("leave");
m_pszPressed = _T("pressed");
// 按钮在不同状态下显示的图标
m_hIconHover = LoadIcon(NULL, IDI_INFORMATION);
m_hIconLeave = LoadIcon(NULL, IDI_QUESTION);
m_hIconPressed = LoadIcon(NULL, IDI_WARNING);

// 2)按钮的样式不能指定 BS_ICON 或 BS_BITMAP 或两者。
m_hButton = CreateWindowEx(WS_EX_LTRREADING|WS_EX_RIGHTSCROLLBAR|WS_EX_NOPARENTNOTIFY,
_T("Button"), m_pszLeave,
WS_CHILD|WS_VISIBLE|WS_GROUP|WS_TABSTOP|BS_TEXT,
prcPos->left, prcPos->top,
prcPos->right - prcPos->left, prcPos->bottom - prcPos->top,
hParent,
NULL,
GetModuleHandle(NULL),
NULL);

// 按钮原来的消息处理函数
m_pfnOldProc = (WNDPROC)SetWindowLongPtr(m_hButton, GWLP_WNDPROC, (LONG_PTR)BtnProc);
SetWindowLongPtr(m_hButton, GWLP_USERDATA, (LONG_PTR)this);

m_bHover = FALSE;

SendMessage(m_hButton, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIconLeave);
}

private:
// 一些API调用时会重复使用的参数,将它们保存为类成员
HWND m_hButton;
HICON m_hIconHover;
HICON m_hIconLeave;
HICON m_hIconPressed;
LPCTSTR m_pszHover;
LPCTSTR m_pszLeave;
LPCTSTR m_pszPressed;
WNDPROC m_pfnOldProc;
BOOL m_bHover;

static LRESULT BtnProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
LRESULT lRet;
IconButton *pib = (IconButton*)GetWindowLongPtr(hWnd, GWLP_USERDATA);

switch (uMsg) {
case WM_MOUSEMOVE:
if (!pib->m_bHover) {
/*
WM_MOUSELEAVE 是当鼠标离开窗口,窗口会收到的消息,
该消息并不是自动由 Windows 操作系统发送到线程消息队列中的,
而是需要程序员在代码中调用 TrackMouseEvent ,
只有这样,操作系统才会把 WM_MOUSELEAVE 消息发送到线程消息队列中。
*/
TRACKMOUSEEVENT tme = { sizeof(tme) };
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = pib->m_hButton;
TrackMouseEvent(&tme);

pib->m_bHover = TRUE;

pib->SetButton(pib->m_pszHover, pib->m_hIconHover);

}
lRet = 0;
break;

case WM_MOUSELEAVE:
pib->m_bHover = FALSE;
pib->SetButton(pib->m_pszLeave, pib->m_hIconLeave);
lRet = 0;
break;

case WM_LBUTTONDOWN:
pib->SetButton(pib->m_pszPressed, pib->m_hIconPressed);
lRet = 0;
break;

case WM_LBUTTONUP:
pib->SetButton(pib->m_pszHover, pib->m_hIconHover);
lRet = 0;
break;

default:
lRet = (*pib->m_pfnOldProc)(hWnd, uMsg, wParam, lParam);
break;
}

return lRet;
}

void SetButton(LPCTSTR pszText, HICON hIcon) {
Button_SetText(m_hButton, pszText);
/*
3)设置按钮图标并启用文本,第二个参数是 BM_SETIMAGE,
第三个参数是 IMAGE_ICON ,如果是位图,第三个参数是 IMAGE_BITMAP ,
第四个参数是图标或位图句柄。

*/
SendMessage(m_hButton, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
}
};

LRESULT CALLBACK NormalProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
LRESULT lRet;

switch (uMsg) {
case WM_CLOSE:
PostQuitMessage(0);
lRet = 0;
break;

default:
lRet = DefWindowProc(hWnd, uMsg, wParam, lParam);
}

return lRet;
}

HWND CreateNormalWindow() {
WNDCLASS wc = { 0 };
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = NormalProc;
wc.lpszClassName = _T("ButtonTestWndClass");
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&wc);

return CreateWindow(_T("ButtonTestWndClass"), _T("Button Test Window"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0,
NULL,
NULL,
GetModuleHandle(NULL),
NULL);
}

int APIENTRY _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) {

/*
1)启用可视化样式,在WIN32编程中,
向导不会为我们启用可视化样式给出向导创建的代码。
在MFC中,启用可视化样式是MFC工程创建向导默认给出的。
在此也就没有必要给出我自己写的 zInitVisualStyle 的代码了。
*/
zInitVisualStyle(ICC_WIN95_CLASSES);
HWND hWnd = CreateNormalWindow();
RECT rc = { 0, 0, 200, 40 };
IconButton ib(hWnd, &rc);// 有关图标文本按钮的类

UpdateWindow(hWnd);

BOOL bQuit = FALSE;
MSG msg;
while (!bQuit) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
bQuit = TRUE;
continue;
}

TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return msg.wParam;
}

楼主的问题第一个就是“按钮的bitmap属性已经改为TRUE”,这个在我的代码中的第二个注释中已经说明。“按钮的bitmap属性已经改为TRUE”意味着设置了按钮的 BS_BITMAP 样式。其次,根据楼主已有的信息,我不知道为何要知道坐标,计算坐标,它们用来干吗的?

真正做职业软件的,涉及到换肤的话,都是用底层WIN32做自己的包装类,就如以上我给出的IconButton,没人会去用MFC作换肤。还是那句话那时如日中天的MFC是做快速开发只用的,兼顾软件项目开发效率和程序运行效率,这两者。但,就我的理解,目前的MFC处境非常尴尬,论程序运行效率,MFC肯定比不上纯粹的WIN32:
1、MFC占更多的内存
2、执行更多的代码
3、生成的文件尺寸更大,还需要依赖MFC库,不利于软件部署。

从快速开发的角度而言,肯定是MFC比WIN32来得效率高,WIN32是要写死人的,而且调试也远比MFC来得困难,但是与此同时,使用C#或VB进行.NET开发,MFC根本比不上.NET的开发效率,若论做界面的话,新崛起的WPF可以做出非常炫的界面(甚至用“让人吃惊”来形容)。
因此,MFC现在是一种高不成(不如C#、VB)低不就(WIN32)的尴尬局面。MFC的路越走越窄。
shuizhi0904
2011-03-20 · TA获得超过380个赞
知道小有建树答主
回答量:231
采纳率:0%
帮助的人:148万
展开全部
我觉得你的方法没错,但是你说的:“然而,我取的按钮的坐标总是不对,无论是ClientToScreen()还是ScreenToClient(),总是坐标有误,往往,鼠标移出了按钮,才做了我要做的事。”我觉得是你的坐标系设定上出了问题,MFC的对话框的坐标比较麻烦,弄不好容易出错,这里有个简短的介绍,你先看看。http://blog.163.com/yx_xie2007/blog/static/102464253201003004416975/

还有,我还给你发了一个我做的界面的小程序,里面有关于移动鼠标和改变按钮的应用,文件名叫做复件 8_2test2,你看一下。(注意:不要用debug里面的exe文件,要打开工程文件后点运行)
希望对你有帮助。
本回答被提问者采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
stone_dongdong
2011-03-21 · TA获得超过2853个赞
知道大有可为答主
回答量:1636
采纳率:0%
帮助的人:1012万
展开全部
其实控制这个很简单。。
需要 SetCapture/ReleaseCapture 函数。具体多用几次就知道了
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
lf460
2011-03-21 · 超过50用户采纳过TA的回答
知道小有建树答主
回答量:144
采纳率:0%
帮助的人:112万
展开全部
我也在做类似的功能,昨天搞好了一个demo,发给你邮箱了,看能否用得上吧
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
纱布爽
2011-03-20 · TA获得超过468个赞
知道答主
回答量:262
采纳率:0%
帮助的人:0
展开全部
你在网上找一个类,叫CButtonST ,功能很强
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 3条折叠回答
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式