Show tooltip onto QLabel

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Show tooltip onto QLabel

Tong Zhang-2
Hello,

Can I show the tooltip of some widget onto a QLabel? e.g. Tooltip will show when I move the mouse onto the pushbutton, how about show the tooltip on another widget, say label?

Thanks,
Tong

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: Show tooltip onto QLabel

Maurizio Berti
Using standard tooltips might be an issue in some (not so special) cases, as QToolTip events are strictly related to the widget events, so you'll need to install an eventFilter on every single widget you'll want the behavior you ask about.
A simple implementation would be something like this:

    def __init__(self, *args, **kwargs):
        [...]
        self.toolTipWidget = QtWidgets.QLabel()
        [...]
        self.someWidget = SomeWidget()
        self.someWidget.setToolTip('I am a tooltip!')
        self.someWidget.installEventFilter(self)
        [...]

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.ToolTip:
            self.toolTipWidget.setText(source.toolTip())
        return QtWidgets.QWidget.eventFilter(self, source, event)

On the other hand, I'd suggest to use the StatusTip instead of the ToolTip: it's something I've successfully used for something similar to your needs: in this way you can keep the StatusTip for "simple" tooltip text and the ToolTips for further customized messages, as they also allow rich text content.
Here's a small example:

    def __init__(self, *args, **kwargs):
        [...]
        self.toolTipWidget = QtWidgets.QLabel()
        [...]
        self.someWidget = SomeWidget()
        self.someWidget.setStatusTip('I am a statustip!')
        [...]

    def event(self, event):
        if event.type() == QtCore.QEvent.StatusTip and event.tip():
            self.toolTipWidget.setText(event.tip())
        return QtWidgets.QWidget.event(self, event)

Note that here I used the setStatusTip() method instead of the setToolTip() one.
Obviously, if you're using Designer you'll set the StatusTip property from there, instead of the ToolTip property.

How does it work?
Usually the StatusTip is only used on a QMainWindow with a QStatusBar installed, but, interestingly enough, the event() method of any widget can be used to catch any StatusTip event called from both that widget and its children.

