PyQt5 dynamici c создание / уничтожение виджетов - PullRequest
0 голосов
/ 19 января 2020

У меня есть приложение, в котором при запуске пользователю предоставляется диалоговое окно для выбора необходимого количества «объектов». Затем он генерирует необходимые объекты в главном окне, используя для l oop (т.е. object1, object2, et c.). Я хочу переместить этот выбор в главное окно, чтобы его можно было изменить без необходимости перезапуска приложения. Я понятия не имею, как подойти к этому, поскольку я не уверен, как динамически создавать / уничтожать, когда приложение работает. Вот пример кода, который генерирует вкладки в виджете вкладок с некоторыми элементами в каждой вкладке.

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


class SelectionWindow(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.settings = QSettings('Example', 'Example')
        self.numberOfTabs = QSpinBox(value = self.settings.value('numberOfTabs', type=int, defaultValue = 3), minimum = 1)
        self.layout = QFormLayout(self)
        self.button = QPushButton(text = 'OK', clicked = self.buttonClicked)
        self.layout.addRow('Select number of tabs', self.numberOfTabs)
        self.layout.addRow(self.button)

    def buttonClicked(self):
        self.settings.setValue('numberOfTabs', self.numberOfTabs.value())
        self.accept()


class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.settings = QSettings('Example', 'Example')
        self.tabs = self.settings.value('numberOfTabs', type = int)
        self.tabWidget = QTabWidget()

        for i in range(1, self.tabs + 1):
            exec(('self.tab{0} = QWidget()').format(i))
            exec(("self.tabWidget.addTab(self.tab{0}, 'Tab{0}')").format(i))
            exec(('self.lineEdit{0} = QLineEdit()').format(i))
            exec(('self.spinBox{0} = QSpinBox()').format(i))
            exec(('self.checkBox{0} = QCheckBox()').format(i))
            exec(('self.layout{0} = QFormLayout(self.tab{0})').format(i))
            exec(("self.layout{0}.addRow('Name', self.lineEdit{0})").format(i))
            exec(("self.layout{0}.addRow('Value', self.spinBox{0})").format(i))
            exec(("self.layout{0}.addRow('On/Off', self.checkBox{0})").format(i))

        self.setCentralWidget(self.tabWidget)


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    dialog = SelectionWindow()
    dialog.show()

    if dialog.exec_() == SelectionWindow.Accepted:
        mainwindow = MainWindow()
        mainwindow.show()
        sys.exit(app.exec_())

1 Ответ

0 голосов
/ 19 января 2020

Прежде всего, вы никогда не должны использовать exec для подобных вещей. Помимо проблем безопасности при использовании exec, он также делает ваш код менее читаемым (а затем и более сложным для отладки) и трудным для взаимодействия.

Лучшее (и более "элегантное") решение - использовать общая функция для создания вкладок и, что наиболее важно, setattr.

Кроме того, вы не должны использовать QSettings таким образом, поскольку он в основном предназначен для постоянных данных между сессиями , чтобы не инициализировать интерфейс. В этом случае вам следует просто переопределить метод exec() диалогового окна и инициализировать главное окно с этим значением в качестве аргумента.
И даже если это так (но я предлагаю вам в любом случае избегать вышеуказанного подхода) ), помните, что для сохранения постоянных настроек должны быть установлены как минимум organizationName и applicationName .

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.settings = QSettings('Example', 'Example')
        # this value does not need to be a persistent instance attribute
        tabCount = self.settings.value('numberOfTabs', type = int)

        # create a main widget for the whole interface
        central = QWidget()
        mainLayout = QVBoxLayout(central)

        tabCountSpin = QSpinBox(minimum=1)
        mainLayout.addWidget(tabCountSpin)
        tabCountSpin.setValue(tabCount)
        tabCountSpin.valueChanged.connect(self.tabCountChanged)

        self.tabWidget = QTabWidget()
        mainLayout.addWidget(self.tabWidget)

        for t in range(tabCount):
            self.createTab(t)

        self.setCentralWidget(central)

    def createTab(self, t):
        t += 1
        tab = QWidget()
        self.tabWidget.addTab(tab, 'Tab{}'.format(t))
        layout = QFormLayout(tab)

        # create all the widgets
        lineEdit = QLineEdit()
        spinBox = QSpinBox()
        checkBox = QCheckBox()
        # add them to the layout
        layout.addRow('Name', lineEdit)
        layout.addRow('Value', spinBox)
        layout.addRow('On/Off', checkBox)

        # keeping a "text" reference to the widget is useful, but not for
        # everything, as tab can be accessed like this:
        # tab = self.tabWidget.widget(index)
        # and so its layout:
        # tab.layout()
        setattr(tab, 'lineEdit{}'.format(t), lineEdit)
        setattr(tab, 'spinBox{}'.format(t), spinBox)
        setattr(tab, 'checkBox{}'.format(t), checkBox)

    def tabCountChanged(self, count):
        if count == self.tabWidget.count():
            return
        elif count < self.tabWidget.count():
            while self.tabWidget.count() > count:
                # note that I'm not deleting the python reference to each object;
                # you should use "del" for both the tab and its children
                self.tabWidget.removeTab(count)
        else:
            for t in range(self.tabWidget.count(), count):
                self.createTab(t)
...