Frage

This fairly minimal code creates a systray item with three right click options. One is an instance of QDialog, another QMainWindow, and also Quit. It's for a systray-driven app that will have some qdialogs and also a qmainwindow containing a table widget (or, is it possible to create a table into a qdialog?). I've been stuck on this for a week or so, read a lot of related materials and do not understand how to resolve it.

From the systray icon menu, clicking on QDialog, the dialog opens, waits for user action, and clicking the Ok or Cancel buttons will print which one was clicked. It would seem this works because QDialog has its own exec_(). Great so far.

However, clicking on the QMainWindow menu option, the main window dialog appears briefly and disappears with no chance for user input, of course. Maybe instead, the qmainwindow dialog would need to rely on the QApplication's exec_() where the object would instead be initialized just before app.exec_() perhaps? If that would work, I'm not clear on how def qmainwindow() would retrieve the information back from the user.

Hopefully a simple matter for someone who knows, a few changes, bingo.

Current environment: Windows 7 or XP, Python 2.7, Pyside

If you run this, there will be a blank place-holder in the systray that is clickable (right click), or you can also give it an actual image in place of 'sample.png'.

#!python

from PySide       import QtGui, QtCore
from PySide.QtGui import QApplication, QDialog, QMainWindow

def qdialog():
    qdialog_class_obj = TestClassQDialog()
    qdialog_class_obj.show()
    qdialog_class_obj.exec_()    # wait for user

    print "qdialog_user_action: ", qdialog_class_obj.qdialog_user_action

def qmainwindow():
    qmainwindow_class_obj = TestClassQMainWindow()
    qmainwindow_class_obj.show()
    #qmainwindow_class_obj.exec_()  # 'TestClassQMainWindow' object has no attribute 'exec_'

class TestClassQDialog(QDialog):
    def __init__(self, parent=None):    
        super(TestClassQDialog, self).__init__(parent)
        self.ok_cancel = QtGui.QDialogButtonBox(self)
        self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel)
        QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("accepted()"), self.button_ok)
        QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("rejected()"), self.button_cancel)

    def button_ok(self):
        self.qdialog_user_action = 'ok'
        self.hide()

    def button_cancel(self):
        self.qdialog_user_action = 'cancel'
        self.hide()

class TestClassQMainWindow(QMainWindow):
    def __init__(self, parent=None):    
        super(TestClassQMainWindow, self).__init__(parent)
        self.ok_cancel = QtGui.QDialogButtonBox(self)
        self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
        QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("accepted()"), self.button_ok)
        QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("rejected()"), self.button_cancel)

    def button_ok(self):
        self.hide()

    def button_cancel(self):
        self.hide()

class SysTrayIcon(QMainWindow):
    def __init__(self, parent=None):
        super(SysTrayIcon, self).__init__(parent)

        self.qdialog_action     = QtGui.QAction("QDialog",     self, triggered=qdialog)
        self.qmainwindow_action = QtGui.QAction("QMainWindow", self, triggered=qmainwindow)
        self.quit_action        = QtGui.QAction("Quit",        self, triggered=QtGui.qApp.quit)

        self.createSystrayIcon()
        self.systrayIcon.show()

    def createSystrayIcon(self):
        self.systrayIconMenu = QtGui.QMenu(self)
        self.systrayIconMenu.addAction(self.qdialog_action)
        self.systrayIconMenu.addAction(self.qmainwindow_action)
        self.systrayIconMenu.addSeparator()
        self.systrayIconMenu.addAction(self.quit_action)
        self.systrayIcon = QtGui.QSystemTrayIcon(self)
        self.systrayIcon.setContextMenu(self.systrayIconMenu)
        self.systrayIcon.setIcon(QtGui.QIcon('sample.png')) # point to a valid image if you want.
        self.systrayIcon.setVisible(True)

if __name__ == '__main__':
    app = QtGui.QApplication([])
    systrayicon = SysTrayIcon()
    app.exec_()
War es hilfreich?

Lösung

I've got it working. What I did was move your external method qmainwindow inside of your SysTrayIcon and created the class parameter self.qmainwindow_class_obj = TestClassQMainWindow(). I've attached the working code below. Also, you're using the old style signal slot method, I take it you're coming from old school PyQt. The new method if very nice, clean and pythonic. I've also put the new style methods in the below code. Another thing I would do is move your qdialog method inside the SysTrayIcon class. I don't really understand why you have it outside the class but maybe I'm missing something. Hope this helps.

#!python

from PySide       import QtGui, QtCore
from PySide.QtGui import QApplication, QDialog, QMainWindow

def qdialog():
    qdialog_class_obj = TestClassQDialog()
    qdialog_class_obj.show()
    qdialog_class_obj.exec_()    # wait for user
    print "qdialog_user_action: ", qdialog_class_obj.qdialog_user_action


class TestClassQDialog(QDialog):
    def __init__(self, parent=None):    
        super(TestClassQDialog, self).__init__(parent)
        self.ok_cancel = QtGui.QDialogButtonBox(self)
        self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel)        
        self.ok_cancel.accepted.connect(self.button_ok)
        self.ok_cancel.rejected.connect(self.button_cancel)

    def button_ok(self):
        self.qdialog_user_action = 'ok'
        self.hide()

    def button_cancel(self):
        self.qdialog_user_action = 'cancel'
        self.hide()

class TestClassQMainWindow(QMainWindow):
    def __init__(self, parent=None):    
        super(TestClassQMainWindow, self).__init__(parent)
        self.ok_cancel = QtGui.QDialogButtonBox(self)
        self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
        self.ok_cancel.accepted.connect(self.button_ok)
        self.ok_cancel.rejected.connect(self.button_cancel)

    def button_ok(self):
        self.hide()

    def button_cancel(self):
        self.hide()

class SysTrayIcon(QMainWindow):
    def __init__(self, parent=None):
        super(SysTrayIcon, self).__init__(parent)

        self.qmainwindow_class_obj = TestClassQMainWindow()

        self.qdialog_action     = QtGui.QAction("QDialog",     self, triggered=qdialog)
        self.qmainwindow_action = QtGui.QAction("QMainWindow", self, triggered=self.qmainwindow)
        self.quit_action        = QtGui.QAction("Quit",        self, triggered=QtGui.qApp.quit)

        self.createSystrayIcon()
        self.systrayIcon.show()

    def createSystrayIcon(self):
        self.systrayIconMenu = QtGui.QMenu(self)
        self.systrayIconMenu.addAction(self.qdialog_action)
        self.systrayIconMenu.addAction(self.qmainwindow_action)
        self.systrayIconMenu.addSeparator()
        self.systrayIconMenu.addAction(self.quit_action)
        self.systrayIcon = QtGui.QSystemTrayIcon(self)
        self.systrayIcon.setContextMenu(self.systrayIconMenu)
        self.systrayIcon.setIcon(QtGui.QIcon('linux.jpeg')) # point to a valid image if you want.
        self.systrayIcon.setVisible(True)

    def qmainwindow(self):
        self.qmainwindow_class_obj.show()


if __name__ == '__main__':
    app = QtGui.QApplication([])
    systrayicon = SysTrayIcon()
    app.exec_()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top