This commit is contained in:
yumoqing 2021-02-21 14:27:01 +08:00
parent d427730a06
commit 9cf729a676
4 changed files with 199 additions and 76 deletions

View File

@ -9,6 +9,7 @@ class BGColorBehavior(object):
if color_level==-1: if color_level==-1:
color_level = 0 color_level = 0
self.color_level = color_level self.color_level = color_level
self.bg_ready = False
self.radius = radius self.radius = radius
self.bgcolor = [] self.bgcolor = []
self.fgcolor = [] self.fgcolor = []
@ -36,6 +37,7 @@ class BGColorBehavior(object):
def on_bgcolor(self,o=None,v=None): def on_bgcolor(self,o=None,v=None):
if self.bgcolor == []: if self.bgcolor == []:
return return
if self.canvas: if self.canvas:
with self.canvas.before: with self.canvas.before:
Color(*self.bgcolor) Color(*self.bgcolor)

View File

@ -4,6 +4,98 @@ from .threadcall import HttpClient
from .utils import absurl from .utils import absurl
from appPublic.registerfunction import RegisterFunction 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): class DataLoader(EventDispatcher):
def __init__(self,data_user): def __init__(self,data_user):
self.data_user = 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_success')
self.register_event_type('on_error') 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): def on_success(self,d):
pass pass
@ -27,7 +113,7 @@ class DataLoader(EventDispatcher):
pass pass
class HttpDataLoader(DataLoader): class HttpDataLoader(DataLoader):
def load(self): def load(self, *args, **kw):
url = absurl(self.data_user.url,self.data_user.target.parenturl) url = absurl(self.data_user.url,self.data_user.target.parenturl)
method = self.data_user.method method = self.data_user.method
params = self.data_user.params.copy() params = self.data_user.params.copy()
@ -36,14 +122,16 @@ class HttpDataLoader(DataLoader):
"rows":self.data_user.page_rows "rows":self.data_user.page_rows
}) })
hc = HttpClient() hc = HttpClient()
hc(url, try:
method=method, r = hc(url, method=method, params=params)
params=params, self.dispatch('on_success', r)
callback=self.success, return r
errback=self.error) except Exception as e:
self.dispatch('on_error', e)
class ListDataLoader(DataLoader): class ListDataLoader(DataLoader):
def load(self): def load(self, *args, **kw):
p = self.data_user.curpage p = self.data_user.curpage
r = self.data_user.page_rows r = self.data_user.page_rows
try: try:
@ -52,12 +140,13 @@ class ListDataLoader(DataLoader):
"total":len(self.data_user.data), "total":len(self.data_user.data),
"rows":s "rows":s
} }
self.success(self,d) self.dispatch('on_success', d)
return d
except Exception as e: except Exception as e:
self.error(self,e) self.dispatch('on_error', e)
class RegisterFunctionDataLoader(DataLoader): class RegisterFunctionDataLoader(DataLoader):
def load(self): def load(self, *args, **kw):
rf = RegisterFunction() rf = RegisterFunction()
try: try:
rfname = self.data_user.rfname rfname = self.data_user.rfname
@ -70,7 +159,9 @@ class RegisterFunctionDataLoader(DataLoader):
"rows":self.data_user.page_rows "rows":self.data_user.page_rows
}) })
s = func(**params) s = func(**params)
self.success(self,s) self.dispatch('on_success', s)
return s
except Exception as e: except Exception as e:
self.error(self,e) self.dispatch('on_error', e)

View File

