PyQt5: изменение текущего индекса QStackedWidget из класса виджетов в отдельном модуле?

Я разрабатываю приложение PyQt с 8 страницами. На каждой странице пользователь должен иметь возможность незаметно перейти к другим 7 существующим страницам. «Бесподобный» означает, что при переключении не должно быть вспышки, и новый экран открывается в том же окне. Будучи новичком в этом, я последовал примеру на YouTube, который показался мне хорошим. Это показано с использованием QStackedWidget. Вот пример кода метода переключения экранов:

def gotologin(self):
    login = LoginScreen()
    widget.addWidget(login)
    widget.setCurrentIndex(widget.currentIndex() + 1)

def gotocreate(self):
    create = CreateAccScreen()
    widget.addWidget(create)
    widget.setCurrentIndex(widget.currentIndex() + 1)

И сначала это работало, потому что все классы были в одном модуле, а основной метод внизу выглядел так:

#main
app = QApplication(sys.argv)
welcome = WelcomeScreen()
widget = QStackedWidget()
widget.addWidget(welcome)
widget.setFixedHeight(800)
widget.setFixedWidth(1200)
widget.show()
try:
    sys.exit(app.exec_())
except:
    print("Exiting")

Однако, поскольку этот файл становится больше, я решил поместить классы для последующих страниц в их собственные файлы. Они находятся в отдельном файле без основного метода, поэтому они не могут ссылаться на «виджет».

Я могу передать ссылку на объект "виджет" конструкторам последующих страниц... но что-то мне подсказывает, что это не лучшая идея. Как я могу изменить текущий виджет из каждого класса? Или предпочтительнее другой подход к структуре приложения?

Обновлено: минимальный воспроизводимый пример ниже:

import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QDialog, QApplication, QStackedWidget

class Page1Screen(QDialog):
    def __init__(self):
        super(Page1Screen, self).__init__()
        self.setupUi(self)

        self.treeWidget.itemClicked.connect(self.switch_screens)

    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(571, 508)
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(310, 130, 121, 51))
        self.label.setStyleSheet("font: 75 12pt \"MS Shell Dlg 2\";")
        self.label.setObjectName("label")
        self.treeWidget = QtWidgets.QTreeWidget(Dialog)
        self.treeWidget.setGeometry(QtCore.QRect(5, 1, 171, 501))
        self.treeWidget.setObjectName("treeWidget")
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.label.setText(_translate("Dialog", "Page 1"))
        self.treeWidget.headerItem().setText(0, _translate("Dialog", "New Column"))
        __sortingEnabled = self.treeWidget.isSortingEnabled()
        self.treeWidget.setSortingEnabled(False)
        self.treeWidget.topLevelItem(0).setText(0, _translate("Dialog", "PAGE 1"))
        self.treeWidget.topLevelItem(1).setText(0, _translate("Dialog", "PAGE 2"))
        self.treeWidget.topLevelItem(2).setText(0, _translate("Dialog", "PAGE 3"))
        self.treeWidget.topLevelItem(3).setText(0, _translate("Dialog", "PAGE 4"))
        self.treeWidget.setSortingEnabled(__sortingEnabled)

    def switch_screens(self):
        item = self.treeWidget.currentItem()
        name = item.text(0)
        if name == "PAGE 1":
            print("We're already on this page")
        elif name == "PAGE 2":
            p2 = Page2Screen()
            widget.addWidget(p2)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 3":
            p3 = Page3Screen()
            widget.addWidget(p3)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 4":
            p4 = Page4Screen()
            widget.addWidget(p4)
            widget.setCurrentIndex(widget.currentIndex() + 1)

