ComboBoxExのツールチップに関する質問

[戻る]
ぱらー [E-Mail] 2002/07/05(金) 18:17:15
はじめまして、ぱらーと申します。

ツールチップに関して質問させてください。

実は、下記の処理でダイアログボックス上の
ボタンやコンボボックス等通常のコントロールの
ツール ヒントが表示されますが、ComboBoxExの
場合は表示できません。
表示するにはどうしたらよいのでしょうか?

方法1:

BEGIN_MESSAGE_MAP(CTstComboBoxExDlg, CDialog)
    //{{AFX_MSG_MAP(CTstComboBoxExDlg)
    ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnToolTipNotify )
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()



BOOL CTstComboBoxExDlg::memberFxn( UINT id, NMHDR * pNMHDR, LRESULT * pResult)
{
    TCHAR szFullText[256];
    CString strTipText;

    TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
    UINT nID =pNMHDR->idFrom;
    if (pTTT->uFlags & TTF_IDISHWND)
    {
        // idFrom is actually the HWND of the tool
        nID = ::GetDlgCtrlID((HWND)nID);
        if(nID)
        {
            strTipText.LoadString( nID);
            // this is the command id, not the button index
            strcpy( szFullText, (LPCTSTR)strTipText);
            AfxExtractSubString( strTipText, szFullText, 1, '\n');
            pTTT->lpszText = MAKEINTRESOURCE(nID);
            return(TRUE);
        }
    }

    *pResult = 0;
    return(FALSE);
}

ちなみに、各コントロールのツール ヒントテキストがリソースの
String Tableには入っています。


開発環境はWin2000、WinXP VC6.0SP5 MFCです。

どなたかご指導ください。よろしくお願い致します。

ぱらー 2002/07/05(金) 18:35:29
訂正させてください。


BEGIN_MESSAGE_MAP(CTstComboBoxExDlg, CDialog)
    //{{AFX_MSG_MAP(CTstComboBoxExDlg)
    ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnToolTipNotify )
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()


BOOL CMyFormView::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * pResult)
{
    TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
    UINT nID =pNMHDR->idFrom;
    if (pTTT->uFlags & TTF_IDISHWND)
    {
        // idFrom is actually the HWND of the tool
        nID = ::GetDlgCtrlID((HWND)nID);
        if(nID)
        {
            pTTT->lpszText = MAKEINTRESOURCE(nID);
            pTTT->hinst = AfxGetResourceHandle();
            return(TRUE);
        }
    }
    return(FALSE);
}


すみませんでした。

2002/07/08(月) 18:19:15
未確認ですが、CToolTipCtrlを使ってもだめですか?

ぱらー 2002/07/08(月) 18:34:05
1.[通りすがりの者]さんへ:
  ご応援ありがとう。
  先ごろ、あの荒らしコメントを見たら、ちょっと頭に
  来ちゃって、その勢いで、マルチポストをしてしまいました。
  失礼いたしました。

2.[?]さんへ
  そうです。
  CToolTipCtrlを使ってもうまくできません。
  この間、色々と調べてみました。ひょっとしたら、
  CToolTipCtrlのサブクラス化で解決できるかもしれない
  ですが...

  ご教授ください。
  宜しくお願いいたします。

2002/07/08(月) 21:06:57
以下のような処理で出ましたが・・・

BOOL CHogeDlg::OnInitDialog() 
{
  m_ToolTip[0].Create( this, TTS_ALWAYSTIP );
  m_ToolTip[0].AddTool( &m_Hoge1, "Hoge1" );
  m_ToolTip[0].Activate( TRUE );
  m_ToolTip[1].Create( this, TTS_ALWAYSTIP );
  m_ToolTip[1].AddTool( &m_Hoge2, "Hoge2" );
  m_ToolTip[1].Activate( TRUE );
  (以下略)
}
BOOL CHogeDlg::PreTranslateMessage(MSG* pMsg) 
{
  for( int i=0; i<n; i++ )
  {
     m_ToolTip[i].RelayEvent( pMsg );
  }
  return CDialog::PreTranslateMessage( pMsg );
}

