Source code for labscript_utils.qtwidgets.elide_label

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 ElideScrollArea(QScrollArea): """A ScrollArea for containing a label that we want to elide. The elision is attained by just letting the text we don't want to see be scrolled off to the side with the scrollbars hidden."""
[docs] def __init__(self, *args, **kwargs): QScrollArea.__init__(self, *args, **kwargs) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setFrameStyle(QFrame.NoFrame) self.setStyleSheet("background-color:transparent;") self.setElideMode(Qt.ElideNone) self.setWidgetResizable(True)
[docs] def event(self, event): if event.type() == QEvent.LayoutRequest: self.updateGeometry() return QScrollArea.event(self, event)
[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
[docs] def minimumSizeHint(self): if self.widget is None or self._elideMode == Qt.ElideNone: return QScrollArea.minimumSizeHint(self) else: actual_minimum_sizehint = self.widget().minimumSizeHint() return QSize(0, actual_minimum_sizehint.height())
[docs] def sizeHint(self): if self.widget is None or self._elideMode == Qt.ElideNone: return QScrollArea.sizeHint(self) else: actual_sizehint = self.widget().sizeHint() return QSize(0, actual_sizehint.height())
[docs] def setWidget(self, widget): QScrollArea.setWidget(self, widget) self.setSizePolicy(QSizePolicy(self.sizePolicy().horizontalPolicy(), widget.sizePolicy().verticalPolicy()))
[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 update_elide_widget(self): label_width = self.label.minimumSizeHint().width() width = self.width() if label_width > width: self.ellipsis_label.setText(ELLIPSIS) else: self.ellipsis_label.setText('') if self._elideMode == Qt.ElideNone: return elif self._elideMode == Qt.ElideLeft: self.scroll_area.ensureVisible(label_width, 0, 0, 0) elif self._elideMode == Qt.ElideRight: self.scroll_area.ensureVisible(0, 0, 0, 0)
[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_()