在QMainWindow的中央窗口小部件之间切换

3

我有一个继承自QMainWindow的主窗口,根据当前任务可能会显示不同的小部件。

下面是我创建的一个简化示例:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys


class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        '''
        Constructor
        '''
        QMainWindow.__init__(self, parent)
        self.central_widget = QStackedWidget()
        self.setCentralWidget(self.central_widget)
        self.start_screen = Start(self)
        self.second_screen = Second(self)
        self.central_widget.addWidget(self.start_screen)
        self.central_widget.addWidget(self.second_screen)
        self.central_widget.setCurrentWidget(self.start_screen)



class Start(QWidget):

    def __init__(self, parent=None):
        super(Start, self).__init__(parent)
        layout = QHBoxLayout()
        button = QPushButton(text=QString('Push me!'))
        layout.addWidget(button)
        self.setLayout(layout)
        self.connect(button, SIGNAL("clicked()"), self.change_widget)

    def change_widget(self):
        self.parent().setCurrentWidget(
            self.parent().parent().second_screen)


class Second(QWidget):

    def __init__(self, parent=None):
        super(Second, self).__init__(parent)
        layout = QHBoxLayout()
        button = QPushButton(text=QString('Back to Start!'))
        layout.addWidget(button)
        self.setLayout(layout)
        self.connect(button, SIGNAL("clicked()"), self.change_widget)

    def change_widget(self):
        self.parent().setCurrentWidget(
            self.parent().parent().start_screen)

app = QApplication(sys.argv)
myWindow = MainWindow(None)
myWindow.show()
app.exec_()

这个程序可以在两个不同的中央小部件之间切换,但是我觉得使用parent()函数来处理很繁琐,想知道是否有更好的方法来组织这些小部件。
使用setCurrentWidget方法可能只需要一个parent()语句就能完成,但如果由于任何原因导致层次深度发生变化,是否有更好的方法访问QMainWindow,而不是使用parent().parent()?或者每次单击按钮时重新创建小部件(如果这是一个具有数据输入可能性的小部件,那么这些数据将会丢失,这是很烦人的)?
非常感谢您提出的任何改进建议。
1个回答

4
你应该使用信号(Signals)。这样可以让任何父层级和子窗口都无需了解它们被如何使用或显示的顺序。主窗口会处理所有的操作。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys


class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        '''
        Constructor
        '''
        QMainWindow.__init__(self, parent)
        self.central_widget = QStackedWidget()
        self.setCentralWidget(self.central_widget)
        self.start_screen = Start(self)
        self.second_screen = Second(self)
        self.central_widget.addWidget(self.start_screen)
        self.central_widget.addWidget(self.second_screen)
        self.central_widget.setCurrentWidget(self.start_screen)

        self.start_screen.clicked.connect(lambda: self.central_widget.setCurrentWidget(self.second_screen))
        self.second_screen.clicked.connect(lambda: self.central_widget.setCurrentWidget(self.start_screen))



class Start(QWidget):

    clicked = pyqtSignal()

    def __init__(self, parent=None):
        super(Start, self).__init__(parent)
        layout = QHBoxLayout()
        button = QPushButton(text=QString('Push me!'))
        layout.addWidget(button)
        self.setLayout(layout)
        button.clicked.connect(self.clicked.emit)


class Second(QWidget):

    clicked = pyqtSignal()

    def __init__(self, parent=None):
        super(Second, self).__init__(parent)
        layout = QHBoxLayout()
        button = QPushButton(text=QString('Back to Start!'))
        layout.addWidget(button)
        self.setLayout(layout)
        button.clicked.connect(self.clicked.emit)


app = QApplication(sys.argv)
myWindow = MainWindow(None)
myWindow.show()
app.exec_()

谢谢,这对我帮助很大,不仅解决了我的问题,还提高了我对基本PyQt方法的理解。作为后续问题:在MainWindow中省略clicked = pyqtSignal()button.clicked.connect(self.clicked.emit),而是使用self.second_screen.button.clicked.connect(lambda: self.central_widget.setCurrentWidget(self.start_screen))可以实现相同的效果。我没有意识到这种方式是否有任何缺点?编辑:button也必须更改为self.button - MichaelA
1
这有点类似于您原来的问题,但是相反。以这种方式进行需要父级知道实现细节和子部件的内部结构。稍后,如果您想更改子部件的结构(添加/删除按钮,更改部件名称等),则无法进行更改,因为父级期望内部结构保持不变。最好定义接口(在本例中使用信号),这些接口与您的部件的内部结构分开,以与其他部件通信。 - Brendan Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接