@ -14,6 +14,8 @@ from .i18n import I18n
from .toolbar import Toolbar from .toolbar import Toolbar
from .color_definitions import getColors from .color_definitions import getColors
from .bgcolorbehavior import BGColorBehavior from .bgcolorbehavior import BGColorBehavior
from .dataloader import DataGraber
from .ready import WidgetReady
""" """
form options form options
@ -94,11 +96,11 @@ uitypes = {
"wclass":SelectInput, "wclass":SelectInput,
}, },
"text":{ "text":{
"orientation":"vertical", "orientation":"horizontal",
"wclass":StrInput, "wclass":StrInput,
"options":{ "options":{
"multiline":True, "multiline":True,
"height":9, "height":4,
} }
}, },
"teleno":{ "teleno":{
@ -114,11 +116,16 @@ class InputBox(BoxLayout):
def __init__(self, form, **options): def __init__(self, form, **options):
self.form = form self.form = form
self.options = options self.options = options
self.uitype = options.get('uitype','string') self.uitype = options.get('uitype',options.get('datatype','string'))
self.uidef = uitypes[self.uitype] self.uidef = uitypes[self.uitype]
orientation = self.uidef['orientation'] orientation = self.uidef['orientation']
width = self.form.inputwidth width = self.form.inputwidth
height = self.form.inputheight 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'] self.labelwidth = self.form.options['labelwidth']
kwargs = { kwargs = {
"orientation":orientation, "orientation":orientation,
@ -138,7 +145,6 @@ class InputBox(BoxLayout):
self.bind(size=self.setSize, self.bind(size=self.setSize,
pos=self.setSize) pos=self.setSize)
self.register_event_type("on_datainput") self.register_event_type("on_datainput")
self.register_event_type("on_ready")
def on_datainput(self,o,v=None): def on_datainput(self,o,v=None):
print('on_datainput fired ...',o,v) print('on_datainput fired ...',o,v)
@ -150,7 +156,7 @@ class InputBox(BoxLayout):
opts = { opts = {
"orientation":"horizontal", "orientation":"horizontal",
"size_hint_y":None, "size_hint_y":None,
"height":CSize(3) "height":CSize(2)
} }
if self.labelwidth<=1: if self.labelwidth<=1:
opts['size_hint_x'] = self.labelwidth opts['size_hint_x'] = self.labelwidth
@ -166,10 +172,6 @@ class InputBox(BoxLayout):
"i18n":True, "i18n":True,
"text":label, "text":label,
"font_size":CSize(1), "font_size":CSize(1),
"size_hint_x":None,
"width":CSize(len(label)),
"size_hint_y":None,
"height":CSize(3)
} }
self.labeltext = Text(**kwargs) self.labeltext = Text(**kwargs)
bl.add_widget(self.labeltext) bl.add_widget(self.labeltext)
@ -184,11 +186,12 @@ class InputBox(BoxLayout):
options = self.uidef.get('options',{}).copy() options = self.uidef.get('options',{}).copy()
options.update(self.options.get('uiparams',{})) options.update(self.options.get('uiparams',{}))
options['allow_copy'] = True options['allow_copy'] = True
options['width'] = options.get('width',20) options['width'] = options.get('width',1)
options['height'] = options.get('height',1) options['height'] = options.get('height',1)
if self.options.get('tip'): if self.options.get('hint_text'):
options['hint_text'] = i18n(self.options.get('tip')) options['hint_text'] = i18n(self.options.get('hint_text'))
Logger.info('Form: uitype=%s', self.uitype)
self.input_widget = self.uidef['wclass'](**options) self.input_widget = self.uidef['wclass'](**options)
if self.options.get('readonly'): if self.options.get('readonly'):
self.input_widget.disabled = True self.input_widget.disabled = True
@ -201,8 +204,7 @@ class InputBox(BoxLayout):
self.add_widget(self.input_widget) self.add_widget(self.input_widget)
self.initflag = True self.initflag = True
self.input_widget.bind(on_focus=self.on_focus) self.input_widget.bind(on_focus=self.on_focus)
self.dispatch('on_ready', self)
def check(self): def check(self):
d = self.getValue() d = self.getValue()
v = d.get(self.options.get('name')) v = d.get(self.options.get('name'))
@ -214,9 +216,6 @@ class InputBox(BoxLayout):
return True return True
def on_ready(self, obj):
Logger.info('kivyblocks: Form input ready')
def clear(self): def clear(self):
self.input_widget.setValue('') self.input_widget.setValue('')
@ -244,8 +243,8 @@ class InputBox(BoxLayout):
def defaultToolbar(): def defaultToolbar():
return { return {
"img_size":2, "img_size":1.5,
"text_size":1, "text_size":0.7,
"tools":[ "tools":[
{ {
"name":"__submit", "name":"__submit",
@ -261,7 +260,7 @@ def defaultToolbar():
} }
class Form(BGColorBehavior, BoxLayout): class Form(BGColorBehavior, WidgetReady, BoxLayout):
def __init__(self, **options): def __init__(self, **options):
self.options = options self.options = options
BoxLayout.__init__(self, orientation='vertical') BoxLayout.__init__(self, orientation='vertical')
@ -269,6 +268,7 @@ class Form(BGColorBehavior, BoxLayout):
BGColorBehavior.__init__(self, BGColorBehavior.__init__(self,
color_level=self.options.get('color_level',-1), color_level=self.options.get('color_level',-1),
radius=self.options.get('radius',[])) radius=self.options.get('radius',[]))
WidgetReady.__init__(self)
self.readiedInput = 0 self.readiedInput = 0
self.cols = self.options_cols = self.options.get('cols',1) self.cols = self.options_cols = self.options.get('cols',1)
if isHandHold() and Window.width < Window.height: if isHandHold() and Window.width < Window.height:
@ -282,7 +282,28 @@ class Form(BGColorBehavior, BoxLayout):
pass pass
def init(self): 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.fsc = VResponsiveLayout(
self.inputwidth, self.inputwidth,
self.cols self.cols
@ -299,7 +320,12 @@ class Form(BGColorBehavior, BoxLayout):
wid.bind(on_press=self.on_submit_button) wid.bind(on_press=self.on_submit_button)
wid = Factory.Blocks.getWidgetById('__clear',from_widget=self) wid = Factory.Blocks.getWidgetById('__clear',from_widget=self)
wid.bind(on_press=self.on_clear_button) 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): def makeInputLink(self,o,v=None):
self.readiedInput += 1 self.readiedInput += 1
if self.readiedInput >= len(self.options['fields']): if self.readiedInput >= len(self.options['fields']):
@ -309,6 +335,12 @@ class Form(BGColorBehavior, BoxLayout):
w.input_widget.focus_previous = p.input_widget w.input_widget.focus_previous = p.input_widget
p = w 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): def getValue(self):
d = {} d = {}
for f in self.fieldWidgets: for f in self.fieldWidgets:
@ -367,6 +399,12 @@ class StrSearchForm(BoxLayout):
} }
return d 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): def submit_input(self,o,v=None):
text = self.input_widget.text text = self.input_widget.text
if text != '': if text != '':

View File

@ -15,7 +15,6 @@ from ..threadcall import HttpClient
from ..utils import CSize from ..utils import CSize
class BoolInput(Switch): class BoolInput(Switch):
change = BooleanProperty(False)
def __init__(self,**kw): def __init__(self,**kw):
a = DictObject() a = DictObject()
if kw.get('defaultvalue',None) is None: if kw.get('defaultvalue',None) is None:
@ -25,7 +24,7 @@ class BoolInput(Switch):
if kw.get('value',None) is not None: if kw.get('value',None) is not None:
a.active = kw.get('value') a.active = kw.get('value')
super().__init__(**a) super().__init__(**a.to_dict())
self.register_event_type('on_changed') self.register_event_type('on_changed')
self.bind(active=on_active) self.bind(active=on_active)
@ -52,11 +51,9 @@ class StrInput(TextInput):
"halign":"left", "halign":"left",
"hint_text":"", "hint_text":"",
} }
if kv.get('tip'): a.update(kv)
a['hint_text'] = kv['tip'] w = kv.get('width',1)
# a.update(kv) h = kv.get('height',1)
w = kv.get('width',20)
h = kv.get('height',2.5)
if w <= 1: if w <= 1:
a['size_hint_x'] = w a['size_hint_x'] = w
else: else:
@ -67,9 +64,7 @@ class StrInput(TextInput):
else: else:
a['size_hint_y'] = None a['size_hint_y'] = None
a['height'] = CSize(h) a['height'] = CSize(h)
a['font_size'] = CSize(kv.get('font_size',1)) a['font_size'] = CSize(kv.get('font_size',0.9))
a['password'] = kv.get('password',False)
a['multiline'] = kv.get('multiline',False)
Logger.info('TextInput:a=%s,kv=%s',a,kv) Logger.info('TextInput:a=%s,kv=%s',a,kv)
super(StrInput,self).__init__(**a) super(StrInput,self).__init__(**a)
@ -107,6 +102,7 @@ class Password(StrInput):
class IntegerInput(StrInput): class IntegerInput(StrInput):
def __init__(self,**kw): def __init__(self,**kw):
print("IntegerInput(), __init__()....")
a = {} a = {}
a.update(kw) a.update(kw)
a['halign'] = 'right' a['halign'] = 'right'
@ -114,6 +110,7 @@ class IntegerInput(StrInput):
pat = re.compile('[^0-9]') pat = re.compile('[^0-9]')
def insert_text(self, substring, from_undo=False): def insert_text(self, substring, from_undo=False):
print('TTTTTTTTTTTTTTTTTTTTTTttt')
pat = self.pat pat = self.pat
s = re.sub(pat, '', substring) s = re.sub(pat, '', substring)
return StrInput.insert_text(self,s, from_undo=from_undo) return StrInput.insert_text(self,s, from_undo=from_undo)
@ -125,6 +122,7 @@ class IntegerInput(StrInput):
class FloatInput(IntegerInput): class FloatInput(IntegerInput):
pat = re.compile('[^0-9]') pat = re.compile('[^0-9]')
def filter(self,substring): def filter(self,substring):
print('FloatInput(), filter():..........')
pat = self.pat pat = self.pat
if '.' in self.text: if '.' in self.text:
s = re.sub(pat, '', substring) s = re.sub(pat, '', substring)
@ -169,7 +167,8 @@ class MyDropDown(DropDown):
self.setDataByUrl(self.url) self.setDataByUrl(self.url)
else: else:
self.si_data = self.options.get('data') 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)) self.bind(on_select=lambda instance, x: self.selectfunc(x))
def selectfunc(self,v): def selectfunc(self,v):
@ -192,38 +191,29 @@ class MyDropDown(DropDown):
def setData(self,data): def setData(self,data):
self.si_data = data self.si_data = data
self.clear_widgets() self.clear_widgets()
w = self.options.get('width',10)
h = self.options.get('height',2.5) h = self.options.get('height',2.5)
a = {} a = {}
if w <= 1: a['size_hint_y'] = None
a['size_hint_x'] = w a['height'] = CSize(h)
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['font_size'] = CSize(self.options.get('font_size',1)) a['font_size'] = CSize(self.options.get('font_size',1))
print('data=',data)
for d in data: for d in data:
dd = (d[self.valueField],d[self.textField]) dd = (d[self.valueField],d[self.textField])
b = Button(text=d[self.textField],**a) b = Button(text=d[self.textField],**a)
setattr(b,'kw_data',dd) setattr(b,'kw_data',dd)
b.bind(on_release=lambda btn: self.select(btn.kw_data)) b.bind(on_release=lambda btn: self.select(btn.kw_data))
self.add_widget(b) self.add_widget(b)
#print(dd) print('setData():',dd)
def setDataByUrl(self,url,params={}): def setDataByUrl(self,url,kw={}):
def x(obj,d): hc = HttpClient()
self.setData(d) params = self.options.get('params', {}).copy()
params.update(kw)
app = App.get_running_app() d = hc.get(url,params=params)
app.hc.get(url,params=params,callback=x) self.setData(d)
def showme(self,w): def showme(self,w):
#print('show it ',w) print('show it ',w)
self.target = w self.target = w
self.open(w) self.open(w)
@ -231,7 +221,7 @@ class SelectInput(BoxLayout):
def __init__(self,**kw): def __init__(self,**kw):
a={} a={}
w = kw.get('width',10) w = kw.get('width',10)
h = kw.get('height',2.5) h = kw.get('height',1.5)
if w <= 1: if w <= 1:
a['size_hint_x'] = w a['size_hint_x'] = w
else: else:
@ -245,11 +235,13 @@ class SelectInput(BoxLayout):
super(SelectInput,self).__init__(orientation='horizontal',\ super(SelectInput,self).__init__(orientation='horizontal',\
**a) **a)
self.tinp = StrInput(size_hint_y=None,height=kw.get('height',2.5)) self.si_value = ''
self.tinp = StrInput()
self.tinp.readonly = True self.tinp.readonly = True
newkw = {} newkw = {}
newkw.update(kw) newkw.update(kw)
newkw.update({'on_select':self.setData}) newkw.update({'on_select':self.setData})
print('selectinput:kw=', newkw)
self.dropdown = MyDropDown(**newkw) self.dropdown = MyDropDown(**newkw)
if kw.get('value'): if kw.get('value'):
self.si_data = kw.get('value') self.si_data = kw.get('value')
@ -273,18 +265,18 @@ class SelectInput(BoxLayout):
self.old_value = self.getValue() self.old_value = self.getValue()
def setData(self,d): def setData(self,d):
self.tinp.si_data = d[0] self.si_value = d[0]
self.tinp.text = d[1] self.tinp.text = d[1]
v = self.getValue() v = self.getValue()
if v != self.old_value: if v != self.old_value:
self.dispatch('on_changed',v) self.dispatch('on_changed',v)
def setValue(self,v): def setValue(self,v):
self.tinp.si_value = v self.si_value = v
self.tinp.text = self.dropdown.getTextByValue(v) self.tinp.text = self.dropdown.getTextByValue(v)
def getValue(self): def getValue(self):
return self.tinp.si_value return self.si_value
if __name__ == '__main__': if __name__ == '__main__':
from kivy.app import App from kivy.app import App