PyQt5动态创建/销毁小部件

时间:2020-01-19 02:13:32

标签: python widget pyqt5

我有一个应用程序,在启动时会向用户显示一个对话框,以选择所需的“对象”数量。然后使用for循环在主窗口中生成必要的对象(即object1,object2等)。我想将此选择移到主窗口,以便可以更改它而无需重新启动应用程序。我不知道如何处理此问题,因为我不确定一旦应用程序运行后如何动态创建/销毁。这是一个示例代码,它在选项卡小部件中生成选项卡,每个选项卡中都有一些元素。

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 :(得分:0)

首先,对于此类情况,切勿使用exec。除了使用exec的安全性问题外,它还使您的代码可读性较低(因此更难调试)并且难以交互。

一种更好(更“优雅”)的解决方案是使用通用功能创建标签,最重要的是创建setattr

此外,您也不应该以这种方式使用QSettings,因为它主要用于跨会话持久性数据,而不是初始化接口。在这种情况下,您应该重写对话框的exec()方法,并以该值作为参数初始化主窗口。
而且,即使是这种情况(但无论如何我还是建议您避免使用上述方法),请记住要使设置持久化,至少organizationNameapplicationName 设置。

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)