Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello โ I'm @olemoritz on Twitter.
Is it possible to Limit the decimals of a float?
-
I need to be able to prevent the user from putting more than 2 decimals on an input, which gets turned into a float. Is there any way to limit the input?
Thanks!
-
@RocketBlaster05 if you use an ui.TextField for introduction of the number, you could use delegate methods.
-
@cvp would you be able to link me to a good example of delegates? I've never used them before. Thanks!
-
@RocketBlaster05 see this topic
-
@RocketBlaster05 try this quick and dirty script to better understand
import ui class MyTextFieldDelegate (object): def textfield_should_change(self, textfield, range_c, replacement): # Build field value if replacement would be accepted fld = textfield.text #print(fld, range_c, replacement) if replacement == '': # Backspace or cut to remove textfield[range[0]to[range[1]-1] new = fld[:range_c[0]]+fld[range_c[1]:] else: # replacement could even be more than 1 character if paste new = fld[:range_c[0]]+replacement+fld[range_c[0]:] i = new.find('.') l = len(new.rstrip()) if i < (l-3): return False return True tf = ui.TextField() tf.frame = (0,0,200,30) tf.delegate = MyTextFieldDelegate() tf.placeholder = 'type your number here' tf.present('sheet')
-
@cvp oh ok nevermind sorry it looks like I don't need a delegate. I can just use round() and it rounds it to 2 decimal places. Sorry for the inconvenience but I appreciate your help nonetheless. Thanks!
-
@RocketBlaster05 ok but that does not prohibit user to introduce more than 2 decimals... even if the effect is The same. Keep topic for when you will need delegate, and you will need it ๐
-
@cvp I will keep this in mind. Thanks!
-
@cvp looks like I might be using delegate soon... for some reason round() is glitching and... well, not rounding properly. It is giving me .9999999999 when I stress test it with long decimals
-
@RocketBlaster05 sorry, no idea
-
@RocketBlaster05, look at
decimal.Decimal
, it handles decimal (duh) numbers sanely. -
@cvp I have it applied to a text field in a presented ui. The sample you showed works but not when I implement it as such:
class MyTextFieldDelegate (object): def textfield_should_change(self, textfield, range_c, replacement): # Build field value if replacement would be accepted fld = textfield.text #print(fld, range_c, replacement) if replacement == '': # Backspace or cut to remove textfield[range[0]to[range[1]-1] new = fld[:range_c[0]]+fld[range_c[1]:] else: # replacement could even be more than 1 character if paste new = fld[:range_c[0]]+replacement+fld[range_c[0]:] i = new.find('.') l = len(new.rstrip()) if i < (l-3): return False return True tf = ui.load_view('GlassInput')['textview1'] tf.delegate = MyTextFieldDelegate() #No errors pop up but delegate doesnโt work when view is presented elsewhere
-
@RocketBlaster05 said: incorrect
tf = ui.load_view('GlassInput')['textview1']
try
v = ui.load_view('GlassInput') tf = v['textview1']
-
@RocketBlaster05 use ร TextField instead of a TextView
-
@cvp this is all my code for the process Iโm trying to complete. Iโve done all you have said yet it doesnโt work. Everything gets properly presented but the delegate just isnโt applied:
def text_entered_glass(sender): global userinput userinput = sender.text try: input = float(userinput) roundedinput = round(input, 2) if roundedinput <= 10 and roundedinput >= 0: global gltot gltot += roundedinput v.name = str(gltot) with open(fil3,mode='wt') as f: f.write(str(gltot)) m.changetotals() print (gltot) nav.close() else: ui.load_view('GlassError').present('sheet') except ValueError: ui.load_view('GlassError').present('sheet') class MyTextFieldDelegate (object): def textfield_should_change(self, textfield, range_c, replacement): # Build field value if replacement would be accepted fld = textfield.text #print(fld, range_c, replacement) if replacement == '': # Backspace or cut to remove textfield[range[0]to[range[1]-1] new = fld[:range_c[0]]+fld[range_c[1]:] else: # replacement could even be more than 1 character if paste new = fld[:range_c[0]]+replacement+fld[range_c[0]:] i = new.find('.') l = len(new.rstrip()) if i < (l-3): return False return True gi = ui.load_view('GlassInput') tf = gi['textfield1'] tf.delegate = MyTextFieldDelegate() ```
-
@RocketBlaster05 I see that the input field is named TextField1 but is it a TextField or a TextView?
And where do you present the view named gi ?
Do you use twice ui.load_view('GlassInput')?
Perhaps, could it be better if you post your entire code...
-
@cvp alright but this is might be a wild ride:
class Menu(ui.View): # Main Menu setup def __init__(self): ui.View.__init__(self) self.scene_view = scene.SceneView() self.present(hide_title_bar=True) self.scene_view.frame = self.bounds self.scene_view.bg_color = '#4fb357' self.add_subview(self.scene_view) self.mm = ui.load_view('MainMenu') self.mm['imageview1'].image = ui.Image('companylogo.PNG') self.changetotals() self.mm.present('fullscreen', hide_title_bar=True) def changetotals(self): #just updates stats below if os.path.exists(fil): with open(fil,mode='rt') as f: global wbtot wbtot = int(f.read()) else: wbtot = 0 if os.path.exists(fil2): with open(fil2,mode='rt') as f: global cbbtot cbbtot = int(f.read()) else: cbbtot = 0 if os.path.exists(fil3): with open(fil3,mode='rt') as f: global gltot gltot = float(f.read()) else: gltot = 0 if os.path.exists(fil4): with open(fil4,mode='rt') as f: global paptot paptot = float(f.read()) else: paptot = 0 self.mm['textview1'].text = 'Water Bottles Recyled: ' + str(wbtot) self.mm['textview2'].text = 'Cardboard Boxes Recycled: ' + str(cbbtot) self.mm['textview3'].text = 'Glass Recycled: ' + str(gltot) + ' lbs' self.mm['textview4'].text = 'Paper Recycled: ' + str(paptot) + ' lbs' def glass_pressed(Glass): # ui button on main menu global v v = ui.load_view('GlassInput') rm.update_menus(nam='View4', col='#4fb357') # changes a navigation view tab to open glass input page; possible source of error class MyTextFieldDelegate (object): # The delegate script def textfield_should_change(self, textfield, range_c, replacement): # Build field value if replacement would be accepted fld = textfield.text #print(fld, range_c, replacement) if replacement == '': # Backspace or cut to remove textfield[range[0]to[range[1]-1] new = fld[:range_c[0]]+fld[range_c[1]:] else: # replacement could even be more than 1 character if paste new = fld[:range_c[0]]+replacement+fld[range_c[0]:] i = new.find('.') l = len(new.rstrip()) if i < (l-3): return False return True def text_entered_glass(sender): # Textfield input process global userinput userinput = sender.text try: input = float(userinput) roundedinput = round(input, 2) if roundedinput <= 10 and roundedinput >= 0: global gltot gltot += roundedinput v.name = str(gltot) with open(fil3,mode='wt') as f: f.write(str(gltot)) m.changetotals() print (gltot) nav.close() else: ui.load_view('GlassError').present('sheet') except ValueError: ui.load_view('GlassError').present('sheet') v = ui.load_view('GlassInput') #attempt at setting delegate tf = v['textfield1'] tf.delegate = MyTextFieldDelegate() class RecycleMenu(): # Navigation menu setup mentioned earlier def __init__(self): self.background_color = '#4fb357' self.start_NavView() def start_NavView(self): self.view = ui.load_view('RecycleMenuOptions') self.view.name='Home' global nav nav = ui.NavigationView(self.view) nav.present(hide_title_bar=True) def update_menus(self, nam=None, col=None): v.name = nam v.background_color = col nav.push_view(v)
-
@RocketBlaster05 it is what I thought, you have twice your view...
Move the tf = after the first onedef glass_pressed(Glass): # ui button on main menu global v v = ui.load_view('GlassInput') tf = v['textfield1'] tf.delegate = MyTextFieldDelegate() rm.update_menus(nam='View4', col='#4fb357') # changes a navigation view tab to open glass input page; possible source of error
Then remove the second one
#v = ui.load_view('GlassInput') #attempt at setting delegate #tf = v['textfield1'] #tf.delegate = MyTextFieldDelegate()
You also would need to move the class MyTextFieldDelegate before the def glass_pressed.
Please, try these modifications and tell me....
-
@cvp YES YES YES YES YES!!!!!!! Thank you so much it is finally working as planned!
-