I’m creating my first GUI app, and I want to use input
(from gui-easy
) to display the output of a long-running command in "real time" (i.e. not waiting until the command is finished). When the output has more lines than can be displayed, I would like to set the text box’s vertical scroll position to the bottom as the output is updated. How does one update the scroll position of an input
? (@bogdan or anyone)
Why use an input for output? You might want to embed some kind of editor-canvas (make it read-only), or use the text
control which is, aesthetically, more like a "label" than a "text box."
A more-complex-than-you-need example of the former is https://github.com/benknoble/frosthaven-manager/blob/main/gui/markdown.rkt; you might also be able to use any of the procedures in https://docs.racket-lang.org/gui-easy/index.html#%28part..Canvases__.Snips%29. I forget which procedure does it, but you can also embed arbitrary racket/gui objects in gui-easy IIUC.
I’m not opinionated about using input
, though I’m not sure what the objection is to using it for output (isn’t a read-only “editor” just as oxymoronic?). It just needs to support scrolling, and I need to know how to tell it to scroll to the bottom when its contents are updated. Something like what DrRacket its “Package Manager” dialog when running package management operations. I’ll take a look at your links, thanks.
The input
view in gui-easy takes a #:mixin
argument that would normally allow you to change the scroll position by overriding its set-value
method and operating on its internal editor. However, that seems to interact badly with some of the logic in that view that tries to preserve the cursor position when the input text changes. So, that's one reason to avoid using input
for this. I could add another keyword argument to disable that functionality, but I'd like to avoid that for now.
The only other option right now is to roll your own view. Here are two examples, the 2nd being just a more efficient variation on the first.
Thanks so much for these! They are very instructive, and I'm studying them to understand how they work. I understand how consing to a buffer list, managing the buffer size and updating the editor (vs complete erase/replace on every update) all make the second example more efficient. This also helps me better understand custom views, and the underlying text/editor-canvas model. I am still digesting why context-mixin
is needed in the second example, and what exactly it does. Obviously it is not a documented part of gui-easy so I know I'd never have gotten there on my own.
You're welcome!
I've just pushed a change to make context-mixin
public, which I had been intending to for a while but never got around to it. I've also added some docs for it. The gist of it is that a view<%>
may be used to create multiple separate GUI widgets (here's a contrived example), so view<%>
implementations should themselves be stateless. But, in most cases, you need to keep track of some additional state (like the buffer in the 2nd example) for every widget. The context-mixin
wraps any class to add methods for associating arbitrary key-value pairs with its instances.