class Page2Screen(QDialog):
    def __init__(self):
        super(Page2Screen, self).__init__()
        self.setupUi(self)

        self.treeWidget.itemClicked.connect(self.switch_screens)

    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(571, 508)
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(310, 130, 121, 51))
        self.label.setStyleSheet("font: 75 12pt \"MS Shell Dlg 2\";")
        self.label.setObjectName("label")
        self.treeWidget = QtWidgets.QTreeWidget(Dialog)
        self.treeWidget.setGeometry(QtCore.QRect(5, 1, 171, 501))
        self.treeWidget.setObjectName("treeWidget")
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        self.label_2 = QtWidgets.QLabel(Dialog)
        self.label_2.setGeometry(QtCore.QRect(0, 0, 571, 511))
        self.label_2.setStyleSheet("background: qlineargradient(spread:pad, x1:0.989, y1:1, x2:0.073, y2:0.119, stop:0 rgba(176, 121, 254, 255), stop:1 rgba(255, 255, 255, 255));")
        self.label_2.setText("")
        self.label_2.setObjectName("label_2")
        self.label_2.raise_()
        self.label.raise_()
        self.treeWidget.raise_()

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.label.setText(_translate("Dialog", "Page 2"))
        self.treeWidget.headerItem().setText(0, _translate("Dialog", "New Column"))
        __sortingEnabled = self.treeWidget.isSortingEnabled()
        self.treeWidget.setSortingEnabled(False)
        self.treeWidget.topLevelItem(0).setText(0, _translate("Dialog", "PAGE 1"))
        self.treeWidget.topLevelItem(1).setText(0, _translate("Dialog", "PAGE 2"))
        self.treeWidget.topLevelItem(2).setText(0, _translate("Dialog", "PAGE 3"))
        self.treeWidget.topLevelItem(3).setText(0, _translate("Dialog", "PAGE 4"))
        self.treeWidget.setSortingEnabled(__sortingEnabled)

    def switch_screens(self):
        item = self.treeWidget.currentItem()
        name = item.text(0)
        if name == "PAGE 1":
            p1 = Page1Screen()
            widget.addWidget(p1)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 2":
            print("We're already on this page")
        elif name == "PAGE 3":
            p3 = Page3Screen()
            widget.addWidget(p3)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 4":
            p4 = Page4Screen()
            widget.addWidget(p4)
            widget.setCurrentIndex(widget.currentIndex() + 1)

class Page3Screen(QDialog):
    def __init__(self):
        super(Page3Screen, self).__init__()
        self.setupUi(self)

        self.treeWidget.itemClicked.connect(self.switch_screens)

    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(571, 508)
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(310, 130, 121, 51))
        self.label.setStyleSheet("font: 75 12pt \"MS Shell Dlg 2\";")
        self.label.setObjectName("label")
        self.treeWidget = QtWidgets.QTreeWidget(Dialog)
        self.treeWidget.setGeometry(QtCore.QRect(5, 1, 171, 501))
        self.treeWidget.setObjectName("treeWidget")
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        self.label_2 = QtWidgets.QLabel(Dialog)
        self.label_2.setGeometry(QtCore.QRect(0, 0, 571, 511))
        self.label_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 0, 0, 255), stop:0.339795 rgba(255, 0, 0, 255), stop:0.339799 rgba(255, 255, 255, 255), stop:0.662444 rgba(255, 255, 255, 255), stop:0.662469 rgba(0, 0, 255, 255), stop:1 rgba(0, 0, 255, 255));")
        self.label_2.setText("")
        self.label_2.setObjectName("label_2")
        self.label_2.raise_()
        self.label.raise_()
        self.treeWidget.raise_()

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.label.setText(_translate("Dialog", "Page 3"))
        self.treeWidget.headerItem().setText(0, _translate("Dialog", "New Column"))
        __sortingEnabled = self.treeWidget.isSortingEnabled()
        self.treeWidget.setSortingEnabled(False)
        self.treeWidget.topLevelItem(0).setText(0, _translate("Dialog", "PAGE 1"))
        self.treeWidget.topLevelItem(1).setText(0, _translate("Dialog", "PAGE 2"))
        self.treeWidget.topLevelItem(2).setText(0, _translate("Dialog", "PAGE 3"))
        self.treeWidget.topLevelItem(3).setText(0, _translate("Dialog", "PAGE 4"))
        self.treeWidget.setSortingEnabled(__sortingEnabled)

    def switch_screens(self):
        item = self.treeWidget.currentItem()
        name = item.text(0)
        if name == "PAGE 1":
            p1 = Page1Screen()
            widget.addWidget(p1)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 2":
            p2 = Page2Screen()
            widget.addWidget(p2)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 3":
            print("We're already on this page")
        elif name == "PAGE 4":
            p4 = Page4Screen()
            widget.addWidget(p4)
            widget.setCurrentIndex(widget.currentIndex() + 1)

