PyQt QLineEdit with QValidator - python

I have a QLineEdit in my project.
I want to use the QValidation on lineEdit.
#Create lineEdit
itemValue = QtWidgets.QLineEdit()
#Create валидатор
objValidator = QtGui.QDoubleValidator(self)
#setup range
objValidator.setRange(-10.0, 100.0, 5)
#lineEdit with validation
itemValue.setValidator(objValidator)
But it doesn't work well.I can type what i want, except symbols.
And range doesn't work!I can type 100500 or -100500, but i want, that user can enter numbers only in range.
How i should use range?
I need help:)
Thanks for your help, guys!

By default, a validator will not prevent values outside the range from being entered, and it won't prevent the user leaving the line-edit if the entered value is Invalid or Intermediate.
However, it does give you an opportunity to reject the input programmatically, because whenever the current value is unacceptable, the line-edit won't emit its editingFinished or returnPressed signals, and its hasAcceptableInput method will return False. In addition, if you subclass the validator, you can reimplement its fixup method to control the values that are entered.
However, as has been suggested already, a far better/simpler solution is to use a QDoubleSpinBox, since it cleans up the input automatically and provides a more user-friendly interface.

As an alternative you could use a QDoubleSpinBox.
has validator build in
prevents invalid input while typing
has build-in setRange()
and adds a little handle to change the value for more mouse oriented users.

Probably you are expecting something what should not happen.
In general when you have validator you should be able to type something in intermediate state what doesn't exactly meet limitation. But this should be fixed, when editor looses focus.
Why? Imagine you have 84 an you want correct this to -8.4. Many people will do this like that: add minus so now you have -84 which is not acceptable then add dot. If validator fixes this immediately it would be annoying for user.
So bottom line does this "problem" happen when editor looses focus?

Related

Make a number restricted QLineEdit box amend to two decimal places when focus is lost? [duplicate]

I have a QLineEdit in my project.
I want to use the QValidation on lineEdit.
#Create lineEdit
itemValue = QtWidgets.QLineEdit()
#Create валидатор
objValidator = QtGui.QDoubleValidator(self)
#setup range
objValidator.setRange(-10.0, 100.0, 5)
#lineEdit with validation
itemValue.setValidator(objValidator)
But it doesn't work well.I can type what i want, except symbols.
And range doesn't work!I can type 100500 or -100500, but i want, that user can enter numbers only in range.
How i should use range?
I need help:)
Thanks for your help, guys!
By default, a validator will not prevent values outside the range from being entered, and it won't prevent the user leaving the line-edit if the entered value is Invalid or Intermediate.
However, it does give you an opportunity to reject the input programmatically, because whenever the current value is unacceptable, the line-edit won't emit its editingFinished or returnPressed signals, and its hasAcceptableInput method will return False. In addition, if you subclass the validator, you can reimplement its fixup method to control the values that are entered.
However, as has been suggested already, a far better/simpler solution is to use a QDoubleSpinBox, since it cleans up the input automatically and provides a more user-friendly interface.
As an alternative you could use a QDoubleSpinBox.
has validator build in
prevents invalid input while typing
has build-in setRange()
and adds a little handle to change the value for more mouse oriented users.
Probably you are expecting something what should not happen.
In general when you have validator you should be able to type something in intermediate state what doesn't exactly meet limitation. But this should be fixed, when editor looses focus.
Why? Imagine you have 84 an you want correct this to -8.4. Many people will do this like that: add minus so now you have -84 which is not acceptable then add dot. If validator fixes this immediately it would be annoying for user.
So bottom line does this "problem" happen when editor looses focus?

How to reset the QValidator to accept all input once some Validator is used

I have used the setValidator(QIntValidator) in PyQt. How to reset this Validator to accept all the inputs like it was before ? I want to dynamically handle the validation thats why ...
Due to Qt documentation:
If v == 0, setValidator() removes the current input validator
So, use setValidator(None).

wx: validate() controls in a container stops after first invalid

i am validating user input controls such as textboxes and dropdowns. The problem i have is, that the validation (the containers.Validate()) stops after finding the first invalid control. I expected it to validate all controls, before it returns. I want to display the user all invalid controls at once, not one by one. Is there a way to do so?
(using wx.WS_EX_VALIDATE_RECURSIVELY will propagate to the children, but only if no other control was invalid before)
Edit:
Instead of overwriting Validate() for every control, i decided to have a separate function, which iterates over all children and validates them.
Note: This function will not be called by default OnOK event. To do so, the event handler must be rebound.
def ValidateRecursively(control):
'''Validate this control and its children recursively'''
validator = control.GetValidator()
# no validator -> valid
isValid = validator.Validate(control) if validator else True
for childControl in control.GetChildren():
# only validate enabled controls
if childControl.IsEnabled():
isValid &= ValidateRecursively(childControl)
return isValid
To do this you would need to override Validate() in your dialog and iterate over all controls yourself without stopping at the first invalid one, like the base class implementation does.
Unfortunately you will probably need to duplicate the code here as there is no way to reuse it. On the bright side, you can use it almost as is with just changing the return false lines to remember the error instead and return it at the end.

