VC 超链接

来源:互联网 发布:hdmi数字矩阵切换器 编辑:程序博客网 时间:2024/04/30 20:54
C语言几乎是很多大学生的必修课,学习了C语言后,虽然风格的确有差别,但是至少也都可以写混杂了C的C++了。可是图形界面的编程,却使得很多人无可适从。
现在从简单的开始谈谈,其实图形界面的编程,也不咋难。事实上,超链接的制作,每个部分都可以从网上找到,但是代码也或多或少有点小问题。并且也没有把代码都综合在一起。这里将详细讲解一下。
想玩编程么?来吧,其实很简单的。
首先,我们创建一个MFC工程,选择基于对话框的程序(本例定名称为SLinkTest)。然后把界面上的东东搞个干净~
01.png
 
然后我们创建两个静态文本框。其中一个是我们要做的超链接,为了伪装的像网页上的超链接那么逼真,我们把这个文本框的大小与文字的尺寸制作的相仿。然后,改变这个静态文本框的ID。这里,我习惯性的修改为了IDC_SLink。
92.png
 
OK,可以开始干活了。
干活之前,要先想象,超链接有什么特征呢?第一,点击后会能打开网页,或者打开其他东西;第二,鼠标移上时,会变成小手型;第三,鼠标移上时,链接字符会变蓝,并且加上了下划线。
我们从最重要也是最简单的开始做。
第一步,增加打开功能。
这时,需要让窗口相应两件事情。第一是判断鼠标放在了这个超链文本框上;第二是判断鼠标左键发生了点击。
由于判断文本框的位置在下两步也能用到,我们给这个对话框类增加一个私有的成员变量m_Rect,其类型为CRect。然后我们在程序界面初试化时,同时给m_Rect敷值上IDC_SLink的位置和尺寸信息。在BOOL CSLinkTest::OnInitDialog()的最后,return TRUE之前,加入这么两句:
  1. GetDlgItem(IDC_SLink)->GetWindowRect ( &m_Rect );
  2. ScreenToClient ( &m_Rect );
复制代码
加入后,对话框初始方法的完整代码为:
  1. BOOL CSLinkTestDlg::OnInitDialog()
  2. {
  3.         CDialog::OnInitDialog();

  4.         // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
  5.         //  执行此操作
  6.         SetIcon(m_hIcon, TRUE);                        // 设置大图标
  7.         SetIcon(m_hIcon, FALSE);                // 设置小图标

  8.         // TODO: 在此添加额外的初始化代码
  9.         GetDlgItem(IDC_SLink)->GetWindowRect ( &m_Rect );
  10.         ScreenToClient ( &m_Rect );
  11.         return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
  12. }
复制代码
这时,我们该让程序响应鼠标左键点击的消息了。不少例子上喜欢用左键按下时为信号,个人觉得不太符合一般的使用习惯,所以在本程序中,使用的是左键抬起时作为启动超链信号。这时在MFC Class Wizard中增加WM_LBUTTONUP的响应函数。对于VS 2008之类没有MFC Class Wizard的,可以点对话框的属性上闪电右边的那个按钮以创建消息响应函数。系统为我们创建消息响应函数后,自动跳转到代码页进行代码书写。我们首先判断鼠标是不是点在了IDC_SLink内,如果是,我们就启动超链。加入几句执行语句后,这个超链就已然可用了(可以Ctrl+F5编译并且试试点击一下那个链接文本框):
  1. void CSLinkTestDlg::OnLButtonUp(UINT nFlags, CPoint point)
  2. {
  3.         // TODO: 在此添加消息处理程序代码和/或调用默认值
  4.         if ( point.x > m_Rect.left && point.x < m_Rect.right && point.y < m_Rect.bottom && point.y > m_Rect.top )
  5.         {
  6.                 ShellExecute ( NULL, NULL, "http://bbs.icpcw.com", NULL, NULL, SW_NORMAL );
  7.         }

  8.         CDialog::OnLButtonUp(nFlags, point);
  9. }
