From: <kc1...@ya...> - 2007-06-21 21:29:23
Attachments:
noresource.py
|
Okay, answering my own question: I discovered the noresource.py in the samples directory and followed it to create a textfield at run time. After that, I went a little further and setup a button on the fly. In fact, I can have a function on_Button1_mouseClick which in turn create another button so that when I click on button1, it creates yet another button. All works. See attached. However, how do I create the event handler on the fly? In my sample, I pre-defined the routine on_Button1_mouseClick but that's not going to work for the general case. So, how can I define the event handler on the fly? --- kc1...@ya... wrote: > Hi list, > > I have a need to create an ap that changes at run > time > depends on what choices were selected. I have a > tree > control on the left, a static text area on the top > right, and now I like to have other components on > the > lower right but it would depend on what the user > clicked on the tree. > > The obvious way would be to design one dialog window > for each of the tree branches, and then when > selected, > pop up the dialog window and off it goes. The > problem > is that not only would that be very boring, it is a > *lot* of work because I have lots of branches - > close > to 100. > > What I am hoping is to simply have a template > document > that says when clicked on branch 1, I need a static > text, followed by a button, a .... and so forth. I > kind of have this document already. Now I need to > figure out how to create these components on the > fly. > > Does anybody has a simple example on how this can be > done? I notice, for example, with the PythonCard > layout Editor, the Property Editor in effect changes > as a function of what the user clicks. So this is > something doable. I did a brief look at the source > code and its too big and complex program to chew on. > > I am hoping that somebody has a simpler example. > > Thanks, > > > > -- > John Henry > -- John Henry -- John Henry |
From: KC <kim...@ya...> - 2007-06-21 21:28:04
Attachments:
noresource.py
|
Okay, answering my own question: I discovered the noresource.py in the samples directory and followed it to create a textfield at run time. After that, I went a little further and setup a button on the fly. In fact, I can have a function on_Button1_mouseClick which in turn create another button so that when I click on button1, it creates yet another button. All works. See attached. However, how do I create the event handler on the fly? In my sample, I pre-defined the routine on_Button1_mouseClick but that's not going to work for the general case. So, how can I define the event handler on the fly? --- kc1...@ya... wrote: > Hi list, > > I have a need to create an ap that changes at run > time > depends on what choices were selected. I have a > tree > control on the left, a static text area on the top > right, and now I like to have other components on > the > lower right but it would depend on what the user > clicked on the tree. > > The obvious way would be to design one dialog window > for each of the tree branches, and then when > selected, > pop up the dialog window and off it goes. The > problem > is that not only would that be very boring, it is a > *lot* of work because I have lots of branches - > close > to 100. > > What I am hoping is to simply have a template > document > that says when clicked on branch 1, I need a static > text, followed by a button, a .... and so forth. I > kind of have this document already. Now I need to > figure out how to create these components on the > fly. > > Does anybody has a simple example on how this can be > done? I notice, for example, with the PythonCard > layout Editor, the Property Editor in effect changes > as a function of what the user clicks. So this is > something doable. I did a brief look at the source > code and its too big and complex program to chew on. > > I am hoping that somebody has a simpler example. > > Thanks, > > > > -- > John Henry > -- John Henry |
From: <kc1...@ya...> - 2007-06-22 16:56:38
|
I've been searching the net for this topic and the one thing that pops up is the addMethod routine. It sounds like something I can use. However, there is no information that I can find on how to use it to help me. Could somebody please help. When I create a button on the fly - with a name defined at run-time, how would I define a method for it? Thanks, > > > Okay, answering my own question: > > I discovered the noresource.py in the samples > directory and followed it to create a textfield at run > time. After that, I went a little further and setup a > button on the fly. In fact, I can have a function > on_Button1_mouseClick which in turn create another button so > that when I click on button1, it creates yet another button. > All works. See attached. > > However, how do I create the event handler on the fly? > In my sample, I pre-defined the routine > on_Button1_mouseClick but that's not going to work for > the general case. > > So, how can I define the event handler on the fly? > > > > --- kc1...@ya... wrote: > > > Hi list, > > > > I have a need to create an ap that changes at run > > time > > depends on what choices were selected. I have a > > tree > > control on the left, a static text area on the top > > right, and now I like to have other components on > > the > > lower right but it would depend on what the user > > clicked on the tree. > > > > The obvious way would be to design one dialog window > > for each of the tree branches, and then when > > selected, > > pop up the dialog window and off it goes. The > > problem > > is that not only would that be very boring, it is a > > *lot* of work because I have lots of branches - > > close > > to 100. > > > > What I am hoping is to simply have a template > > document > > that says when clicked on branch 1, I need a static > > text, followed by a button, a .... and so forth. I > > kind of have this document already. Now I need to > > figure out how to create these components on the > > fly. > > > > Does anybody has a simple example on how this can be > > done? I notice, for example, with the PythonCard > > layout Editor, the Property Editor in effect changes > > as a function of what the user clicks. So this is > > something doable. I did a brief look at the source > > code and its too big and complex program to chew on. > > > > I am hoping that somebody has a simpler example. > > > > Thanks, > > > > > > > > -- > > John Henry > > > > -- > John Henry > -- John Henry |
From: Kevin A. <al...@se...> - 2007-06-22 21:47:45
|
On Jun 22, 2007, at 9:56 AM, kc1...@ya... wrote: > I've been searching the net for this topic and the one > thing that pops up is the addMethod routine. It > sounds like something I can use. However, there is no > information that I can find on how to use it to help > me. > > Could somebody please help. > > When I create a button on the fly - with a name > defined at run-time, how would I define a method for > it? > > Thanks, http://pythoncard.sourceforge.net/text/addmethod.txt addMethod was the way to do it in versions of PythonCard prior to release 0.8, but when I changed to event binding to a more efficient static system, rather than looking for event handlers each time an event fires, the old addMethod stopped working as described. Now, for some reason I thought that I was going to have to redo the "magic" code in model.py for the addMethod method, so I let this issue hanging. However, I just did a little experiment which seemed to work fine, so let me know if this works for you. Simply add your event handlers to your code BEFORE you create the components you want the events to bind to: >>> def on_btn1_mouseClick(self, event): ... self.components.field1.text = event.target.name ... >>> self.addMethod(on_btn1_mouseClick) >>> comp['btn1'] = {'type':'Button', 'name':'btn1', 'position':(0, 30), 'label':'btn1 hello'} Other than the last two lines this is identical to the way it used to work, we're simply making sure the event handler method is added to our code before the component is created so its event binding works correctly. Now, assuming I didn't just get lucky, this is pretty nice that it works again, but this example is done totally in the shell with the minimal.py sample application. What I can't remember offhand, is which Python module and method you need to use to pass in an arbitrary string and get back a function that we can do something with. For example, compiling... c = someComboOfCompileAndEval('def on_btn1_mouseClick(self, event): \n self.components.field1.text = event.target.name\n\n') self.addMethod(c) Maybe it is a combination of compile and eval, but the correct globals and locals will have to be passed in order for it to make sense as a method. I could probably dig into the Python interpreter to see what it is doing with the text at the shell prompt, but if you know, please post to the list. Thanks, ka |
From: John H. <ec...@ya...> - 2007-06-22 21:56:15
Attachments:
noresource.py
|
Thanks for the response. While waiting, I experimented and I came up with a Python way (as oppose to the PythonCard way) to do it. See attached file. When you run the attached program, each time a button is pushed, a new button is created. When that new button is pushed, yet another new button gets created...so on and so forth... Ain't Python fun? --- Kevin Altis <al...@se...> wrote: > > On Jun 22, 2007, at 9:56 AM, > kc1...@ya... wrote: > > > I've been searching the net for this topic and the > one > > thing that pops up is the addMethod routine. It > > sounds like something I can use. However, there > is no > > information that I can find on how to use it to > help > > me. > > > > Could somebody please help. > > > > When I create a button on the fly - with a name > > defined at run-time, how would I define a method > for > > it? > > > > Thanks, > > http://pythoncard.sourceforge.net/text/addmethod.txt > > addMethod was the way to do it in versions of > PythonCard prior to > release 0.8, but when I changed to event binding to > a more efficient > static system, rather than looking for event > handlers each time an > event fires, the old addMethod stopped working as > described. > > Now, for some reason I thought that I was going to > have to redo the > "magic" code in model.py for the addMethod method, > so I let this > issue hanging. However, I just did a little > experiment which seemed > to work fine, so let me know if this works for you. > Simply add your > event handlers to your code BEFORE you create the > components you want > the events to bind to: > > >>> def on_btn1_mouseClick(self, event): > ... self.components.field1.text = event.target.name > ... > >>> self.addMethod(on_btn1_mouseClick) > >>> comp['btn1'] = {'type':'Button', 'name':'btn1', > 'position':(0, > 30), 'label':'btn1 hello'} > > Other than the last two lines this is identical to > the way it used to > work, we're simply making sure the event handler > method is added to > our code before the component is created so its > event binding works > correctly. > > Now, assuming I didn't just get lucky, this is > pretty nice that it > works again, but this example is done totally in the > shell with the > minimal.py sample application. What I can't remember > offhand, is > which Python module and method you need to use to > pass in an > arbitrary string and get back a function that we can > do something > with. For example, compiling... > > c = someComboOfCompileAndEval('def > on_btn1_mouseClick(self, event): > \n self.components.field1.text = > event.target.name\n\n') > self.addMethod(c) > > Maybe it is a combination of compile and eval, but > the correct > globals and locals will have to be passed in order > for it to make > sense as a method. I could probably dig into the > Python interpreter > to see what it is doing with the text at the shell > prompt, but if you > know, please post to the list. > > Thanks, > > ka > > > > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 > express and take > control of your XML. No limits. Just data. Click to > get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Pythoncard-users mailing list > Pyt...@li... > https://lists.sourceforge.net/lists/listinfo/pythoncard-users > -- John Henry -- John Henry |
From: John H. <ec...@ya...> - 2007-06-23 19:36:40
|
There are people at the Python newsgroup suggesting that I should avoid using exec to accomplish this. Here's what they suggested: #!/usr/bin/python """ __version__ = "$Revision: 1.6 $" __date__ = "$Date: 2004/08/17 19:46:06 $" """ import new from PythonCard import model rsrc = {'application':{'type':'Application', 'name':'Minimal', 'backgrounds': [ {'type':'Background', 'name':'bgMin', 'title':'Minimal PythonCard Application', 'size':(200, 300), 'components': [ ] # end components } # end background ] # end backgrounds } } def mouseclick_factory(parent, name): id_num=int(name[-1:]) parent.components[name] = {'type':'Button', 'name':name, 'label':name, 'position':(5, 5+id_num*30), 'text':name} def function(self, event): print "You clicked '%s'." % name function.name = "on_%s_mouseClick" % name return function class Minimal(model.Background): def on_initialize(self, event): self.components['field1'] = {'type':'TextField','name':'field1','position':(5, 5),'size':(150, -1),'text':'Hello PythonCard'} name = "Button1" function = mouseclick_factory(self, name) # as before method = new.instancemethod(function, self, self.__class__) setattr(self, function.name, method) if __name__ == '__main__': app = model.Application(Minimal, None, rsrc) app.MainLoop() Unfortunately, it doesn't work. PythonCard doesn't calll the fuction created by the mouseclick_factory. However, if I place the following statement right after the setattr call, it works (proving that the function actually gets created). self.on_Button1_mouseClick(event) Any idea why this doesn't work? Thanks, -- John Henry |
From: Kevin A. <al...@se...> - 2007-06-24 05:21:59
|
On Jun 23, 2007, at 12:36 PM, John Henry wrote: > There are people at the Python newsgroup suggesting > that I should avoid using exec to accomplish this. > Here's what they suggested: > ... > function = mouseclick_factory(self, name) # as > before > method = new.instancemethod(function, self, > self.__class__) > setattr(self, function.name, method) ... You're basically doing what addMethod does, so after the setattr call, try self._addHandler(method) As mentioned before you're going to have to create the component after the event handler is created and bound or its bind events "magic" won't happen correctly. That means this bit in your factory needs to be moved out and after the _addHandler call. parent.components[name] = {'type':'Button', 'name':name, 'label':name, 'position':(5, 5+id_num*30), 'text':name} The way the PythonCard event binding works now is more efficient as I said but it is faster in part because of the caching of event handler names which is what the call to _addHandler is doing. You can see all this code in model.py. The handler name is added to a simple dictionary used for lookups by the findHandler method. In the old system, there was a lot of looping done at event dispatch time to find the right handler, back when everything was dynamic, but when I streamlined the code, I kept the old strategy, but simply moved it into a one-time event binding when a component is created. > Unfortunately, it doesn't work. PythonCard doesn't > calll the fuction created by the mouseclick_factory. > However, if I place the following statement right > after the setattr call, it works (proving that the > function actually gets created). > > self.on_Button1_mouseClick(event) > > Any idea why this doesn't work? > > Thanks, > > -- > John Henry ka |
From: John H. <ec...@ya...> - 2007-06-24 08:44:09
|
No dice. Here's what I have: def mouseclick_factory(parent, name): def function(self, event): print "You clicked '%s'." % name function.name = "on_%s_mouseClick" % name method = new.instancemethod(function, parent, parent.__class__) setattr(parent, function.name, method) parent._addHandler(method) parent.components[name] = {'type':'Button', 'name':name, 'label':name, 'position':(5, 5+int(name[-1:])*30), 'text':name} return function class Minimal(model.Background): def on_initialize(self, event): self.components['field1'] = {'type':'TextField','name':'field1','position':(5, 5),'size':(150, -1),'text':'Hello PythonCard'} mouseclick_factory(self, "Button1") if __name__ == '__main__': app = model.Application(Minimal, None, rsrc) app.MainLoop() When I click on Button1, nothing happens. --- Kevin Altis <al...@se...> wrote: > > On Jun 23, 2007, at 12:36 PM, John Henry wrote: > > > There are people at the Python newsgroup > suggesting > > that I should avoid using exec to accomplish this. > > Here's what they suggested: > > > > ... > > > function = mouseclick_factory(self, name) > # as > > before > > method = new.instancemethod(function, > self, > > self.__class__) > > setattr(self, function.name, method) > > ... > > You're basically doing what addMethod does, so after > the setattr > call, try > > self._addHandler(method) > > As mentioned before you're going to have to create > the component > after the event handler is created and bound or its > bind events > "magic" won't happen correctly. That means this bit > in your factory > needs to be moved out and after the _addHandler > call. > > parent.components[name] = {'type':'Button', > 'name':name, > 'label':name, > 'position':(5, > 5+id_num*30), > 'text':name} > > The way the PythonCard event binding works now is > more efficient as I > said but it is faster in part because of the caching > of event handler > names which is what the call to _addHandler is > doing. You can see all > this code in model.py. The handler name is added to > a simple > dictionary used for lookups by the findHandler > method. In the old > system, there was a lot of looping done at event > dispatch time to > find the right handler, back when everything was > dynamic, but when I > streamlined the code, I kept the old strategy, but > simply moved it > into a one-time event binding when a component is > created. > > > Unfortunately, it doesn't work. PythonCard > doesn't > > calll the fuction created by the > mouseclick_factory. > > However, if I place the following statement right > > after the setattr call, it works (proving that the > > function actually gets created). > > > > self.on_Button1_mouseClick(event) > > > > Any idea why this doesn't work? > > > > Thanks, > > > > -- > > John Henry > > ka > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 > express and take > control of your XML. No limits. Just data. Click to > get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Pythoncard-users mailing list > Pyt...@li... > https://lists.sourceforge.net/lists/listinfo/pythoncard-users > -- John Henry |
From: Kevin A. <al...@se...> - 2007-06-24 17:20:33
|
After a bit of research I came up with the following working example which uses a slightly modified version of your original factory. func_name seems to be the important attribute. I was able to use addMethod to clean up the code a bit . This still doesn't solve the problem of creating an arbitrary function/method from a string, but that's a generic Python problem that I don't know the answer to rather than something PythonCard- specific. ka --- from PythonCard import model rsrc = {'application':{'type':'Application', 'name':'Minimal', 'backgrounds': [ {'type':'Background', 'name':'bgMin', 'title':'Minimal PythonCard Application', 'size':(200, 100), 'components': [ ] # end components } # end background ] # end backgrounds } } class Minimal(model.Background): def on_initialize(self, event): self.components['field1'] = {'type':'TextField', 'name':'field1', 'position':(5,5), 'size':(150, -1), 'text':'Hello PythonCard'} self.mouseclick_factory("Button1") self.mouseclick_factory("Button2") def mouseclick_factory(self, name): def function(self, event): # changed to event.target.name to verify we're getting # the correct target when button is clicked print "You clicked '%s'." % event.target.name # func_name seems to be the magic attribute rather than # just setting func.name function.func_name = "on_%s_mouseClick" % name self.addMethod(function) self.components[name] = {'type':'Button', 'name':name, 'label':name, 'position':(5,5+int(name[-1:]) *30), 'text':name} return function if __name__ == '__main__': app = model.Application(Minimal, None, rsrc) app.MainLoop() |
From: John H. <ec...@ya...> - 2007-06-24 19:32:22
|
Thanks for the response. The code almost worked. The offending line is: function.func_name = "on_%s_mouseClick" % name which is a TypeError violation (readonly attribute). I ran into this too when I try to set method.__name__ directly. The workaround, as it seems, is to have an addHandler function (rather then the _addHandler function) that does this: def addHandler(self, aMethod): # Add the Handler to our Handler list. if aMethod.name not in self._handlers: log.debug("addHandler: " + aMethod.name) #self._handlers[aMethod.name] = event.Handler(aMethod) self._handlers[aMethod.name] = aMethod instead of this: def _addHandler(self, aMethod): # Add the Handler to our Handler list. if aMethod.__name__ not in self._handlers: log.debug("_addHandler: " + aMethod.__name__) #self._handlers[aMethod.__name__] = event.Handler(aMethod) self._handlers[aMethod.__name__] = aMethod When I call addHandler then, the code works. When I click the first button, a new button gets created. One minor puzzle though, Python passes down 3 parameters to the handler (rather then just 2). The first 2 are both the same and it's the normal "self" parameter you get with other handlers. The 3rd one is the event object. I don't know why I get "self" twice though. --- Kevin Altis <al...@se...> wrote: > After a bit of research I came up with the following > working example > which uses a slightly modified version of your > original factory. > func_name seems to be the important attribute. I was > able to use > addMethod to clean up the code a bit . > > This still doesn't solve the problem of creating an > arbitrary > function/method from a string, but that's a generic > Python problem > that I don't know the answer to rather than > something PythonCard- > specific. > > ka > --- > > from PythonCard import model > > rsrc = {'application':{'type':'Application', > 'name':'Minimal', > 'backgrounds': [ > {'type':'Background', > 'name':'bgMin', > 'title':'Minimal PythonCard Application', > 'size':(200, 100), > 'components': [ > > ] # end components > } # end background > ] # end backgrounds > } } > > class Minimal(model.Background): > def on_initialize(self, event): > self.components['field1'] = > {'type':'TextField', > > 'name':'field1', > > 'position':(5,5), > > 'size':(150, -1), > > 'text':'Hello PythonCard'} > self.mouseclick_factory("Button1") > self.mouseclick_factory("Button2") > > def mouseclick_factory(self, name): > def function(self, event): > # changed to event.target.name to > verify we're getting > # the correct target when button is > clicked > print "You clicked '%s'." % > event.target.name > # func_name seems to be the magic attribute > rather than > # just setting func.name > function.func_name = "on_%s_mouseClick" % > name > self.addMethod(function) > self.components[name] = {'type':'Button', > 'name':name, > 'label':name, > > 'position':(5,5+int(name[-1:]) > *30), > 'text':name} > return function > > > if __name__ == '__main__': > app = model.Application(Minimal, None, rsrc) > app.MainLoop() > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 > express and take > control of your XML. No limits. Just data. Click to > get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Pythoncard-users mailing list > Pyt...@li... > https://lists.sourceforge.net/lists/listinfo/pythoncard-users > -- John Henry |
From: Kevin A. <al...@se...> - 2007-06-24 22:01:04
|
On Jun 24, 2007, at 12:32 PM, John Henry wrote: > Thanks for the response. > > The code almost worked. The offending line is: > > function.func_name = "on_%s_mouseClick" % name > > which is a TypeError violation (readonly attribute). > I ran into this too when I try to set method.__name__ > directly. > Hmm, the code I sent to the list worked perfectly on my machine. Did you try and run the code as is? Which version of Python are you using? I was trying it with 2.4.3 on a Mac, but if you're using 2.5 maybe they added additional flags you're supposed to use at the command-line so that Python doesn't give you a warning?! I'm also a bit confused about the multiple args. I added the line... print "You clicked '%s'." % event.target.name to show that the event being passed in is what we're expecting and again on my box it works as expected. ka |
From: John H. <ec...@ya...> - 2007-06-25 06:40:46
|
> Hmm, the code I sent to the list worked perfectly on > my machine. Don't you just love software development? > Did > you try and run the code as is? Yes I did. Same failure. > Which version of > Python are you > using? Latest version of Python 2.3 under Windows XP w latest FP >I was trying it with 2.4.3 on a Mac, but if > you're using 2.5 > maybe they added additional flags you're supposed to > use at the > command-line so that Python doesn't give you a > warning?! I'm also a > bit confused about the multiple args. I added the > line... > > print "You clicked '%s'." % event.target.name > > to show that the event being passed in is what we're > expecting and > again on my box it works as expected. > > ka > > That part doesn't bother me. Now, I've played around the idea more and I came up with a version that works in the general case - for all controls, and in-line with the resource structure of PythonCard. See below: def addHandler(self, aMethod): # Add the Handler to our Handler list. if aMethod.name not in self._handlers: log.debug("addHandler: " + aMethod.name) #self._handlers[aMethod.name] = event.Handler(aMethod) self._handlers[aMethod.name] = aMethod def Control_factory(self, attribute, eventHandlers): name=attribute['name'] for eventName in eventHandlers.keys(): eventFct=eventHandlers[eventName] def function(self, background, event): if eventFct==None: return None return eventFct(self, event) function.name = "on_%s_%s" % (name,eventName) method = new.instancemethod(function, self, self.__class__) setattr(self, function.name, method) self.addHandler(method) self.components[name] = {} for key in attribute.keys(): self.components[name][key]=attribute[key] return function Now, everytime I need to create a control - any kind of PythonCard controls, I simply do a: # This is my button mouseClick handler def on_Button_mouseClick(self, event): return Create a button: Control_factory(self, attribute={"type":"Button", "name":"Button1", "label":"Button1","position":(5,35)}, eventHandlers={"mouseClick":on_Button_mouseClick}) Notice that the attribute is a standard dictionary no different from that in the resource file. And it works for all controls. Some form of this should exist in standard form of PythonCard. -- John Henry |
From: John H. <ec...@ya...> - 2007-06-24 21:00:17
|
Okay, here's a version that works, clean, and not requiring any changes to PythonCard. #!/usr/bin/python """ __version__ = "$Revision: 1.6 $" __date__ = "$Date: 2004/08/17 19:46:06 $" """ import new from PythonCard import log from PythonCard import model from PythonCard.model import SetInitParam rsrc = {'application':{'type':'Application', 'name':'Minimal', 'backgrounds': [ {'type':'Background', 'name':'bgMin', 'title':'Minimal PythonCard Application', 'size':(200, 300), 'components': [ ] # end components } # end background ] # end backgrounds } } class Background_Dynamic(model.Background): def __init__(self, aParent, aBgRsrc, SetInitParamFct=SetInitParam): model.Background.__init__(self, aParent, aBgRsrc, SetInitParamFct) def addHandler(self, aMethod): # Add the Handler to our Handler list. if aMethod.name not in self._handlers: log.debug("addHandler: " + aMethod.name) #self._handlers[aMethod.name] = event.Handler(aMethod) self._handlers[aMethod.name] = aMethod def mouseclick_factory(self, name): def function(self, background, event): self.mouseclick_factory("Button"+str(int(name[-1:])+1)) function.name = "on_%s_mouseClick" % name method = new.instancemethod(function, self, self.__class__) setattr(self, function.name, method) self.addHandler(method) self.components[name] = {'type':'Button', 'name':name, 'label':name, 'position':(5, 5+int(name[-1:])*30), 'text':name} return function class Minimal(Background_Dynamic): def on_initialize(self, event): self.components['field1'] = {'type':'TextField','name':'field1','position':(5, 5),'size':(150, -1),'text':'Hello PythonCard'} self.mouseclick_factory("Button1") if __name__ == '__main__': app = model.Application(Minimal, None, rsrc) app.MainLoop() --- Kevin Altis <al...@se...> wrote: > After a bit of research I came up with the following > working example > which uses a slightly modified version of your > original factory. > func_name seems to be the important attribute. I was > able to use > addMethod to clean up the code a bit . > > This still doesn't solve the problem of creating an > arbitrary > function/method from a string, but that's a generic > Python problem > that I don't know the answer to rather than > something PythonCard- > specific. > > ka > --- > > from PythonCard import model > > rsrc = {'application':{'type':'Application', > 'name':'Minimal', > 'backgrounds': [ > {'type':'Background', > 'name':'bgMin', > 'title':'Minimal PythonCard Application', > 'size':(200, 100), > 'components': [ > > ] # end components > } # end background > ] # end backgrounds > } } > > class Minimal(model.Background): > def on_initialize(self, event): > self.components['field1'] = > {'type':'TextField', > > 'name':'field1', > > 'position':(5,5), > > 'size':(150, -1), > > 'text':'Hello PythonCard'} > self.mouseclick_factory("Button1") > self.mouseclick_factory("Button2") > > def mouseclick_factory(self, name): > def function(self, event): > # changed to event.target.name to > verify we're getting > # the correct target when button is > clicked > print "You clicked '%s'." % > event.target.name > # func_name seems to be the magic attribute > rather than > # just setting func.name > function.func_name = "on_%s_mouseClick" % > name > self.addMethod(function) > self.components[name] = {'type':'Button', > 'name':name, > 'label':name, > > 'position':(5,5+int(name[-1:]) > *30), > 'text':name} > return function > > > if __name__ == '__main__': > app = model.Application(Minimal, None, rsrc) > app.MainLoop() > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 > express and take > control of your XML. No limits. Just data. Click to > get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Pythoncard-users mailing list > Pyt...@li... > https://lists.sourceforge.net/lists/listinfo/pythoncard-users > -- John Henry |
From: Alex T. <al...@tw...> - 2007-06-22 23:08:38
|
kc1...@ya... wrote: > I've been searching the net for this topic and the one > thing that pops up is the addMethod routine. It > sounds like something I can use. However, there is no > information that I can find on how to use it to help > me. > > Could somebody please help. > > When I create a button on the fly - with a name > defined at run-time, how would I define a method for > it? > > use the 'command' option in the button definition I *think* that should do it, but I'm not in a position to try it out right now, so I'm afraid it's an untested suggestion. -- Alex |
From: John H. <ec...@ya...> - 2007-06-23 06:18:03
|
Hi, Thanks for the response. But that would respond to "command" only - it doesn't respond to mouseClick and other events. --- Alex Tweedly <al...@tw...> wrote: > kc1...@ya... wrote: > > I've been searching the net for this topic and the > one > > thing that pops up is the addMethod routine. It > > sounds like something I can use. However, there > is no > > information that I can find on how to use it to > help > > me. > > > > Could somebody please help. > > > > When I create a button on the fly - with a name > > defined at run-time, how would I define a method > for > > it? > > > > > use the 'command' option in the button definition > > I *think* that should do it, but I'm not in a > position to try it out > right now, so I'm afraid it's an untested > suggestion. > > -- Alex > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 > express and take > control of your XML. No limits. Just data. Click to > get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Pythoncard-users mailing list > Pyt...@li... > https://lists.sourceforge.net/lists/listinfo/pythoncard-users > -- John Henry |
From: John H. <ec...@ya...> - 2007-06-25 17:56:35
|
Oh, silly me. Control_factory can be further simplied: def Control_factory(self, attribute, eventHandlers): name=attribute['name'] for eventName in eventHandlers.keys(): eventFct=eventHandlers[eventName] def function(self, background, event): if eventFct==None: return None return eventFct(self, event) function.name = "on_%s_%s" % (name,eventName) method = new.instancemethod(function, self, self.__class__) setattr(self, function.name, method) self.addHandler(method) self.components[name] = attribute return function --- John Henry <ec...@ya...> wrote: > > Hmm, the code I sent to the list worked perfectly > on > > my machine. > > Don't you just love software development? > > > Did > > you try and run the code as is? > > Yes I did. Same failure. > > > Which version of > > Python are you > > using? > > Latest version of Python 2.3 under Windows XP w > latest > FP > > >I was trying it with 2.4.3 on a Mac, but if > > you're using 2.5 > > maybe they added additional flags you're supposed > to > > use at the > > command-line so that Python doesn't give you a > > warning?! I'm also a > > bit confused about the multiple args. I added the > > line... > > > > print "You clicked '%s'." % event.target.name > > > > to show that the event being passed in is what > we're > > expecting and > > again on my box it works as expected. > > > > ka > > > > > > That part doesn't bother me. > > Now, I've played around the idea more and I came up > with a version that works in the general case - for > all controls, and in-line with the resource > structure > of PythonCard. See below: > > def addHandler(self, aMethod): > # Add the Handler to our Handler list. > if aMethod.name not in self._handlers: > log.debug("addHandler: " + aMethod.name) > #self._handlers[aMethod.name] = > event.Handler(aMethod) > self._handlers[aMethod.name] = aMethod > > def Control_factory(self, attribute, > eventHandlers): > name=attribute['name'] > for eventName in eventHandlers.keys(): > eventFct=eventHandlers[eventName] > def function(self, background, event): > if eventFct==None: > return None > return eventFct(self, event) > function.name = "on_%s_%s" % (name,eventName) > method = new.instancemethod(function, self, > self.__class__) > setattr(self, function.name, method) > self.addHandler(method) > self.components[name] = {} > for key in attribute.keys(): > self.components[name][key]=attribute[key] > return function > > > Now, everytime I need to create a control - any kind > of PythonCard controls, I simply do a: > > # This is my button mouseClick handler > def on_Button_mouseClick(self, event): > return > > Create a button: > > Control_factory(self, attribute={"type":"Button", > "name":"Button1", > "label":"Button1","position":(5,35)}, > eventHandlers={"mouseClick":on_Button_mouseClick}) > > Notice that the attribute is a standard dictionary > no > different from that in the resource file. > > And it works for all controls. Some form of this > should exist in standard form of PythonCard. > > -- > John Henry > -- John Henry |
From: John H. <ec...@ya...> - 2007-06-26 22:05:56
|
Man, life is gooooooooooood.... By creating controls dynamically, my efficiency in creating GUI code went up many many fold. I must have created 50 different panels in less than a day - including code for designing, presentation, and processing of user input. I can not imagine how long it would have taken me to do the same thing using the static method. Just for completeness, I am posting the final version of my Control_Factory code, along with code for destruction of controls on the fly. May be this code would be of use to other PythonCard users: #!/usr/bin/python """ __version__ = "$Revision: 1.6 $" __date__ = "$Date: 2004/05/05 16:53:27 $" """ import wx from PythonCard import model import new from PythonCard import log from PythonCard import model class Minimal(model.Background): def addHandler(self, aMethod): # Add the Handler to our Handler list. if aMethod.name not in self._handlers: log.debug("addHandler: " + aMethod.name) #self._handlers[aMethod.name] = event.Handler(aMethod) self._handlers[aMethod.name] = aMethod def delHandler(self, aMethod): # Add the Handler to our Handler list. if aMethod.name in self._handlers: log.debug("delHandler: " + aMethod.name) del self._handlers[aMethod.name] del aMethod def Control_factory(self, attribute, eventHandlers): name=attribute['name'] methods=[] for eventName in eventHandlers.keys(): eventFct=eventHandlers[eventName] def function(self, background, event): if eventFct==None: return None return eventFct(event) function.name = "on_%s_%s" % (name,eventName) method = new.instancemethod(function, self, self.__class__) setattr(self, function.name, method) self.addHandler(method) methods.append(method) self.components[name] = attribute return methods To use it, I simply set up a table like this: ({"type":"StaticText","name":"stFIELD1","text":"This is easy:",'position':(5, 10), },{}), ({"type":"TextField", "name":"tfFIELD1",'position':(35, 10-4), 'size':(70,-1)},{}), ({"type":"Button", "name":"pbBUTTON",'label':'Execute', 'position':(70, 10+75)}, {"mouseClick":self.on_pbBUTTON_mouseClick}), and then invoke Control_factory repeatedly. Thanks for a wonderful package PythonCard. Couldn't do this work without it. > -----Original Message----- > From: pyt...@li... > [mailto:pyt...@li...] On > Behalf Of John Henry > Sent: Monday, June 25, 2007 10:57 AM > To: Kevin Altis; pythoncard-Users > Subject: Re: [Pythoncard-users] Creating dynamic window > > > Oh, silly me. Control_factory can be further > simplied: > > def Control_factory(self, attribute, eventHandlers): > name=attribute['name'] > for eventName in eventHandlers.keys(): > eventFct=eventHandlers[eventName] > def function(self, background, event): > if eventFct==None: > return None > return eventFct(self, event) > function.name = "on_%s_%s" % (name,eventName) > method = new.instancemethod(function, self, > self.__class__) > setattr(self, function.name, method) > self.addHandler(method) > self.components[name] = attribute > return function > -- John Henry |