在PyQt中,如何获得共享菜单和工具栏以与当前活动的子窗口进行通信?

时间:2017-02-08 17:36:23

标签: python python-2.7 pyqt pyqt4

我有一个应用程序,它有一个主窗口,可以有多个子窗口。我想在主窗口中有一组与当前所选窗口交互的QActions。例如,应用程序可能是文本编辑器,单击file-> save应保存用户当前正在处理的文本文件。此外,某些QAction是可检查的,因此其检查状态应反映当前活动窗口的状态。

这是一个具有我想要的基本功能的最小工作示例,但我怀疑有更好的方法(在代码下面进一步讨论)。

import sys
import PyQt4.QtGui as QtGui

class DisplayWindow(QtGui.QWidget):
    def __init__(self, parent=None, name="Main Window"):
        # run the initializer of the class inherited from
        super(DisplayWindow, self).__init__()

        self.myLayout = QtGui.QFormLayout()

        self.FooLabel = QtGui.QLabel(self)
        self.FooLabel.setText(name)

        self.myLayout.addWidget(self.FooLabel)
        self.setLayout(self.myLayout)

        self.is_foo = False

    def toggle_foo(self):
        self.is_foo = not self.is_foo
        if self.is_foo:
            self.FooLabel.setText('foo')
        else: 
            self.FooLabel.setText('bar')

class WindowActionMain(QtGui.QMainWindow):
    def __init__(self):
        super(WindowActionMain, self).__init__()

        self.fooAction = QtGui.QAction('Foo', self) 
        self.fooAction.triggered.connect(self.set_foo)
        self.fooAction.setCheckable(True)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(self.fooAction)
        self.toolbar = self.addToolBar('File')
        self.toolbar.addAction(self.fooAction)

        self.centralZone = QtGui.QMdiArea()
        self.centralZone.subWindowActivated.connect(
                               self.update_current_window)
        self.setCentralWidget(self.centralZone)
        self.create_dw("Window 1")
        self.create_dw("Window 2")

    def create_dw(self, name):
        dw = DisplayWindow(name=name)
        self.centralZone.addSubWindow(dw)
        dw.show()

    def update_current_window(self):
        """ redirect future actions to affect the newly selected window,
        and update checked statuses to reflect state of selected window"""

        current_window = self.centralZone.activeSubWindow()
        if current_window:
            self.current_dw = self.centralZone.activeSubWindow().widget()

        self.fooAction.setChecked(self.current_dw.is_foo)

    def set_foo(self):
        self.current_dw.toggle_foo()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    ex = WindowActionMain()
    ex.show()
    sys.exit(app.exec_())

我的DisplayWindow的实际版本在许多不同的项目中都很有用,我想打包它,这样你就不必在主窗口中添加大量代码来使用它。因此,DisplayWindow,其所有功能和可用操作列表应位于一个模块中,该模块将导入WindowActionMain模块中。然后,我应该能够为DisplayWindow添加更多操作,而无需更改WindowActionMain中的任何代码。特别是,我不想写一个像WindowActionMain.set_foo(self)这样的小函数,只是为了将每个动作重定向到正确的位置。

1 个答案:

答案 0 :(得分:1)

是的,这可以通过处理QMenu的aboutToShow信号来实现 并考虑QGuiApplication的焦点窗口(或者你在Qt4中得到它) 下面的示例显示了作用于最前面窗口的通用“窗口”菜单。

http://doc.qt.io/qt-4.8/qmenu.html#aboutToShow
http://doc.qt.io/qt-5/qguiapplication.html#focusWindow

def on_windowMenu_aboutToShow(self):
    self.windowMenu.clear()
    self.newWindowAction = QtWidgets.QAction(self)
    self.newWindowAction.setShortcut("Ctrl+n")
    self.newWindowAction.triggered.connect(self.on_newWindowAction)
    self.newWindowAction.setText("New Window")
    self.windowMenu.addAction(self.newWindowAction)
    self.windowMenu.addSeparator()
    playerWindows = [w for w in self.topLevelWindows() if w.type()==QtCore.Qt.Window and w.isVisible()]
    for i, w in enumerate(playerWindows):
        def action(i,w):
            a = QtWidgets.QAction(self)
            a.setText("Show Window {num} - {title}".format(num=i+1, title=w.title()))
            a.triggered.connect(lambda : w.requestActivate())
            a.triggered.connect(lambda : w.raise_())
            self.windowMenu.addAction(a)
        action(i,w)
    self.windowMenu.addSeparator()
    self.closeWindowAction = QtWidgets.QAction(self)
    self.closeWindowAction.setShortcut("Ctrl+w")
    self.closeWindowAction.triggered.connect(lambda : self.focusWindow().close())
    self.closeWindowAction.setText("Close")
    self.windowMenu.addAction(self.closeWindowAction)