QTabWidget Access Actual Tab (не виджет контента) - PullRequest
0 голосов
/ 01 марта 2020

На этом изображении:

enter image description here

Я хотел бы получить доступ к фактическим вкладкам, а не к содержимому, чтобы я мог установить QPropertyAnimation на фактической вкладке, когда он находится на. Я знаю, как заставить работать событие наведения, и я могу получить индекс вкладки на наведении, я просто не могу получить доступ к реальной вкладке, когда на нее наведен курсор. Есть ли где-нибудь список вкладок в качестве атрибута QTabBar или QTabWidget, или где я могу найти вкладки? Или мне нужно создать подкласс функции addTab для индивидуального создания вкладок?

Дополнительная информация

  • Использование PyQt5.14.1
  • Windows 10
  • Python 3.8.0

1 Ответ

1 голос
/ 02 марта 2020

Вы не можете получить доступ к "вкладкам", так как они не являются объектами, а представляют собой абстрактное представление содержимого списка панелей вкладок.

Единственный способ настроить их внешний вид - это создать подкласс QTabBar и переопределить paintEvent().

Чтобы добавить дополнительный эффект, необходимо предоставить уникальную анимацию для каждой вкладки, чтобы отслеживать все вкладки, которые были вставлены или удалены. Методы addTab, insertTab и removeTab не являются допустимыми параметрами, поскольку они не используются QTabWidget. Вместо этого он использует tabInserted() и tabRemoved(), поэтому их тоже нужно переопределить.

Однако это может быть проблемой с таблицами стилей, особенно если вы хочу установить шрифты или поля.
К счастью, мы можем использовать объявление qproperty-* с пользовательскими свойствами PyQt, и в следующем примере я использую их для цветов вкладки.

A cool animated tab bar

class AnimatedTabBar(QtWidgets.QTabBar):
    def __init__(self, *args):
        super().__init__(*args)
        palette = self.palette()
        self._normalColor = palette.color(palette.Dark)
        self._hoverColor = palette.color(palette.Mid)
        self._selectedColor = palette.color(palette.Light)

        self.animations = []
        self.lastHoverTab = -1

    @QtCore.pyqtProperty(QtGui.QColor)
    def normalColor(self):
        return self._normalColor

    @normalColor.setter
    def normalColor(self, color):
        self._normalColor = color
        for ani in self.animations:
            ani.setEndValue(color)

    @QtCore.pyqtProperty(QtGui.QColor)
    def hoverColor(self):
        return self._hoverColor

    @hoverColor.setter
    def hoverColor(self, color):
        self._hoverColor = color
        for ani in self.animations:
            ani.setStartValue(color)

    @QtCore.pyqtProperty(QtGui.QColor)
    def selectedColor(self):
        return self._selectedColor

    @selectedColor.setter
    def selectedColor(self, color):
        self._selectedColor = color
        self.update()

    def tabInserted(self, index):
        super().tabInserted(index)
        ani = QtCore.QVariantAnimation()
        ani.setStartValue(self.normalColor)
        ani.setEndValue(self.hoverColor)
        ani.setDuration(150)
        ani.valueChanged.connect(self.update)
        self.animations.insert(index, ani)

    def tabRemoved(self, index):
        super().tabRemoved(index)
        ani = self.animations.pop(index)
        ani.stop()
        ani.deleteLater()

    def event(self, event):
        if event.type() == QtCore.QEvent.HoverMove:
            tab = self.tabAt(event.pos())
            if tab != self.lastHoverTab:
                if self.lastHoverTab >= 0:
                    lastAni = self.animations[self.lastHoverTab]
                    lastAni.setDirection(lastAni.Backward)
                    lastAni.start()
                if tab >= 0:
                    ani = self.animations[tab]
                    ani.setDirection(ani.Forward)
                    ani.start()
            self.lastHoverTab = tab
        elif event.type() == QtCore.QEvent.Leave:
            if self.lastHoverTab >= 0:
                lastAni = self.animations[self.lastHoverTab]
                lastAni.setDirection(lastAni.Backward)
                lastAni.start()
                self.lastHoverTab = -1
        return super().event(event)


    def paintEvent(self, event):
        selected = self.currentIndex()
        qp = QtGui.QPainter(self)
        qp.setRenderHints(qp.Antialiasing)

        style = self.style()
        fullTabRect = QtCore.QRect()
        tabList = []
        for i in range(self.count()):
            tab = QtWidgets.QStyleOptionTab()
            self.initStyleOption(tab, i)
            tabRect = self.tabRect(i)
            fullTabRect |= tabRect
            if i == selected:
                # make the selected tab slightly bigger, but ensure that it's
                # still within the tab bar rectangle if it's the first or the last
                tabRect.adjust(
                    -2 if i else 0, 0, 
                    2 if i < self.count() - 1 else 0, 1)
                pen = QtCore.Qt.lightGray
                brush = self._selectedColor
            else:
                tabRect.adjust(1, 1, -1, 1)
                pen = QtCore.Qt.NoPen
                brush = self.animations[i].currentValue()
            tabList.append((tab, tabRect, pen, brush))

        # move the selected tab to the end, so that it can be painted "over"
        if selected >= 0:
            tabList.append(tabList.pop(selected))

        # ensure that we don't paint over the tab base
        margin = max(2, style.pixelMetric(style.PM_TabBarBaseHeight))
        qp.setClipRect(fullTabRect.adjusted(0, 0, 0, -margin))

        for tab, tabRect, pen, brush in tabList:
            qp.setPen(pen)
            qp.setBrush(brush)
            qp.drawRoundedRect(tabRect, 4, 4)
            style.drawControl(style.CE_TabBarTabLabel, tab, qp, self)


class Example(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QVBoxLayout(self)
        self.tabWidget = QtWidgets.QTabWidget()
        layout.addWidget(self.tabWidget)
        self.tabBar = AnimatedTabBar(self.tabWidget)
        self.tabWidget.setTabBar(self.tabBar)
        self.tabWidget.addTab(QtWidgets.QCalendarWidget(), 'tab 1')
        self.tabWidget.addTab(QtWidgets.QTableWidget(4, 8), 'tab 2')
        self.tabWidget.addTab(QtWidgets.QGroupBox('Group'), 'tab 3')
        self.tabWidget.addTab(QtWidgets.QGroupBox('Group'), 'tab 4')
        self.setStyleSheet('''
            QTabBar { 
                qproperty-hoverColor: rgb(128, 150, 140); 
                qproperty-normalColor: rgb(150, 198, 170);
                qproperty-selectedColor: lightgreen;
            }
        ''')

Некоторые заключительные примечания:

  • Я реализовал только ориентацию панели вкладок top , если вы хотите использовать вкладки в в других направлениях вам придется изменить поля и настройки прямоугольника;
  • помните, что использование таблиц стилей нарушит внешний вид кнопок со стрелками; (когда вкладки go превышают ширину панели вкладок), вы ' нужно будет их аккуратно установить
  • окраска подвижных (перетаскиваемых) вкладок нарушена;
  • сейчас я не знаю, как это исправить;
...