标题栏问号按钮帮助功能的实现

       下面这篇文章,是实现问号按钮的一种响应方式。现象是,点击问号按钮后,出现了带问号的鼠标,然后点击界面上的控件,之后显示控件的提示信息。

       文章实用,不可多得,谢谢楼主guogangj。

      转自:http://blog.csdn.net/guogangj/article/details/2108700

      对下面这样的界面我们一定很熟悉,一个对话框,右上角有两个按钮,一个是小问号(我称之“问号按钮”),一个是叉(关闭按钮),点一下问号按钮,鼠标光标通常就变成了一个带问号的箭头,用这个光标点击一下对话框里的元素,就能弹出一个简要的帮助说明。

        这个功能我十分喜欢,因为它很直观,简单,不用查询繁琐的帮助文档去寻找答案。从事软件开发之后,我写过很多程序,很多都有用户界面的,却一般都没有实现这个功能,今天想起来,想尝试实现它,于是有此文。

        我最早是这样考虑的:要在标题栏上增加一个问号按钮,得参考一些系统菜单操作API,点这个问号按钮会产生一个系统消息,我在处理这个消息的时候把对话框的鼠标光标改为带问号的指针,用这个带问号的指针点击对话框的某个元素,就产生一个“WM_LBUTTONDOWN”的消息,处理这个消息,根据鼠标光标的位置判定鼠标点击的是对话框上的那个元素,获取这个元素的帮助字符串,创建一个没有Title的很小的窗口,把这个小窗口在鼠标光标位置处Pop出来,然后在上面Draw一些帮助字符串,当这个小窗口失去焦点,或被用户用鼠标点击了一下,或按了一下键盘什么的,就会Hide起来,当用户又执行了上述的“问号点击操作”之后,这个小窗口才会再次Show出,最后在对话框关闭的时候Destroy这个小窗口。

看起来是不是比较复杂?我也觉得复杂,首先在对话框的标题栏上增加一个问号按钮就不容易,有没有简单些的方法?当然有,看下图:

其实只需要在对话框属性上选中Context Help这个选项就OK了,把对话框显示出来就能发现右上角的小问号按钮。(感谢AShen同学教了我这招)现在点击这个小问号,鼠标光标就自动变成了带问号的指针,然后再点击对话框中的某一处……当然了,你没有编写接下去的处理代码,所以什么都没有出现,而鼠标光标又变回了正常的箭头。



我们现在关心的是这么一个点击的动作会产生些什么消息,消息确实是有的,并且非常好用,完全没有我前面推测的什么根据光标位置判定点击的对话框元素等等那么复杂,这个消息叫WM_HELP,MSDN上能找到,我大致说明一下:



lphi = (LPHELPINFO) lParam;



typedef struct tagHELPINFO {

UINT cbSize;

int iContextType

int iCtrlId;

HANDLE hItemHandle;

DWORD dwContextId;

POINT MousePos;

} HELPINFO, FAR *LPHELPINFO;



WM_HELP的lParam参数是指向HELPINFO这个结构的指针,我们需要用到这个结构的几个成员,一是iContextType==HELPINFO_WINDOW的时候,iCtrlId的值,这个值就是点击的对话框上元素的ID,具体看resource.h中的定义;另一个就是MousePos,光标位置;至于其它,就自己看看MSDN,在别处会用到的,但这里就简单些,暂时不用,此文只是起个抛砖引玉的作用。



现在只剩下一个问题了,那就是如何实现那个pop出来的小窗口?我马上想到了tooltip control,什么是tooltip control?我想你天天见,天天用,只是不知道它就是tooltip control而已,看看下面这截图:

当鼠标光标停留在工具栏上片刻(通常是你最长的双击间隔时间),光标下面就会出现一个小提示窗口,你把鼠标移动到别处后,这个小提示就消失或者换成别的了,当然它还有别的形式,这里就不一一列举了,这个就是tooltip control,没错,它是一个控件,它的实现在comctl32.dll中,这个dll是windows带的,这也意味着使用它并不需要额外的库。不过说了这么多最后我还是发现这个tooltip control不怎么适合,我在这里提起它是鼓励读者你自己去试试看,具体参考MSDN,在“PlatformSDK/User Interface/Windows Common Control/Tooltip Controls”下能找到。最后我是自己手动实现了这么一个窗口的,下面我将给出代码:



在对话框的WM_INITDIALOG消息处理中:

{

WNDCLASS wndclass;

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc = MyToolTipProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = g_hInstance;

wndclass.hIcon = LoadIcon(g_hInstance, (LPCTSTR)IDI_ICONAPP);

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);

wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);

wndclass.lpszMenuName = NULL;