class Page4Screen(QDialog):
    def __init__(self):
        super(Page4Screen, self).__init__()
        self.setupUi(self)

        self.treeWidget.itemClicked.connect(self.switch_screens)

    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(571, 508)
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(310, 130, 121, 51))
        self.label.setStyleSheet("font: 75 12pt \"MS Shell Dlg 2\";")
        self.label.setObjectName("label")
        self.treeWidget = QtWidgets.QTreeWidget(Dialog)
        self.treeWidget.setGeometry(QtCore.QRect(5, 1, 171, 501))
        self.treeWidget.setObjectName("treeWidget")
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        self.label_2 = QtWidgets.QLabel(Dialog)
        self.label_2.setGeometry(QtCore.QRect(0, 0, 571, 511))
        self.label_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:0.132, y2:0.153682, stop:0 rgba(58, 169, 255, 255), stop:1 rgba(255, 255, 255, 255));")
        self.label_2.setText("")
        self.label_2.setObjectName("label_2")
        self.label_2.raise_()
        self.label.raise_()
        self.treeWidget.raise_()

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.label.setText(_translate("Dialog", "Page 4"))
        self.treeWidget.headerItem().setText(0, _translate("Dialog", "New Column"))
        __sortingEnabled = self.treeWidget.isSortingEnabled()
        self.treeWidget.setSortingEnabled(False)
        self.treeWidget.topLevelItem(0).setText(0, _translate("Dialog", "PAGE 1"))
        self.treeWidget.topLevelItem(1).setText(0, _translate("Dialog", "PAGE 2"))
        self.treeWidget.topLevelItem(2).setText(0, _translate("Dialog", "PAGE 3"))
        self.treeWidget.topLevelItem(3).setText(0, _translate("Dialog", "PAGE 4"))
        self.treeWidget.setSortingEnabled(__sortingEnabled)

    def switch_screens(self):
        item = self.treeWidget.currentItem()
        name = item.text(0)
        if name == "PAGE 1":
            p1 = Page1Screen()
            widget.addWidget(p1)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 2":
            p2 = Page2Screen()
            widget.addWidget(p2)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 3":
            p3 = Page3Screen()
            widget.addWidget(p3)
            widget.setCurrentIndex(widget.currentIndex() + 1)
        elif name == "PAGE 4":
            print("We're already on this page")

#main
app = QApplication(sys.argv)
welcome = Page1Screen()
widget = QStackedWidget()
widget.addWidget(welcome)
widget.setFixedHeight(571)
widget.setFixedWidth(508)
widget.show()
try:
    sys.exit(app.exec_())
except:
    print("Exiting")

Когда вы говорите: «...но что-то мне подсказывает, что это не лучшая идея», почему это плохая идея?

Carl HR 20.02.2023 19:09

Ваши методы gotocreate и gotologin создают новый экземпляр виджета всякий раз, когда они вызываются. Если вы планируете переключаться между двумя экранами, то это не идеальный способ добиться этого.

Alexander 20.02.2023 19:14

Если вы беспокоитесь, потому что создали экземпляр объекта, скажем foo = Foo(), и теперь хотите передать ссылку на этот экземпляр другой функции в качестве параметра: do_something('a', 'b', foo, 1, 2, 3), не волнуйтесь, это довольно распространено. На самом деле лучше передать его как параметр, чем использовать глобальную переменную для доступа к ссылке из другой области или модуля.

Carl HR 20.02.2023 19:14

Если этот учебник принадлежит какой-то Hala, я настоятельно рекомендую вам полностью игнорировать его, так как известно, что он содержит множество ужасных предложений и плохих практик.

musicamante 20.02.2023 19:21

@ Александр Какой подход был бы лучше? Тот, который будет держать страницы в одном и том же месте на экране без «мигания» между переключением страниц?

Unstable Andy 20.02.2023 19:53

@UnstableAndy, пожалуйста, создайте минимальный воспроизводимый пример вашего текущего кода

Alexander 20.02.2023 20:48

@UnstableAndy Дочерний объект никогда не должен вызывать родительскую функцию или принимать глобальную переменную. Кроме того, QStackedWidget работает точно так же, как QTabWidget (который, по сути, встраивает частный QStackedWidget): вы не добавляете постоянно новые вкладки, вы повторно используете существующие. Эти функции gotologin и gotocreate должны быть в основном родительском элементе (который, вероятно, должен быть подклассом QStackedWidget или подклассом QMainWindow с установленным центральным виджетом), и эти функции должны быть либо подключены к button.clicked каждой страницы, либо с помощью пользовательского сигнала.

musicamante 20.02.2023 21:01

@Alexander отредактировал сообщение с примером копирования/вставки для запуска.

Unstable Andy 21.02.2023 18:21

Почему вы не используете макеты?

