高分急求:VC中鼠标移到按钮上后,更改按钮图片的实现代码
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高分急求:VC中鼠标移到按钮上后,更改按钮图片的实现代码相关的知识,希望对你有一定的参考价值。
是这样的,我想做一个用 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,您自己做的工程或者别人写的类都行。
分不是问题,实现了我要的功能的,我将分加到最高!
在线急等各位前辈的指导!
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的路越走越窄。 参考技术A 我觉得你的方法没错,但是你说的:“然而,我取的按钮的坐标总是不对,无论是ClientToScreen()还是ScreenToClient(),总是坐标有误,往往,鼠标移出了按钮,才做了我要做的事。”我觉得是你的坐标系设定上出了问题,MFC的对话框的坐标比较麻烦,弄不好容易出错,这里有个简短的介绍,你先看看。http://blog.163.com/yx_xie2007/blog/static/102464253201003004416975/
还有,我还给你发了一个我做的界面的小程序,里面有关于移动鼠标和改变按钮的应用,文件名叫做复件 8_2test2,你看一下。(注意:不要用debug里面的exe文件,要打开工程文件后点运行)
希望对你有帮助。本回答被提问者采纳 参考技术B 其实控制这个很简单。。
需要 SetCapture/ReleaseCapture 函数。具体多用几次就知道了 参考技术C 我也在做类似的功能,昨天搞好了一个demo,发给你邮箱了,看能否用得上吧 参考技术D 你在网上找一个类,叫CButtonST ,功能很强
C#中,当鼠标移动到按钮上时,按钮边框闪烁,鼠标移开时恢复正常,急急急
参考技术A 如果是做WPF,修改一下Button的Template,加一个IsMouseOver的触发器就可以了;如果是WinForm,在MouseMove事件和MouseHover事件里面切换Button.BackgroundImage的图片。 参考技术B private void button1_Click(object sender, EventArgs e)this.button1_Paint(sender, new PaintEventArgs(this.txt2.CreateGraphics(), txt2.ClientRectangle));
或者在botton1事件中mousemove
private void botton1_Paint(object sender,PaintEventArgs e)
Pen pen = new Pen(Color.HotPink, 4.5f);
e.Graphics.DrawRectangle(pen,txt2.ClientRectangle );
pen.Dispose();
不知道对不对,我也是新手,如果你会的话给我也发一下。我的本本还没安VS呢!
使用timer
定义变量 Timer t=new Timer();
在Load函数里初始化
...
t.Interval=1000;//时间间隔
t.Tick+= t_Tick(object sender, eventags e);
t.Start();
...
Random r=new Random();
private void t_Tick(object sender, eventags e)
Color c=Color.FromARGB(255,r.Next(255),Next(255),Next(255));
b.BackColor=x;
参考技术C 个人觉得可以这样做,不管对不对以正我发了,不对也别笑我!
1.可以用Button 事件,更换不同的图片,
2.GDI+ 做即时绘图,当然也得根据button事件来做不同的事情
3.自定义控件,。。。(这个好像跟前面两个一样)
总之这个问题,一个是更换图片,一个是重绘。别的我还真想不出来有什麼好的办法。。
拙见,希望有帮助本回答被提问者和网友采纳 参考技术D 我估计是按下的时候,触发了一个load的动作
以上是关于高分急求:VC中鼠标移到按钮上后,更改按钮图片的实现代码的主要内容,如果未能解决你的问题,请参考以下文章