0

BoundedNumericProperty, in fact any Property, can have an errorhandler at creation to deal with invalid values:

class MyCl(EventDispatcher):
    # returns the boundary value when exceeded
    bnp = BoundedNumericProperty(0, min=-500, max=500,
        errorhandler=lambda x: 500 if x > 500 else -500)

I tried to change the errorhandler property at runtime, in a method of MyCl:

def set_err(self, new_err):
    self.property('bnp').errorhandler = lambda x: new_err

but to my surprise, I get

AttributeError: "'kivy.properties.BoundedNumericProperty' object has no attribute 'errorhandler'"

So, how do I change the errorhandler after creation of the property?

zeeMonkeez
  • 5,057
  • 3
  • 33
  • 56
  • @wolfsgang `value` was a mistake; I corrected it to `bnp`. `self.property('bnp')` returns the `BoundedNumericProperty`. Indeed it turns out the attribute cannot be accessed like this, but I don't understand why, or how else to do that. – zeeMonkeez Feb 20 '16 at 21:27
  • FWIW, I came across [this discussion about the `bounds` property](https://www.bountysource.com/issues/30092659-bounds-property-of-boundednumericproperty-is-not-updated-after-set_min-set_max) which kind of does something similar. I guess currently there is no way around the fact that errorhandler does not deal with individual objects' min/max settings – zeeMonkeez Feb 20 '16 at 21:32

1 Answers1

3

Properties are implemended in Cython and they don't expose their internal attributes outside of defaultvalue. Looks like the only way to set this handler is through the __init__ method. Let's do it. Since __init__ isn't a construcor (__new__ is) but an initializer and it doesn't create a new instance, we can just call it multiple times:

#!/usr/bin/kivy

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import NumericProperty
from kivy.properties import BoundedNumericProperty

Builder.load_string('''
<MyWidget>:
    Button:
        text: "Set error handler"
        on_press: root.set_error_handler()
    Button:
        text: "Test"
        on_press: root.bnp = 10000
''')

class MyWidget(BoxLayout):
    bnp = BoundedNumericProperty(0, min=-500, max=500)

    def error_handler(self, *args):
        print("error_handler")
        return 0   

    def set_error_handler(self):
        # we need to add default value as the first argument
        self.property('bnp').__init__(0, errorhandler=self.error_handler)

class MainApp(App):
    def build(self):
        return MyWidget()

if __name__ == '__main__':
    MainApp().run()

Of course this will erase previous initialization options. Look at property's __init__ method to see what will be changed.

Community
  • 1
  • 1
Nykakin
  • 8,657
  • 2
  • 29
  • 42
  • Thanks for your answer. It does work, however it really just shows the (IMHO) flaws of the current implementation of `BoundedNumericProperty` in kivy. Being able to change the min/max on a per-instance basis without being able to do error handling on a per-instance basis doesn't make sense (I'm aware of the workaround by redefining `bounds`, but that comes with its own issues). Of course for things like `StringProperty` it doesn't matter (unless there are different ideas of what is a string). – zeeMonkeez Feb 21 '16 at 03:30