- es.davy.ai/
- Programación /
- Se trata de la interacción entre la señal editingFinished del QLineEdit y la pulsación de un botón.
Se trata de la interacción entre la señal editingFinished del QLineEdit y la pulsación de un botón.
Tengo un QLineEdit
en un QDialog
con un QButtonBox
en el diálogo. La señal editingFinished
de QLineEdit
está conectada a una función. La función se llama si QLineEdit
pierde el enfoque, como se espera. Cuando se pierde el foco al presionar el botón Ok es donde me confundo. Mi manejador de señal se llama, como se espera, pero la señal accepted()
del botón Ok no se emite. ¿Por qué se pierde esta señal? En particular, si el cuadro de diálogo se ejecuta con exec()
, al presionar el botón OK cuando el foco está en mi QLineEdit
, no se termina el cuadro de diálogo, simplemente se invoca el controlador editingFinished
. Mi controlador llama a un QMessageBox
y esto es lo que parece estar rompiendo la señal accepted
. Si lo comento, entonces obtengo el comportamiento esperado.
¿Está la señal accepted()
de QMessageBox
interfiriendo con la señal de QButtonBox
? Si es así, ¿cuál es la forma correcta de manejar esto?
edición – Ejecute el código a continuación. Haga clic en el cuadro QLineEdit
, luego haga clic en Ok. Verá una ventana de mensaje. Haga clic en OK en la ventana de mensaje y volverá al cuadro de diálogo, con el botón Ok con enfoque e indicando el estado “abajo”. Verificando el botón con isDown()
devuelve falso, por lo que aparentemente no hace la transición al estado de abajo hasta que myHandler devuelve. Ahora comenta la línea msg_box.exec() y repita los pasos anteriores. Al hacer clic en el botón Ok, se cierra el cuadro de diálogo.
El comportamiento que busco es que la acción del botón Ok (accepted
) se ejecute después del retorno de myHandler(). Sé que puedo emitir
la señalaccepted
o rejected
desde myHandler, pero eso requiere comprobar qué botón se presionó. Creo que puedo saber eso comprobando el enfoque, pero espero que haya un enfoque más limpio. Y más generalmente, me pregunto qué está sucediendo con las señales que el botón presionado está emitiendo, pero que parecen estar perdidas o ser capturadas.
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(640, 480)
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
self.buttonBox.setGeometry(QtCore.QRect(10, 440, 621, 32))
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.lineEdit = QtWidgets.QLineEdit(Dialog)
self.lineEdit.setGeometry(QtCore.QRect(180, 180, 251, 31))
self.lineEdit.setObjectName("lineEdit")
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept)
self.buttonBox.rejected.connect(Dialog.reject)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
class MyDialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent= None):
QtWidgets.QDialog.__init__(self)
self.setupUi(self)
self.lineEdit.editingFinished.connect(self.myHandler)
def myHandler(self):
print("My handler called")
msg_box = QtWidgets.QMessageBox()
msg_box.setText("Your Message here")
msg_box.exec()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
myapp = MyDialog()
myapp.show()
sys.exit(app.exec())
Answer
Comments are closed.
davy.ai
El problema aquí es que el
QMessageBox
invocado enmyHandler
está bloqueando el ciclo de eventos y no permite que la señalaccepted()
del botónOk
se emita hasta que se cierre el cuadro de diálogo. Esto lleva a un comportamiento inesperado cuando se ejecuta elQDialog
.Una forma de manejar esto es usar la clase
QTimer
para retrasar la ejecución del cuadro de diálogo hasta que se haya emitido la señalaccepted()
. Esto se puede hacer modificando la funciónmyHandler
de la siguiente manera:Esta versión modificada de
myHandler
primero llama aQtWidgets.QApplication.processEvents()
para procesar cualquier evento pendiente y permitir que se emita la señalaccepted()
. Luego, usaQtCore.QTimer.singleShot()
para retrasar la invocación de la funciónshowMessage
hasta después de que se haya emitido la señal.showMessage
luego crea y muestra el cuadro de diálogo como antes.Este enfoque evita la necesidad de probar qué botón se presionó y permite una ejecución más limpia del código.
En general, es importante ser consciente de la obstrucción del ciclo de eventos en las aplicaciones de PyQt5 para evitar comportamientos inesperados. La clase
QTimer
puede ser una herramienta útil para retrasar la ejecución y evitar la obstrucción.