From 9cf729a676a6bf7661af40388620112ddb4d689d Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sun, 21 Feb 2021 14:27:01 +0800 Subject: [PATCH] bugfix --- kivyblocks/bgcolorbehavior.py | 2 + kivyblocks/dataloader.py | 127 ++++++++++++++++++++++++++----- kivyblocks/form.py | 82 ++++++++++++++------ kivyblocks/widgetExt/inputext.py | 64 +++++++--------- 4 files changed, 199 insertions(+), 76 deletions(-) diff --git a/kivyblocks/bgcolorbehavior.py b/kivyblocks/bgcolorbehavior.py index 8fd1881..64cc593 100644 --- a/kivyblocks/bgcolorbehavior.py +++ b/kivyblocks/bgcolorbehavior.py @@ -9,6 +9,7 @@ class BGColorBehavior(object): if color_level==-1: color_level = 0 self.color_level = color_level + self.bg_ready = False self.radius = radius self.bgcolor = [] self.fgcolor = [] @@ -36,6 +37,7 @@ class BGColorBehavior(object): def on_bgcolor(self,o=None,v=None): if self.bgcolor == []: return + if self.canvas: with self.canvas.before: Color(*self.bgcolor) diff --git a/kivyblocks/dataloader.py b/kivyblocks/dataloader.py index b102582..0d7aa13 100644 --- a/kivyblocks/dataloader.py +++ b/kivyblocks/dataloader.py @@ -4,6 +4,98 @@ from .threadcall import HttpClient from .utils import absurl from appPublic.registerfunction import RegisterFunction +class DataGraber(EventDispatcher): + """ + Graber format + { + "widgettype":"DataGraber", + "options":{ + "dataurl":"first", + "datarfname":"second", + "target":"third", + "params": + "method": + "pagging":"default false" + } + } + if dataurl present, the DataGraber using this dataurl to get and + return data + else if datarfname present, it find a registered function named + by 'datarfname' to return data + else if datatarget present, it find the widget and uses target + method(default is 'getValue') to return data + else it return None + """ + def __init__(self, **kw): + super().__init__() + self.options = kw + self.register_event_type('on_success') + self.register_event_type('on_error') + + def load(self, *args, **kw): + dataurl = self.options.get('dataurl') + if dataurl: + return self.loadUrlData(*args, **kw) + + rfname = self.options.get('datarfname') + if rfname: + return self.loadRFData(*args, **kw) + + target = self.options.get('datatarget') + if target: + return self.loadTargetData(*args, **kw) + return None + + def loadUrlData(self, *args, **kw): + dataurl = self.options.get('dataurl') + hc = HttpClient() + params = self.options.get('params',{}).copy() + params.update(kw) + method = self.options.get('method','GET') + d = hc.get(dataurl, params=params,method=method) + return d + + def loadRFData(self, *args, **kw): + rfname = self.options.get('datarfname') + rf = RegisterFunction() + f = rf.get(rfname) + if not f: + return None + params = self.options.get('params',{}).copy() + params.update(kw) + try: + d = f(**params) + return d + except Exception as e: + Logger.info('blocks : Exception:%s',e) + print_exc() + return None + + def loadTargetData(self, *args, **kw): + target = self.options.get('datatarget') + w = Factory.Blocks.getWidgetById(target) + if not w: + return None + params = self.options.get('params',{}).copy() + params.update(kw) + method = params.get('method', 'getValue') + if not has(w, method): + return None + try: + f = getattr(w, method) + d = f() + return d + except Exception as e: + Logger.info('blocks : Exception %s', e) + print_exc() + return None + + def on_success(self,d): + pass + + def on_error(self,e): + pass + class DataLoader(EventDispatcher): def __init__(self,data_user): self.data_user = data_user @@ -11,12 +103,6 @@ class DataLoader(EventDispatcher): self.register_event_type('on_success') self.register_event_type('on_error') - def success(self,o,d): - self.dispatch('on_success',d) - - def error(self,o,e): - self.dispatch('on_error',e) - def on_success(self,d): pass @@ -27,7 +113,7 @@ class DataLoader(EventDispatcher): pass class HttpDataLoader(DataLoader): - def load(self): + def load(self, *args, **kw): url = absurl(self.data_user.url,self.data_user.target.parenturl) method = self.data_user.method params = self.data_user.params.copy() @@ -36,14 +122,16 @@ class HttpDataLoader(DataLoader): "rows":self.data_user.page_rows }) hc = HttpClient() - hc(url, - method=method, - params=params, - callback=self.success, - errback=self.error) + try: + r = hc(url, method=method, params=params) + self.dispatch('on_success', r) + return r + except Exception as e: + self.dispatch('on_error', e) + class ListDataLoader(DataLoader): - def load(self): + def load(self, *args, **kw): p = self.data_user.curpage r = self.data_user.page_rows try: @@ -52,12 +140,13 @@ class ListDataLoader(DataLoader): "total":len(self.data_user.data), "rows":s } - self.success(self,d) + self.dispatch('on_success', d) + return d except Exception as e: - self.error(self,e) + self.dispatch('on_error', e) class RegisterFunctionDataLoader(DataLoader): - def load(self): + def load(self, *args, **kw): rf = RegisterFunction() try: rfname = self.data_user.rfname @@ -70,7 +159,9 @@ class RegisterFunctionDataLoader(DataLoader): "rows":self.data_user.page_rows }) s = func(**params) - self.success(self,s) + self.dispatch('on_success', s) + return s except Exception as e: - self.error(self,e) + self.dispatch('on_error', e) + diff --git a/kivyblocks/form.py b/kivyblocks/form.py index dc9c8f0..f7fd258 100644 --- a/kivyblocks/form.py +++ b/kivyblocks/form.py @@ -14,6 +14,8 @@ from .i18n import I18n from .toolbar import Toolbar from .color_definitions import getColors from .bgcolorbehavior import BGColorBehavior +from .dataloader import DataGraber +from .ready import WidgetReady """ form options @@ -94,11 +96,11 @@ uitypes = { "wclass":SelectInput, }, "text":{ - "orientation":"vertical", + "orientation":"horizontal", "wclass":StrInput, "options":{ "multiline":True, - "height":9, + "height":4, } }, "teleno":{ @@ -114,11 +116,16 @@ class InputBox(BoxLayout): def __init__(self, form, **options): self.form = form self.options = options - self.uitype = options.get('uitype','string') + self.uitype = options.get('uitype',options.get('datatype','string')) self.uidef = uitypes[self.uitype] orientation = self.uidef['orientation'] width = self.form.inputwidth height = self.form.inputheight + if self.uitype == 'text': + if not options.get('height'): + self.options['height'] = 4 + height = self.options.get('height',4) + self.labelwidth = self.form.options['labelwidth'] kwargs = { "orientation":orientation, @@ -138,7 +145,6 @@ class InputBox(BoxLayout): self.bind(size=self.setSize, pos=self.setSize) self.register_event_type("on_datainput") - self.register_event_type("on_ready") def on_datainput(self,o,v=None): print('on_datainput fired ...',o,v) @@ -150,7 +156,7 @@ class InputBox(BoxLayout): opts = { "orientation":"horizontal", "size_hint_y":None, - "height":CSize(3) + "height":CSize(2) } if self.labelwidth<=1: opts['size_hint_x'] = self.labelwidth @@ -166,10 +172,6 @@ class InputBox(BoxLayout): "i18n":True, "text":label, "font_size":CSize(1), - "size_hint_x":None, - "width":CSize(len(label)), - "size_hint_y":None, - "height":CSize(3) } self.labeltext = Text(**kwargs) bl.add_widget(self.labeltext) @@ -184,11 +186,12 @@ class InputBox(BoxLayout): options = self.uidef.get('options',{}).copy() options.update(self.options.get('uiparams',{})) options['allow_copy'] = True - options['width'] = options.get('width',20) + options['width'] = options.get('width',1) options['height'] = options.get('height',1) - if self.options.get('tip'): - options['hint_text'] = i18n(self.options.get('tip')) + if self.options.get('hint_text'): + options['hint_text'] = i18n(self.options.get('hint_text')) + Logger.info('Form: uitype=%s', self.uitype) self.input_widget = self.uidef['wclass'](**options) if self.options.get('readonly'): self.input_widget.disabled = True @@ -201,8 +204,7 @@ class InputBox(BoxLayout): self.add_widget(self.input_widget) self.initflag = True self.input_widget.bind(on_focus=self.on_focus) - self.dispatch('on_ready', self) - + def check(self): d = self.getValue() v = d.get(self.options.get('name')) @@ -214,9 +216,6 @@ class InputBox(BoxLayout): return True - def on_ready(self, obj): - Logger.info('kivyblocks: Form input ready') - def clear(self): self.input_widget.setValue('') @@ -244,8 +243,8 @@ class InputBox(BoxLayout): def defaultToolbar(): return { - "img_size":2, - "text_size":1, + "img_size":1.5, + "text_size":0.7, "tools":[ { "name":"__submit", @@ -261,7 +260,7 @@ def defaultToolbar(): } -class Form(BGColorBehavior, BoxLayout): +class Form(BGColorBehavior, WidgetReady, BoxLayout): def __init__(self, **options): self.options = options BoxLayout.__init__(self, orientation='vertical') @@ -269,6 +268,7 @@ class Form(BGColorBehavior, BoxLayout): BGColorBehavior.__init__(self, color_level=self.options.get('color_level',-1), radius=self.options.get('radius',[])) + WidgetReady.__init__(self) self.readiedInput = 0 self.cols = self.options_cols = self.options.get('cols',1) if isHandHold() and Window.width < Window.height: @@ -282,7 +282,28 @@ class Form(BGColorBehavior, BoxLayout): pass def init(self): - self.toolbar = Toolbar(**self.options.get('toolbar',defaultToolbar())) + desc = defaultToolbar() + desc1 = self.options.get('toolbar') + if desc1: + tools = desc['tools'] + desc1['tools'] + desc1['tools'] = tools + desc = desc1 + if self.options.get('submit'): + kw = self.options.get('submit').copy() + if kw.get('name'): + del kw['name'] + for t in desc['tools']: + if t['name'] == '__submit': + t.update(kw) + if self.options.get('clear'): + kw = self.options.get('clear').copy() + if kw.get('name'): + del kw['name'] + for t in desc['tools']: + if t['name'] == '__clear': + t.update(kw) + + self.toolbar = Toolbar(**desc) self.fsc = VResponsiveLayout( self.inputwidth, self.cols @@ -299,7 +320,12 @@ class Form(BGColorBehavior, BoxLayout): wid.bind(on_press=self.on_submit_button) wid = Factory.Blocks.getWidgetById('__clear',from_widget=self) wid.bind(on_press=self.on_clear_button) - + if self.options.get('dataloader'): + self.dataloader = DataGraber(**self.options['dataloader']) + d = self.dataloader.load() + if d: + self.setValue(d) + def makeInputLink(self,o,v=None): self.readiedInput += 1 if self.readiedInput >= len(self.options['fields']): @@ -309,6 +335,12 @@ class Form(BGColorBehavior, BoxLayout): w.input_widget.focus_previous = p.input_widget p = w + def setValue(self,d): + for f in self.fieldWidgets: + v = f.getValue() + for k in v.keys(): + f.setValue({k:d[k]}) + def getValue(self): d = {} for f in self.fieldWidgets: @@ -367,6 +399,12 @@ class StrSearchForm(BoxLayout): } return d + def setValue(self, d): + if isinstance(d,str): + self.input_widget.text = d + if isinstance(d,{}): + self.input_widget.text = d.get(self.name,'') + def submit_input(self,o,v=None): text = self.input_widget.text if text != '': diff --git a/kivyblocks/widgetExt/inputext.py b/kivyblocks/widgetExt/inputext.py index a105d45..e8b1b17 100755 --- a/kivyblocks/widgetExt/inputext.py +++ b/kivyblocks/widgetExt/inputext.py @@ -15,7 +15,6 @@ from ..threadcall import HttpClient from ..utils import CSize class BoolInput(Switch): - change = BooleanProperty(False) def __init__(self,**kw): a = DictObject() if kw.get('defaultvalue',None) is None: @@ -25,7 +24,7 @@ class BoolInput(Switch): if kw.get('value',None) is not None: a.active = kw.get('value') - super().__init__(**a) + super().__init__(**a.to_dict()) self.register_event_type('on_changed') self.bind(active=on_active) @@ -52,11 +51,9 @@ class StrInput(TextInput): "halign":"left", "hint_text":"", } - if kv.get('tip'): - a['hint_text'] = kv['tip'] - # a.update(kv) - w = kv.get('width',20) - h = kv.get('height',2.5) + a.update(kv) + w = kv.get('width',1) + h = kv.get('height',1) if w <= 1: a['size_hint_x'] = w else: @@ -67,9 +64,7 @@ class StrInput(TextInput): else: a['size_hint_y'] = None a['height'] = CSize(h) - a['font_size'] = CSize(kv.get('font_size',1)) - a['password'] = kv.get('password',False) - a['multiline'] = kv.get('multiline',False) + a['font_size'] = CSize(kv.get('font_size',0.9)) Logger.info('TextInput:a=%s,kv=%s',a,kv) super(StrInput,self).__init__(**a) @@ -107,6 +102,7 @@ class Password(StrInput): class IntegerInput(StrInput): def __init__(self,**kw): + print("IntegerInput(), __init__()....") a = {} a.update(kw) a['halign'] = 'right' @@ -114,6 +110,7 @@ class IntegerInput(StrInput): pat = re.compile('[^0-9]') def insert_text(self, substring, from_undo=False): + print('TTTTTTTTTTTTTTTTTTTTTTttt') pat = self.pat s = re.sub(pat, '', substring) return StrInput.insert_text(self,s, from_undo=from_undo) @@ -125,6 +122,7 @@ class IntegerInput(StrInput): class FloatInput(IntegerInput): pat = re.compile('[^0-9]') def filter(self,substring): + print('FloatInput(), filter():..........') pat = self.pat if '.' in self.text: s = re.sub(pat, '', substring) @@ -169,7 +167,8 @@ class MyDropDown(DropDown): self.setDataByUrl(self.url) else: self.si_data = self.options.get('data') - self.setData(self.si_data) + if self.si_data: + self.setData(self.si_data) self.bind(on_select=lambda instance, x: self.selectfunc(x)) def selectfunc(self,v): @@ -192,38 +191,29 @@ class MyDropDown(DropDown): def setData(self,data): self.si_data = data self.clear_widgets() - w = self.options.get('width',10) h = self.options.get('height',2.5) a = {} - if w <= 1: - a['size_hint_x'] = w - else: - a['size_hint_x'] = None - a['width'] = CSize(w) - if h <= 1: - a['size_hint_y'] = h - else: - a['size_hint_y'] = None - a['height'] = CSize(h) + a['size_hint_y'] = None + a['height'] = CSize(h) a['font_size'] = CSize(self.options.get('font_size',1)) + print('data=',data) for d in data: dd = (d[self.valueField],d[self.textField]) b = Button(text=d[self.textField],**a) setattr(b,'kw_data',dd) b.bind(on_release=lambda btn: self.select(btn.kw_data)) self.add_widget(b) - #print(dd) + print('setData():',dd) - def setDataByUrl(self,url,params={}): - def x(obj,d): - self.setData(d) - - app = App.get_running_app() - app.hc.get(url,params=params,callback=x) - + def setDataByUrl(self,url,kw={}): + hc = HttpClient() + params = self.options.get('params', {}).copy() + params.update(kw) + d = hc.get(url,params=params) + self.setData(d) def showme(self,w): - #print('show it ',w) + print('show it ',w) self.target = w self.open(w) @@ -231,7 +221,7 @@ class SelectInput(BoxLayout): def __init__(self,**kw): a={} w = kw.get('width',10) - h = kw.get('height',2.5) + h = kw.get('height',1.5) if w <= 1: a['size_hint_x'] = w else: @@ -245,11 +235,13 @@ class SelectInput(BoxLayout): super(SelectInput,self).__init__(orientation='horizontal',\ **a) - self.tinp = StrInput(size_hint_y=None,height=kw.get('height',2.5)) + self.si_value = '' + self.tinp = StrInput() self.tinp.readonly = True newkw = {} newkw.update(kw) newkw.update({'on_select':self.setData}) + print('selectinput:kw=', newkw) self.dropdown = MyDropDown(**newkw) if kw.get('value'): self.si_data = kw.get('value') @@ -273,18 +265,18 @@ class SelectInput(BoxLayout): self.old_value = self.getValue() def setData(self,d): - self.tinp.si_data = d[0] + self.si_value = d[0] self.tinp.text = d[1] v = self.getValue() if v != self.old_value: self.dispatch('on_changed',v) def setValue(self,v): - self.tinp.si_value = v + self.si_value = v self.tinp.text = self.dropdown.getTextByValue(v) def getValue(self): - return self.tinp.si_value + return self.si_value if __name__ == '__main__': from kivy.app import App