hi.
i've tryied to play with more dynamic aspects of the integration with ltk. now, i can use wish and fire of 'pack's for different objects, and wish will nicely display the new object within the current frame/window.
when i try to do the same with ltk, i always get a new window/frame with the object inside it. i don't want this behaviour and it seems like ltk automatically adds some extra parameters to the call. i've tried a lot of ways, but haven't managed to get this working. there seems to be some magic behind the "master" slot, etc, and maybe it's the default behaviour that is my problem?
serve-event seems needed to get rid of the "main-loop" thing (which annoys me incredibly). and while that works, it still do not display a new object, that's been asked to be displayed later on, within the same frame as before.
anyone know how to get this working?
by the way, i noticed that the examples is hooking into the main-loop with "with-ltk" without further arguments - is this just a compatibility thing for lisps without serve-event or threads?
i've never designed guis before, but i want to "communicate" with the gui-subsystem of my application, not get hooked into it. i wanna say, "add this to window X now" and "add this handler for button y", without further interruptions. i don't want my lisp to be tight up in some -- seemingly -- very badly designed main-loop thing; i want protocol exchange and buffered communication.
am i approaching this the wrong way?
thanks, jz
Hi Johnny,
On 4/26/07, Johnny Zackrisson jz@student.chalmers.se wrote:
hi.
i've tryied to play with more dynamic aspects of the integration with ltk. now, i can use wish and fire of 'pack's for different objects, and wish will nicely display the new object within the current frame/window.
when i try to do the same with ltk, i always get a new window/frame with the object inside it. i don't want this behaviour and it seems like ltk automatically adds some extra parameters to the call. i've tried a lot of ways, but haven't managed to get this working. there seems to be some magic behind the "master" slot, etc, and maybe it's the default behaviour that is my problem?
I am not completely sure what your problem is, please for future questions, always include the offending Tcl or Lisp code, it makes it more likely to point out to solutions. However, I induce that you did something like: button .frame.mybutton in Tcl to have the button appear within .frame - in Ltk you would replace this with something like: (setf button (make-instance 'button :master frame ..)) assuming frame is the Ltk widget for your frame you want to put your button in. So nothing magical in the master slot but expressing the same parent-child relationship that the Tcl pathname to a widget does.
serve-event seems needed to get rid of the "main-loop" thing (which annoys me incredibly). and while that works, it still do not display a new object, that's been asked to be displayed later on, within the same frame as before.
anyone know how to get this working?
by the way, i noticed that the examples is hooking into the main-loop with "with-ltk" without further arguments
- is this just a compatibility thing for lisps without
serve-event or threads?
i've never designed guis before, but i want to "communicate" with the gui-subsystem of my application, not get hooked into it. i wanna say, "add this to window X now" and "add this handler for button y", without further interruptions. i don't want my lisp to be tight up in some -- seemingly -- very badly designed main-loop thing; i want protocol exchange and buffered communication.
am i approaching this the wrong way?
Most likely :) I am again not sure what exactly your problem with mainloop is, but it is only for event processing. The only difference with respect to serve-event is, that it kind of puts the event processing in the background, that is parallelizing it. The only use of that is, that you keep your lisp REPL responsive while running the ltk application. In a lisp with threads, you can just spawn the whole ltk application in a thread of its own. In any way, this is only about event dispatching and has no influence how the GUI is rendered. Unless you need to run another task in the background (like reading data from a serial port) the default behaviour is what you want. If not, I can tell you more detailled later on, how to do it elsewise.
I hope this helps, but if not, don't heasitate to ask for more detaills, but please attach the corresponding code :)
Peter
Here is a simple example:
;-- snip (start-wish)
(with-ltk (:stream (wish-stream *wish*)) (let* ((a (make-instance 'frame :width 60 :height 60 :border 2)) (b (make-instance 'frame :width 100 :height 230)) (c (make-instance 'button :text "Press blah..")) (d (make-instance 'label :master a :text "foo")) (e (make-instance 'label :master b :text "bar"))) (pack a) (pack b) (pack c) (pack d) (pack e)))
(with-ltk (:stream (wish-stream *wish*)) (let ((f (make-instance 'label :text "zot"))) (pack f))) ; -- snip
the second call to the "with-ltk" macro wont work. the point here is i want to be able to continue hacking around at the repl, doing other things, and then later on perhaps add another entity to the gui.
what if i wanted to add the "f" label to the "b" frame; am i forced to use globally declared variables for the initial frame, or is there other ways to deal with such a situation? (observe that the "f" label call is done /after/ the first packing).
furthermore, is it also possible to attach handlers to objects (say buttons or a keyboard event) in such a way that it automatically dispatches a separate thread and excecute the handler assigned to that thread, without interrupting the rest of the lisp system (ie, the repl will be interactive, as well as other concurrently running threads).
another example would be: how would you design a lisp-repl in a tk frame, sending the lisp code to the lisp-environment for execution and then return the answer of course, or even add tk objects from within that tk-repl?
thanks, -- johnny zackrisson, gothenburg, sweden.
On 4/26/07, Johnny Zackrisson jz@student.chalmers.se wrote:
Here is a simple example:
;-- snip (start-wish)
(with-ltk (:stream (wish-stream *wish*)) (let* ((a (make-instance 'frame :width 60 :height 60 :border 2)) (b (make-instance 'frame :width 100 :height 230)) (c (make-instance 'button :text "Press blah..")) (d (make-instance 'label :master a :text "foo")) (e (make-instance 'label :master b :text "bar"))) (pack a) (pack b) (pack c) (pack d) (pack e)))
(with-ltk (:stream (wish-stream *wish*)) (let ((f (make-instance 'label :text "zot"))) (pack f))) ; -- snip
the second call to the "with-ltk" macro wont work. the point here is i want to be able to continue hacking around at the repl, doing other things, and then later on perhaps add another entity to the gui.
Things become much clearer now :). with-ltk is thought for applications which should run as one application, but not for tinkering in the REPL, so just do the start-wish and none of the with-ltk's. Then you can do exactly as you want. If you want events processed, just call mainloop from the repl and break and exit it (without quitting wish) to return to the REPL. Alternatively, keep calling (process-events) which directly returns after processing all pending events.
what if i wanted to add the "f" label to the "b" frame; am i forced to use globally declared variables for the initial frame, or is there other ways to deal with such a situation? (observe that the "f" label call is done /after/ the first packing).
Well that has nothing to do with LTk, you need to "see" the variables you want to use... so you need to be in the scope of the variable, for the REPL this means that they need to be global.
furthermore, is it also possible to attach handlers to objects (say buttons or a keyboard event) in such a way that it automatically dispatches a separate thread and excecute the handler assigned to that thread, without interrupting the rest of the lisp system (ie, the repl will be interactive, as well as other concurrently running threads).
Well, if your lisp has threads, spawn mainloop in a thread. Or use serve-event. But with threads a word of caution: LTk hasn't been stress-tested with respect to multi-threading yet (proper threading support is still in the planning phase), so use it at you own risk :)
another example would be: how would you design a lisp-repl in a tk frame, sending the lisp code to the lisp-environment for execution and then return the answer of course, or even add tk objects from within that tk-repl?
That is easy to do with LTk as it is: just get the code from the Tk entry widget, read and eval it, and output the result to the Tk GUI. However, it might be a good idea to run the GUI in a different process than the lisp code to execute, as when the lisp process locks up, or enters the debugger, the GUI still runs happily...
Peter
Things become much clearer now :). with-ltk is thought for applications which should run as one application, but not for tinkering in the REPL, so just do the start-wish and none of the with-ltk's. Then you can do exactly as you want. If you want events processed, just call mainloop from the repl and break and exit it (without quitting wish) to return to the REPL. Alternatively, keep calling (process-events) which directly returns after processing all pending events.
Bingo! You nailed it there. It wasn't at first clear to me how I should send objects to Tk, and then I realized that all I had to do was to call pack. :)
The "Running it manually" part of the documentation sort of tells you this, but not explicitly how such behvaiour is to be invoked. Perhaps you should add a comment that you just call pack for sending objects?
Well, if your lisp has threads, spawn mainloop in a thread. Or use serve-event. But with threads a word of caution: LTk hasn't been stress-tested with respect to multi-threading yet (proper threading support is still in the planning phase), so use it at you own risk :)
Oh, how.. simple. :)
That is easy to do with LTk as it is: just get the code from the Tk entry widget, read and eval it, and output the result to the Tk GUI. However, it might be a good idea to run the GUI in a different process than the lisp code to execute, as when the lisp process locks up, or enters the debugger, the GUI still runs happily...
Ah.. I will work on this later on, and perhaps post an example. :)
I'm starting to see the light here. I guess I'm looking at GUI programming from a network programmers perspective. I would imagine keeping the repl intact and interactive would be /essential/ for dynamic GUI programming, let alone rapid prototyping, debugging and whatnot. I suppose most people have simple, very easy designed GUI's with pretty much static behaviour, in which case you can just wrap it all up around a with-ltk call and be done with the GUI part.
Another question, LTK is said to be just fine as long as you do not need high-performance. How do you define high-performance in this context? Is a CAD application a high-performance application? Is realtime stock trading curves high-performance? Or are we talking about the obvious; FPS game with intense graphics?
Thanks a bunch Peter, I think we've sorted out my problems by now. :)
-- Johnny Zackrisson, Gothenburg, Sweden.
Well, if your lisp has threads, spawn mainloop in a thread. Or use serve-event. But with threads a word of caution: LTk hasn't been stress-tested with respect to multi-threading yet (proper threading support is still in the planning phase), so use it at you own risk :)
Oh, how.. simple. :)
Actually, not only has Ltk not been stress tested with two threads interacting with the GUI, but I can think of a few race conditions there. I fixed them once, but the fix was too ugly to be justifiable ... I've been planning on taking another stab at it "sometime". But if you're using SBCL, serve-event is perfect for interactivity -- the serve-event facility was in fact developed to allow a single-threaded lisp to run an application while preserving the REPL.
I'm starting to see the light here. I guess I'm looking at GUI programming from a network programmers perspective. I would imagine keeping the repl intact and interactive would be /essential/ for dynamic GUI programming, let alone rapid prototyping, debugging and whatnot. I suppose most people have simple, very easy designed GUI's with pretty much static behaviour, in which case you can just wrap it all up around a with-ltk call and be done with the GUI part.
Most of the time what you're actually doing is redefining functions or classes and invoking them from the GUI, not calling Ltk functions directly from the repl -- at least, once you get the basics in place for your application. So you don't really need the repl as much as something like Slime to let you redefine at will.
Another question, LTK is said to be just fine as long as you do not need high-performance. How do you define high-performance in this context? Is a CAD application a high-performance application? Is realtime stock trading curves high-performance? Or are we talking about the obvious; FPS game with intense graphics?
More like the obvious ... it's been used no problem for CAD, server load monitors, tetris, xeyes, pong, etc. Image editing is pushing the limits a little, but worked surprisingly well. Ken Tilton found he needed native bindings to get reasonable performance for OpenGL, which isn't too surprising.