.hでCComboBoxをCComboBoxExに変えただけなのでテストとして不十分かもですが。
データはリソースで定義した文字列だけです。(InsertItemとかは使ってません。)
#配列にする必要はないはずだけど、(他人の)既存のソースを流用したので・・・。

ぱらー 2002/07/09(火) 09:22:36
ご返答ありがとう。
やってみます。
よろしくお願い致します。

ぱらー 2002/07/09(火) 15:09:59
大変お待たせ致しまして申し訳ございません。
[?]さんが教えていただいた方法でやってみたが,
どうやらうまくいかないです。

詳細は以下の通りです。
1.ダイアログボックス上にComboBoxとComboBoxEx
  一個ずつ配置します。
  コントロールIDはIDC_COMBO1 と IDC_COMBOBOXEX1 にします。

2.ClassWizardにて
 @IDC_COMBO1 に対し、メンバー変数m_combo1(コントロール)を
  追加します。
 AIDC_COMBOBOXEX1 に対し、メンバー変数m_comboex1(コントロール)を
  追加します。

3.ソースコード

CToolTipCtrl m_ToolTip[ 2];

BOOL CTstToolTipDlg::OnInitDialog() 
{
  ...
  ...

  EnableToolTips( TRUE);   // enable tool tips for view
  m_ToolTip[ 0].Create( this, TTS_ALWAYSTIP );
  m_ToolTip[ 0].AddTool( &m_combo1, "combo1" );
  m_ToolTip[ 0].Activate( TRUE );
  m_ToolTip[ 1].Create( this, TTS_ALWAYSTIP );
  m_ToolTip[ 1].AddTool( &m_comboex1, "comboex1" );
  m_ToolTip[ 1].Activate( TRUE );

  return TRUE;  // TRUE を返すとコントロールに設定したフォーカスは失われませ
ん。
}

BOOL CTstToolTipDlg::PreTranslateMessage( MSG* pMsg) 
{
  for( int i = 0; i < 2; i++ )
  {
    m_ToolTip[ i].RelayEvent( pMsg );
  }
  return CDialog::PreTranslateMessage( pMsg );
}

4.TstToolTipDlg.hでCComboBoxをCComboBoxExに変えました。
  (実際には、変えなくても結果は同様でした)

上記の手順でやってみましたが、結局はカーソルがComboBoxに
当たるとツールヒントが出るが、ComboBoxExの場合だと、依然として
出ないが、もしかしたら、私の手順なんかは間違ったかもしれないが。
忙しいところ、申し訳ございませんが、
間違ったところや不備なところが有ったら、ご指摘いただければと思います。
宜しくお願いいたします。

dairygoods 2002/07/09(火) 15:43:17
Spy++で調べてみると、拡張コンボの場合、本来のコンボボックスの上に
1つ余分なウィンドウが被さっているのが分かります。
これが何か悪さしているような気がします。

そこで、CWnd::OnToolHitTest() にて以下のように細工してみたところ、
ドロップダウンリストではうまく表示されるようになりました。
ドロップダウンの場合は、矢印の上でだけ表示されます…。
(最初のCToolTipCtrlを使わないバージョンの場合)

本質的な解決になってないですけど、ご参考まで。


int C*View::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
  int r = CView::OnToolHitTest(point, pTI);
  HWND hwnd = (HWND)pTI->uId;
  char name[13];
  ::GetClassName(hwnd, name, sizeof(name));
  if (strcmp(name, "ComboBoxEx32") == 0) {
    //拡張コンボの場合、その子ウィンドウに置き換える
    pTI->uId = (UINT)::GetWindow(hwnd, GW_CHILD);
  }
  return r;
}

#ところで、CToolTipCtrlはコントロールごとに用意しなくても
#1つのツールチップにいくつもAddToolできますよ。

2002/07/10(水) 12:59:57
ごめんなさい。申し訳ない。お恥ずかしい。
2002/07/08(月) 21:06:57 のレス
リソースのほうを直し忘れてました。(通常のコンボのままでした。)
なのでツールチップがでたというのは私の勘違いです。
本当にごめんなさい。

ぱらー 2002/07/10(水) 13:20:26
dairygoodsさんへ

ご返答ありがとうございます。
返信遅くなってすみません。

教えて頂いた方法でやってみたんですが、
どうも上手くいかないんです。
調べたところ、OnToolHitTest()関数が
一度も呼び出されることはなかったんです。
すみませんが、もう少しOnToolHitTest()の
使い方を教えていただけませんか?
私は素人なので、MSDNを調べてもOnToolHitTestの
内容がよく理解できません。

それでは宜しくお願い致します。

ぱらー 2002/07/10(水) 13:55:30
[?]さんへ
そんなことありません。
でもほんとに勉強になりましたよ。
どうもありがとうございました。
また、いい方法があれば、
教えていただければと思います。

宜しくお願いいたします。

dairygoods 2002/07/10(水) 15:20:23
> 調べたところ、OnToolHitTest()関数が
> 一度も呼び出されることはなかったんです。

関数定義はあってますか?戻り値intやconstが付いてるなど。
この関数を定義したウィンドウでEnableToolTips()を呼び出してますか?

ぱらー 2002/07/10(水) 15:49:21
dairygoodsさんへ

ご返答ありがとうございます。

ご指摘した通り、EnableToolTips()を忘れて
しまいました。
もう少しやってみてから状況を報告致しますので
宜しくお願いいたします。

ぱらー 2002/07/10(水) 16:40:54
dairygoodsさんへ

EnableToolTips( true)を入れて、再度確認して
みましたが、改善は見られないです。
ご判断が容易のため、検証用の主なソースを以下に
リストアップいたします。

1.プロジェクト名
 CheckToolTip

2.基本クラス
 CFormView

3.フォームビュー上に配置するコントロール
 ComboBox   一個
 ComboBoxEx  一個

4.CheckToolTipView.hにおいて

class CCheckToolTipView : public CFormView
{
   ...
   ...

// オーバーライド
  // ClassWizard は仮想関数のオーバーライドを生成します。
  //{{AFX_VIRTUAL(CCheckToolTipView)
  protected:
   ...
   ...
  virtual int OnToolHitTest(CPoint point, TOOLINFO* pTI) const;
  //}}AFX_VIRTUAL
   ...
   ...
}

5.CheckToolTipView.cppにおいて

void CCheckToolTipView::OnInitialUpdate()
{
  CFormView::OnInitialUpdate();
  GetParentFrame()->RecalcLayout();
  ResizeParentToFit();

  EnableToolTips( true);
}

int CCheckToolTipView::OnToolHitTest( CPoint point, TOOLINFO* pTI) const
{
  int r = CView::OnToolHitTest( point, pTI);
  HWND hwnd = (HWND)pTI->uId;
  char name[ 13];
  ::GetClassName( hwnd, name, sizeof( name));
  if ( strcmp( name, "ComboBoxEx32") == 0) {
   // 拡張コンボの場合、その子ウィンドウに置き換える
   pTI->uId = (UINT)::GetWindow( hwnd, GW_CHILD);
  }
  return r;
}

疑問:
OnToolHitTest()関数は自分で呼び出すのですか、
それともON_NOTIFYやON_NOTIFY_EXなどによって
呼び出すのですか?そのへんはよく分かりませんが。

宜しくお願いいたします。

dairygoods 2002/07/10(水) 17:12:33
問題ないように見えますが…。
OnToolHitTest()が呼び出されないと言うことでしょうか?

> OnToolHitTest()関数は自分で呼び出すのですか、
> それともON_NOTIFYやON_NOTIFY_EXなどによって
> 呼び出すのですか?そのへんはよく分かりませんが。

フォーム上でマウスカーソルを動かすと、
その位置に何があるかを調べるためにMFCが呼び出します。

CWnd::PreTranslateMessage()内でその処理をやっていますので、
これをオーバーライドしてしまうと呼び出されません。

ぱらー 2002/07/10(水) 17:31:35
dairygoodsさんへ

お返事ありがとうございます。

