ToolTipWindows JUCE 3 -> Juce 4 Problem

Hey all,

I was operating in JUCE 3 before and have just now recently updated. Everything with the update went smoothly except for one component - the ToolTipWindow. It had originally been working for me in JUCE 3 but with the update to JUCE 4 modules, it no longer displays correctly. I have updated to the various virtual functions now used (getTooltipBounds override, etc).

To describe the behavior: It appears, drawn correctly, but then quickly disappears. The remnant of it still is shown (the dropdown + 1px border) but the body of it is not shown. Breakpointing through Juce_TooltipWindow, it never calls the hidetip() function. Below is the actual uploaded image of what it appears like. Before it actually disappears, I breakpointed and it gets lost in the DefWindowProcW function call in WinUser.h.

It happens, regardless of the component used. Generally speaking, though, the tooltips are generated from buttons located on a TopLevelWindow.

Has anybody had an issue like this before? Anybody know where to go from here to investigate this?

Additionally: The TooltipWindow appears like this regardless of if I moved the mouse or not. As in, if I set it to appear in 2 seconds, and wait 2 seconds without moving the mouse, it appears and then the body disappears to have it remain like above. Therefore, it has nothing to do with the mouse movement itself (there was the addition of the mouse listener in 3 to 4, and I was wondering if it had caused this issue).

Another observation is that the TooltipWindow never grabs focus (focus always remains on the button, even when I hover in the TooltipWindow area.)

Setting the parent to the TopLevelWindow corrects this entire problem. However, I have multiple TopLevelWindows with Tooltips. As a result, I don’t have the ability to set the parent to just a single TopLevelWindow and expect it to work across the board.

Not sure if this your case at all, but a possible/common cause of erratic behaviour with the ToolTipWindow is when more than one instance is created. so perhaps double check that you only create one.

Thanks for the suggestion but I definitely only have one instance of it ever running - which is part of the reason why it is so problematic since I have four TopLevelWindows open in one circumstance (none overlapping) and all four use ToolTips. However, this problem occurs even when there is only one TopLevelWindow open.

Do you also see this in the juce demo (see screenshot below)? If no, then try comparing your code with the juce demo code.

It is almost entirely 1-1. The difference is that I have the tooltip in my application singleton as a member and it doesn’t display anything in there - instead, it displays tooltips in member TopLevelWindows that I have. When I have the parent assigned as nullptr, it doesn’t display correctly as above but when I assign the parent to a particular TopLevelWindow, it operates and shows correctly.

This same code, also, to note, worked before upgrading to JUCE 4.

I’m going to attempt to create a barebone VS2013 project mimicing the above in its barebone form to see what it takes to truly trigger. I’ll get back with my results.

Currently held up on creating a barebone application with tooltips. Does anybody have any other suggestions?

I believe, ultimately, that the parent of the ToolTipWindow is actually an underlying window (CView class). As a result, the TopLevelWindow, when generating the ToolTip, is generating the CView class as the parent, and the TopLevelWindow is actually above the CView class, resulting in the behavior above. Hence, the tooltip actually appears underneath the TopLevelWindow.

This is why, defining the parent as the TopLevelWindow, actually works well because it places the hierarchy correctly. However, the hierarchy has changed from JUCE 3 to JUCE 4 with regards to this and is now causing this issue…

Figured a crappy way of doing it but I added a repaint() call into the timerCallback, located:

void TooltipWindow::timerCallback()
    Desktop& desktop = Desktop::getInstance();
    const MouseInputSource mouseSource (desktop.getMainMouseSource());
    const unsigned int now = Time::getApproximateMillisecondCounter();

    Component* const newComp = mouseSource.isMouse() ? mouseSource.getComponentUnderMouse() : nullptr;
    const String newTip (getTipFor (newComp));
    const bool tipChanged = (newTip != lastTipUnderMouse || newComp != lastComponentUnderMouse);
    lastComponentUnderMouse = newComp;
    lastTipUnderMouse = newTip;

    const int clickCount = desktop.getMouseButtonClickCounter();
    const int wheelCount = desktop.getMouseWheelMoveCounter();
    const bool mouseWasClicked = (clickCount > mouseClicks || wheelCount > mouseWheelMoves);
    mouseClicks = clickCount;
    mouseWheelMoves = wheelCount;

    const Point<float> mousePos (mouseSource.getScreenPosition());
    const bool mouseMovedQuickly = mousePos.getDistanceFrom (lastMousePos) > 12;
    lastMousePos = mousePos;

    if (tipChanged || mouseWasClicked || mouseMovedQuickly)
        lastCompChangeTime = now;

    if (isVisible() || now < lastHideTime + 500)
        // if a tip is currently visible (or has just disappeared), update to a new one
        // immediately if needed..
        if (newComp == nullptr || mouseWasClicked || newTip.isEmpty())
            if (isVisible())
                lastHideTime = now;
        else if (tipChanged)
            displayTip (mousePos.roundToInt(), newTip);

        // if there isn't currently a tip, but one is needed, only let it
        // appear after a timeout..
        if (newTip.isNotEmpty()
             && newTip != tipShowing
             && now > lastCompChangeTime + (unsigned int) millisecondsBeforeTipAppears)
            displayTip (mousePos.roundToInt(), newTip);


In fact I’ve also got this issue after porting Juce from 4.0.1 to 4.3.0
(I’m running on Windows 7 SP1 64 in a 64bit app)

It seems that removing the newly added flag ComponentPeer::windowIgnoresMouseClicks from addToDesktop call in juce::TooltipWindow.cpp solve this issue.

Maybe the WS_EX_TRANSPARENT flag added in this case made an invisible windows in some case ?

Edit: to be more precise, the fist time tooltip seems to be shown the following does not.
I’ve got a class inherits from TooltipWindow and DeletedAtShutdown using the juce_DeclareSingleton/juce_ImplementSingleton


Awesome suggestion. You actually made me check on the other cases and I changed the setOpaque() call in the constructor of TooltipWindow to false. This changed the behavior for me to completely fix everything. I no longer have to do the above fix of mine to do a constant repaint!