Issue
I want to make a QDoubleSpinBox
controllable via the arrow keys, i.e. increase the value when pressing up and decrease it when pressing down while the box is selected. I currently do this by setting singleStep
to a certain value. However, I would like to be able to change the value of singleStep
depending on the cursor position when editing the field.
For example for a box with two decimals, 1.23
, if the cursor |
is at the first decimal 1.2|3
I want to increase or decrease by 0.1
but if the cursor is at the second decimal 1.23|
I only want to increase/decrease by 0.01.
Note: Not sure if relevant, but I currently have keyboardTracking
set to False
to avoid signal emission while editing the value by typing it in via the number keys. The values are still emitted when using the error keys.
Solution
Following aavit's answer I did also redefine stepBy
within PyQt. Since I am looking for a solution that works for floats and negative values, I had to handle some special cases and I display the + sign for positive values by redefining textFromValue
. Special cases are commented in the solution below:
import sys
from PyQt5.QtWidgets import QDoubleSpinBox, QMainWindow, QApplication, QLabel
class MyQDoubleSpinBox(QDoubleSpinBox):
def textFromValue(self, value):
# show + sign for positive values
text = super().textFromValue(value)
if value >= 0:
text = "+" + text
return text
def stepBy(self, steps):
cursor_position = self.lineEdit().cursorPosition()
# number of characters before the decimal separator including +/- sign
n_chars_before_sep = len(str(abs(int(self.value())))) + 1
if cursor_position == 0:
# set the cursor right of the +/- sign
self.lineEdit().setCursorPosition(1)
cursor_position = self.lineEdit().cursorPosition()
single_step = 10 ** (n_chars_before_sep - cursor_position)
# Handle decimal separator. Step should be 0.1 if cursor is at `1.|23` or
# `1.2|3`.
if cursor_position >= n_chars_before_sep + 2:
single_step = 10 * single_step
# Change single step and perform the step
self.setSingleStep(single_step)
super().stepBy(steps)
# Undo selection of the whole text.
self.lineEdit().deselect()
# Handle cases where the number of characters before the decimal separator
# changes. Step size should remain the same.
new_n_chars_before_sep = len(str(abs(int(self.value())))) + 1
if new_n_chars_before_sep < n_chars_before_sep:
cursor_position -= 1
elif new_n_chars_before_sep > n_chars_before_sep:
cursor_position += 1
self.lineEdit().setCursorPosition(cursor_position)
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 600, 400)
self.UiComponents()
self.show()
def UiComponents(self):
self.spin = MyQDoubleSpinBox(self)
self.spin.setGeometry(100, 100, 150, 40)
self.spin.setRange(-10000, 10000)
self.spin.setValue(50)
self.spin.setKeyboardTracking(False)
if __name__ == "__main__":
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
Answered By - frankundfrei
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.