如何从stackedLayout访问centralWidget中的小部件?

Posted

技术标签:

【中文标题】如何从stackedLayout访问centralWidget中的小部件?【英文标题】:How to access widgets in centralWidget from stackedLayout? 【发布时间】:2019-08-24 11:16:38 【问题描述】:

我在 Controller.py 文件中有一个 QMainWindow,它在 centralWidget 上创建了一个 QmenuBar,并在 QstackedLayout 中嵌套了多个名为 win0.py、win1.py、... 的文件。 现在我想在Controller的主窗口中启用/禁用菜单栏中的按钮,并在centralWidget中获取一些变量/调用函数

此示例基于以下未回答我的问题:

Using QStackedWidget for multi-windowed PyQt application

How to make nested StackedLayouts in PyQt5?

最接近的问题是:

Setting up stateChanged signal in QStackedWidget, pyqt

但是它们都没有更改 MainWindow(控制器)上的项目,就像我尝试做的那样。详情见代码。

controller.py:

import sys

from PyQt5.QtWidgets import *
from PyQt5 import QtCore

from win0 import W0     # sample window
#from win1 import W1     # further windows
#from win2 import W2

class Controller (QMainWindow):
    def __init__(self, parent=None):
        #super(Controller, self).__init__(parent)
        QMainWindow.__init__(self, parent)
        # used variables
        self.winDict = 
        self.v1 = " self.V1 in Controller"

        # create stack
        self.stackLayout = QStackedLayout ()

        # put stack on MainWindow
        self.MainWidget =QWidget()
        self.MainWidget.setLayout(self.stackLayout)
        self.setCentralWidget(self.MainWidget)
        self.init_MenuBar ()

        # add further layouts
        self.init_Windows()
        # swith to first layout
        self.activeWin = self.switchWin (0)

    def init_MenuBar(self):

        self.toolbarButton_file = QPushButton (self.tr ("File"))
        self.toolbarButton_0 = QPushButton (self.tr ("Win0"))
        self.toolbarButton_1 = QPushButton (self.tr ("Win1"))
        self.toolbarButton_2 = QPushButton (self.tr ("Win2"))

        toolbar = self.addToolBar ("Window Manager")
        toolbar.addWidget (self.toolbarButton_file)
        toolbar.addWidget (self.toolbarButton_0)
        toolbar.addWidget (self.toolbarButton_1)
        toolbar.addWidget (self.toolbarButton_2)
        toolbar.setMovable (False)

        self.toolbarButton_0.clicked.connect ( (lambda: self.switchWin (0)))
        self.toolbarButton_1.clicked.connect ((lambda: self.switchWin (1)))
        self.toolbarButton_2.clicked.connect ((lambda: self.switchWin (2)))
        self.toolbarButton_0.setCheckable (False)
        self.toolbarButton_1.setCheckable(False)
        self.toolbarButton_2.setCheckable(False)
        self.toolbarButton_0.setEnabled (True)
        self.toolbarButton_1.setEnabled (True)
        self.toolbarButton_2.setEnabled (True)

    def init_Windows(self):
        self.switchWin(0, True)
        self.switchWin(1, True)
        self.switchWin(2, True)


    def switchWin(self, id=0, initonly = False):
        print ("-> switchWin:", id)
        if id not in self.winDict.keys ():
            if id == 0:
                self.winDict[id] = W0 ()
            #elif id == 1:
            #    self.winDict[id] = W1 ()
            #elif id == 2:
            #    self.winDict[id] = W2 ()
            self.stackLayout.addWidget (self.winDict[id])

        if not initonly:
            self.stackLayout.setCurrentIndex (id)
        Window = self.winDict[id]
        return Window

    def list_v1(self):
        print("-> Controller.list_V1")
        print("V1:", self.v1)

def main():
    App = QApplication(sys.argv)
    ProgramWindow = Controller()
    ProgramWindow.show()
    App.exec_()

if __name__ == "__main__":
    main()

win0.py(win1.py ...同基础)

import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic

class W0(QMainWindow):
    def __init__(self):
        super().__init__()
        self.ui = self.init_UI()
        self.v1 ="Variable in W0"
        self.ui.pushButton.clicked.connect (self.pbClicked)

    def init_UI(self):
        mainForm = ("win0.ui")
        print ("mainForm:", mainForm)
        Widget = uic.loadUi (mainForm, self)
        return Widget

    def pbClicked(self):
        print ("-> win0.pbClicked")
        self.parent().toolbarButton_0.setEnabled (False)       # There is the question
                                                               # How to access widgets and functions, variables on the
                                                               # centralWidget or MainWindow of Controller.py. I want to en/disable button in the menuBar e.g.

if __name__ == "__main__":
    App = QApplication (sys.argv)
    ProgramWindow = W0()
    ProgramWindow.show ()
    App.exec_ ()

win0.ui(win1.ui中相同...)

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>0</y>
      <width>43</width>
      <height>13</height>
     </rect>
    </property>
    <property name="text">
     <string>Win 0</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>60</x>
      <y>0</y>
      <width>80</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>PushButton</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton_0">
    <property name="geometry">
     <rect>
      <x>180</x>
      <y>0</y>
      <width>80</width>
      <height>16</height>
     </rect>
    </property>
    <property name="text">
     <string>PushButton_0</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>20</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

使用 pyqt5 和 python 3.7。我试着用 import from Controller 导致无限循环和self.parent().toolbarButton_0.setEnabled (False) 导致AttributeError: 'QWidget' object has no attribute 'toolbarButton_0'

【问题讨论】:

使用槽和信号,而不是尝试直接从W0 操作Controller 好的,请给我一个例子。我已经尝试过了,但似乎我做错了。 我发布了一个小例子。 【参考方案1】:

您可以使用信号和槽进行通信,而不是尝试直接从W0 操作Controller 小部件。例如,在W0 中,您可以执行类似的操作

class W0(QMainWindow):
    button_clicked = QtCore.pyqtSignal()

    def __init__(self):
        ...
        self.ui.pushButton.clicked.connect(self.pbClicked)

    ....

    def pbClicked(self):
        print (f"-> winself.id.pbClicked")
        self.button_clicked.emit()

Controller

class Controller(QMainWindow):

    ....

    def switchWin(self, id=0, initonly = False):
        print ("-> switchWin:", id)
        if id not in self.winDict.keys ():
            if id == 0:
                self.winDict[id] = W0 ()
                self.winDict[id].button_clicked.connect(self.W0_button_clicked)
        ....

    def W0_button_clicked(self):
        self.toolbarButton_0.setEnabled (False)

当然,在Controller.SwitchWin 中你可以直接连接到信号self.winDict[id].ui.pushButton.clicked,但是在W0 中创建一个单独的信号并在单击按钮时发出它的优点是你可以更改@987654330 的 Gui @ 无需重写Controller 中的信号槽连接。此外,如果需要,您可以通过为信号指定输入参数来使用该信号发送额外的数据。

【讨论】:

以上是关于如何从stackedLayout访问centralWidget中的小部件?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 maven 工件从 jcenter 同步到 maven Central?

如何使用 Gradle 中的本地 JUnit Jar 而不是 Maven Central?

使 Sonatype Nexus 存储库可公开访问,以便能够下载带有 maven Central 等 URL 的工件

G. Gangsters in Central City

在 iOS 的后台模式下将数据从 Central 传输到外围设备

从maven central下载javax.media.jai_core:1.1.3时出错