1

I was inspired by this repo to add custom tooltip text to items when they are added to the QListWidget. However, I only want the tooltip message to appear when the item is chosen. How would I implement this?

Here is a GUI example that I have to test this feature:

import serial, time, sys
import serial.tools.list_ports
from PyQt5 import QtGui, QtWidgets, QtCore
import json, time

class GUI(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.__init_ui()

    def closeEvent(self, event):
        super().closeEvent(event)

    def __init_ui(self):
        
        self.setWindowTitle('QListWidgetToolTipDemo')

        self.history_log = HistoryList()
        self.history_log.itemDoubleClicked.connect(self.history_item_selected)
        self.history_log.returnPressed.connect(self.history_item_selected)
        self.history_log.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) 
        self.line_edit = QtWidgets.QLineEdit()
        self.line_edit.returnPressed.connect(self.populate_history)

        self.middle_layout = QtWidgets.QHBoxLayout()
        self.middle_layout.addWidget(self.history_log)
        self.middle_layout.addWidget(self.line_edit)
        middle_layout_wrapper = QtWidgets.QWidget()
        middle_layout_wrapper.setLayout(self.middle_layout)
        middle_layout_wrapper.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)

    
        # Sets full GUI layout
        gui_layout = QtWidgets.QVBoxLayout()
        gui_layout.addWidget(middle_layout_wrapper)
        gui_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
        gui_layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
        self.setLayout(gui_layout)


    def populate_history(self):
        self.history_log.addItem(self.line_edit.text())
        self.line_edit.clear()

    def history_item_selected(self):
        self.line_edit.setText(self.history_log.currentItem().text())

class HistoryList(QtWidgets.QListWidget):
    returnPressed = QtCore.pyqtSignal()
    def __init__(self) -> None:
        super().__init__()
        self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        self.setMouseTracking(True)
        self.itemEntered.connect(self.__showToolTip)
    
    def keyPressEvent(self, ev):
        super().keyPressEvent(ev)
        if ev.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
            self.returnPressed.emit()

    def addItem(self, aitem) -> None:
        item = ''
        text = ''
        if isinstance(aitem, str):
            item = QtWidgets.QListWidgetItem()
            text = aitem
            item.setText(text)
        elif isinstance(aitem, QtWidgets.QListWidgetItem):
            item = aitem
            text = item.text()
        self.setItemWidget(item, QtWidgets.QWidget())
        super().addItem(item)

    def __showToolTip(self, item: QtWidgets.QListWidgetItem):
        text = item.text()
        text_width = self.fontMetrics().boundingRect(text).width()
        width = self.width()
        info = {"time":str(time.time()), "entry":text}
        info = json.dumps(info, indent=4)
        item.setToolTip(info)
    
        
if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    console = GUI()
    screensize = app.desktop().availableGeometry().size()
    console.show()

    exit(app.exec_())
    

Currently, the following is how a tooltip works for any item:

Current_ui

Example where only display tooltip when item is selected:

FINAL_gui

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
kyrlon
  • 1,065
  • 2
  • 8
  • 16
  • 1
    What about checking if the item is selected? `if not item in self.selectedItems():` `QToolTip.hideText()` `return` – musicamante Jul 17 '22 at 17:13
  • Thanks for the suggestion! I think with this, I can get the ball rolling with something. – kyrlon Jul 18 '22 at 03:25

1 Answers1

1

Expanding on the suggestion from musicamante in the comments, I was able to get tooltip to display only for the selected item by overriding the event method and watch for a tooltip event (inspired from this SO post)

import serial, time, sys
import serial.tools.list_ports
from PyQt5 import QtGui, QtWidgets, QtCore
import json, time

class GUI(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.__init_ui()

    def closeEvent(self, event):
        super().closeEvent(event)

    def __init_ui(self):
        
        self.setWindowTitle('QListWidgetToolTipDemo')

        self.history_log = HistoryList()
        self.history_log.itemDoubleClicked.connect(self.history_item_selected)
        self.history_log.returnPressed.connect(self.history_item_selected)
        self.history_log.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) 
        self.line_edit = QtWidgets.QLineEdit()
        self.line_edit.returnPressed.connect(self.populate_history)

        self.middle_layout = QtWidgets.QHBoxLayout()
        self.middle_layout.addWidget(self.history_log)
        self.middle_layout.addWidget(self.line_edit)
        middle_layout_wrapper = QtWidgets.QWidget()
        middle_layout_wrapper.setLayout(self.middle_layout)
        middle_layout_wrapper.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)

    
        # Sets full GUI layout
        gui_layout = QtWidgets.QVBoxLayout()
        gui_layout.addWidget(middle_layout_wrapper)
        gui_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
        gui_layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
        self.setLayout(gui_layout)


    def populate_history(self):
        self.history_log.addItem(self.line_edit.text())
        self.line_edit.clear()

    def history_item_selected(self):
        self.line_edit.setText(self.history_log.currentItem().text())

class HistoryList(QtWidgets.QListWidget):
    returnPressed = QtCore.pyqtSignal()
    def __init__(self) -> None:
        super().__init__()
        self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        self.setMouseTracking(True)
        self.itemEntered.connect(self.__addToolTip)
        self.items_tooltip_info_dict = dict()
    
    def keyPressEvent(self, ev):
        super().keyPressEvent(ev)
        if ev.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
            self.returnPressed.emit()

    def event(self, e: QtCore.QEvent) -> bool:
        if e.type() == QtCore.QEvent.ToolTip:
            if not self.selectedItems():
                QtWidgets.QToolTip.hideText()
                return True
            else:
                index = self.indexFromItem(self.currentItem()).row()
                info = json.dumps(self.items_tooltip_info_dict[index], indent=4)
                QtWidgets.QToolTip.showText(e.globalPos(),info)
                e.accept()
        return super().event(e)

    def addItem(self, aitem) -> None:
        item = ''
        text = ''
        if isinstance(aitem, str):
            item = QtWidgets.QListWidgetItem()
            text = aitem
            item.setText(text)
        elif isinstance(aitem, QtWidgets.QListWidgetItem):
            item = aitem
            text = item.text()
        self.setItemWidget(item, QtWidgets.QWidget())
        super().addItem(item)

    def __addToolTip(self, item: QtWidgets.QListWidgetItem):
        text = item.text()
        info = {"time":str(time.time()), "entry":text}
        index = self.indexFromItem(item).row()
        self.items_tooltip_info_dict[index] = info
       

if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    console = GUI()
    screensize = app.desktop().availableGeometry().size()
    console.show()
    exit(app.exec_())
kyrlon
  • 1,065
  • 2
  • 8
  • 16