wndclass.lpszClassName = TEXT("MyToolTipWindow");

RegisterClass (&wndclass);

hwndToolTip = CreateWindow(TEXT("MyToolTipWindow"), TEXT(""),

WS_POPUP|WS_BORDER, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, hDlg, (HMENU)NULL, g_hInstance, NULL);

}



其中"MyToolTipWindow"是我要注册的窗口类名,你可以起别的名字,注意这个窗口是没有标题栏的,hDlg是这个小小窗口的父窗口,也就是对话框的句柄,g_hInstance是进程实例句柄,我是把它存在一个全局变量中的,所以有个“g_”前缀,还要注意一下,把hwndToolTip作为全局变量或者static变量,以保存它的值,因为之后我们还需要用。



在对话框的WM_DESTROY消息中:



{

DestroyWindow(hwndToolTip);

}



把这个tooltip control删除。



好,现在我们看看"MyToolTipWindow"这个窗口的消息处理函数MyToolTipProc:



#define WM_USER_SETTEXT (WM_USER+10) //wParam : Pointer to the TCHAR string; lParam : NULL

#define WM_USER_SHOWWINDOW (WM_USER+11) //wParam: mouse.x; lParam : mouse.y



// Message handler for MyToolTipWindow.

LRESULT CALLBACK MyToolTipProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

static TCHAR szToDisp[1024];

switch (message)

{

case WM_CREATE:

return TRUE;



case WM_LBUTTONDOWN:

case WM_RBUTTONDOWN:

case WM_KEYDOWN:

case WM_KILLFOCUS:

ShowWindow(hwnd, FALSE);

break;



case WM_PAINT:

{

RECT rect;

PAINTSTRUCT ps;

HDC hdc = BeginPaint (hwnd, &ps);

GetWindowRect(hwnd, &rect);

rect.right = rect.right-rect.left;

rect.bottom = rect.bottom-rect.top;

rect.top = 0;

rect.left = 0;

DrawText(hdc, szToDisp, lstrlen(szToDisp), &rect, DT_LEFT|DT_WORDBREAK);

EndPaint (hwnd, &ps);

}

break;

case WM_USER_SETTEXT:

lstrcpy(szToDisp, (TCHAR *)wParam);

return TRUE;

case WM_USER_SHOWWINDOW:

{

PAINTSTRUCT ps;

HDC hdc = BeginPaint (hwnd, &ps);

DWORD dwRtn = GetTabbedTextExtent(hdc, szToDisp, lstrlen(szToDisp), 0, NULL);

EndPaint (hwnd, &ps);



UINT iScreenWidth = GetSystemMetrics(SM_CXFULLSCREEN);

UINT iXPos = wParam+LOWORD(dwRtn)+4>iScreenWidth?iScreenWidth-LOWORD(dwRtn)-4:wParam;

MoveWindow(hwnd, iXPos, lParam+21, LOWORD(dwRtn)+4, HIWORD(dwRtn)+3, FALSE);

ShowWindow(hwnd, TRUE);

}

return TRUE;

}

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

}



接到WM_LBUTTONDOWN,WM_RBUTTONDOWN,WM_KEYDOWN,WM_KILLFOCUS这几个消息之后,就把窗口隐藏起来,用WM_USER_SETTEXT这个消息设置要在mytooltip中显示的文本,然后用WM_USER_SHOWWINDOW把mytooltip show出来,WM_USER_SHOWWINDOW里面那些处理是为了根据要显示的文本和鼠标的位置调整mytooltip的窗口大小和位置,其它倒是很简单,没什么好解释的。



最后就是在对话框处理函数中加入对WM_HELP消息的响应:



{

LPHELPINFO lphi = (LPHELPINFO) lParam;

if (lphi->iContextType==HELPINFO_WINDOW)

{

TCHAR szDisp[256];

memset(szDisp, 0, sizeof(szDisp));

LoadString(g_hInstance, lphi->iCtrlId, szDisp, 255);

SendMessage(hwndToolTip, WM_USER_SETTEXT, (WPARAM)(szDisp), NULL);

if (0==lstrlen(szDisp))

break;

SendMessage(hwndToolTip, WM_USER_SHOWWINDOW, lphi->MousePos.x, lphi->MousePos.y);

}

}



LoadString函数能在程序资源中Load出相应对话框元素ID的string,这个需要自己编辑一下string资源。大功告成,看看效果吧:

留点作业给读者了,这个MyToolTip并不怎么完美,也许你看出来了,如果文本太长了,不会自动换行,很难看,而且没有“阴影效果”,这两个功能就交给读者你了,写好了给我一份,我先干活去了。byebye!

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值