Alexander 21.02.2023 21:31
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
Учебник по веб-скрапингу
Учебник по веб-скрапингу
Привет, ребята... В этот раз мы поговорим о веб-скрейпинге. Целью этого обсуждения будет узнать и понять, что такое веб-скрейпинг, а также узнать, как...
Тонкая настройка GPT-3 с помощью Anaconda
Тонкая настройка GPT-3 с помощью Anaconda
Зарегистрируйте аккаунт Open ai, а затем получите ключ API ниже.
Learning Data Analytics Two: Filtering data in a DataFrame.
Learning Data Analytics Two: Filtering data in a DataFrame.
В Learning Data Analytics One: Using Python and Pandas , я рассказываю о:
0
9
77
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Например, в верхней части вашего кода рядом с импортом добавьте

import tracemalloc
tracemalloc.start()

А затем в конце каждого из ваших конструкторов PageScreen класса __init__ добавьте print(tracemalloc.get_traced_memory()), затем запустите свой код и переместите начало переключения страниц вперед и назад, и вы увидите, как объем памяти растет и растет с каждым изменением страницы.

Это связано с тем, что каждый раз, когда вы переключаетесь на новую страницу, вы создаете новый экземпляр своего PageScreen, не уничтожая предыдущую копию. Было бы намного эффективнее и стабильнее просто определить все ваши различные страницы один раз и добавить их в stackedWidget в самом первом виджете верхнего уровня, который вы создаете, а затем добавить его и виджет дерева, который вы используете для изменения страниц. окно верхнего уровня. Это также дает дополнительное преимущество, заключающееся в сокращении повторяющегося кода.

Например, ниже я создаю виджет, который ведет себя аналогично вашему примеру, примите его, используя всю информацию, которую я уже указал. Я также использую QWidget вместо QDialog просто потому, что документы Qt описывают QDialog как:

«Диалоговое окно — это окно верхнего уровня, в основном используемое для краткосрочных задач и краткого общения с пользователем».

Кроме того, поскольку все ваши виджеты PageScreen идентичны, за исключением их таблицы стилей, я собираюсь определить только один QWidget для представления всех их, а затем передать таблицу стилей в качестве параметра.

import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QStackedWidget, QWidget, QVBoxLayout, QHBoxLayout, QLabel
import tracemalloc

class Window(QWidget):
    stylesheets = [   # you can store your stylesheets in a list to easily reuse
        "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 0, 0, 255), stop:0.339795 rgba(255, 0, 0, 255), stop:0.339799 rgba(255, 255, 255, 255), stop:0.662444 rgba(255, 255, 255, 255), stop:0.662469 rgba(0, 0, 255, 255), stop:1 rgba(0, 0, 255, 255));",
        "background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:0.132, y2:0.153682, stop:0 rgba(58, 169, 255, 255), stop:1 rgba(255, 255, 255, 255));",
        "background: qlineargradient(spread:pad, x1:0.989, y1:1, x2:0.073, y2:0.119, stop:0 rgba(176, 121, 254, 255), stop:1 rgba(255, 255, 255, 255));",
        "font: 75 12pt \"MS Shell Dlg 2\";"
    ]

    def __init__(self, parent=None) -> None:
        super().__init__(parent=parent)
        layout = QHBoxLayout(self)   # use layout managers
        self.treeWidget = QtWidgets.QTreeWidget(self)
        # The tree widget is created only once in the top level window
        self.stacked = QStackedWidget()   # same thing for the stacked widget
        self.widgets = []
        self.treeWidget.setHeaderLabel("New Column")
        self.treeWidget.currentItemChanged.connect(self.switch_screens)
        for i in range(1, 9):
            # create each of the tree items and each of the stack pages
            # only once for each page.
            QtWidgets.QTreeWidgetItem(self.treeWidget, [f"PAGE {i}"], 0)
            self.widgets.append(
                PageScreen(self.stylesheets[i % len(self.stylesheets)])
            )
            self.stacked.addWidget(self.widgets[-1])  # add each page to the stacked widget
        self.resize(571,508)
        layout.addWidget(self.treeWidget)    # add the tree and the stacked widget
        layout.addWidget(self.stacked)       # to the layout manager

    def switch_screens(self):
        # Here I am using the the tree items text to identify which page to switch
        # to, however there are countless ways to achieve the same thing.
        item = self.treeWidget.currentItem()
        name = item.text(0)   # name = Page 1
        index = int(name.split()[1])  # index = 1
        self.stacked.setCurrentIndex(index)
        print(tracemalloc.get_traced_memory())

