Pygmalion
Pygmalion

Reputation: 919

How to return value from the QWidget

I have a widget that ends with pressing OK button. I want that the widget returns a value to the main program (which is in simple example below the obtained value increased by 1). How can I do this?

Also, is there any more elegant way to show the same QWidget with the different title?

MWE:

import sys
from PyQt5 import QtGui, QtCore, QtWidgets

class MainWindow(QtWidgets.QWidget):
    def __init__(self,val):
        self.val=val
        super(MainWindow, self).__init__()
        self.initUI()

    def initUI(self):
        self.End= QtWidgets.QPushButton('OK', self)
        self.End.clicked.connect(self.end)

        MainLayout = QtWidgets.QVBoxLayout()
        MainLayout.addWidget(self.End)
        self.setLayout(MainLayout)
        self.setWindowTitle(str(self.val))
        self.show()

    def end(self):
        # return self.val+1
        self.close()

def main(): 
    app = QtWidgets.QApplication(sys.argv)

    for i in range(10):
        ex = MainWindow(i)
        ex.show()
        res = app.exec_()
        print(res)
    sys.exit()

if __name__ == '__main__':
    main()

Upvotes: 3

Views: 6861

Answers (2)

eyllanesc
eyllanesc

Reputation: 243955

If you want to use a widget to get some value after some processing, the correct thing is to use QDialog, that prevents any other window from opening if you use exec_():

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Dialog(QtWidgets.QDialog):
    def __init__(self, val, parent=None):
        super(Dialog, self).__init__(parent)
        self.val = val
        self.initUI()

    def initUI(self):
        endButton = QtWidgets.QPushButton('OK')
        endButton.clicked.connect(self.on_clicked)
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(endButton)
        self.setWindowTitle(str(self.val))

    @QtCore.pyqtSlot()
    def on_clicked(self):
        self.val += 1
        self.accept()

def main(): 
    app = QtWidgets.QApplication(sys.argv)
    for i in range(10):
        ex = Dialog(i)
        ex.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        if ex.exec_() == QtWidgets.QDialog.Accepted:
            print(ex.val)

if __name__ == '__main__':
    main()

Upvotes: 3

rbaleksandar
rbaleksandar

Reputation: 9691

It is unclear what exactly your intention is with this code. If val is supposed to be a counter for the number of MainWindow instances, then you must declare it as a static:

class MainWindow(QtWidgets.QWidget):
    val = 0
    def __init__(self):
        super(MainWindow, self).__init__()
        MainWindow.val += 1
        self.initUI()

    def initUI(self):
        # ...
        self.setWindowTitle(str(MainWindow.val))
        # ...

def main():
    # ...
    for i in range(10):
        ex = MainWindow()
        # ...
    # ...

There is nothing wrong in calling QWidget::setWindowTitle() so I don't see a problem here.

If you really want to have it as a non-static class member and each MainWindow uses it as some sort of ID, you can easily call the value right after the ex.show():

def main(): 
    app = QtWidgets.QApplication(sys.argv)

    for i in range(10):
        ex = MainWindow()
        ex.show()
        print(MainWindow.val)
        res = app.exec_()
        print(res)
    sys.exit()

Just because you close a widget doesn't mean you have destroyed it so calling the values stored inside the object is not an issue.

However it appears you are not familiar what QApplication::exec() is intended for. It runs the main loop of the given application and returns the exit status (you can set it when calling exit() as the parameter passed to that function). If you simply want to get the value of val upon closing a widget you can simply override the closeEvent handler and emit a signal. Create a QObject instance and connect each MainWindow instance's custom close signal to a slot and do with the value whatever you want to.

Upvotes: 0

Related Questions