【问题标题】:Replace a widget at runtime in Qt5在 Qt5 运行时替换小部件
【发布时间】:2020-03-14 02:04:34
【问题描述】:

我有这个在 python3(.8) 中制作的 Qt5 GUI。它的左侧有一个QButtonGroup。按下这些按钮之一应该会在右侧显示相关的设备 QWidget 类(此处未显示)。 所以主布局中只有 2 个小部件。

此代码运行。我知道 device_clicked 中的功能并没有真正意义,但这只是为了演示一个小的工作代码 sn-p。

import logging
import sys

from PyQt5.QtWidgets import (QApplication, QButtonGroup, QHBoxLayout, QTabBar, QTabWidget,
                             QMainWindow, QPushButton, QVBoxLayout, QWidget, QLabel)

logging.basicConfig(
    format="%(asctime)s,%(msecs)d - %(name)s - %(levelname)s: %(message)s",
    datefmt="%H:%M:%S",
    level=logging.INFO,
)

DEVICES = [("DEV1", QLabel), ("2222", QLabel), ("HUPP", QLabel), ("FOOO", QLabel), ("BOOO", QLabel)]


class MainApp(QMainWindow):
    """Documentation for MainApp(QMainWindow)

    """
    def __init__(self):
        super().__init__()

        self.logger = logging.getLogger("MAIN")
        self.logger.info("Starting main program")

        self.title = "Title"
        self.left = 300
        self.top = 200
        self.width = 1100
        self.height = 600

        self.init_ui()

    def init_ui(self) -> None:
        """
        Initializs the UI
        """
        self.logger.info("Starting UI")

        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.main_widget = QWidget()
        self.setCentralWidget(self.main_widget)

        layout = QHBoxLayout()
        self.main_widget.setLayout(layout)

        dev_layout = QVBoxLayout()
        self.devices = QButtonGroup()
        for i, (t, w) in enumerate(DEVICES):
            btn = QPushButton(t)
            self.devices.addButton(btn, i)
            dev_layout.addWidget(btn)

        self.devices.buttonClicked[int].connect(self.device_clicked)

        layout.addLayout(dev_layout, 10)
        layout.addWidget(QLabel("test"), 90)
        self.prev_device_id = 0
        self.devices.button(0).setDown(True)

    def device_clicked(self, btn_id: int) -> None:
        self.logger.info(f"BTN {btn_id} clicked")
        self.devices.button(self.prev_device_id).setDown(False)
        self.devices.button(btn_id).setDown(True)

        # replace gives my an AttributeError: 'QHBoxLayout' object has no attribute 'replace'
        # self.main_widget.layout().replace(DEVICES[self.prev_device_id][1], DEVICES[btn_id][1])

        self.main_widget.layout().takeAt(1)
        self.main_widget.layout().addWidget(DEVICES[btn_id][1](DEVICES[btn_id][0]), 90)
        self.main_widget.layout().update()

        self.prev_device_id = btn_id

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainApp()
    main.show()
    app.exec_()

我现在遇到的问题是旧的小部件没有被删除,新的小部件被放置在它上面,同时显示它们。

是因为MainAppQMainWindow 并且有一个self.main_widget = QWidget() centralWidget?是否推荐使用setCentralWidget()

【问题讨论】:

    标签: python widget pyqt5 qt5 runtime


    【解决方案1】:

    takeAt() 仅从布局中删除布局项,不会删除其小部件。请注意,我指定了布局项,因为布局使用QLayoutItems,这是布局用来管理其内容的抽象项:布局项可以包含布局本身或小部件。

    在任何情况下,删除小部件后(通过使用removeWidget() 删除布局项或小部件本身),您还必须调用deleteLater()
    这是必要的,因为即使从布局中删除了一个小部件,该小部件仍然会有一个父集(设置布局的小部件)。

        layoutItem = self.main_widget.layout().itemAt(1)
        if layoutItem.widget():
            layoutItem.widget().deleteLater()
    

    或者,如果您已经拥有对小部件的引用:

        self.someWidget.deleteLater()
    

    【讨论】:

    • 谢谢,我把小部件和布局项弄混了,而且在两次尝试之间没有真正清理我的代码
    猜你喜欢
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多