VC 超鏈接

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. }
發佈了16 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章