In both cases you'd better think about a way to "clear" the tool/status tip, as leaving it there might be confusing.
If you don't have too many widgets, the eventFilter way might be a good solution, as you can also catch the QEvent.Leave event type to hide the "tooltip" by clearing the label text, otherwise it's probably better using a QTimer on the parent widget or the label, and set it as singleShot (don't use the static method, as it could hide a new statustip activated in the meantime), then connect it to something like lambda: self.toolTipWidget.setText('') whenever you catch the StatusTip event.

If for some reason you'll need to stick with ToolTips, there's a solution anyway.
If all widgets already have their tooltips, and the layout is static and permanent once the main parent widget is being instantiated, just use the children() iterator and check for both isWidgetType() and toolTip() contents: if those condition match, install the eventFilter; if the layout is dynamic instead, use the childEvent method on the parent and check for QEvent.childAdded and QEvent.childRemoved events, then use installEventFilter or removeEventFilter respectively.

Regards,
Maurizio


Il giorno lun 21 gen 2019 alle ore 23:22 Tong Zhang <[hidden email]> ha scritto:
Hello,

Can I show the tooltip of some widget onto a QLabel? e.g. Tooltip will show when I move the mouse onto the pushbutton, how about show the tooltip on another widget, say label?

Thanks,
Tong
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt


--
È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: Show tooltip onto QLabel

Maurizio Berti
I forgot...
If you don't want to display the actual QToolTip whenever it's displayed in your label, remember to return True in the positive if statement: the event will be considered as accepted and will not be processed further.
The same goes for the status tip, in case you are using a QMainWindow with an active QStatusBar (which automatically catches the StatusTip events).

Il giorno mar 22 gen 2019 alle ore 00:40 Maurizio Berti <[hidden email]> ha scritto:
Using standard tooltips might be an issue in some (not so special) cases, as QToolTip events are strictly related to the widget events, so you'll need to install an eventFilter on every single widget you'll want the behavior you ask about.
A simple implementation would be something like this:

    def __init__(self, *args, **kwargs):
        [...]
        self.toolTipWidget = QtWidgets.QLabel()
        [...]
        self.someWidget = SomeWidget()
        self.someWidget.setToolTip('I am a tooltip!')
        self.someWidget.installEventFilter(self)
        [...]

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.ToolTip:
            self.toolTipWidget.setText(source.toolTip())
        return QtWidgets.QWidget.eventFilter(self, source, event)

On the other hand, I'd suggest to use the StatusTip instead of the ToolTip: it's something I've successfully used for something similar to your needs: in this way you can keep the StatusTip for "simple" tooltip text and the ToolTips for further customized messages, as they also allow rich text content.
Here's a small example:

    def __init__(self, *args, **kwargs):
        [...]
        self.toolTipWidget = QtWidgets.QLabel()
        [...]
        self.someWidget = SomeWidget()
        self.someWidget.setStatusTip('I am a statustip!')
        [...]

    def event(self, event):
        if event.type() == QtCore.QEvent.StatusTip and event.tip():
            self.toolTipWidget.setText(event.tip())
        return QtWidgets.QWidget.event(self, event)

Note that here I used the setStatusTip() method instead of the setToolTip() one.
Obviously, if you're using Designer you'll set the StatusTip property from there, instead of the ToolTip property.

How does it work?
Usually the StatusTip is only used on a QMainWindow with a QStatusBar installed, but, interestingly enough, the event() method of any widget can be used to catch any StatusTip event called from both that widget and its children.

In both cases you'd better think about a way to "clear" the tool/status tip, as leaving it there might be confusing.
If you don't have too many widgets, the eventFilter way might be a good solution, as you can also catch the QEvent.Leave event type to hide the "tooltip" by clearing the label text, otherwise it's probably better using a QTimer on the parent widget or the label, and set it as singleShot (don't use the static method, as it could hide a new statustip activated in the meantime), then connect it to something like lambda: self.toolTipWidget.setText('') whenever you catch the StatusTip event.

If for some reason you'll need to stick with ToolTips, there's a solution anyway.
If all widgets already have their tooltips, and the layout is static and permanent once the main parent widget is being instantiated, just use the children() iterator and check for both isWidgetType() and toolTip() contents: if those condition match, install the eventFilter; if the layout is dynamic instead, use the childEvent method on the parent and check for QEvent.childAdded and QEvent.childRemoved events, then use installEventFilter or removeEventFilter respectively.

Regards,
Maurizio


Il giorno lun 21 gen 2019 alle ore 23:22 Tong Zhang <[hidden email]> ha scritto:
Hello,

Can I show the tooltip of some widget onto a QLabel? e.g. Tooltip will show when I move the mouse onto the pushbutton, how about show the tooltip on another widget, say label?

Thanks,
Tong
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt


--
È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net


--
È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: Show tooltip onto QLabel

Tong Zhang-2
In reply to this post by Maurizio Berti
Thanks, Maurizio! I've got what I want from your message, BTW, I used
hover event to trig the help message to show on a textedit, since I
found tooltip event responses a little bit slower than I want, maybe
there is someway to speed up.

Tong

On 1/21/19 6:40 PM, Maurizio Berti wrote:

> Using standard tooltips might be an issue in some (not so special)
> cases, as QToolTip events are strictly related to the widget events, so
> you'll need to install an eventFilter on every single widget you'll want
> the behavior you ask about.
> A simple implementation would be something like this:
>
>      def __init__(self, *args, **kwargs):
>          [...]
>          self.toolTipWidget = QtWidgets.QLabel()
>          [...]
>          self.someWidget = SomeWidget()
>          self.someWidget.setToolTip('I am a tooltip!')
>          self.someWidget.installEventFilter(self)
>          [...]
>
>      def eventFilter(self, source, event):
>          if event.type() == QtCore.QEvent.ToolTip:
>              self.toolTipWidget.setText(source.toolTip())
>          return QtWidgets.QWidget.eventFilter(self, source, event)
>
> On the other hand, I'd suggest to use the StatusTip instead of the
> ToolTip: it's something I've successfully used for something similar to
> your needs: in this way you can keep the StatusTip for "simple" tooltip
> text and the ToolTips for further customized messages, as they also
> allow rich text content.
> Here's a small example:
>
>      def __init__(self, *args, **kwargs):
>          [...]
>          self.toolTipWidget = QtWidgets.QLabel()
>          [...]
>          self.someWidget = SomeWidget()
>          self.someWidget.setStatusTip('I am a statustip!')
>          [...]
>
>      def event(self, event):
>          if event.type() == QtCore.QEvent.StatusTip and event.tip():
>              self.toolTipWidget.setText(event.tip())
>          return QtWidgets.QWidget.event(self, event)
>
> Note that here I used the setStatusTip() method instead of the
> setToolTip() one.
> Obviously, if you're using Designer you'll set the StatusTip property
> from there, instead of the ToolTip property.
>
> How does it work?
> Usually the StatusTip is only used on a QMainWindow with a QStatusBar
> installed, but, interestingly enough, the event() method of *any* widget
> can be used to catch /any/ StatusTip event called from both that widget
> /and/ its children.
>
> In both cases you'd better think about a way to "clear" the tool/status
> tip, as leaving it there might be confusing.
> If you don't have too many widgets, the eventFilter way might be a good
> solution, as you can also catch the QEvent.Leave event type to hide the
> "tooltip" by clearing the label text, otherwise it's probably
> better using a QTimer on the parent widget or the label, and set it as
> singleShot (don't use the static method, as it could hide a new
> statustip activated in the meantime), then connect it to something like
> lambda: self.toolTipWidget.setText('')whenever you catch the StatusTip
> event.
>
> If for some reason you'll need to stick with ToolTips, there's a
> solution anyway.
> If all widgets already have their tooltips, and the layout is static and
> permanent once the main parent widget is being instantiated, just use
> the children() iterator and check for both isWidgetType() and toolTip()
> contents: if those condition match, install the eventFilter; if the
> layout is dynamic instead, use the childEvent method on the parent and
> check for QEvent.childAdded and QEvent.childRemoved events, then use
> installEventFilter or removeEventFilter respectively.
>
> Regards,
> Maurizio
>
>
> Il giorno lun 21 gen 2019 alle ore 23:22 Tong Zhang
> <[hidden email] <mailto:[hidden email]>> ha scritto:
>
>     Hello,
>
>     Can I show the tooltip of some widget onto a QLabel? e.g. Tooltip
>     will show when I move the mouse onto the pushbutton, how about show
>     the tooltip on another widget, say label?
>
>     Thanks,
>     Tong
>     _______________________________________________
>     PyQt mailing list [hidden email]
>     <mailto:[hidden email]>
>     https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>
>
>
> --
> È difficile avere una convinzione precisa quando si parla delle ragioni
> del cuore. - "Sostiene Pereira", Antonio Tabucchi
> http://www.jidesk.net
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: Show tooltip onto QLabel

Maurizio Berti
Glad I could help!
I've never used HoverEvents, but if it suits your needs, that's ok :-)

Yes, another issue with QToolTip is the delay after their event is called.
Since Qt5 it can be customized, though, by setting a QProxyStyle that returns the timeout in milliseconds when SH_ToolTip_WakeUpDelay styleHint is requested.
This is a small example that allows you to set a 0 timeout for specific widgets:

class MyStyle(QtWidgets.QProxyStyle):
    toolTipTimeouts = {}
    def styleHint(self, hint, option, widget, returnData):
        if hint == QtWidgets.QStyle.SH_ToolTip_WakeUpDelay:
            try:
                return self.toolTipTimeouts[widget]
            except:
                pass
        return QtWidgets.QProxyStyle.styleHint(self, hint, option, widget, returnData)

class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        [...]
        self.widget = SomeWidget()
        self.style().toolTipTimeouts[self.widget] = 0
        #optional, if you need to remove widgets at a certain point, 
        #allowing the garbage collector to free up memory
        self.widget.destroyed.connect(self.style().toolTipTimeouts.pop)

app = QtWidgets.QApplication(sys.argv)
app.setStyle(MyStyle())

In this way the QProxyStyle will immediately call the QEvent.ToolTip for the specified widgets.

Maurizio

Il giorno mar 22 gen 2019 alle ore 16:21 Tong Zhang <[hidden email]> ha scritto:
Thanks, Maurizio! I've got what I want from your message, BTW, I used
hover event to trig the help message to show on a textedit, since I
found tooltip event responses a little bit slower than I want, maybe
there is someway to speed up.

Tong

On 1/21/19 6:40 PM, Maurizio Berti wrote:
> Using standard tooltips might be an issue in some (not so special)
> cases, as QToolTip events are strictly related to the widget events, so
> you'll need to install an eventFilter on every single widget you'll want
> the behavior you ask about.
> A simple implementation would be something like this:
>
>      def __init__(self, *args, **kwargs):
>          [...]
>          self.toolTipWidget = QtWidgets.QLabel()
>          [...]
>          self.someWidget = SomeWidget()
>          self.someWidget.setToolTip('I am a tooltip!')
>          self.someWidget.installEventFilter(self)
>          [...]
>
>      def eventFilter(self, source, event):
>          if event.type() == QtCore.QEvent.ToolTip:
>              self.toolTipWidget.setText(source.toolTip())
>          return QtWidgets.QWidget.eventFilter(self, source, event)
>
> On the other hand, I'd suggest to use the StatusTip instead of the
> ToolTip: it's something I've successfully used for something similar to
> your needs: in this way you can keep the StatusTip for "simple" tooltip
> text and the ToolTips for further customized messages, as they also
> allow rich text content.
> Here's a small example:
>
>      def __init__(self, *args, **kwargs):
>          [...]
>          self.toolTipWidget = QtWidgets.QLabel()
>          [...]
>          self.someWidget = SomeWidget()
>          self.someWidget.setStatusTip('I am a statustip!')
>          [...]
>
>      def event(self, event):
>          if event.type() == QtCore.QEvent.StatusTip and event.tip():
>              self.toolTipWidget.setText(event.tip())
>          return QtWidgets.QWidget.event(self, event)
>
> Note that here I used the setStatusTip() method instead of the
> setToolTip() one.
> Obviously, if you're using Designer you'll set the StatusTip property
> from there, instead of the ToolTip property.
>
> How does it work?
> Usually the StatusTip is only used on a QMainWindow with a QStatusBar
> installed, but, interestingly enough, the event() method of *any* widget
> can be used to catch /any/ StatusTip event called from both that widget
> /and/ its children.
>
> In both cases you'd better think about a way to "clear" the tool/status
> tip, as leaving it there might be confusing.
> If you don't have too many widgets, the eventFilter way might be a good
> solution, as you can also catch the QEvent.Leave event type to hide the
> "tooltip" by clearing the label text, otherwise it's probably
> better using a QTimer on the parent widget or the label, and set it as
> singleShot (don't use the static method, as it could hide a new
> statustip activated in the meantime), then connect it to something like
> lambda: self.toolTipWidget.setText('')whenever you catch the StatusTip
> event.
>
> If for some reason you'll need to stick with ToolTips, there's a
> solution anyway.
> If all widgets already have their tooltips, and the layout is static and
> permanent once the main parent widget is being instantiated, just use
> the children() iterator and check for both isWidgetType() and toolTip()
> contents: if those condition match, install the eventFilter; if the
> layout is dynamic instead, use the childEvent method on the parent and
> check for QEvent.childAdded and QEvent.childRemoved events, then use
> installEventFilter or removeEventFilter respectively.
>
> Regards,
> Maurizio
>
>
> Il giorno lun 21 gen 2019 alle ore 23:22 Tong Zhang
> <[hidden email] <mailto:[hidden email]>> ha scritto:
>
>     Hello,
>
>     Can I show the tooltip of some widget onto a QLabel? e.g. Tooltip
>     will show when I move the mouse onto the pushbutton, how about show
>     the tooltip on another widget, say label?
>
>     Thanks,
>     Tong
>     _______________________________________________
>     PyQt mailing list [hidden email]
>     <mailto:[hidden email]>
>     https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>
>
>
> --
> È difficile avere una convinzione precisa quando si parla delle ragioni
> del cuore. - "Sostiene Pereira", Antonio Tabucchi
> http://www.jidesk.net


--
È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt