[ltk-user] ensure-ltk ?
Peter Herth
herth at peter-herth.de
Tue Jan 5 10:29:03 UTC 2010
Hi Daniel,
testing *wish* like that should work. However, why or for which
purpose do you want to use ensure-ltk?
I usually split my code in two parts: functions that create the UI
which assume that Wish is running, and
start functions like "main" which only start wish and then call the UI
creation functions. So if I need a
different entry point to my program I just write a different startup function.
Besides, you can have any number of wish processes running at the same
time. So e.g. for a debugging
tool, you can create a separate Wish with with-ltk.
On Sun, Jan 3, 2010 at 4:42 AM, Daniel Herring <dherring at tentpost.com> wrote:
> On Fri, 1 Jan 2010, Daniel Herring wrote:
>
>> What's the proper idiom when writing a function that might start wish or
>> might be called inside another with-ltk?
>>
>> For example,
>> (defun some-window ()
>> (ensure-ltk ()
>> ...))
>>
>> Where some-window could be called from a REPL or from a tk callback? Is
>> there already a way to do this in ltk, or should I define a macro
>> something like the following seemingly broken code?
>>
>> (defmacro ensure-ltk ((&rest options) &body body)
>> (let ((fname (gensym)))
>> `(labels ((,fname () , at body))
>> (if (wish-stream *wish*)
>> (,fname)
>> (with-ltk ,options (,fname))))))
>
> Here's my current macro. Could it be added to ltk.lisp?
>
> (defmacro ensure-ltk ((&rest options &key (debug 2)
> &allow-other-keys)
> &body body)
> "Wrap BODY in with-ltk unless a connection already exists."
> (declare (ignore debug))
> (let ((fname (gensym)))
> `(flet ((,fname () , at body))
> (if (wish-stream *wish*)
> (,fname)
> (with-ltk ,options (,fname))))))
>
> It turns out that both ensure-ltk macros work. However care must be
> exercised; my first use triggered Tk bug #219967. My distilled Ltk sample
> appears below.
>
> ;;; CAUTION
> ;;
> http://sourceforge.net/tracker/index.php?func=detail&aid=219967&group_id=12997&atid=112997
> ;; This can freeze a graphical window manager.
> ;; To run on linux and recover:
> ;; - log into a text console (e.g. Ctrl-Alt-F2)
> ;; - switch graphical (Ctrl-F7) and run the bomb
> ;; - switch back to text and `killall wish`
> ;; - watch `top` until things calm down
> (defun bomb ()
> (with-ltk ()
> (pack (make-instance 'treeview))
> ;; commenting out the sleep might save your window manager
> (sleep 1) ; just to let the treeview appear
> (grid (make-instance 'label :master nil) 0 0)))
>
>
> Even without this Tk bug, its probably a good idea to always pass a proper
> :master to other functions which create widgets...
Yes, you must not mix pack and grid. I think every Tk programmer does that
exactly one time :). In practice that has not been an issue with me. Whenever
the UI becomes so complex that I want to split it in several functions - that is
for any nontrivial LTk program - I actually split it in several "widgets".
So I do something like: (untested code, might not compile)
(defclass my-widget (frame)
...)
(defmethod initialize-instance :after ((w my-widget) &key)
;; .. now create the whole part of the UI that my-widget covers
;; all such created UI elements have :master w
)
and then just use it by instantiating it. In the current LTk branch, there
is also the nice defwidget macro, which makes this even nicer...
So essentially, the layout of a container is only done within one function,
that reduces the chance of mixing up pack and grid. So a main function
could look like:
(with-ltk ()
(let ((w1 (make-instance 'my-widget))
(w2 (make-instance 'another-widget))
(pack w1)
(pack w2)))
Peter
More information about the ltk-user
mailing list