class PageScreen(QWidget):
    def __init__(self, stylesheet):
        # passing the stylesheet in as a parameter allows to reduce a bunch of duplicate code.
        super().__init__()
        self.setStyleSheet(stylesheet)
        self.layout = QVBoxLayout(self)  # use a layout manager
        self.label = QLabel("Label")
        self.layout.addWidget(self.label)

if __name__ == "__main__":
    tracemalloc.start()
    app = QApplication([])
    window = Window()
    window.show()
    print(tracemalloc.get_traced_memory())
    app.exec()

Если вы сделаете то, что я предложил выше, с модулем tracemalloc в своем коде, а затем запустите мой пример, который также распечатывает снимки памяти, вы легко сможете увидеть разницу, как только начнете переключать страницы.

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

Наконец, если по какой-то причине вы хотите, чтобы каждая страница сложенного виджета имела свою собственную копию treeWidget, все, что вам нужно сделать, это определить treeWidget внутри класса PageScreen, и вместо прямого переключения страницы вы будете посылать сигнал от PageScreen который получает окно верхнего уровня, которое затем запускает сложенный виджет для переключения страниц, поэтому в глобальной переменной все равно не будет необходимости.

Эта конфигурация может выглядеть примерно так.

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

class Window(QStackedWidget):
    stylesheets = [   # you can store your stylesheets in a list to easily reuse
        "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 0, 0, 255), stop:0.339795 rgba(255, 0, 0, 255), stop:0.339799 rgba(255, 255, 255, 255), stop:0.662444 rgba(255, 255, 255, 255), stop:0.662469 rgba(0, 0, 255, 255), stop:1 rgba(0, 0, 255, 255));",
        "background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:0.132, y2:0.153682, stop:0 rgba(58, 169, 255, 255), stop:1 rgba(255, 255, 255, 255));",
        "background: qlineargradient(spread:pad, x1:0.989, y1:1, x2:0.073, y2:0.119, stop:0 rgba(176, 121, 254, 255), stop:1 rgba(255, 255, 255, 255));",
        "font:  \"MS Shell Dlg 2\";"
    ]

    def __init__(self, parent=None) -> None:
        super().__init__(parent=parent)
        self.widgets = {}
        for i in range(9):
            page = PageScreen(self.stylesheets[i % len(self.stylesheets)])
            self.widgets[i] = page
            self.addWidget(page)
            page.pageSelected.connect(self.switch_page)
        self.resize(571,508)

    def switch_page(self, index):
        self.setCurrentWidget(self.widgets[index])
        self.widgets[index].select_tree_item(index)


class PageScreen(QWidget):

    pageSelected = pyqtSignal(int)

    def __init__(self, stylesheet):
        super().__init__()
        self.setStyleSheet(stylesheet)
        self.layout = QHBoxLayout(self)
        self.label = QLabel("Label")
        policy = self.label.sizePolicy()
        policy.setHorizontalPolicy(policy.Policy.MinimumExpanding)
        self.label.setSizePolicy(policy)
        self.treeWidget = QTreeWidget(self)
        self.treeWidget.setHeaderLabel("New Column")
        for i in range(1, 9):
            QTreeWidgetItem(self.treeWidget, [f"PAGE {i}"], 0)
        self.treeWidget.itemClicked.connect(self.switch_screens)
        self.layout.addWidget(self.treeWidget)
        self.layout.addWidget(self.label)

    def select_tree_item(self, index):
        for i in range(self.treeWidget.topLevelItemCount()):
            if self.treeWidget.topLevelItem(i).text(0).endswith(str(index)):
                self.treeWidget.setCurrentItem(self.treeWidget.topLevelItem(i))
                break

    def switch_screens(self, item, column):
        text = item.text(column)
        index = int(text.split()[1])
        self.pageSelected.emit(index)


if __name__ == "__main__":
    app = QApplication([])
    window = Window()
    window.show()
    app.exec()

Надеюсь это поможет.

Большое спасибо! Первый пример полезен. Второй вроде не работает. В первом примере стиль виджета дерева не меняется, и он очень отзывчив. Во втором: иногда щелчок не меняет страницу, стиль применяется к виджету дерева, а выделенный элемент дерева не соответствует текущей странице.

Unstable Andy 21.02.2023 23:28

@UnstableAndy Я исправил это. второй пример теперь должен выглядеть так же быстро и отзывчиво, как и первый.

Alexander 22.02.2023 01:33

Другие вопросы по теме