SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

軽量で高速なハイパーリンクコントロールを実現するC++クラス

Win32 APIとMFCの両方で使えるハイパーリンクコントロールの自作

デモプログラム

 ここで紹介するデモは、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_ctlTTCSubclassToolTipCtrl型のオブジェクトであり、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に初期化したのです。使用前に構造体を初期化しておくのは、問題を未然に防ぐための予防措置です。初期化しないままこの構造体定義に新しいフィールドを追加すると、未初期化フィールドにランダムな値が入るため、厄介で見つかりにくいバグになるおそれがあります。構造体をリセットすることで、この問題からプログラムを守ることができます。

まとめ

 説明は以上です。本稿が皆さんの参考になれば幸いです。本稿がお役に立ったようでしたら、少しだけ時間をとって評価をしていただけると助かります。評価は、本稿の一番下の部分から行えます。

参考文献

改訂履歴

2005年12月3日

  • WTLおよび「comctlr32.dll」バージョン6による代替案を追加。
  • CHyperLinkをUNICODEに準拠するよう変更。
  • CHyperLinkとツールチップを連動させる方法の例を追加。

2005年11月17日

  • 第一稿を発表。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

lano1106(lano1106)

電気通信業界にて組み込みプロトコルスタックなどに携わる。米連邦航空局(FAA)の次世代の洋上航空交通管理(ATM)システム開発では(冗談のようだが)ATMプロトコルを担当。UNIXという歴史の深いテクノロジーを用いる環境に倦怠感を覚え、現在はフリーランスの開発者としてWindowsを対象としたC/C++開発に従事。お問い合わせは本人のWebサイトまで。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/341 2006/04/11 19:14

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー