Tooltip aus einem View wieder entfernen



  • Hallo zusammen,

    Meine Anwendung besteht aus einfachen Views.
    In solch einem View (also einfach der gesamte Fensterinhalt) setze ich einen Tooltip.
    Das funktioniert auch weitgehend. Nur das Verhalten sollte noch angepasst werden.

    Folgende Verhaltensauffälligkeiten:

    1. Ich bekomme das Ding nicht wieder weg.
      Es verschwindet zwar nach einer kurzen Zeit.
      Wenn man aber mit der Maus kurz aus dem Fenster rausgeht und wieder rein,
      erscheint es wieder, selbst wenn ich meinen View wechsle.
    2. Ich würde den Tooltip gerne ohne diesen Timout haben.
      Er sollte solange da bleiben, bis ich wieder eine Maustaste im View drücke.

    Hier der Code:
    Aufgerufen wird das über "OnRButtonDown(UINT nFlags, CPoint point)"

    //----------------------------------------------------------------------
    void DeleteToolTipForRect()
    {
        SendMessage(m_hwndTT, TTM_POP, NULL, NULL);
    //    CloseWindow(m_hwndTT);
    //    m_hwndTT = 0;
    }
    
    //----------------------------------------------------------------------
    void CreateToolTipForRect(HWND hwndParent, int iZeile, CString csTitle, CString csContent)
    {
        if(m_hwndTT)
            DeleteToolTipForRect();
    
        if(!m_hwndTT)
            // Create a tooltip.
            m_hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T("ToolTipWindow"), 
                                      WS_POPUP | TTS_BALLOON | WS_CAPTION | TTS_NOPREFIX | TTS_ALWAYSTIP, 
                                      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
                                      hwndParent, NULL, NULL,NULL);
    
        SetWindowPos(m_hwndTT, HWND_TOPMOST, 0, 0, 0, 0, 
                     SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    
        // Set up "tool" information. In this case, the "tool" is the entire parent window.
        TOOLINFO ti = { 0 };
        ti.cbSize   = sizeof(TOOLINFO);
        ti.uFlags   = TTF_SUBCLASS;
        ti.hwnd     = hwndParent;
        ti.hinst    = NULL;
        ti.lpszText = csContent.GetBuffer();
        
        ::GetClientRect (hwndParent, &ti.rect);
    
        // Associate the tooltip with the "tool" window.
        SendMessage(m_hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); 
        SendMessage(m_hwndTT, TTM_SETMAXTIPWIDTH, 0, 1000); // HP: Das brauch man zusätzlich, um Multiline zu bekommen!
        SendMessage(m_hwndTT, TTM_SETTITLE, 0, (LPARAM)csTitle.GetBuffer());// HP: Zusatz für Header
    } 
    

    Also das "DeleteToolTipForRect()" macht eigentlich gar nix!

    Und zu Punkt 2 fällt mir gar nix ein.

    Kann mir da bitte jemand helfen?

    Grüsse
    Helmut


  • |  Mod

    Lies mal die Doku zu Tracking Tooltips!
    https://docs.microsoft.com/en-us/windows/desktop/controls/implement-tracking-tooltips

    Du musst dann aber TTM_RELAY... verwenden.

    Evtl. solltest Du Dich mit der MFC Implementierung auseinandersetzen. (CWnd::EnableTooltips und CWnd::EnableTrackingTooltips)...

    Siehe z.B.
    https://www.codeproject.com/Articles/28885/CListCtrl-and-Displaying-a-Tooltip



  • @martin-richter

    Danke Martin,

    allerdings ist mein Tooltip nicht an ein Control gebunden.
    Ich habe gar keine Controls in diesem View.
    Daher habe ich auch auf die Verwendung eines Tooltip-Controls verzichtet.
    Meine Grundlage war da z.B. "How to get tooltip text for a given HWND?"
    aus Stackoverflow und ein ähnlicher Artikel.


  • |  Mod

    @elmut19 Seit wann ist ein CView kein Control? Nur mal so am Rande 😉



  • @elmut19 ich brauch wohl wieder Urlaub....



  • @martin-richter
    Hi Martin,

    nun klappt fast alles.
    Leider wird der Tooltip aber nun nicht mehrin meinem Anwendungsfenster platziert, wie zuvor noch,
    sondern es snid nun die absoluten Bildschirm-Koordinaten.

    Mein Point ist aber auf die Anwendung bezogen.
    Vorher war das korrekt. Also sogar relativ zum aktuellen "ClientRect".
    Was mache ich nun wieder falsch?

    void CViewListStd::CreateToolTipForRect(HWND hwndParent, int iZeile, CString csTitle, CString csContent, WORD wXpos, WORD wYpos)
    {
        if(m_hwndTT)
            DeleteToolTipForRect();
    
        if(!m_hwndTT)
            // Create a tooltip.
            m_hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T("ToolTipWindow"), 
                                      WS_POPUP | TTS_BALLOON | WS_CAPTION | TTS_NOPREFIX | TTS_ALWAYSTIP, 
                                      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
                                      hwndParent, NULL, NULL,NULL);
        if (!m_hwndTT)
          return;
    
     //   SetWindowPos(m_hwndTT, HWND_TOPMOST, 0, 0, 0, 0, 
     //                SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    
        // Set up "tool" information. In this case, the "tool" is the entire parent window.
        TOOLINFO m_ti = { 0 };
        m_ti.cbSize   = sizeof(TOOLINFO);
        m_ti.uFlags   = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
        m_ti.hwnd     = hwndParent;
        m_ti.hinst    = NULL;
        m_ti.lpszText = csContent.GetBuffer();
        
        ::GetClientRect (hwndParent, &m_ti.rect);
    
        // Associate the tooltip with the "tool" window.
        SendMessage(m_hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &m_ti); 
        SendMessage(m_hwndTT, TTM_SETMAXTIPWIDTH, 0, 1000); // HP: Das brauch man zusätzlich, um Multiline zu bekommen!
        SendMessage(m_hwndTT, TTM_TRACKPOSITION, 0, (LPARAM)MAKELONG(wXpos,wYpos)); // HP: Das brauch man zusätzlich, um Multiline zu bekommen!
        SendMessage(m_hwndTT, TTM_SETTITLE, 0, (LPARAM)csTitle.GetBuffer());// HP: Zusatz für Header
        SendMessage(m_hwndTT, TTM_SETTOOLINFO, 0, (LPARAM)&m_ti);
        SendMessage(m_hwndTT, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&m_ti);
    } 
    


  • Mit TTF_ABSOLUTEgibst du an, dass die Position bei TTM_TRACKPOSITIONübernommen wird und das Tooltipfenster wird mit dem Stil WS_POPUP erstellt.
    Es ist ja alles soweit richtig, ein Tooltip kann sich auch außerhalb des Fenster befinden (daher kein WS_CHILD) - wenn du den Punkt jetzt noch vorher mit ClientToScreen transformiest, sollte es passen.



  • @yahendrik Hallo yahendrik

    Vielen Dank für die Hilfe.
    Das war die Lösung.
    Also:

        ClientToScreen(hwndParent,&point);
    

    habe ich, nach dem GetClientRect(..) noch ergänzt. Dann hat alles geklappt.

    Grüsse
    Helmut