> OnToolHitTest()が呼び出されないと言うことでしょうか?

そういうことですね。


> CWnd::PreTranslateMessage()内でその処理をやっていますので、
> これをオーバーライドしてしまうと呼び出されません。

PreTranslateMessage()をオーバーライドしていませんが。



確認するために、下記のようにメッセージ表示を入れました。

int CCheckToolTipView::OnToolHitTest( CPoint point, TOOLINFO* pTI) const
{
::MessageBox( NULL, "OnToolHitTest()に入った", "確認メッセージ", 0);

  int r = CView::OnToolHitTest( point, pTI);
  HWND hwnd = (HWND)pTI->uId;
  char name[ 13];
  ::GetClassName( hwnd, name, sizeof( name));
  if ( strcmp( name, "ComboBoxEx32") == 0) {
   // 拡張コンボの場合、その子ウィンドウに置き換える
   pTI->uId = (UINT)::GetWindow( hwnd, GW_CHILD);
  }
  return r;
}

確認の結果、カーソルがウインドウのクライアント領域に
入るたびに"OnToolHitTest()に入った"メッセージが決まって
表示されます。この時、カーソルがビュー上のコントロールに
当たらなくてもそのメッセージが表示されます。


忙しいところすみませんが、宜しくお願いいたします。

dairygoods 2002/07/11(木) 09:46:58
>> OnToolHitTest()が呼び出されないと言うことでしょうか?
> そういうことですね。

> 確認の結果、カーソルがウインドウのクライアント領域に
> 入るたびに"OnToolHitTest()に入った"メッセージが決まって
> 表示されます。この時、カーソルがビュー上のコントロールに
> 当たらなくてもそのメッセージが表示されます。

つまり、OnToolHitTest()は呼び出されていることになりますが…。

ぱらー 2002/07/11(木) 10:18:02
dairygoodsさんへ

お返事ありがとうございます。


> つまり、OnToolHitTest()は呼び出されていることになりますが…。
おっしゃる通りです。


宜しくお願いいたします。

dairygoods 2002/07/11(木) 11:49:12
>> OnToolHitTest()が呼び出されないと言うことでしょうか?
> そういうことですね。

>> つまり、OnToolHitTest()は呼び出されていることになりますが…。
> おっしゃる通りです。

お返事が矛盾していてよく分からなくなってしまいました。
OnToolHitTest()が呼び出されないという問題は
解決したということでよろしいですか?

そして、OnToolHitTest()は呼び出されるが、
ツールヒントは出ない。というのが現在の問題点でしょうか?

そうであれば、ヒントを出すには、
元のソースにあった、TTN_NEEDTEXTのハンドラも必要なのですが、
ありますでしょうか?
既にあるのでしたら、拡張コンボ上にカーソルをしばらく置いたとき、
OnToolTipNotify()は呼び出されますか?

ぱらー 2002/07/11(木) 12:49:42
dairygoodsさんへ

大変お世話になっております。

先、誤解を招いてしまって申し訳ないです。

1.OnToolHitTest()が呼び出されないという問題に関して
 解決しました。

2.TTN_NEEDTEXTのハンドラに関して
 下記のようにTTN_NEEDTEXTのハンドラを入れたが、
 ComboBoxのヒントは出るが、ComboBoxExのヒントは出ないです。


BEGIN_MESSAGE_MAP(CCheckToolTipView, CFormView)
 //{{AFX_MSG_MAP(CCheckToolTipView)
  // メモ - ClassWizard はこの位置にマッピング用のマクロを追加または削除しま
す。
  //    この位置に生成されるコードを編集しないでください。
 //}}AFX_MSG_MAP
 // 標準印刷コマンド
 ...
 ...
 ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnToolTipNotify)
END_MESSAGE_MAP()

 ...
 ...

BOOL CCheckToolTipView::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * 
pResult )
{
    TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
    UINT nID =pNMHDR->idFrom;
    if (pTTT->uFlags & TTF_IDISHWND)
    {
        // idFrom is actually the HWND of the tool
        nID = ::GetDlgCtrlID((HWND)nID);
        if(nID)
        {
            pTTT->lpszText = MAKEINTRESOURCE(nID);
            pTTT->hinst = AfxGetResourceHandle();
            return(TRUE);
        }
    }
    return(FALSE);
}