复制代码
第一步,也是最核心的一步完成,下面是开始鱼目混珠了。
第二步,更换鼠标图标。
这就需要程序判断,鼠标在移动时,是否移动到了IDC_SLink之上,如果是,就更换鼠标。我们再给对话框添加一个鼠标移动的消息响应函数(消息为:WM_MOUSEMOVE),实时检测鼠标位置。
如果鼠标在IDC_SLink文本框之上,则变为手型。这里可以用系统提供的全局函数(也就是系统的API来完成)。处理后的鼠标移动消息响应函数如下:
  1. void CSLinkTestDlg::OnMouseMove(UINT nFlags, CPoint point)
  2. {
  3.         // TODO: 在此添加消息处理程序代码和/或调用默认值
  4.         if ( point.x > m_Rect.left && point.x < m_Rect.right && point.y < m_Rect.bottom && point.y > m_Rect.top )
  5.         {
  6.                 HCURSOR hCursor;
  7.                 hCursor = ::LoadCursor ( NULL, IDC_HAND );
  8.                 ::SetCursor ( hCursor );
  9.         }

  10.         CDialog::OnMouseMove(nFlags, point);
  11. }
复制代码
现在,鼠标的工作也结束了。
我们进入第三步,对文本内容的操作了,这步也是最麻烦的一步。该步,又分为了文本色彩变化和文本加下划线两个部分。本着由简到难的顺序,先处理加下划线的部分。
由于IDC_SLink的文本存在有鼠标选中和没有鼠标的两个状态,所以我们需要两种不同的字体状态,一种是纯天然的,另一种则是加了下划线的,但是其他字体信息与纯天然的完全相同。所以,我们给CSLinkTestDlg类加入四个私有的成员变量:
CFont* m_cfNtr;
CFont m_cfUL;
LOGFONT m_lfNtr, m_lfUL;
至于为什么两个CFont要一个创建为指针,另一个则是原始变量,这个是为了以后的初始化方便。
在刚才修改过的OnInitDialog()代码下,继续填加下面几句:
  1.         m_cfNtr = this->GetFont();
  2.         m_cfNtr->GetLogFont ( &m_lfNtr );
  3.         m_cfNtr->GetLogFont ( &m_lfUL );
  4.         m_lfUL.lfUnderline = TRUE;
  5.         m_cfUL.CreateFontIndirect ( &m_lfUL );
复制代码
修改后的CSLinkTest::OnInitDialog()进一步变为:
  1. BOOL CSLinkTestDlg::OnInitDialog()
  2. {
  3.         CDialog::OnInitDialog();

  4.         // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
  5.         //  执行此操作
  6.         SetIcon(m_hIcon, TRUE);                        // 设置大图标
  7.         SetIcon(m_hIcon, FALSE);                // 设置小图标

  8.         // TODO: 在此添加额外的初始化代码
  9.         GetDlgItem(IDC_SLink)->GetWindowRect ( &m_Rect );
  10.         ScreenToClient ( &m_Rect );

  11.         m_cfNtr = this->GetFont();
  12.         m_cfNtr->GetLogFont ( &m_lfNtr );
  13.         m_cfNtr->GetLogFont ( &m_lfUL );
  14.         m_lfUL.lfUnderline = TRUE;
  15.         m_cfUL.CreateFontIndirect ( &m_lfUL );
  16.         return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
  17. }
复制代码
我们再让鼠标移动的消息响应函数也响应一下字体的变化。由于系统不能自动设置字体,所以还需要判断当鼠标不在IDC_SLink上时,字体要还原。于是在鼠标的移动消息响应函数中,添加代码后,该段代码修改为:
  1. void CSLinkTestDlg::OnMouseMove(UINT nFlags, CPoint point)
  2. {
  3.         // TODO: 在此添加消息处理程序代码和/或调用默认值
  4.         if ( point.x > m_Rect.left && point.x < m_Rect.right && point.y < m_Rect.bottom && point.y > m_Rect.top )
  5.         {
  6.                 HCURSOR hCursor;
  7.                 hCursor = ::LoadCursor ( NULL, IDC_HAND );
  8.                 ::SetCursor ( hCursor );

  9.                 GetDlgItem(IDC_SLink)->SetFont ( &m_cfUL );
  10.         }
  11.         else
  12.         {
  13.                 GetDlgItem(IDC_SLink)->SetFont ( m_cfNtr );
  14.         }

  15.         CDialog::OnMouseMove(nFlags, point);
  16. }
