[racket] Does Racket GUI scale?

227 views
Skip to first unread message

Dmitry Pavlov

unread,
Jul 9, 2014, 4:58:02 AM7/9/14
to us...@racket-lang.org
Hello,

I have to do a simple spreadsheet editor and I wonder
whether Racket suits my needs. The main challenge
is that the spreadsheet editor should be able to edit
tables as big as 1000x1000 or 10000x100 cells.

Here is a stub that I have done, using williams/table-panel
package from PLaneT: http://pastebin.com/aAjg2TZT

It initializes pretty slow and does the scrolling pretty slow
even with 20x10 cells, and 100x100 is already almost
impossible to work with, let alone 1000x1000 or 10000x100.

OK, I thought, maybe I should use the single canvas
(not separate controls) for the cells, and leave only
buttons as controls for rows and columns.

But having just 1000 buttons with a scrollbar turned out
to be slow enough:

#lang racket
(require racket/gui/base)

(define frame
(instantiate frame%
("Test")))

(define scrolling-panel
(new vertical-panel%
(parent frame)
(style '(auto-vscroll))))

(for ((i (in-range 1000)))
(new button%
(parent scrolling-panel)
(horiz-margin 0)
(vert-margin 0)
(label (number->string (+ 1 i)))))

(send frame resize 100 400)
(send frame show #t)

It takes considerable time to initialize, and the scrolling
is pretty much of a slide-show kind. Raising the
number to 10000 makes it a complete no-go.

So I am wondering whether there are hacks to speed
up the GUI that I am creating.


Best regards,

Dmitry
____________________
Racket Users list:
http://lists.racket-lang.org/users

Matthew Flatt

unread,
Jul 9, 2014, 5:15:08 AM7/9/14
to Dmitry Pavlov, us...@racket-lang.org
No, instances of `button%` (or generally `control<%>`) in a scrolling
panel will not scale well. The `racket/gui` library is not designed for
it.

I'm not sure how much the problem is in `racket/gui` versus the
underlying toolkits. Your example program scrolls nicely for me on
Windows and Mac OS X, but not Unix/Gtk, but I would not conclude from that
experiment that the problem is in Gtk. The problem might be the
Gtk-specific part of the implementation of `racket/gui`. Also, I
wouldn't expect any of the platforms to scale to 1000x1000 buttons.
When I tried 100x100 on Mac OS X, it took a couple of seconds to create
all of the buttons.

I think you would have to use `canvas%` and draw/manage the grid and
controls manually. It's possible that the classes of `embedded-gui`
will be useful, if you can set up a suitable harness for snips. (I've
always wanted to make a `table%` class to go along with `text%` and
`pasteboard%`, but I never got around to it.)

Dmitry Pavlov

unread,
Jul 9, 2014, 6:06:10 AM7/9/14
to Matthew Flatt, us...@racket-lang.org
Matthew,

> I'm not sure how much the problem is in `racket/gui` versus the
> underlying toolkits. Your example program scrolls nicely for me on
> Windows

Interesting, thanks! You are right -- Windows does the scrolling
smoothly with 1000 buttons. As a separate issue: look what
happened when I raised the number to 1500:

#lang racket
(require racket/gui/base)

(define frame
(instantiate frame%
("Test")))

(define scrolling-panel
(new vertical-panel%
(parent frame)
(style '(auto-vscroll))))

(for ((i (in-range 1500)))
(new button%
(parent scrolling-panel)
(horiz-margin 0)
(vert-margin 0)
(label (number->string (+ 1 i)))))

(send frame resize 100 400)
(send frame show #t)

Result:

http://imgur.com/jDP9E2u

Do you have any clue what this can be?

> I think you would have to use `canvas%` and draw/manage the grid and
> controls manually. It's possible that the classes of `embedded-gui`
> will be useful, if you can set up a suitable harness for snips.

OK, thank you for the pointers.

Best regards,

Dmitry

P.S. I am lost and really hoping for an answer from you to the
Racket VM crash report which I posted Thursday :(

Matthew Flatt

unread,
Jul 9, 2014, 6:16:49 AM7/9/14
to Dmitry Pavlov, us...@racket-lang.org
At Wed, 9 Jul 2014 13:59:31 +0400, Dmitry Pavlov wrote:
> Interesting, thanks! You are right -- Windows does the scrolling
> smoothly with 1000 buttons. As a separate issue: look what
> happened when I raised the number to 1500:

It looks like drawing is cut off at 32767 pixels (= largest positive
value of a 16-bit signed integer). I think I looked into this before
and concluded that it's a limitation of Win32 controls, but I don't
recall how hard I tried to fix it.

Hendrik Boom

unread,
Jul 9, 2014, 12:38:59 PM7/9/14
to us...@racket-lang.org
On Wed, Jul 09, 2014 at 11:10:06AM +0100, Matthew Flatt wrote:
> At Wed, 9 Jul 2014 13:59:31 +0400, Dmitry Pavlov wrote:
> > Interesting, thanks! You are right -- Windows does the scrolling
> > smoothly with 1000 buttons. As a separate issue: look what
> > happened when I raised the number to 1500:
>
> It looks like drawing is cut off at 32767 pixels (= largest positive
> value of a 16-bit signed integer). I think I looked into this before
> and concluded that it's a limitation of Win32 controls, but I don't
> recall how hard I tried to fix it.

I hit this limit in a gtk program a few years ago.
It also exists on the Amiga.
It's a rather common restriction in GUI toolkits.

Dmitry Pavlov

unread,
Jul 9, 2014, 6:41:19 PM7/9/14
to Hendrik Boom, Matthew Flatt, us...@racket-lang.org
> I hit this limit in a gtk program a few years ago.

On my present GTK on Linux the limit does not apply.
Maybe that is because it is 64-bit, or just more recent, I do not know.

Also I saw a lot of scrollable things in Windows who were
longer than 32768 pixels (take big Excel tables, for example).
Maybe they are implemented in a different way.

Best regards,

Dmitry

Greg Hendershott

unread,
Jul 9, 2014, 9:27:45 PM7/9/14
to Dmitry Pavlov, us...@racket-lang.org
> Also I saw a lot of scrollable things in Windows who were
> longer than 32768 pixels (take big Excel tables, for example).
> Maybe they are implemented in a different way.

I don't think that a big-grid GUI application like Excel will use
controls for very much in its main window. Generally it is managing
all that itself.

It might use a _few_ plain windows, such as one for the column names
on top, another for the row names on the left, and then a big one for
the main grid client area. Just to make it easier to clip output.

If the user clicks in a button-like area, it will handle that itself.
e.g. If you click somewhere in the column header, it will calculate
which column, and draw that column as selected.

If the user clicks in a region it calculates to be a cell, it _might_
create a text-edit control there for in-place editing -- but just
temporarily, and destroy it when editing finishes.

All the logic for scrolling... managed itself.

At least, that's how I did Windows GUI stuff like this, 15+ years ago.
Usings hundreds or thousands of windows/controls was just too much
overhead to get desirable speed and space. Although the overhead might
be less, now, I imagine if you want a really crisp UI it's probably
much the same story.

Doug Williams

unread,
Jul 10, 2014, 3:17:24 PM7/10/14
to Greg Hendershott, Dmitry Pavlov, us...@racket-lang.org
Another alternative might be to make a visible grid of cells (using table-panel, for example) and rather than scrolling the canvas they are on, use the scroll bars to change what data is displayed in those cells. That is, have the visible grid of cells be a window into the (potential much larger) grid of cell contents.

Doug

Greg Hendershott

unread,
Jul 10, 2014, 5:57:42 PM7/10/14
to Doug Williams, Dmitry Pavlov, us...@racket-lang.org
> Another alternative might be to make a visible grid of cells (using
> table-panel, for example) and rather than scrolling the canvas they are on,
> use the scroll bars to change what data is displayed in those cells. That
> is, have the visible grid of cells be a window into the (potential much
> larger) grid of cell contents.

That's a good idea, too. In that case I think you *might* want to make
the table-panel be the full *potential* size of the window (i.e the
desktop size). That way, when the user resizes the window
interactively (e.g. dragging the window border) it will smoothly
expose/hide the already-existing parts, like say Excel would. (I'm
assuming recreating the table-panel on each tiny size change message
would not be smooth, and, that having it be jerky would be
undesirable. Or that having "blank" parts until the resize completes,
would be undesirable.)

Of course this might not work well if someone's desktop is enormous
(multi monitor). And/or if its size changes dynamically (change res in
OS display properties). In which case you might decide to manage the
client area "from scratch", after all. It depends on how smooth and
"professional" you want the GUI to be.

In any case, the main point I intended to make is: These GUI design
decisions are (I think) basically the same in C or Racket. In other
words using many window controls would be OK (or bad) equally whether
it's C or Racket or whatever. So Dmitry I wouldn't let that particular
issue discourage you from using Racket for a GUI project.

Neil Van Dyke

unread,
Jul 10, 2014, 6:39:54 PM7/10/14
to Dmitry Pavlov, us...@racket-lang.org
Dmitry Pavlov wrote at 07/09/2014 04:50 AM:
> I have to do a simple spreadsheet editor and I wonder
> whether Racket suits my needs. The main challenge
> is that the spreadsheet editor should be able to edit
> tables as big as 1000x1000 or 10000x100 cells.

For a million cells like that, when using any language and toolkit that
I know of, I would probably implement it with a mix of manual drawing
and using the occasional toolkit widgets in only small numbers at a time
(only for actively editing of a single cell).

Fortunately, doing the drawing and mouse-click object picking for a grid
is very easy to do efficiently and scalably, and doing it with
scrollbars is only a little bit more arithmetic. (If it were 2D objects
of arbitrary shape, position, and layering, then that would be harder to
do scalably, and likely require fancy data structures to do fast, but
simple spreadsheet-like grids are easy.)

I would first try it with a full redraw of the visible part of the grid
at each repaint/expose event. If that flickered, I would add
double-buffering to the full redraw. If there was still something slow
(say, if your anti-aliased text drawing was unusually slow while
scrolling or when redrawing on-the-fly while typing the edited contents
of a cell), then I would look at delaying/coalescing updates, or
simplifying the intermediate updates before getting to an idle update
when the full detail is done. As an extreme last resort, I would look
at doing partial (damage region) redraws to a double-buffer and block
moves within the buffer for scrolling and window resizes, but this is
more complicated and a likely source of hard-to-QA bugs. I doubt that
you will need the extreme last resort, so it should be pretty
straightforward.

For editing the contents of cells in this manually-drawn grid, you can
put the GUI toolkit editing controls:
* permanently in the enclosing GUI toolkit window (beside the grid, not
over it),
* in a transient pop-up window of some kind, or
* transiently in-place over the grid (with pixel-exact position and
geometry).

I think that this simple approach of a manually-drawn grid and minimal
use of toolkit controls will be fast with even a million cells, without
much programming difficulty.

Neil V.

Dmitry Pavlov

unread,
Jul 11, 2014, 5:48:33 PM7/11/14
to Doug Williams, us...@racket-lang.org
Doug,

Interesting suggestion, thanks!

A screen can easily contain ~ 50x30 cells, which is too many
if I want to have cells as text controls. So I think I will resort to
a big canvas instead of a table of cells. But I think I will use
the approach that you proposed for row/column controls (buttons).

Regards,

Dmitry

Dmitry Pavlov

unread,
Jul 11, 2014, 5:58:56 PM7/11/14
to Greg Hendershott, Doug Williams, us...@racket-lang.org
Greg,

You are right, managing the scrolling bars manually and
creating an in-place cell editor by demand seems
the only way under given circumstances.

I agree that other platforms have the same limitations
with GUI performance as Racket has. However, other platforms
may have a spreadsheet control included :)
No complaints, though, I will use Racket for this.

Regards,

Dmitry

Dmitry Pavlov

unread,
Jul 19, 2014, 4:50:04 AM7/19/14
to us...@racket-lang.org
Hello,

Thanks again everybody for the pointers.

Here it is, a stub for a very basic spreadsheet editor in 419 lines
of Racket code. http://pastebin.com/m6pCATsU

Screenshot: http://imgur.com/k0vygX8

For simplicity, I decided to create all the buttons for columns at once
(seems to be OK when that are not in a scrolled panel).
Buttons for rows are created ad-hoc.

The implementation may have its glitches, but it is usable enough
for my purposes.

I will list the things that I am not quite happy with, and I will
appreciate for any pointers to how to work them around.
In case it is not possible, I will take them the way they are,
though.

1. Lack of scroll bars that one can use independently from
canvas or panel. I currently use sliders instead of scroll bars,
but with slider, it is impossible to go up/down by exactly
one point.

2. No auto-scrolling of text in a (small, limited by size)
text snip when the user enters more text than can fit in
the snip.

3. Strange white border around the text (or text snip?),
is visible on the screenshot, where the grid lines break.

4. Is there a way to disable multiline input in a text%?
For now, I just hook the handling of the "Enter" key,
but the user still can copy-paste multi-line text etc.

5. (Probably my own problem) Implementation relies
on several global variables (text-snip, row-buttons etc)
that potentially can be accessed from multiple GUI
threads simultaneously. I really do not know how
to do a reliable thread-safe GUI, especially in Racket,
are there any manuals or examples?

Best regards,

Dmitry

Vincent St-Amour

unread,
Jul 19, 2014, 12:22:21 PM7/19/14
to Dmitry Pavlov, us...@racket-lang.org
At Sat, 19 Jul 2014 12:46:51 +0400,
Dmitry Pavlov wrote:
>
> Hello,
>
> Thanks again everybody for the pointers.
>
> Here it is, a stub for a very basic spreadsheet editor in 419 lines
> of Racket code. http://pastebin.com/m6pCATsU
>
> Screenshot: http://imgur.com/k0vygX8

That's pretty cool. Is the code available on pkg.racket-lang.org?

Vincent

Dmitry Pavlov

unread,
Jul 19, 2014, 2:42:19 PM7/19/14
to Vincent St-Amour, us...@racket-lang.org
Vincent,


>> Screenshot: http://imgur.com/k0vygX8
>
> That's pretty cool. Is the code available on pkg.racket-lang.org?

The code is pretty basic, does not provide enough interfaces for
generic usage, and has the glitches I told about, so I think it does
not deserve to be published as a library in its present state.

However, the code is available at http://pastebin.com/m6pCATsU
and everybody is welcome to look, play, and reuse.

Regards,

Dmitry
Reply all
Reply to author
Forward
0 new messages