Как перехватить QProgressDialog, отменить клик

У меня есть стандартный QProgressDialog с кнопкой отмены. Если/когда пользователь нажимает кнопку отмены, я не хочу, чтобы диалоговое окно немедленно скрывалось, вместо этого я бы предпочел отключить кнопку отмены и выполнить некоторую очистку, а затем закрыть QProgressDialog, как только я уверен, что эта работа завершено. Как перехватить текущую функцию?

Из документов кажется, что я должен перезаписать:

PySide.QtGui.QProgressDialog.cancel()

Сбрасывает диалог прогресса.PySide.QtGui.QProgressDialog.wasCanceled() становится истинным до тех пор, пока диалоговое окно прогресса не будет сброшено. Диалоговое окно прогресса становится скрытым.

Я пробовал создать подкласс этого метода, но он даже не вызывается, когда я нажимаю кнопку отмены.

1 ответ

Чтобы отключить кнопку диалога, вы должны получить ссылку на нее. Поскольку это базовый QPushButton, вы можете использоватьfindChild():

      dialog = QProgressDialog(self)
cancelButton = dialog.findChild(QPushButton)
cancelButton.setEnabled(False)

Учтите, что отключение кнопки, которая никогда не будет активирована, раздражает с точки зрения UX, поэтому лучшим выбором было бы вообще не показывать ее, иsetCancelButton()объясняет, как это сделать:

Если он пройден, кнопка отмены отображаться не будет.

С точки зрения питона, nullptrозначает None:

      dialog = QProgressDialog(self)
dialog.setCancelButton(None)

К сожалению, это не помешает пользователю отменить диалог, закрыв его или нажав Esc.

Это справедливо для любого QDialog, и, чтобы избежать этого, лучше выбрать подклассы: вам нужно предотвратить отклонение диалога ( Escключа) и события закрытия . Хотя они имеют схожие результаты, они обрабатываются по-разному.

Переопределение (и ничегонеделание) предотвращает любое действие, которое могло бы вызвать отклонение (отмену), включая нажатие Esc.

Переопределение closeEvent()требуется дополнительный шаг: вы должны убедиться, что событиеspontaneous()(запускается системой - обычно пользователь нажимает кнопку закрытия окна) и в конечном итоге игнорирует это. Это необходимо, так как вам может понадобиться позвонить close()или фактически закрыть диалоговое окно после завершения процесса.

      class NonStopProgressDialog(QtWidgets.QProgressDialog):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setCancelButton(None)

    def reject(self):
        pass

    def closeEvent(self, event):
        if event.spontaneous():
            event.ignore()

Обратите внимание, что нет прямого способа узнать, вызвано ли событие самопроизвольного закрытия непосредственно пользователем (попыткой закрыть окно) или системой (при завершении работы).

Также обратите внимание, что если вам нужно закрыть диалоговое окно программно, вы либо вызываете accept(), или вы вызываете базовую реализацию, которая позволяет вам получить правильное возвращаемое значение из диалогового окна reject():

          def rejectNoMatterWhat(self):
        super().reject()

Наконец, если по какой-либо причине вам все еще нужна кнопка отмены, вы должны отключить ее сигналы.

В общем, это может сделать работу:

      dialog = QProgressDialog(self)
cancelButton = dialog.findChild(QPushButton)
cancelButton.disconnect()

Но вышеперечисленное приведет к отключению любого сигнала от любого слота, и в некоторых случаях этого следует избегать.
мы знаем , что Из источниковclickedсигнал фактически подключен к canceled()слот, поэтому лучшим решением было бы сделать следующее:

      dialog = QProgressDialog(self)
cancelButton = dialog.findChild(QPushButton)
cancelButton.clicked.disconnect(self.canceled)

Поскольку вам может потребоваться уведомление об этом в родительском/основном классе, более подходящим решением будет создание пользовательского сигнала в подклассе, использованном выше:

      class NonStopProgressDialog(QtWidgets.QProgressDialog):
    userCancel = QtCore.pyqtSignal()
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        cancelButton = self.findChild(QPushButton)
        cancelButton.clicked.disconnect(self.canceled)
        cancelButton.clicked.connect(
            lambda: cancelButton.setEnabled(False))
        cancelButton.clicked.connect(self.userCancel)

    def reject(self):
        pass

    def closeEvent(self, event):
        if event.spontaneous():
            event.ignore()

class SomeWindow(QtWidgets.QWidget):
    def showProgress(self):
        self.progressDialog = NonStopProgressDialog(self)
        self.progressDialog.userCancel.connect(self.stopSomething)
        # ...

    def stopSomething(self):
        self.progressDialog.setCancelButtonText('Please wait')
        # do something...
Другие вопросы по тегам