import sys
from qtutils.qt.QtCore import *
from qtutils.qt.QtGui import *
from qtutils.qt.QtWidgets import *
from qtutils import *
ELLIPSIS = u'\u2026'
[docs]
class ElidedLabelContainer(QWidget):
"""A QWidget to contain a QLabel with a single line of (possibly rich)
text that we want to elide. The elision is obtained by putting the QLabel
in a QScrollArea and having the QScrollarea only show the part of the text
we want to see. An extra label with the elision indication "..." is also
inserted next to the QScrollArea.
"""
[docs]
def __init__(self, label):
QWidget.__init__(self)
if label.wordWrap():
raise ValueError("Cannot elide label with word wrapping enabled")
self.label = label
self.layout = QHBoxLayout(self)
self.layout.setSpacing(0)
self.layout.setContentsMargins(0,0,0,0)
self.ellipsis_label = QLabel(ELLIPSIS)
self.scroll_area = ElideScrollArea()
self.scroll_area.setWidget(self.label)
self.setElideMode(Qt.ElideNone)
self.setSizePolicy(label.sizePolicy())
self.scroll_area.horizontalScrollBar().rangeChanged.connect(self.update_elide_widget)
# self.scroll_area.horizontalScrollBar().valueChanged.connect(self.update_elide_widget)
self.update_elide_widget()
[docs]
def event(self, event):
if event.type() == QEvent.ToolTip:
self.setToolTip(self.label.text())
return QWidget.event(self, event)
[docs]
def elideMode(self):
return self._elideMode
[docs]
def setElideMode(self, elideMode):
if not isinstance(elideMode, Qt.TextElideMode):
raise TypeError("Argument must be of type Qt.TextElideMode")
if elideMode == Qt.ElideMiddle:
raise NotImplementedError("The hack being used to elidetext does not work for ElideMiddle")
self._elideMode = elideMode
self.scroll_area.setElideMode(self._elideMode)
if self.layout.count():
self.layout.removeWidget(self.ellipsis_label)
self.layout.removeWidget(self.scroll_area)
if self._elideMode == Qt.ElideLeft:
self.layout.addWidget(self.ellipsis_label)
self.layout.addWidget(self.scroll_area)
elif self._elideMode == Qt.ElideRight:
self.layout.addWidget(self.scroll_area)
self.layout.addWidget(self.ellipsis_label)
# def resizeEvent(self, event):
# result = QWidget.resizeEvent(self, event)
# self.update_elide_widget()
# return result
[docs]
def minimumSizeHint(self):
return self.scroll_area.minimumSizeHint()
[docs]
def sizeHint(self):
return self.scroll_area.minimumSizeHint()
[docs]
def elide_label(label, layout, elide_mode):
"""Take an existing label that is in a layout, and wrap it in our widgets
that elide the text, and insert it back into the layout. This is a hack
that allows us to elide a QLabel with a single line of (possibly rich)
text, a task that seems pretty much impossible to do in any kosher way.
This function is for modifying an existing label already in a layout, but
if you are programatically creating a label, then you can wrap it in
ElidedLabelContainer(label) before inserting it into a layout or other
container widget, which is more flexible than this function which only
works if the label is in a QBoxLayout"""
if not (isinstance(layout, QBoxLayout) or isinstance(layout, QSplitter)):
raise NotImplementedError("Only labels that are in QBoxLayouts or QSplitters supported")
index = layout.indexOf(label)
if index == -1:
raise ValueError("Label not found in given layout")
container = ElidedLabelContainer(label)
label.setParent(container.scroll_area)
label.setVisible(False)
label.setVisible(True)
layout.insertWidget(index, container)
container.setElideMode(elide_mode)
if __name__ == '__main__':
# test:
test_text = "The <b>quick</b> brown fox <b>jumped over the lazy dog</b>"
app = QApplication(sys.argv)
window = QWidget()
hlayout = QHBoxLayout(window)
tabwidget = QTabWidget()
widget = QWidget()
tabwidget.addTab(widget, 'test')
layout = QVBoxLayout(widget)
normal_label = QLabel("Normal label")
normal_label.setStyleSheet("QLabel { background-color : red; color : blue; }")
hlayout.addWidget(normal_label)
hlayout.addWidget(tabwidget)
elide_left = QLabel("ElideLeft: " + test_text)
elide_left.setAlignment(Qt.AlignCenter)
elide_right = QLabel("ElideRight: " + test_text)
smaller_label = QLabel("Smaller label")
smaller_label2 = QLabel("Smaller label")
smaller_label3 = QLabel("Smaller label")
smaller_label.setStyleSheet("QLabel { background-color : red; color : blue; }")
smaller_label2.setStyleSheet("QLabel { background-color : red; color : blue; }")
smaller_label3.setStyleSheet("QLabel { background-color : red; color : blue; }")
layout.setSpacing(0)
layout.addWidget(smaller_label)
layout.addWidget(elide_left)
layout.addWidget(smaller_label2)
layout.addWidget(elide_right)
layout.addWidget(smaller_label3)
window.show()
window.resize(20, 20)
elide_label(elide_left, layout, Qt.ElideLeft)
elide_label(elide_right, layout, Qt.ElideRight)
def foo():
elide_left.setText("The <b>quick</b><br>brown fox <b>jumped <br>over the lazy dog</b>")
QTimer.singleShot(3000, foo)
app.exec_()