SpinBox с сигналом только по Enter
Задача: спинбокс должен принимать данные как текстовое поле (как QLineEdit
) либо изменением введённых данных стрелками.
Но отдавать должен только по Enter.
Встроенный метод valueChanged()
не подходит.
Метод editingFinished()
, взятый у QAbstractSpinBox
, лучше.
Но он отдаёт данные не только по Enter
, но и по смене фокуса - это неприемлемо.
Также есть метод setKeyboardTracking(False)
, который работает хорошо для ручного ввода, но при использовании стрелок сигнал всё равно реагирует по каждому нажатию, т.е. не подходит.
Также можно вспомнить, что QSpinBox
наследуется от QLineEdit
и применить my_spinbox.lineEdit().returnPressed.connect(...)
. Этот метод работает в песочнице, но в реальном проекте нет, не буду углубляться.
Также есть вот такая ссылка где предлагается несколько решений, одно из них я привожу ниже (оно тоже на базе my_spinbox.lineEdit().returnPressed...
, но там ещё и создание спинбокса в кастомном классе). В песочнице работает, в реальном проекте сигнал класса кастомного спинбокса не виден вообще, не понимаю почему.
Вопрос - что делать? Там по ссылке хорошие, вроде бы, решения типа отключения слота, но не пойму как их применить.
Update:
Проблема в том, что mySpinbox.lineEdit().returnPressed.connect()
определяет нажатие key_Return
(клавиша справа) как Enter
,
а нажатия самой key_Enter
не видит совсем.
В моём случае это неприемлемо. Я делал обычные спинбокс (определял в классе представления), делал отдельный класс с его кастомизацией, применял event()
и eventFilter()
.
Это и есть: 'Этот метод работает в песочнице, но в реальном проекте нет, не буду углубляться'.
from PySide6.QtWidgets import QWidget, QVBoxLayout, QApplication, QSpinBox
from PySide6.QtCore import Signal
import sys
class MySpinBox(QSpinBox):
valueHasChanged = Signal(int)
def __init__(self, object_name:str):
super().__init__()
self.setObjectName(object_name)
self.lineEdit().returnPressed.connect(self.spinBoxReturnPressed)
def spinBoxReturnPressed(self):
result = self.sender().text()
self.valueHasChanged.emit(result)
class MyClass(QWidget):
def __init__(self):
super().__init__()
self.resize(300,200)
self.sb1 = MySpinBox('_sb1_')
self.sb1.setRange(-1000, 1000)
self.sb1.valueHasChanged.connect(self.returnValue)
self.sb2 = MySpinBox('_sb2_')
self.sb2.setRange(-1000, 1000)
self.sb2.valueHasChanged.connect(self.returnValue)
vbox = QVBoxLayout()
vbox.addWidget(self.sb1)
vbox.addWidget(self.sb2)
self.setLayout(vbox)
def returnValue(self):
value = self.sender().text()
print(value, self.sender().objectName())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyClass()
window.show()
sys.exit(app.exec())
Ответы (1 шт):
Sorry, я не совсем понимаю, что у вас работает в песочнице, но в реальном проекте нет и почему.
Попробуйте мой пример и расскажите, что в нем не так.
'''
from PySide6.QtWidgets import QWidget, QVBoxLayout, \
QApplication, QSpinBox
from PySide6.QtCore import Signal
'''
import sys
from PyQt5.Qt import *
class MySpinBox(QSpinBox):
# --------------------------> vvv ?????? <----------------------
# valueHasChanged = Signal(int) # PySide6
# -----------------------------> vvv ++++++ <----------------------
valueHasChanged = pyqtSignal(str) # PyQt5
def __init__(self, object_name:str):
super().__init__()
self.setObjectName(object_name)
self.lineEdit().returnPressed.connect(self.spinBoxReturnPressed)
def spinBoxReturnPressed(self):
result = self.sender().text()
self.valueHasChanged.emit(result)
class MyClass(QWidget):
def __init__(self):
super().__init__()
self.resize(300,200)
self.sb1 = MySpinBox('_sb1_')
self.sb1.setRange(-1000, 1000)
self.sb1.valueHasChanged.connect(self.returnValue)
self.sb2 = MySpinBox('_sb2_')
self.sb2.setRange(-1000, 1000)
self.sb2.valueHasChanged.connect(self.returnValue)
vbox = QVBoxLayout(self)
vbox.addWidget(self.sb1)
vbox.addWidget(self.sb2)
def returnValue(self, value): # +++ , value
# ? value = self.sender().text()
print(f'Значенин={value}; объект={self.sender().objectName()};\n')
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
def event(self, event):
if event.type() == QEvent.KeyPress and event.key() in (
Qt.Key_Enter,
Qt.Key_Return,
):
self.focusNextPrevChild(True)
return super().event(event)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyClass()
window.show()
sys.exit(app.exec())
Update:
Проблема в том, что
mySpinbox.lineEdit().returnPressed.connect()
определяет нажатиеkey_Return
(клавиша справа) какEnter
, а нажатия самойkey_Enter
не видит совсем.
В моём случае это неприемлемо. Я делал обычные спинбокс (определял в классе представления), делал отдельный класс с его кастомизацией, применялevent()
иeventFilter()
.
Это и есть: 'Этот метод работает в песочнице, но в реальном проекте нет, не буду углубляться'.
Я не могу проверить то, что вы пишите:
"mySpinbox.lineEdit().returnPressed.connect()
определяет нажатие key_Return
(клавиша справа) как Enter
,
а нажатия самой key_Enter
не видит совсем."
Попробуйте другой вариант решения вашей задачи:
'''
from PySide6.QtWidgets import QWidget, QVBoxLayout, \
QApplication, QSpinBox
from PySide6.QtCore import Signal
'''
import sys
from PyQt5.Qt import *
class MySpinBox(QSpinBox):
# --------------------------> vvv +++ <---------------------------
# valueHasChanged = Signal(int, str) # PySide6
# -----------------------------> vvv +++ ++++++ <----------------- !!!
valueHasChanged = pyqtSignal(int, str) # PyQt5
def __init__(self, object_name:str):
super().__init__()
self.setObjectName(object_name)
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
def keyPressEvent(self, event):
if event.key() in (Qt.Key_Enter, Qt.Key_Return):
self.valueHasChanged.emit(self.value(), self.objectName())
super().keyPressEvent(event)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
class MyClass(QWidget):
def __init__(self):
super().__init__()
self.resize(300,200)
self.sb1 = MySpinBox('_sb1_')
self.sb1.setRange(-1000, 1000)
self.sb1.valueHasChanged.connect(self.returnValue)
self.sb2 = MySpinBox('_sb2_')
self.sb2.setRange(-1000, 1000)
self.sb2.valueHasChanged.connect(self.returnValue)
vbox = QVBoxLayout(self)
vbox.addWidget(self.sb1)
vbox.addWidget(self.sb2)
def returnValue(self, value, object): # +++ , value, object
# print(f'Значенин={value}; объект={self.sender().objectName()};\n')
print(f'Значенин={value}; объект={object};\n') # +++
def event(self, event):
if event.type() == QEvent.KeyPress and event.key() in (
Qt.Key_Enter,
Qt.Key_Return,
):
self.focusNextPrevChild(True)
return super().event(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyClass()
window.show()
sys.exit(app.exec())