さらに、OnToolTipNotify()の最初に
::MessageBox( NULL, "OnToolTipNotify()に入った", "確認メッセージ", 0);
を入れてみたが、やはりコンボ上にカーソルを置いたら、確認メッセージが
出たけど、拡張コンボ上にカーソルをしばらく置いても、確認メッセージが
出なかったんです。よって、ハンドラOnToolTipNotifyは拡張コンボを認識
しないではと思いますが。

度々すみませんが、宜しくお願いいたします。

dairygoods 2002/07/11(木) 15:09:30
最初に書いたように、この方法はドロップダウンリスト
(コンボに文字列を入力できないタイプ)
でないと、まともに動かないと思いますが、問題ないでしょうか?

それ以外はちょっと原因が思いつかないです。

トオリスガリ 2002/07/11(木) 15:10:57
スタイルはどうなってますか?
>ドロップダウンリストではうまく表示されるようになりました。
>ドロップダウンの場合は、矢印の上でだけ表示されます…。

OnToolHitTestについて
>  if ( strcmp( name, "ComboBoxEx32") == 0) {
>   // 拡張コンボの場合、その子ウィンドウに置き換える
 ///////  ここにブレークポイントまたは確認メッセージをいれてみては? ///////
>   pTI->uId = (UINT)::GetWindow( hwnd, GW_CHILD);
 /////// pTI->uId の値は ComboBoxExのIDになればいいのかな?
>  }

ぱらー 2002/07/11(木) 17:04:35
dairygoodsさんへ

大変お世話になっております。

> 最初に書いたように、この方法はドロップダウンリスト
>(コンボに文字列を入力できないタイプ)
> でないと、まともに動かないと思いますが、問題ないでしょうか?

再度、確認しましたが、ドロップダウンリストとドロップダウンの
いずれの場合はツールヒントは出なかったんです。

dairygoodsさんはどうやったんですか?
恐縮ですが、簡単なサンプルをいただけませんか?
急がないです。不便なら、結構でございますが。
でも、dairygoodsさんから色々と勉強になりましたので、
感謝しています。

e-mail: cje58130@ams.odn.ne.jp

ぱらー 2002/07/11(木) 17:38:01
トオリスガリさんへ

ご回答頂いてありがとうございます。

早速ですが、ご提示の件を確認しました。

件1:
> スタイルはどうなってますか?
ComboBoxExがドロップダウンリストとドロップダウンの
いずれの場合はツールヒントは出なかったんです。

件2:
>OnToolHitTestについて
>>  if ( strcmp( name, "ComboBoxEx32") == 0) {
>>   // 拡張コンボの場合、その子ウィンドウに置き換える
> ///////  ここにブレークポイントまたは確認メッセージをいれてみては? ///////
>>   pTI->uId = (UINT)::GetWindow( hwnd, GW_CHILD);
> /////// pTI->uId の値は ComboBoxExのIDになればいいのかな?
>>  }


OnToolHitTest()はこんな感じです。

int CCheckToolTipView::OnToolHitTest( CPoint point, TOOLINFO* pTI) const
{
    int r = CView::OnToolHitTest( point, pTI);
    HWND hwnd = (HWND)pTI->uId;

    char name[ 13];

    ::GetClassName( hwnd, name, sizeof( name));
    if ( strcmp( name, "ComboBoxEx32") == 0)
    {
::MessageBox( NULL, "ComboBoxEx です", "msg", 0);
        // 拡張コンボの場合、その子ウィンドウに置き換える
        pTI->uId = (UINT)::GetWindow( hwnd, GW_CHILD);
    }
    else if ( strcmp( name, "ComboBox") == 0)
    {
::MessageBox( NULL, "ComboBox です", "msg", 0);
    }
    return r;
}

