0

During handling of a clicked signal I would like to show a wait cursor until this is done.
All mouse clicks on other widgets should be ignored during that time.

The cursor part is working fine using setCursor().

But all mouse clicks on other buttons (or the original one) are still detected and cached, so they are handled after the first button operation is finished.

How can I make sure that no user interface events are generated until my operation is finished?

This code shows the things I have already tried:

  • pushButton_B.setEnabled()
  • pushButton_B.clicked.disconnect()
  • pushButton_B.blockSignals()

None of those have led to the desired behaviour.

I am hoping for some way to disable user interface events for the whole window, so I don't need to do this for every widget I introduce, but I couldn't find the right methods for this.

I'd appreciate any hints on how to do this properly.

import sys
import time

from PySide6.QtCore import Qt, QRect, QCoreApplication, QMetaObject
from PySide6.QtWidgets import QApplication, QWidget, QMainWindow, QPushButton


class Ui_MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(200, 200)
        self.centralwidget = QWidget(self)
        self.pushButton_A = QPushButton(self.centralwidget)
        self.pushButton_A.setText('A')
        self.pushButton_A.setGeometry(QRect(20, 20, 100, 24))
        self.pushButton_B = QPushButton(self.centralwidget)
        self.pushButton_B.setText('B')
        self.pushButton_B.setGeometry(QRect(20, 60, 100, 24))
        self.setCentralWidget(self.centralwidget)

        self.pushButton_A.clicked.connect(self.pushButton_A_clicked)
        self.pushButton_B.clicked.connect(self.pushButton_B_clicked)

    def pushButton_A_clicked(self):
        print("pushButton_A clicked...")
        self.setCursor(Qt.CursorShape.WaitCursor)
        self.pushButton_B.setEnabled(False)
        self.pushButton_B.clicked.disconnect(self.pushButton_B_clicked)
        self.pushButton_B.blockSignals(True)
        self.repaint()
        time.sleep(3)  # Some lengthy operation
        self.setCursor(Qt.CursorShape.ArrowCursor)
        self.pushButton_B.setEnabled(True)
        self.pushButton_B.clicked.connect(self.pushButton_B_clicked)
        self.pushButton_B.blockSignals(False)
        print("pushButton_A done.")

    def pushButton_B_clicked(self):
        print("pushButton_B clicked.")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Ui_MainWindow()
    w.show()
    app.exec()
musicamante
  • 41,230
  • 6
  • 33
  • 58
silmaril
  • 1
  • 2
  • Just disable the button and call `QApplication.processEvents()` right after that, then you can remove all other attempts as they have different purposes. Also, considering moving things to another QThread, if what you do instead of that `sleep()` can provide improvements with multithreading. – musicamante Jan 30 '23 at 13:27
  • @musicamante: Unfortunately, adding `processEvents()` does not resolve this issue. – silmaril Jan 30 '23 at 16:16
  • Then, since Qt6 doesn't provide `hasPendingEvents()`, call processEvents right after the sleep and *queue* the button enabling with a 0-singleShot QTimer: `QTimer.singleShot(0, lambda: self.pushButton_B.setEnabled(True))`. Note that you shouldn't add an answer to a question. If it's closed, editing should only used to add details and clarify the question for possible reopening. Answers should only go in the answer field, but since your question is closed, there's no answer to provide until it's reopened. Since your new code is actually taken from a duplicated answer, it's pointless to add it. – musicamante Jan 30 '23 at 17:43
  • Besides, boilerplate is when sections of code are repeated in multiple places. Using threading may add some level of complexity, but it's the expected thing to do when (pseudo) concurrent operations are required, and that's *not* boilerplate. – musicamante Jan 30 '23 at 17:46
  • So that basically means, there is no way to provide an answer that really fits the question if a similar (but not quite fitting) answer already exists? – silmaril Jan 31 '23 at 12:51
  • While the duplicated answer(s) may not exactly fit your question, they conceptually answer the problem. We cannot (nor should) provide answers for *every specific case*, otherwise StackOverflow would have billions of posts that are practically identical, and finding any solution would become a nightmare. While answers often solve a specific problem, they are intended for any similar case; it's up to the developer to understand the concept behind the answer and adapt it to their needs. – musicamante Jan 31 '23 at 14:46

0 Answers0