user13786679
user13786679

Reputation:

Script doesn't stop

This is the code

Entrypoint.py

   def Data_For_MakePdf_Db(self):
      mese = self.MakePdf_Strip_Month_select.currentText()
      anno = self.MakePdf_Strip_Year_select.currentText()
      MakeStrip(anno, mese)

      return ### Breakpoint here

and MakeStrip.py

class SpecialStyledItemDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._values = dict()

    def add_text(self, text, row):
        self._values[row] = text

    def initStyleOption(self, option, index):
        super().initStyleOption(option, index)
        row = index.row()
        if row in self._values:
            option.text = self._values[row]
            option.displayAlignment = QtCore.Qt.AlignCenter


class MakeStrip(QtWidgets.QWidget):
    def __init__(self, anno, mese):
        super().__init__()
        self.initUI(anno, mese)

    def initUI(self, anno, mese):
        self.title = "MAMbo - Strips di '%s' '%s' "%(mese, anno)
        self.setWindowTitle(self.title)
        self.setGeometry(50, 100, 900, 800)
        self.callTable(anno, mese)
        self.button = QtWidgets.QPushButton(self.tableWidget)
        self.button.setGeometry(QtCore.QRect(440, 169, 70, 20))
        self.button.setObjectName("button")
        self.button.setText("close")

        self.layout = QtWidgets.QHBoxLayout(self)
        self.layout.addWidget(self.tableWidget)

        self.show()
        self.button.clicked.connect(self.on_click)
        pippo = 0   ### Breakpoint here


    def on_click(self):
        print('Clicked')
        # Functions.message_handler(message = "THIS WILL CLOSE THE APP")
        return


    def callTable(self, anno, mese):

        # Create table
        self.tableWidget = QtWidgets.QTableWidget()
        self.tableWidget.move(100, 700)
        self.tableWidget.setRowCount(33)
        self.tableWidget.setColumnCount(3)
        self.special_delegate = SpecialStyledItemDelegate()
        self.tableWidget.setItemDelegate(self.special_delegate)

        h_header = self.tableWidget.horizontalHeader()
        h_header.hide()
        for i in range(h_header.count()):
            h_header.setSectionResizeMode(i, QtWidgets.QHeaderView.ResizeToContents)

        v_header = self.tableWidget.verticalHeader()
        v_header.hide()
        v_header.setDefaultSectionSize(13)

        self.tableWidget.setSpan(1, 0, 1, 3)
        self.tableWidget.setSpan(0, 0, 1, 3)
        ...
        pluto = 0


   def on_click(self):
       print('Clicked')
       return

I use pycharm

Main problem If I run the script I see for a fraction of second the result of Makescript even if there a push button Alternative problem If I debug it I need to put some breakpoints as shown in the scripts to see the result of the script I know that the debugger keeps alive the connection but why do I need to put breakpoints in those positions to see the result?

Upvotes: 0

Views: 55

Answers (1)

musicamante
musicamante

Reputation: 48231

The problem is in the following line:

    MakeStrip(anno, mese)

What happens there is that you create an instance of MakeStrip which has absolutely no reference. The result is that it's created and immediately garbage collected as soon as its __init__ returns.

Imagine doing something like this:

    def Data_For_MakePdf_Db(self):
        list()

As soon as no reference to an object is left, python automatically destroys it. In the case above, you create an instance without any reference, so it gets immediately deleted.

Note that creating a local reference (a variable that exists only in the function) might be a solution, but since there is no locking, you'll have almost the same results, because the function will immediately returns, causing the instance to be destroyed as well:

    def Data_For_MakePdf_Db(self):
        strip = MakeStrip(anno, mese)

A possibility is to create a persistent reference, by making the object a member of the current instance:

    def Data_For_MakePdf_Db(self):
        self.strip = MakeStrip(anno, mese)

This has some, possibly unwanted, side effects: first of all, you could still switch between the current window to the new one (which will probably make things a bit confusing), and, most importantly, if you call Data_For_MakePdf_Db again while another MakeStrip window already exists, it will be probably destroyed and replaced by a new one.

A better and more consistent solution is to have MakeStrip a subclass of QDialog instead, and use its exec_(): it will make it a modal window and will return control only when the window is finally closed.

    def Data_For_MakePdf_Db(self):
        MakeStrip(self, anno, mese).exec_()

class MakeStrip(QtWidgets.QDialog):
    def __init__(self, parent, anno, mese):
        super().__init__(parent)
        self.initUI(anno, mese)

    def initUI(self, anno, mese):
        # ...
        self.button.clicked.connect(self.accept)
        

Note that in this specific case we can even create the dialog without the local or instance reference, thanks to the fact that exec_ creates an event loop that blocks the execution until the dialog is closed.

This is always a good idea, though, as you might need to know if the dialog was actually "accepted" or "rejected", or need access to some of the dialog's objects.

In that case, a local reference is required:

    def Data_For_MakePdf_Db(self):
        dialog = MakeStrip(<b>self</b>, anno, mese)
        if dialog.exec_():
            print(dialog.tableWidget.rowCount())

PS: capitalized names should always be used only for classes and constants, not for functions, so it should be data_for_MakePdf_Db; while you can name your function as you like, this standard convention is highly suggested, as it improves readability (it makes clear distinction between classes and functions). Read more on the official Style Guide for Python Code.

Upvotes: 1

Related Questions