如何正确删除小部件并更新/重新加载小部件

Posted

技术标签:

【中文标题】如何正确删除小部件并更新/重新加载小部件【英文标题】:how to properly remove qwidgets and update/reload that widget 【发布时间】:2019-07-31 01:07:36 【问题描述】:

尝试删除一个 qwidget 并用另一个 qwidget 替换它,然后重新加载 qwidget 所属的布局

我已经尝试过 update 和 removeWidget 方法,虽然我可能使用不当

from PyQt5.Qt import *
import sys

validUser = False
app = None

class App(QMainWindow):
    def __init__(self):
        super().__init__()
        screen = app.primaryScreen().size()
        self.title = 'Restaurant Application'
        width = screen.width()
        height = screen.height()
        self.left = 0
        self.top = 0
        self.width = width
        self.height = height
        self.setMouseTracking(True)
        self.table_widget = MyTableWidget(self)
        self.setCentralWidget(self.table_widget)
        self.initUI()

        self.show()

    def initUI(self):
        # window
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # statusbar
        self.statusBar().showMessage('Welcome to el restaurante')

    def mousePressEvent(self, event):
        print('Mouse coords: ( %d : %d )' % (event.x(), event.y()))


class MyTableWidget(QWidget):

    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        self.layout = QVBoxLayout(self)

        # Initialize tab screen
        self.tabs = QTabWidget()
        self.login = QWidget()
        self.menu = QWidget()
        self.checkOut = QWidget()
        self.tabs.resize(500, 200)

        # Add tabs
        self.tabs.addTab(self.login, "Login")
        self.tabs.addTab(self.menu, "Menu")
        self.tabs.addTab(self.checkOut, "Check out")

        # Create login tab
        self.login.layout = QVBoxLayout(self)
        self.menu.layout = QVBoxLayout(self)

        # login text
        self.loginPrompt = QLabel("Please provide a valid login")
        self.loginPrompt.setFixedSize(315,30)
        self.loginPromptFont = QFont("Times", 27, QFont.Bold)
        self.loginPrompt.setFont(self.loginPromptFont)
        self.login.layout.addWidget(self.loginPrompt)
        self.login.setLayout(self.login.layout)

        # Create textbox
        self.loginTextbox = QLineEdit(self)
        self.loginTextbox.returnPressed.connect(self.on_click_login)
        self.loginTextbox.setFixedSize(170,20)

        # Create a button in the window
        self.loginButton = QPushButton('Login button', self)
        self.loginButton.clicked.connect(self.on_click_login)
        self.loginButton.setFixedSize(100,40)
        self.login.layout.addWidget(self.loginTextbox,alignment=Qt.AlignCenter)
        self.login.layout.addWidget(self.loginButton,alignment=Qt.AlignCenter)


        #widget code i use to decide which widget to add
        self.menuInvalidUserLogin = QLabel("Please login in to view")
        self.menuValidUserLogin = QLabel("Here's the menu")

        if(validUser):
            self.menu.layout.addWidget(self.menuValidUserLogin)
        else:
            self.menu.layout.addWidget(self.menuInvalidUserLogin)
        self.menu.setLayout(self.menu.layout)

        # Add tabs to widget
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)

    def on_click_login(self):
        global validUser
        global app
        textboxValue = self.loginTextbox.text()
        if(textboxValue.lower() == 'pass'):
            validUser=True
            #the solutions i have been trying
            self.menu.layout.removeWidget(self.menuInvalidUserLogin)
            self.layout.removeWidget(self.menuInvalidUserLogin)
            self.menu.layout.update()

            QMessageBox.question(self, 'Response', "Login successful: Welcome", QMessageBox.Ok,QMessageBox.Ok)
        else:
            validUser=False
            QMessageBox.question(self, 'Response', "Login unsuccessful: EXPLAIN YOURSELF", QMessageBox.Ok,QMessageBox.Ok)
        self.loginTextbox.setText("")

app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())

预期的结果应该是删除旧的小部件,添加新的小部件,然后刷新这些小部件所属的布局

【问题讨论】:

【参考方案1】:

这是你所期待的吗?

另外,您在课堂上使用全局变量是否有特定原因?这是不好的做法,您应该让他们成为班级成员。

from PyQt5 import QtWidgets, QtCore, QtGui
import sys

class App(QtWidgets.QMainWindow):
    def __init__(self):
        super(App,self).__init__()
        app = QtWidgets.QApplication.instance()
        screen = app.primaryScreen().size()
        self.title = 'Restaurant Application'
        width = screen.width()
        height = screen.height()
        self.left = 0
        self.top = 0
        self.width = width
        self.height = height
        self.setMouseTracking(True)
        self.table_widget = MyTableWidget(self)
        self.setCentralWidget(self.table_widget)
        self.initUI()
        self.show()

    def initUI(self):
        # window
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # statusbar
        self.statusBar().showMessage('Welcome to el restaurante')

    def mousePressEvent(self, event):
        print('Mouse coords: ( %d : %d )' % (event.x(), event.y()))