TraitsUI TextEditor enter_set causes input to be rejected

I am trying to build a traitsui application. As part of this application, I listen to a float that the user inputs. The editor for this float by default is a TextEditor with auto_set on. However, when the user finishes inputting this number the program does a long computation, so it is really annoying when the program listens to the new trait 1 when the user really wanted to enter 1.7.
I tried to solve this problem with the enter_set attribute of the TextEditor factory. But, when I do this, it doesn't allow the trait to be updated at all and the box appears in red no matter what value is entered. This is clearly not how enter_set and auto_set are supposed to work. What am I doing wrong?
Here's my test code:
from traits.api import *
from traitsui.api import *
class FloatEditorClass(HasTraits):
f=Float
click=Button('clickme')
view=View(Item('f',editor=TextEditor(auto_set=False,enter_set=True)),
# removing one or the other of these settings doesn't change anything
Item(name='click'))
def _click_fired(self):
print self.f
fec=FloatEditorClass()
fec.configure_traits()
You can use CFloat instead of Float, which tries to transform the value you assign to the trait to float. If you try to assign a string to Float, it detects that the type is wrong.
For example:
class CFloatDemo(HasTraits):
f = Float
cf = CFloat
demo = CFloatDemo()
demo.f = '3.0' # This raises a TraitError
demo.cf = '3.0' # This assigns 3.0 to 'cf'
Update:
The other option is to tell the TextEditor how to map the string to the traits value:
traits_view=View(
Item('f', editor=TextEditor(auto_set=False,enter_set=True, evaluate=float)),
Item(name='click')
)
This is how the default editor for Float is set up by Traits UI.
Actually, I figured out what my own problem was, and while I would argue this is unavoidably a bug in the editor factory, I do have a fix.
The problem is that when you enter into a text editor, say the string '4', the editor interprets your string as precisely this, the string '4' and not the number. If you specify an Int trait and let it use its default editor, it must do something unseen to convert this string to an int (probably, it just specifies the function int() as the 'evaluate' attribute of the editor).
Instead, if you specify the editor yourself with the parameter fixes you are interested in, this fix is bypassed (which is a bug in TextEditor, or perhaps a bug of python itself if you argue that duck typing is inherently an error), so you have to supply the fix (e.g. the evaluate parameter) yourself. As an equivalent solution that is slightly easier in the general case, use the DefaultOverride factory instead which was created for this purpose.

Is it considered bad practice to use a widgets title attribute to refer to it?

Would it be considered bad practice to use a widgets title attribute to refer it?
For example I have a number of custom radioBoxCtrls on a panel
I only ever need to get/set all the values at once
so the container class(a panel) for the radioBoxCtrls objects has the following methods
get_options()
set_options()
To set options for all the radioBoxCtrls a dictionary is passed to the set_options() method.
Each key, value pair in the dictionary is a title of a radioBoxCtrl and the title of the button on the radioBoxCtrl that should be set
def set_options(self, options={}):
"""
This method sets which radio button is selected
on each RadioBoxCtrl object
#param options: A dictionary
Each key is the title of a RadioBoxCtrl
each keys value is the button on the radio box that is to be selected
"""
for option_box in self.option_boxes:
if option_box.title in options.keys()
option_box.set_selected_button(options[option_box.title])
def get_options(self):
"""
This method returns a dictionary of the selected options
Each key is the title of a RadioBoxCtrl object
and each keys value is the name of the button selected on the radio box
"""
options = defaultdict(list)
for option_box in self.option_boxes:
options[option_box.title]=option_box.get_selected_btn()
return options
So (in an attempt to be clear) when I call the set method from my controller
I pass in a dictionary like so:
options = {"Name of radioBoxCtrl": "Option 2", ... }
self.gui.optionsPanel.set_options(options)
Why the hell do you want do that? (you may ask)
Short answer: mvc
I want to create a suitable layer of abstraction. All that my controller needs to know with
regard to the options is how to get them to pass to the model when some processing needs to be done and how set them when a config file is loaded...
I thought it would simplify things if I could just call one method to set and vice-versa -but Im not so sure now!
I realize that this is probably more of question on the acceptability of refering to objects by some string attribute they posses, which in my case just happens to be the title.. so feel free to answer it accordingly..
Please feel free to improve the title of question(I wasnt really sure how to word it) and add tags.
Thanks
I can't tell whether the gurus would call it bad practive. I just know I'd never do it - it is slower, more error-prone, possibly makes it very hard to change a title's name (admittedly, only if you hardcode it everywhere) and (arguably) very inelegant. At least you should associate te options with the widget's identity, which still smells imho, but at least has a few problems less. Maybe that whole part of the application should be refactored to be less centralized so the issue disappears completely.
Edit on how to refactor: Honestly, I can't tell - I know little about the application. The obvious approach would be subclassing all widgets and making them responsible for somehow getting the options and changing accordingly. But I can't tell whether that's really feasible.

Categories

Resources