def set_corner_text(self, table, text): """Set table corner text.""" # As this is an ugly hack, do everything in # try - except blocks, as it may stop working in newer Qt. if not hasattr(table, "btn") and not hasattr(table, "btnfailed"): try: btn = table.findChild(QAbstractButton) class efc(QObject): def eventFilter(self, o, e): if (isinstance(o, QAbstractButton) and e.type() == QEvent.Paint): # paint by hand (borrowed from QTableCornerButton) btn = o opt = QStyleOptionHeader() opt.initFrom(btn) state = QStyle.State_None if btn.isEnabled(): state |= QStyle.State_Enabled if btn.isActiveWindow(): state |= QStyle.State_Active if btn.isDown(): state |= QStyle.State_Sunken opt.state = state opt.rect = btn.rect() opt.text = btn.text() opt.position = QStyleOptionHeader.OnlyOneSection painter = QStylePainter(btn) painter.drawControl(QStyle.CE_Header, opt) return True # eat event return False table.efc = efc() # disconnect default handler for clicks and connect a new one, which supports # both selection and deselection of all data btn.clicked.disconnect() btn.installEventFilter(table.efc) btn.clicked.connect(self._on_select_all) table.btn = btn if sys.platform == "darwin": btn.setAttribute(Qt.WA_MacSmallSize) except Exception: table.btnfailed = True if hasattr(table, "btn"): try: btn = table.btn btn.setText(text) opt = QStyleOptionHeader() opt.text = btn.text() s = btn.style().sizeFromContents( QStyle.CT_HeaderSection, opt, QSize(), btn).expandedTo(QApplication.globalStrut()) if s.isValid(): table.verticalHeader().setMinimumWidth(s.width()) except Exception: pass
def set_corner_text(self, table, text): """Set table corner text.""" # As this is an ugly hack, do everything in # try - except blocks, as it may stop working in newer Qt. # pylint: disable=broad-except if not hasattr(table, "btn") and not hasattr(table, "btnfailed"): try: btn = table.findChild(QAbstractButton) class Efc(QObject): @staticmethod def eventFilter(o, e): if (isinstance(o, QAbstractButton) and e.type() == QEvent.Paint): # paint by hand (borrowed from QTableCornerButton) btn = o opt = QStyleOptionHeader() opt.initFrom(btn) state = QStyle.State_None if btn.isEnabled(): state |= QStyle.State_Enabled if btn.isActiveWindow(): state |= QStyle.State_Active if btn.isDown(): state |= QStyle.State_Sunken opt.state = state opt.rect = btn.rect() opt.text = btn.text() opt.position = QStyleOptionHeader.OnlyOneSection painter = QStylePainter(btn) painter.drawControl(QStyle.CE_Header, opt) return True # eat event return False table.efc = Efc() # disconnect default handler for clicks and connect a new one, which supports # both selection and deselection of all data btn.clicked.disconnect() btn.installEventFilter(table.efc) btn.clicked.connect(self._on_select_all) table.btn = btn if sys.platform == "darwin": btn.setAttribute(Qt.WA_MacSmallSize) except Exception: table.btnfailed = True if hasattr(table, "btn"): try: btn = table.btn btn.setText(text) opt = QStyleOptionHeader() opt.text = btn.text() s = btn.style().sizeFromContents(QStyle.CT_HeaderSection, opt, QSize(), btn) if s.isValid(): table.verticalHeader().setMinimumWidth(s.width()) except Exception: pass
def paintSection(self, painter, rect, logicalIndex): # type: (QPainter, QRect, int) -> None """ Reimplemented from `QHeaderView`. """ # What follows is similar to QHeaderView::paintSection@Qt 6.0 if not rect.isValid(): return # pragma: no cover oldBO = painter.brushOrigin() opt = QStyleOptionHeader() opt.rect = rect self.initStyleOption(opt) oBrushButton = opt.palette.brush(QPalette.Button) oBrushWindow = opt.palette.brush(QPalette.Window) self.initStyleOptionForIndex(opt, logicalIndex) opt.rect = rect nBrushButton = opt.palette.brush(QPalette.Button) nBrushWindow = opt.palette.brush(QPalette.Window) if oBrushButton != nBrushButton or oBrushWindow != nBrushWindow: painter.setBrushOrigin(opt.rect.topLeft()) # draw the section self.style().drawControl(QStyle.CE_Header, opt, painter, self) painter.setBrushOrigin(oldBO)
def set_corner_text(self, table, text): """Set table corner text.""" # As this is an ugly hack, do everything in # try - except blocks, as it may stop working in newer Qt. if not hasattr(table, "btn") and not hasattr(table, "btnfailed"): try: btn = table.findChild(QAbstractButton) class efc(QObject): def eventFilter(self, o, e): if isinstance( o, QAbstractButton) and e.type() == QEvent.Paint: # paint by hand (borrowed from QTableCornerButton) btn = o opt = QStyleOptionHeader() opt.initFrom(btn) state = QStyle.State_None if btn.isEnabled(): state |= QStyle.State_Enabled if btn.isActiveWindow(): state |= QStyle.State_Active if btn.isDown(): state |= QStyle.State_Sunken opt.state = state opt.rect = btn.rect() opt.text = btn.text() opt.position = QStyleOptionHeader.OnlyOneSection painter = QStylePainter(btn) painter.drawControl(QStyle.CE_Header, opt) return True # eat event return False table.efc = efc() btn.installEventFilter(table.efc) table.btn = btn if sys.platform == "darwin": btn.setAttribute(Qt.WA_MacSmallSize) except Exception: table.btnfailed = True if hasattr(table, "btn"): try: btn = table.btn btn.setText(text) opt = QStyleOptionHeader() opt.text = btn.text() s = (btn.style().sizeFromContents( QStyle.CT_HeaderSection, opt, QSize(), btn).expandedTo(QApplication.globalStrut())) if s.isValid(): table.verticalHeader().setMinimumWidth(s.width()) except Exception: pass
def test_header_view_clickable(self): model = QStandardItemModel() model.setColumnCount(3) header = HeaderView(Qt.Horizontal) header.setModel(model) header.setSectionsClickable(True) header.adjustSize() pos = header.sectionViewportPosition(0) size = header.sectionSize(0) # center of first section point = QPoint(pos + size // 2, header.viewport().height() / 2) QTest.mousePress(header.viewport(), Qt.LeftButton, Qt.NoModifier, point) opt = QStyleOptionHeader() header.initStyleOptionForIndex(opt, 0) self.assertTrue(opt.state & QStyle.State_Sunken) QTest.mouseRelease(header.viewport(), Qt.LeftButton, Qt.NoModifier, point) opt = QStyleOptionHeader() header.initStyleOptionForIndex(opt, 0) self.assertFalse(opt.state & QStyle.State_Sunken)
def eventFilter(o, e): if (isinstance(o, QAbstractButton) and e.type() == QEvent.Paint): # paint by hand (borrowed from QTableCornerButton) btn = o opt = QStyleOptionHeader() opt.initFrom(btn) state = QStyle.State_None if btn.isEnabled(): state |= QStyle.State_Enabled if btn.isActiveWindow(): state |= QStyle.State_Active if btn.isDown(): state |= QStyle.State_Sunken opt.state = state opt.rect = btn.rect() opt.text = btn.text() opt.position = QStyleOptionHeader.OnlyOneSection painter = QStylePainter(btn) painter.drawControl(QStyle.CE_Header, opt) return True # eat event return False
def eventFilter(self, o, e): if (isinstance(o, QAbstractButton) and e.type() == QEvent.Paint): # paint by hand (borrowed from QTableCornerButton) btn = o opt = QStyleOptionHeader() opt.initFrom(btn) state = QStyle.State_None if btn.isEnabled(): state |= QStyle.State_Enabled if btn.isActiveWindow(): state |= QStyle.State_Active if btn.isDown(): state |= QStyle.State_Sunken opt.state = state opt.rect = btn.rect() opt.text = btn.text() opt.position = QStyleOptionHeader.OnlyOneSection painter = QStylePainter(btn) painter.drawControl(QStyle.CE_Header, opt) return True # eat event return False
def initStyleOptionForIndex(self, option: QStyleOptionHeader, logicalIndex: int) -> None: """ Similar to initStyleOptionForIndex in Qt 6.0 with the difference that `isSectionSelected` is not used, only `sectionIntersectsSelection` is used (isSectionSelected will scan the entire model column/row when the whole column/row is selected). """ hover = self.logicalIndexAt(self.mapFromGlobal(QCursor.pos())) pressed = self.__pressed if self.highlightSections(): is_selected = self.__sectionIntersectsSelection else: is_selected = lambda _: False state = QStyle.State_None if self.isEnabled(): state |= QStyle.State_Enabled if self.window().isActiveWindow(): state |= QStyle.State_Active if self.sectionsClickable(): if logicalIndex == hover: state |= QStyle.State_MouseOver if logicalIndex == pressed: state |= QStyle.State_Sunken if self.highlightSections(): if is_selected(logicalIndex): state |= QStyle.State_On if self.isSortIndicatorShown() and \ self.sortIndicatorSection() == logicalIndex: option.sortIndicator = ( QStyleOptionHeader.SortDown if self.sortIndicatorOrder() == Qt.AscendingOrder else QStyleOptionHeader.SortUp) style = self.style() model = self.model() orientation = self.orientation() textAlignment = model.headerData(logicalIndex, self.orientation(), Qt.TextAlignmentRole) defaultAlignment = self.defaultAlignment() textAlignment = (textAlignment if isinstance(textAlignment, int) else defaultAlignment) option.section = logicalIndex option.state = QStyle.State(int(option.state) | int(state)) option.textAlignment = Qt.Alignment(int(textAlignment)) option.iconAlignment = Qt.AlignVCenter text = model.headerData(logicalIndex, self.orientation(), Qt.DisplayRole) text = str(text) if text is not None else "" option.text = text icon = model.headerData(logicalIndex, self.orientation(), Qt.DecorationRole) try: option.icon = QIcon(icon) except (TypeError, ValueError): # pragma: no cover pass margin = 2 * style.pixelMetric(QStyle.PM_HeaderMargin, None, self) headerArrowAlignment = style.styleHint(QStyle.SH_Header_ArrowAlignment, None, self) isHeaderArrowOnTheSide = headerArrowAlignment & Qt.AlignVCenter if self.isSortIndicatorShown() and \ self.sortIndicatorSection() == logicalIndex \ and isHeaderArrowOnTheSide: margin += style.pixelMetric(QStyle.PM_HeaderMarkSize, None, self) if not option.icon.isNull(): margin += style.pixelMetric(QStyle.PM_SmallIconSize, None, self) margin += style.pixelMetric(QStyle.PM_HeaderMargin, None, self) if self.textElideMode() != Qt.ElideNone: elideMode = self.textElideMode() if hasattr(option, 'textElideMode'): # Qt 6.0 option.textElideMode = elideMode # pragma: no cover else: option.text = option.fontMetrics.elidedText( option.text, elideMode, option.rect.width() - margin) foregroundBrush = model.headerData(logicalIndex, orientation, Qt.ForegroundRole) try: foregroundBrush = QBrush(foregroundBrush) except (TypeError, ValueError): pass else: option.palette.setBrush(QPalette.ButtonText, foregroundBrush) backgroundBrush = model.headerData(logicalIndex, orientation, Qt.BackgroundRole) try: backgroundBrush = QBrush(backgroundBrush) except (TypeError, ValueError): pass else: option.palette.setBrush(QPalette.Button, backgroundBrush) option.palette.setBrush(QPalette.Window, backgroundBrush) # the section position visual = self.visualIndex(logicalIndex) assert visual != -1 first = self.__isFirstVisibleSection(visual) last = self.__isLastVisibleSection(visual) if first and last: option.position = QStyleOptionHeader.OnlyOneSection elif first: option.position = QStyleOptionHeader.Beginning elif last: option.position = QStyleOptionHeader.End else: option.position = QStyleOptionHeader.Middle option.orientation = orientation # the selected position (in QHeaderView this is always computed even if # highlightSections is False). if self.highlightSections(): previousSelected = is_selected(self.logicalIndex(visual - 1)) nextSelected = is_selected(self.logicalIndex(visual + 1)) else: previousSelected = nextSelected = False if previousSelected and nextSelected: option.selectedPosition = QStyleOptionHeader.NextAndPreviousAreSelected elif previousSelected: option.selectedPosition = QStyleOptionHeader.PreviousIsSelected elif nextSelected: option.selectedPosition = QStyleOptionHeader.NextIsSelected else: option.selectedPosition = QStyleOptionHeader.NotAdjacent