class MyTableWidget(QtWidgets.QWidget):

    def __init__(self, parent):
        super(MyTableWidget, self).__init__(parent)
        self.layout = QtWidgets.QVBoxLayout()
        self.validUser = False

        # Initialize tab screen
        self.tabs = QtWidgets.QTabWidget()
        self.login = QtWidgets.QWidget()
        self.menu = QtWidgets.QWidget()
        self.checkOut = QtWidgets.QWidget()
        self.tabs.resize(500, 200)

        # Add tabs
        self.tabs.addTab(self.login, "Login")
        self.tabs.addTab(self.menu, "Menu")
        self.tabs.addTab(self.checkOut, "Check out")

        # Create login tab
        self.login.layout = QtWidgets.QVBoxLayout()
        self.menu.layout = QtWidgets.QVBoxLayout()

        # login text
        self.loginPrompt = QtWidgets.QLabel("Please provide a valid login")
        self.loginPrompt.setFixedSize(315,30)
        self.loginPromptFont = QtGui.QFont("Times", 27, QtGui.QFont.Bold)
        self.loginPrompt.setFont(self.loginPromptFont)
        self.login.layout.addWidget(self.loginPrompt)
        self.login.setLayout(self.login.layout)

        # Create textbox
        self.loginTextbox = QtWidgets.QLineEdit()
        self.loginTextbox.returnPressed.connect(self.on_click_login)
        self.loginTextbox.setFixedSize(170,20)

        # Create a button in the window
        self.loginButton = QtWidgets.QPushButton('Login button')
        self.loginButton.clicked.connect(self.on_click_login)
        self.loginButton.setFixedSize(100,40)
        self.login.layout.addWidget(self.loginTextbox,alignment=QtCore.Qt.AlignCenter)
        self.login.layout.addWidget(self.loginButton,alignment=QtCore.Qt.AlignCenter)


        #widget code i use to decide which widget to add
        self.menuInvalidUserLogin = QtWidgets.QLabel("Please login in to view")
        self.menuValidUserLogin = QtWidgets.QLabel("Here's the menu")

        if(self.validUser):
            self.menu.layout.addWidget(self.menuValidUserLogin)
        else:
            self.menu.layout.addWidget(self.menuInvalidUserLogin)
        self.menu.setLayout(self.menu.layout)

        # Add tabs to widget
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)

    def on_click_login(self):
        textboxValue = self.loginTextbox.text()
        if(textboxValue.lower() == 'pass'):
            self.validUser=True
            for i in reversed(range(self.menu.layout.count())): 
                widgetToRemove = self.menu.layout.itemAt(i).widget()
                self.menu.layout.removeWidget(widgetToRemove)
                widgetToRemove.deleteLater()
            self.menu.layout.addWidget(self.menuValidUserLogin)
            QtWidgets.QMessageBox.question(self, 'Response', "Login successful: Welcome", QtWidgets.QMessageBox.Ok,QtWidgets.QMessageBox.Ok)
            self.tabs.setCurrentIndex(1)
        else:
            self.validUser=False
            QtWidgets.QMessageBox.question(self, 'Response', "Login unsuccessful: EXPLAIN YOURSELF", QtWidgets.QMessageBox.Ok,QtWidgets.QMessageBox.Ok)
        self.loginTextbox.setText("")

def main():        
    app = QtWidgets.QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

【讨论】:

是的,这行得通!你能解释一下代码对 setParent(None) 的作用吗?代码如何知道在没有“update()”方法的情况下调用用于菜单选项卡的方法。你知道为什么 removeWidget 方法不起作用吗?而且我还收到有关“QLayout:尝试将 QLayout”添加到 MyTableWidget“”的警告,它已经有一个布局” @ShahrozImtiaz 我更新了代码以从布局列表和 GUI 中删除小部件。从技术上讲,您并没有删除只是将其设置为***小部件的对象。更新后的代码是否仍会向您发出有关 QLayout 的警告?另外,它在哪里抛出这个错误? @ShahrozImtiaz removeWidget 只是从布局中删除小部件,但实际上并没有删除对象,它使布局不再使用它,但对象仍然存在。 @ShahrozImtiaz 如果我的回答解决了您的问题,请点赞并标记为已解决。 是的,警告会打印到控制台,所以我不知道是哪里/是什么原因造成的

以上是关于如何正确删除小部件并更新/重新加载小部件的主要内容,如果未能解决你的问题,请参考以下文章

颤振更新文本小部件变量而无需重新加载

如何在通知中心频繁更新今日小部件?

ajax 请求后重新加载 dojo 小部件

如何删除小部件之间的线条并使其他小部件居中?

在Streamlit中使用Python选择任何小部件后如何停止重新加载页面

如何从另一个小部件类更新小部件树 - Flutter