Paul McNett wrote:
> Carl Karsten wrote:
>> Paul McNett wrote:
>>> Carl Karsten wrote:
>>>> Paul McNett wrote:
>>>>> Carl Karsten wrote:
>>>>>> Paul McNett wrote:
>>>>>>> Carl Karsten wrote:
>>>>>>>>> Where are these files again? Please don't point me to the list
>>>>>>>>> archives,
>>>>>>>>> as I can't easily copy/paste code from that webpage.
>>>>>>>> Oh yeah, that whole html eats whitespace thing...
>>>>>>>>
>>>>>>>> hnmm, looks like I botched the file name too. - was called bd1,
>>>>>>>> renamed the
>>>>>>>> files to cdxml2objDemo1 but didn't change dabo.ui.createForm()
>>>>>>>>
>>>>>>>> http://dev.personnelware.com/carl/temp/May31/a/cdxml2objDemo1.tgz
>>>>>>> Ok, your code runs, and when I click "swap" it swaps. What's the
>>>>>>> problem?
>>>>>>>
>>>>>> I am trying to replace this code in this file:
>>>>>>
>>>>>> # cdxml2objDemo1-code.py
>>>>>> ## *!* ## Dabo Code ID: dButton-dForm
>>>>>> def onHit(self, evt):
>>>>>> self.Form.myObj1.swap()
>>>>>> self.Form.update()
>>>>>>
>>>>>> With something in the cdxml file that connects the button to
>>>>>> myObj1.swap() in a
>>>>>> similar way that the text box's are connected to the attributes. (once
>>>>>> that
>>>>>> happens, the displaced .update() can be dealt wtih.)
>>>>> Well, it appears that Ed hasn't yet added the ability to put a
>>>>> OnHit="self.Form.myObj1.swap" in the attributes for the button, but
>>>>> that's how you would do it if it were supported. You'd also have to add
>>>>> an evt arg to your swap function:
>>>>>
>>>>> def swap(self, evt=None):
>>>> um, if it hasn't been implemented, then how do you know it would need the
>>>> parameter?
>>> Because that's how event binding works - the callback takes an argument
>>> that contains the event object. This *has been* implemented in Dabo for
>>> years now. What hasn't been implemented in cdxml is the ability to
>>> specify the binding in the constructor. Here, in raw-dabo:
>>>
>>> import dabo
>>> dabo.ui.loadUI("wx")
>>>
>>> def onButtonHit(evt):
>>> print "hit!", evt.EventObject
>>>
>>> app = dabo.App()
>>> app.setup()
>>> but = dabo.ui.dButton(app.MainForm, OnHit=onButtonHit, Caption="!")
>>> app.start()
>>>
>> OK, so it could be implemented without that:
>>
>> well, first it has to run with it....
>> app = dabo.App()
>> AttributeError: 'module' object has no attribute 'App'
>>
>> ok, no prob, I can add a d...
>
> :) Cool, you passed that test.
>
>
>> it runs, but I see no button.
>
> Forgot that there's a platform inconsistency there. It works on Mac, BTW.
eh!? Is anyone cataloging the platform inconsistencies? I think I am now
aware
of 3,
Any chance of a linux ver?
>
>> The plan was to pipe the call through a generic function that strips the
>> event
>> argument.
>
> The event argument is kind of important; I never thought of trying to
> strip it out. Good luck with that. :)
>
So far the only use I have seen for the event argument is to identify what
object raised the event, which can be dealt with by having each event call a
unique function. I am not sure which is better :)
current way (kinda):
UI1 calls OnHitX(1)
UI2 calls OnHitX(2)
UI3 calls OnHitX(3)
Without event arg:
UI1 calls OnHit1()
UI2 calls OnHit2()
UI3 calls OnHit3()
def OnHitX(objID): pass
def OnHit1(): OnHitX(1)
def OnHit2(): OnHitX(2)
def OnHit3(): OnHitX(3)
>
>>>> or, why does it need that parameter?
>>> Because that's how event binding works, the callback function takes an
>>> event argument.
>> um, you may as well say "because it is written that way." The code you
>> posted
>> doesn't use the parameter for anything useful. I can see the thought that
>> it
>> might be handy, but has anyone actually used it?
>
> Occasionally it is useful,
That defines everything in a computer, but I sure don't everything passed :)
I know in VFE I often wished that my BO code had a reference to the UI, but
right now I can't really think of a good reason.
> usually my code doesn't need it, but as I
> said above it is somewhat important to keep alive because of the way wx
> events work. Once that event object goes out of scope, wx takes over
> again and propagates it up a level. In order to keep things working
> sanely, you really need to accept the evt arg even if you don't actually
> use it.
When you say "out of scope" you really mean released/destroyed right?
otherwise this would not work:
def onButtonHit(evt):
foo()
return
def foo():
print "hit!"
Which means the evt arg could be kept alive in some framework code.
>
>>>>> ... and yes, you do need to explicitly call update(): how else do you
>>>>> expect Dabo to know that your object's attribute values have changed?
>>>> Few things come to mind:
>>>>
>>>> Given that most button clicks cause something to happen that requires the
>>>> form
>>>> to be updated, build it into the button. If that causes a problem, add an
>>>> switch to turn it off.
>>> You are saying that every time any button on the form gets clicked, call
>>> but.Form.update()?
>> yes. given my given, seems reasonable. (course I am not sure how valid my
>> given is.)
>
> Is it too much to ask the end programmer to make some explicit calls now
> and then?
Yes, if the framework can take care of it. I pretty much don't want code in my
app that could be coded in the framework.
>
The Dabo framework has no idea how much processing is going to
> be triggered by a call to update(). Could be minimal, but could be huge.
> I, for one, would like to have control over when it is called.
"If that causes a problem, add an switch to turn it off."
How many of your button's don't result in a .update()?
>
>
>>>> Create a class that is specifically for storing values that might be
>>>> displayed
>>>> using Dabo UI objects. When the Dabo UI object is bound to the 'value
>>>> object',
>>>> it registers itself. Now the value object has a reference to all the UI
>>>> objects
>>>> that are bound to it. When the value object's value is updated, it calls
>>>> the
>>>> .update() of the UI objects bound to it. This may sound like a bit of
>>>> overhead
>>>> that will slow things down, but I bet it is faster than calling .update().
>>> FWIW, there is just such a device already: binding controls to a
>>> dBizobj, and registering the bizobj with the dForm: whenever the bizobj
>>> field value changes, the form calls update() automatically.
>> um, make up your mind...
>>
>> I'm guessing you meant .update() needed to be called somehow, and that I
>> needed
>> to do something to make that happen. sounds like one thing that could be
>> done
>> is change
>> class myClass(object):
>> to
>> class myClass(dabo.biz.dBizobj):
>> and register the bizobj with the dForm -
>> which sounds pretty good. course I have no idea how to register it with the
>> form. shouldn't this be something that happens when the UI control is bound?
>
> Ok, ok... it is when the dForm recognizes that the record pointer has
> moved, or that a requery has happened, that update() is called
> automatically. The dForm methods like next(), prior(), new(), delete(),
> requery() all result in a update() being called. It only relies on a
> bizobj being present because those form methods assume that a bizobj is
> present.
>
> Remember, we designed Dabo assuming a database, mediated by a dBizobj,
> and a form mediating the dBizobj calls.
I'm starting to think the n-tier thing didn't get done as well as it could.
otoh, I may be trying to take some short cuts and screwing things up.
thrird hand, it isn't as important as having something working, so I am not
going to loose too much sleep over it.
>
>
>>>> I am somewhat surprised that the wx controls don't do this automatically,
>>>> but I
>>>> have 0.0 idea what wx controls can/can't do.
>>> You have to do programming to specify what the wx controls
>>> should/shouldn't do. You say that a wx.Button should call
>>> dabo.ui.dForm.update(), when wx is completely unaware of the existence
>>> of Dabo?
>> No, I am saying that the wx text box should update itself (just the text
>> box)
>> when the value it is bound to changes. (again, I have no clue how feasible
>> that
>> is.)
>
> wx has no notion of data binding at all. To set the value, you call
> wx.TextCtrl.SetValue(), and to get the value, you call GetValue(). Data
> binding is one of the things Dabo adds to the picture.
>
>
Oh... see, your comment about learning raw dabo could be extended to learning
wxPyton, and on to pure wx - none of witch I have enough desire to do :)
>>>>> Until the OnHit works within cdxml, you can put the following at the
>>>>> bottom of your main .py file:
>>>>>
>>>>> if __name__ == "__main__":
>>>>>
>>>>> app = dabo.dApp(MainFormClass=None)
>>>>> app.setup()
>>>>> frm = dabo.ui.createForm('cdxml2objDemo1.cdxml')
>>>>> frm.myObj1=myClass()
>>>>> ## - new line below
>>>>> frm.but.bindEvent(dabo.dEvents.Hit, frm.myObj1.swap)
>>>>> ## - new line above
>>>>> frm.show()
>>>>> app.start()
>>>>>
>>>>> ...and then get rid of the -code.py file.
>>>>>
>>>> Traceback (most recent call last):
>>>> File "cdxml2objDemo1.py", line 31, in ?
>>>> frm.but.bindEvent(dabo.dEvents.Hit, frm.myObj1.swap)
>>>> AttributeError: 'dForm_276318141' object has no attribute 'but'
>>>>
>>>> <dButton sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign':
>>>> 'Center', 'VAlign': 'Middle', 'Border': 0, 'Expand': False}"
>>>> code-ID="dButton-dForm" designerClass="controlMix" Caption="Swap" />
>>>>
>>>> Where did the 'but' in frm.but.bindEvent come from?
>>> Sorry, forgot to tell you to add RegID="but" in the dButton attributes
>>> in the xml.
>>>
>> bingo.
>>
>> OK, added some code:
>>
>> def swap(self, evt):
>> self.myAttrib1, self.myAttrib2 = self.myAttrib2, self.myAttrib1
>> print evt.EventObject
>> code.interact(local=locals())
>>
>>
>> >>> dir(evt)
>> ['Application', 'BaseClass', 'BasePrefKey', 'Class', 'Continue',
>> 'EventData',
>> 'EventObject', 'LogEvents', 'Name', 'Parent', 'PreferenceManager',
>> '_EventBindings', '__class__', '__delattr__', '__dict__', '__doc__',
>> '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__',
>> '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
>> '__slots__', '__str__', '__weakref__', '_addCodeAsMethod', '_afterInit',
>> '_args', '_autoBindEvents', '_baseClass', '_beforeInit', '_call_afterInit',
>> '_call_beforeInit', '_call_initProperties', '_continue', '_eventData',
>> '_eventObject', '_expandPropStringValue', '_extractKey',
>> '_extractKeyWordEventBindings', '_extractKeywordProperties',
>> '_getApplication',
>> '_getBaseClass', '_getBasePrefKey', '_getClass', '_getContinue',
>> '_getEventBindings', '_getEventData', '_getEventObject', '_getLogEvents',
>> '_getName', '_getParent', '_getPreferenceManager', '_initProperties',
>> '_insertEventData', '_kwargs', '_logEvent', '_removeAutoBindings',
>> '_setBasePrefKey', '_setContinue', '_setEventBindings', '_setEventData',
>> '_setEventObject', '_setKwEventBindings', '_setLogEvents', '_setName',
>> '_setParent', '_setPreferenceManager', '_uiEvent', 'afterInit',
>> 'appliesToClass', 'autoBindEvents', 'beforeInit', 'bindEvent', 'bindEvents',
>> 'doDefault', 'getAbsoluteName', 'getEventList', 'getMethodList',
>> 'getProperties', 'getPropertyInfo', 'getPropertyList', 'getValidEvents',
>> 'initEvents', 'initProperties', 'raiseEvent', 'setProperties',
>> 'setPropertiesFromAtts', 'stop', 'super', 'unBindEvent', 'unbindEvent']
>>
>> What is the point of the evt parameter?
>
> 1) It gives you a hook into the event propagation process. Call
> evt.stop() and no other handlers bound to that event will be called.
> This includes base native behavior.
I think this caused something to click:
frm.but.bindEvent(dabo.dEvents.Hit, frm.myObj1.swap)
This is connecting the wx event to frm.myObj1.swap - no Dabo code will be run,
right?
If so, then I totally see the point in "all of this." Not sure I like it, but
I
sure don't know enough to have an opinion that matters :)
>
> 2) If you have a generic event handler that could receive events from
> several objects, you may well need to know what object emitted the
> event, so you'd get that reference using evt.EventObject.
I can shoot that one down in a heartbeat: Don't have a generic event handler.
That reason could be applied to every single function: you need to pass a
reference of the calling object in case the function needs to know who called
it. no, that's dumb.
>
> 3) Some data is included with the event that may or may not otherwise be
> available from the object directly, such as the exact position of the
> mouse on the screen when the event occurred (mouse could be in a
> completely different place by the time our event handler responds to the
> event), what modifier keys were down when the event occurred, what list
> item was selected when the event occurred, etc. etc.
>
yeah, I'm seeing that whatever gets called is the first place any 'app side'
code can run, maybe even framework code. I may actually be breaking n-tier
rules by having the wx object call my BO method - (n>3 in this case. i'm
seeing
wx in it's own tier, above some python UI code (mix of dabo and app), above the
BO code.
>
>> Is there any way I can use it to get to the form to call .update?
>
> No, and I don't understand why you are resisting just calling
> self.Form.update() when needed.
cuz self is my BO, which has no Form or any other reference to the form.
>
>
>> (not that I think that is a good idea, just trying to get a grip on what I
>> can
>> do with that parameter.)
>
> The three things I listed comprise nearly 100% of the use I've seen for it.
>
>
>>>>>> 4. To me it is poor style to have code in the UI, and I thought Ed
>>>>>> claimed the
>>>>>> x-code.py file was just for the convince of the developer that wanted to
>>>>>> edit
>>>>>> code using the Dabo CD.
>>>>> I don't see how you'll get rid of all UI code. I have a ton of UI code
>>>>> and don't feel badly about it at all.
>>>> I think we need to define what this UI code is I want to get rid of. I
>>>> see a
>>>> typical 3-tier framework app having 6 places code can live: each of the 3
>>>> tiers
>>>> will have framework code and 'app developer code.' For the UI tier, if
>>>> the
>>>> app's UI is not doing anything that the Framework UI code can't handle,
>>>> then the
>>>> closest thing to code will be config data describing how to setup the
>>>> controls
>>>> (exactly what is in the .cdxml)
>>>>
>>>> If the app needs some loopy UI gizmo like "increase the font every time
>>>> the
>>>> mouse passes over it" then I need to write some UI code.
>>> Most UI code is layout code, yes. But also event handlers for acting
>>> when the user clicks a button or something.
>> so tying the button to some method code, and the method code isn't UI
>> specific,
>> right?
>
> Well, it receives the event parameter, which is ui specific. But
> typically my event handler will call some bizobj method to actually do
> the logical processing of whatever needs to happen, and get the return
> value to work with at the UI level.
right.
So typically you don't need the event parameter. same here, and I bet same
with
many other developers. May want to consider a framework feature that deals
with
this so the app developers can concentrate on there app an not this extra
parameter.
VFE had a button with a prop that contained the name of a method to call. at
run time, when the button was clicked, it magically figured out what object had
the method. it was handy, but I did not like the way the magic was implemented
- cuz sometimes I had to help it, and i still wonder if it was worth the hassle
it caused.
>
>>>>>> Assuming this is correct:
>>>>>> >> Just add that line to the object's afterInit() method.
>>>>>> (which it isn't - object, [event], and .myMethod need to be replaced
>>>>>> with the
>>>>>> right names, and my object doesn't have an afterInit() method. but
>>>>>> assuming it
>>>>>> is correct anyway...)
>>>>> That's where you edit it from within the -code.py file. You add the
>>>>> afterInit() method there.
>>>>>
>>>> huh? I can't even guess what you are talking about. please elaborate.
>>> Open up your -code.py file, and after the "def onHit.." block, add:
>>>
>>> def afterInit(self):
>>> print "afterInit", self
>>>
>>> Now run the main .py file. You should see:
>>> afterInit <dButton_9370141723 (baseclass dabo.ui.dButton)>
>>>
>>> Now put whatever code Ed wanted you to put there in that method. It gets
>>> called after the button's init cycle is complete.
>> Ok, that seems plausible. kinda goes against the goal of eliminating the
>> -code.py file.
>
> That was your goal, not mine. Eliminating the -code.py file is akin to
> confining yourself to writing no code at all in the ui level. A bit
> limiting, to say the least.
If I have no special (non framework provided) UI needs, I should not be writing
UI code. After using a framework for 10 years you may get on board with this
concept :)
>
>
>>>>>> It seems awkward to have to have the BO layer attach itself to the UI
>>>>>> objects,
>>>>>> especially when some of the UI object attach themselves to the BO object
>>>>>> (like
>>>>>> the text box.) Not to mention that means you can't use that BO object
>>>>>> without
>>>>>> the UI, unless you write some conditional code, which seems beyond
>>>>>> awkward.
>>>>> I don't understand. How does the BO layer "attach itself" to the UI
>>>>> objects? dBizobj isn't even aware that the UI layer exists.
>>>> I was assuming I had to add that line to my BO class. I don't know what
>>>> else
>>>> "the object's afterInit() method" would refer to.
>>> I interpreted it to be the button, but whatever, afterInit() is a hook
>>> method of all Dabo objects. It is in fact one of the most commonly-used
>>> hook methods, and I'm surprised you didn't know about it yet.
>> I kinda know about it, but in what I posted there just isn't anything
>> applicable. The only 2 things I could think of were myClass(object) which
>> isn't a dabo object, and it sure seemed like the button couldn't get to the
>> instance of my class for scope reasons or something.
>
> Well, it could get to it because your form has a reference to it, but
> I'm not clear on what you were trying to do so I'll stop at that.
>
Someone should ask Ed what he was talking about :)
>>>> I see you added it to the app's 'main' which is 'better' but still not the
>>>> "Don't Repeat Yourself" mentality that I would expect from a framework.
>>>> Actually nothing is being repeated... but it seems there is an extra step.
>>>> hmm,
>>>> maybe it is just the 2 places to set things up: in the .cdxml for text
>>>> boxes,
>>>> and app's main for the button. bah, this is just a side effect of the
>>>> workaround to an unconfirmed missing feature. This paragraph may not have
>>>> anything to do with reality :)
>>> I think maybe you should take cdxml out of the picture for a while. Get
>>> comfy with raw-dabo. You'll have a better understanding and appreciation
>>> for what cdxml brings to the table.
>> I can see the value, but I am skeptical it is worth the time. I think my
>> biggest problem is knowing what limitations the cdxml imposes.
>
> It imposes some limits, sure. Not a lot of limits, I don't think. It's
> biggest benefit is saving time laying out the controls. But it is in
> active flux, and always changing, while the underlying Dabo is actually
> quite stable. In the future I think people could start with cdxml and be
> just fine; currently, I think everyone should spend the time to learn
> the base Dabo way to do things first. But that's just me, I think.
In the end, I was able to use the CD much more effectively than trying to do it
by hand. The stuff I did by hand looked like total crap. With the CD and less
time I created a UI that was good enough.
BTW, thanks for waling me though this. I think I learned something.
Carl K
_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-users
Searchable Archives: http://leafe.com/archives/search/dabo-users
This message: http://leafe.com/archives/byMID/dabo-users/[EMAIL PROTECTED]