2

I am trying to open a QDialog from a QMainWindow, and after closing the `QDialog, if I need to open it again, it has to open and show the same information that had when I close it.

Here is the code of the QMainWindow:

class A (QMainWindow):
  def __init__(self):
    QMainWindow.__init__(self)

    #I create a QPushButton to open the QDialog
    self.axes1 = self.figure_canvas.figure.add_axes ([0.8, 0.01, 0.19, 0.05])
    self.button = QPushButton(self.axes1,"Open Dialog")
    self.button.on_clicked(self.OpenDialog)

    #This is the method to open the QDialog which is in another module
  def OpenDialog(self, event):
    text = configurePort.ConfigurePort.retrieve_data(self)
    print text

What this code does is create a button in my QMainWindow and when I click it, it opens a QDialog, which is created in another module. And this is the code of the QDialog:

class ConfigurePort(QDialog):
  def __init__(self, parent = None):
     QDialog.__init__(self, parent)
     uic.loadUi("configurePort.ui", self)

    #I create a button to check active ports and show them
    self.connect(self.btn_checkconn, SIGNAL("clicked()"), self.check_ports)

    #This method calls another class which opens another QDialog
    #and I select the port that I want
  def check_ports(self):
     self.check_serial = CheckPorts(self)
     self.check_serial.exec_()

    #After selecting the port, when I close the QDialog of the class named above
    #the port´s name appears in the first QDialog
  @classmethod
  def retrieve_data(cls, parent = None):
     dlg = cls(parent)
     dlg.exec_()
     text = dlg.getPortText()
     return text

  def closeEvent(self, event):
     #Here is where I need to write the code to close the QDialog 
     #and it does not has to be an event

In the method, closeEvent, I need to write the necessary code, so I can close the window, and using the same button that I use to open it, open it again with the last information that it showed when I closed it.

I have tried to use QSettings but it did not worked (maybe I used it wrong). And I tried the show() and hide() classes of PyQt too, but it did not work. Hope you can help me.

----- EDIT -----

I edited the code of above. and I added some methods for a better understanding. So, i open the QDialog called ConfigurePort and it shows this:

enter image description here

The red circle, surrounds the port´s name. It is shown in a QLabel,and I take this text from the QDialog and then print it when I close the QDialog. I acomplish this thanks to a question I asked before, wich is in this link:

Getting data from child using PyQt

The check_port method shown in the code above, opens another QDialog that works great. With this I can select the ports that I need in my pc. So, this does not matter.

So, after closing the QDialog(and selecting for example "COM3", as you can see in the picture), I need to open it again, and see the same information that was shown before I closed it.

I tried to add this lines, using QSettings :

self.settings = QSettings("MyCompany", "MyApp")
  if not self.settings.value("windowsState") == None:
    self.restoreState(self.settings.value("windowState"))

But as I said before, I think that I did not use it right, but I hope that I solve this using something simpler.

----- EDIT 2 -----

Thank to the help of @Brendan Abel I have this code:

class ConfigurePort(QDialog):
  def __init__(self, parent):
    super(ConfigurePort, self).__init__(parent)
    uic.loadUi("configurePort.ui", self)

    self.myValue = 10
    self.restoreSettings()

    self.connect(self.btn_checkconn, SIGNAL("clicked()"), self.check_ports)
    self.buttonBox.button(QDialogButtonBox.Cancel).clicked.connect(self.close)
    self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.closeEvent)

    self.iniUi()

  def check_ports(self):
    pass

  def iniUi(self):
    pass #I just create some QLabels in here

  @classmethod
  def retrieve_data(cls, parent = None):
    dlg = cls(parent)
    dlg.exec_()
    text = dlg.getPortText()
    return text

  def closeEvent(self, event):
    self.saveSettings()
    super(QDialog,self).closeEvent(event)

  def saveSettings(self):
    settings = QSettings("MyOrg", "MyApp")
    settings.setValue("myValue", self.myValue)

  def restoreSettings(self):
    settings = QSettings("MyOrg", "MyApp")
    self.myValue = settings.value("myValue", self.myValue)

This gives me this error: TypeError: QWidget.closeEvent(QCloseEvent): argument 1 has unexpected type 'bool' I know that I am missing something, but I can not see it.

Community
  • 1
  • 1
Pablo Flores
  • 667
  • 1
  • 13
  • 33
  • What happened when you used QSettings? what OS are you on? – Tom Myddeltyn May 20 '16 at 13:26
  • Also, it doesn't look like you are instantiating `ConfigurePort` as an object, you are just calling the `retrieve_data` method – Tom Myddeltyn May 20 '16 at 13:28
  • 1
    How long should the data persist? Should it open up with the same data if you close and restart your application? What if the dialog is used by another applications, should both applications have different sets of saved data? – Brendan Abel May 20 '16 at 17:16
  • Thank you for your answers. I edited my question for a better understanding. @BrendanAbel , the data only needs to stay until the app is closed, but is better (not necessary) if it stays "forever". And the `QDialog` does not need to be open with another app. – Pablo Flores May 20 '16 at 18:25
  • Are you using the dialog to just display data from the main application or does the user modify data in the dialog? If it is the latter, then you really don't need to get data back from the dialog, just push data up when you open it. – Tom Myddeltyn May 23 '16 at 13:28

2 Answers2

2

There are a couple ways you could persist this data Generally, to persist data across sessions, you use QSettings and load the data in the __init__ and save it in the closeEvent method

Generally it looks something like this. This also assumes your using the v2 version of the QVariant api; otherwise, the results returned from QSettings.value is going to be a QVariant and you'll need to cast it to the appropriate python type. If you're using a recent version of PyQt then you should be on v2, but if not you can force it by sticking this at the top of your file

import sip
sip.setapi('QVariant', 2)
sip.setapi('QString', 2)


class MyDialog(QDialog):

    def __init__(self, parent):
        super(MyDialog, self).__init__(parent)
        self.myvalue = 10
        self.restoreSettings()

    def closeEvent(self, event):
        self.saveSettings()
        super(MyDialog, self).closeEvent(event)

    def saveSettings(self):
        settings = QSettings('myorg', 'myapp')
        settings.setValue('myvalue', self.myvalue)

    def restoreSettings(self):
        settings = QSettings('myorg', 'myapp')
        self.myvalue = settings.value('myvalue', self.myvalue)

EDIT:

The error in your code is caused by this:

self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.closeEvent)

You shouldn't be calling or connecting to closeEvent directly. Instead, you should connect to .close or .accept

self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.accept)
Community
  • 1
  • 1
Brendan Abel
  • 35,343
  • 14
  • 88
  • 118
  • 1
    Handy tip for `QSettings` is when you make the `QApplication`, use `qApplicationObject.setApplicationName("myapp")`, `qApplicationObject.setOrganizationDomain("myorg.com")` and `qApplicationObject.setOrganizationName("myorg")` (put what you will for `"myapp"` and `"myorg"`) this allows you to call `QSettings()` and not have to specify those in each instance. – Tom Myddeltyn May 20 '16 at 19:56
  • Thank you for your answer. This line: `super(MyDialog, self).closeEvent(event)` , gives me this error : `TypeError: QDialog.closeEvent(QCloseEvent): argument 1 has unexpected type 'bool'` . What could be the problem? I also think that where you put `MyWidget`, I must put `MyDialog` instead. Thank you again, for all your help – Pablo Flores May 20 '16 at 21:12
  • I'm guessing you're reassigning `event` to a boolean before you call the parent class? – Brendan Abel May 20 '16 at 21:49
  • I edited the question, and I added the code that i have with the one that you wrote above (I use the same variables for now). That gives me the `TypeError` with the "unexpected bool" – Pablo Flores May 20 '16 at 22:09
  • @PabloFlores Updated the answer – Brendan Abel May 20 '16 at 22:15
1

You need to instantiate the ConfigurePort class then the self.configurePortDialog object should keep consistent. You will need to make sure if you have the user enter data that a cancel does not store the data and that an "ok" stores the data, but I not sure what you are putting in your dialog.

class A (QMainWindow):
  def __init__(self):
    QMainWindow.__init__(self)

    #I create a QPushButton to open the QDialog
    self.button = QPushButton("Open Dialog")
    self.button.on_clicked(self.OpenDialog)
    self.configurePortDialog = configurePort.ConfigurePort(parent=self)
    self.configurePortDialog.accepted.connect(self.get_data)

    #This is the method to open the QDialog which is in another module
  def OpenDialog(self, event):
     self.configurePortDialog.show()

  @QtCore.Slot()
  def get_data(self)
    text = self.configurePortDialog.retrieve_data()
    print text
Tom Myddeltyn
  • 1,307
  • 1
  • 13
  • 27
  • Thank you for your answer. I edited my question fro a better understanding of what I need to do. Hope you can help me. – Pablo Flores May 20 '16 at 18:26
  • @BrendanAbel Thanks! Fixed – Tom Myddeltyn May 20 '16 at 19:49
  • Thank you for your answer. I have one question: doesn´t this line: `text = self.configurePortDialog.retrieve_data()` opens the `QDialog` again? – Pablo Flores May 20 '16 at 20:41
  • Correct, at the time I didn't have the code that showed that you are calling the `exec_()` function in `retrieve_data()` I had wrongly assumed that all it did was return data from the dialog – Tom Myddeltyn May 20 '16 at 21:04
  • @busfault yes, that is all that must do jeje. Retrieve the data that i need from the dialog. So i must take out `dlg.exec_()` ? – Pablo Flores May 20 '16 at 21:27
  • Not necessarily. Also it depends on what you want to do, when you call the exec_() it blocks the current code execution until it returns for more info on modal dialogs: http://doc.qt.io/qt-4.8/qdialog.html#modal-dialogs – Tom Myddeltyn May 23 '16 at 13:22