やってみた結果、コンボ上にカーソルを置くと"ComboBox です"という
メッセージが出ます。また、拡張コンボ上にカーソルを置くと
"ComboBoxEx です"というメッセージが出ますが、OnToolTipNotify()に
入れ替えると、拡張コンボのツールヒントが出なくなります。
ちょっと不思議ですね。


また、ヒントがございましたら、教えていただければ幸いです。
宜しくお願いいたします。

XXX 2002/07/11(木) 18:54:08
http://hpcgi1.nifty.com/MADIA/Vcbbs/wwwlng.cgi?print+200207/02070006.txt

? 2002/07/11(木) 23:11:00
XXX さんへ
マルチポストはいけないことですがこのマルチポストにはそれなりの理由があったので
無言で責めるようなことは・・・

らららさんへ
このレス 上のと一緒に消してください。

? 2002/07/11(木) 23:20:36
リベンジ! というわけでもないけど
dairygoodsさんの方法で試してみました。
ドロップダウンで。矢印の上と微妙な境界部分で表示されます。
ただ、コンボボックスと拡張コンボボックス、その他のボタンなどを配置してみて
コンボボックスにフォーカスがあると(キャレット?がチカチカしてると)
マウスを拡張コンボボックスの上に移動しても
OnToolHitTestが呼ばれたり呼ばれなかったり?
他のコントロールをクリックした後などはちゃんと呼ばれるのですが???

コントロールを増やしてテストされてみては?

関係ないかもしれませんが、Win2000,VC++6,COMCTL32.DLLのバージョンは5.81.3103.1000で
す。

それと
>入れ替えると、拡張コンボのツールヒントが出なくなります。
入れ替える?
OnToolHitTest()とOnToolTipNotify()、両方あって良いんですよね?
入れ替えたりしなくても?


?だらけの?でした。

トスポ 2002/07/12(金) 02:20:45
マルチポストはダメですよ。
無言で通報するのはイメージ悪いですけど。

マルチポストを許可するならするで、「使用上の注意」を書き換える必要があります。
今のところ、止めて下さいと書いています。

dairygoods 2002/07/12(金) 10:19:30
> dairygoodsさんはどうやったんですか?
> ですが、簡単なサンプルをいただけませんか?

掲示板上で解決するのが筋だと思いますので、
もうちょっと粘ってみます。

私は以下のように作成しました。
1) SDIプロジェクトを作りビューはCFormViewを選択。
2) OnInitialUpdate()にEnableToolTips(TRUE)を追加。
3) OnToolHitTest()関数を追加。
4) TTN_NEEDTEXTハンドラOnToolTipNotify()を追加。
5) ダイアログリソースに適当にコントロールを配置。
6) 文字列リソースにコントロールに対応したヒントを追加。

各関数の中身は、ここに書き込まれている通りです。

コントロールを操作してしまうと出にくく?なるようです。

ぱらー 2002/07/12(金) 10:37:54
?さん

レスありがとうございます。

> コントロールを増やしてテストされてみては?
実際には、ボタンとかエディットなどのコントロールを
増やしてやってみたが、いずれは拡張コンボ以外の
コントロールは問題がなかったが.


> OnToolHitTest()とOnToolTipNotify()、両方あって良いんですよね?
> 入れ替えたりしなくても?
実際には、両方あってのパターンもやりましたが、
だめでした。


どうしようもないかね。

またよろしくお願いいたします。

ぱらー 2002/07/12(金) 11:13:12
[[解決]]

dairygoodsさん、?さん、トオリスガリさん、
皆さんのお蔭様でうまくできました。

よかった。

dairygoodsさんの教えていただいた手順の
通りやったら、ツールヒントがちゃんと
出ました。
でも、これまでの手順とはほとんど一緒で、
うまくいかない場合のソースとうまくいく
場合のソースとはまったく同じだが、
なんで結果が違ったのは分からないですけど。
きっと間違ったところがあります。
後で自分がじっくり見比べます。


みなさん、ほんとにどうもありがとうございました。

ぱらー 2002/07/12(金) 11:14:43
[[解決]]
解決のマークをチェックしなかった、
ごめんなさい。

古いスレッドには追加発言できません。