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())