复制代码
现在我们最后完成第三步的第二部分。控件色彩的改变,需要让程序响应WM_CLTCOLOR消息。而触发该消息响应的条件,依然是鼠标的位置。所以总的来说,我们要先判断鼠标位置,然后处罚相应的CLTCOLOR消息响应。
我们先定义两个CSLinkTestDlg的私有成员函数,用来设置和储存字体的颜色和控件的背景:
COLORREF m_color;
CBrush m_brush;
由于程序的背景色彩是可以随系统的设置发生改变的,所以这就要求我们的控件背景色彩画刷要与系统的设置相同。
继续在初始化函数OnInitDialog()中添加如下的初始化信息:
  1.         m_brush.CreateSysColorBrush ( COLOR_MENU );
  2.         m_color = RGB (0,0,0);
复制代码
此时,OnInitDialog()已经被完全改造结束,看看三次改造后的完整代码:
  1. BOOL CSLinkTestDlg::OnInitDialog()
  2. {
  3.         CDialog::OnInitDialog();

  4.         // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
  5.         //  执行此操作
  6.         SetIcon(m_hIcon, TRUE);                        // 设置大图标
  7.         SetIcon(m_hIcon, FALSE);                // 设置小图标

  8.         // TODO: 在此添加额外的初始化代码
  9.         GetDlgItem(IDC_SLink)->GetWindowRect ( &m_Rect );
  10.         ScreenToClient ( &m_Rect );

  11.         m_cfNtr = this->GetFont();
  12.         m_cfNtr->GetLogFont ( &m_lfNtr );
  13.         m_cfNtr->GetLogFont ( &m_lfUL );
  14.         m_lfUL.lfUnderline = TRUE;
  15.         m_cfUL.CreateFontIndirect ( &m_lfUL );

  16.         m_brush.CreateSysColorBrush ( COLOR_MENU );
  17.         m_color = RGB (0,0,0); //黑色
  18.         return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
  19. }
复制代码
然后在鼠标移动响应函数中,添加鼠标在不同位置时对字体颜色的设置。一般来说,网页的超链在鼠标选择时,都是蓝色的,也就是RGB(0,0,225)。我们同样是分两种情况对IDC_SLink的文本颜色进行消息发送。于是,完整的鼠标移动响应函数为:
  1. void CSLinkTestDlg::OnMouseMove(UINT nFlags, CPoint point)
  2. {
  3.         // TODO: 在此添加消息处理程序代码和/或调用默认值
  4.         if ( point.x > m_Rect.left && point.x < m_Rect.right && point.y < m_Rect.bottom && point.y > m_Rect.top )
  5.         {
  6.                 HCURSOR hCursor;
  7.                 hCursor = ::LoadCursor ( NULL, IDC_HAND );
  8.                 ::SetCursor ( hCursor );

  9.                 GetDlgItem(IDC_SLink)->SetFont ( &m_cfUL );

  10.                 m_color = RGB (0,0,225);
  11.                 CStatic* m_pStatic = (CStatic*)GetDlgItem(IDC_SLink);
  12.                 m_pStatic->RedrawWindow ();
  13.         }
  14.         else
  15.         {
  16.                 GetDlgItem(IDC_SLink)->SetFont ( m_cfNtr );

  17.                 m_color = RGB (0,0,0);
  18.                 CStatic* m_pStatic = (CStatic*)GetDlgItem(IDC_SLink);
  19.                 m_pStatic->RedrawWindow ();
  20.         }

  21.         CDialog::OnMouseMove(nFlags, point);
  22. }
复制代码
其实,这个色彩部分由于重复率高,完全也可以拿出来作为一个单独函数处理,如果需要处理的情况比较多的话,那是很方便的。但是本程序只有两个情况,所以就干脆复制粘贴一下,并且只修改修改色彩的值就OK了。
最后,给修改颜色的信息WM_CLTCOLOR创建响应的消息响应函数,并且对颜色数据的修改转化为对文字颜色的修改。代码很简单,添加自主执行的代码后,CLTCOLOR响应函数的全部代码为:
  1. HBRUSH CSLinkTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  2. {
  3.         HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

  4.         // TODO:  在此更改 DC 的任何属性
  5.         if ( nCtlColor == CTLCOLOR_STATIC )
  6.         {
  7.                 pDC->SetBkMode ( TRANSPARENT );
  8.                 pDC->SetTextColor ( m_color );

  9.                 return (HBRUSH)m_brush.GetSafeHandle ();
  10.         }

  11.         // TODO:  如果默认的不是所需画笔,则返回另一个画笔
  12.         return hbr;
  13. }
原创粉丝点击