デモプログラム
ここで紹介するデモは、MFC AppWizardで生成した簡単なアプリケーションです。私が作成したCHyperLinkクラスの使い方を示すために、バージョン情報ダイアログのクラスに変更を加えています。
まず、ダイアログエディタにいくつかの静的コントロールを追加します。TABSTOPスタイルを選択し、各コントロールにユニークなIDを与えます。また、CHyperLinkクラスから新しいクラス(CDemoLink)を派生させ、OnSelect()およびOnDeselect()メソッドをオーバーライドします。ここでは、フレームウィンドウのSetMessageText()関数を呼び出すことで、URLテキストをステータスバーに送ります。
class CDemoLink : public CHyperLink { protected: virtual void OnSelect(void) { ((CFrameWnd *)AfxGetMainWnd())->SetMessageText(m_strURL); } virtual void OnDeselect(void) { ((CFrameWnd *)AfxGetMainWnd())-> SetMessageText(AFX_IDS_IDLEMESSAGE); } };
次に、このダイアログクラスにCDemoLink型のメンバ変数を追加し、WM_INITDIALOGハンドラで次の処理を行います。
void CAboutDlg::setURL(CHyperLink &ctr, int id) { TCHAR buffer[128]; int nLen = ::LoadString(AfxGetResourceHandle(), id, buffer, 128); if( !nLen ) { lstrcpy( buffer, __TEXT("")); } ctr.ConvertStaticToHyperlink(GetSafeHwnd(),id,buffer); } BOOL CAboutDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here setURL(m_DemoLink,IDC_HOMEPAGE); setURL(m_DemoMail,IDC_EMAIL); return TRUE; // return TRUE unless you set the focus // to a control // EXCEPTION: OCX Property Pages should // return FALSE }
このデモプログラムは、CHyperLinkとツールチップコントロールを連動させる方法も示しています。そのためには、MFCのCToolTipCtrlクラスから新しいクラス(CSubclassToolTipCtrl)を派生させる必要があります。まずは、この新たな派生クラスを利用するコードを示したうえで、この新しいクラスのねらいを説明します。
BOOL CAboutDlgWithToolTipURL::OnInitDialog()
{
CAboutDlg::OnInitDialog();
// TODO: Add extra initialization here
m_ctlTT.Create(this);
setURL(m_DemoLink,IDC_HOMEPAGE);
setURL(m_DemoMail,IDC_EMAIL);
/*
* It is OK to add a Window tool to the tool tip
* control with the CHyperLink dynamically allocated
* URL string because the windows are destroyed with
* WM_DESTROY before the CHyperLink destructor where
* the URL string is freed.
*/
m_ctlTT.AddWindowTool(GetDlgItem(IDC_HOMEPAGE)
->GetSafeHwnd(),
(LPTSTR)m_DemoLink.getURL());
m_ctlTT.AddWindowTool(GetDlgItem(IDC_EMAIL)->GetSafeHwnd(),
(LPTSTR)m_DemoMail.getURL());
return TRUE; // return TRUE unless you set the focus
// to a control
// EXCEPTION: OCX Property Pages should
// return FALSE
}
m_ctlTTはCSubclassToolTipCtrl型のオブジェクトであり、AddWindowTool()は新しい関数です。MFCのCToolTipCtrlクラスをそのまま使わなかったのは、ツールのメッセージを受け取る必要があったからです。ここでは低レベルのツールチップAPIを使用してメッセージを受け取るようにしています。MFCのCToolTipCtrlクラスで同じことをしようと思ったら、CToolTipCtrl::RelayEvent()を介してツールのメッセージを中継していく必要があります。RelayEvent()の使い方は比較的簡単ですが、今回のCHyperLinkの設計目標の1つはユーザーにMFCの使用を強制しないことなので、あまり好ましい方法ではありません。この低レベルAPIは、TTM_RELAYEVENTメッセージと共に使うこともできますが、ツールチップを使っていないハイパーリンクのすべてに不必要なオーバーヘッドを課すことになってしまいます。この問題の解決策は『Programming Windows with MFC』という本の中にありました。ツールチップコントロールの、ツールウィンドウをサブクラス化できるという機能を利用すればよいのです。
CSubclassToolTipCtrlクラスの定義を次に示します。
class CSubclassToolTipCtrl : public CToolTipCtrl { // Construction public: CSubclassToolTipCtrl(); // Operations public: /********************************************************* * * Name : AddWindowTool * * Purpose : Add a window tool by using the Tooltip * subclass feature * * Parameters: * hWin (HWND) Tool window * pszText (LPCTSTR) Tip text (can also be * a string resource ID). * * Return value : Returns TRUE if successful, * or FALSE otherwise. * *********************************************************/ BOOL AddWindowTool( HWND hWin, LPTSTR pszText ); // Implementation public: virtual ~CSubclassToolTipCtrl(); }; /* * Function CSubclassToolTipCtrl::AddWindowTool */ BOOL CSubclassToolTipCtrl::AddWindowTool( HWND hWin, LPTSTR pszText ) { TOOLINFO ti; ::ZeroMemory(&ti, sizeof(TOOLINFO)); ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; ti.hwnd = ::GetParent(hWin); ti.uId = (UINT)hWin; ti.hinst = AfxGetInstanceHandle(); ti.lpszText = pszText; return (BOOL)SendMessage(TTM_ADDTOOL,0,(LPARAM)&ti); }
ここでは、『Programming Windows with MFC』の解決策にちょっとした改善を加えてあります。TOOLINFO構造体を、使う前に0に初期化したのです。使用前に構造体を初期化しておくのは、問題を未然に防ぐための予防措置です。初期化しないままこの構造体定義に新しいフィールドを追加すると、未初期化フィールドにランダムな値が入るため、厄介で見つかりにくいバグになるおそれがあります。構造体をリセットすることで、この問題からプログラムを守ることができます。
まとめ
説明は以上です。本稿が皆さんの参考になれば幸いです。本稿がお役に立ったようでしたら、少しだけ時間をとって評価をしていただけると助かります。評価は、本稿の一番下の部分から行えます。
参考文献
- CodeGuru 『Transforming Static Text Controls into Active Hyperlinks Using the Win32 API』 Neil Stublen 著
- MSDN magazine 『Making Static Links Keyboard-Capable, Launching URLs from Your App』 Paul DiLascia 著、2005年3月
- 『Programming Windows, Fifth Edition』 Charles Petzold 著、Microsoft Press、1998年11月
- 『Programming Windows with MFC, Second Edition』 Jeff Prosise 著、Microsoft Press、1999年5月
- 『MFC Internals』 George Shepherd・Scot Wingo 著、Addison Wesley、1996年5月
改訂履歴
2005年12月3日
- WTLおよび「comctlr32.dll」バージョン6による代替案を追加。
CHyperLinkをUNICODEに準拠するよう変更。CHyperLinkとツールチップを連動させる方法の例を追加。
2005年11月17日
- 第一稿を発表。
