[racket] question/problem on racket/gui and "on-paint" flooding

From: Neil Toronto (neil.toronto at gmail.com)
Date: Tue Jun 11 20:18:22 EDT 2013

Yes, that's bad.

I don't have a fix (ain't my bailiwick), but a possible workaround. 
Drawing a bitmap should be much less expensive than drawing a plot, and 
IIRC bitmaps don't draw themselves on un-invalidated parts of a GUI 
device context. (Plots shouldn't, either, but they send a lot of drawing 
commands to the dc, which all have to be clipped, and there's a lot of 
processing behind those commands.) For now, you could try using 
`plot-bitmap' to plot once and then draw them using the `draw-bitmap' 

In the meantime, I think you should submit a bug report.

If you're feeling frisky, you could check out the `unstable/gui/snip' 
module. It defines a `snip-canvas%' class, whose instances allow you to 
put arbitrary "snips" in a GUI. Plot snips - the things you get in 
DrRacket's REPL when you use the `plot' function - cache their 
appearance in a bitmap and draw that bitmap when painted. They only 
recompute the bitmap when the plot is manipulated (i.e. zoomed or 
rotated). If you put plot snips on your GUI, you would get manipulatable 
plots, and the snips' internal caching might keep your app responsive 
when being flooded by paint messages.

Neil ⊥

On 06/11/2013 02:19 PM, Mag. Dr. Nikolaus Klepp wrote:
> As I'm writing a real-world application in racket (and it's a great tool to do
> so!) I just ran into another problem:
> When a a panel% has a visible scrollbar and there are enough children to
> actually use that scrollbar, then all children get flooded with on-paint
> calls when the scrollbar is used.
> To be precise, the problem is not that the children get lots of on-paint, but
> that invisible children get that calls, too, which results in a pileup of
> on-paint calls that block the application when the drawing operation is
> expensive.
> In my case I have several dozen graphs to present and even touching the
> scrollbar results in a desaster.
> Is there a workaround, say, can I find out if a child is visible at all?
> Example code - just scroll around and watch how often the first child is
> redrawn, even when invisible:
> #lang racket
> (require racket/gui)
> (require plot)
> (define counter 0)
> (define frame (new frame% [label "on-paint flooding"] [min-height 800]
> [min-width 800]))
> (define panel (new vertical-panel%  [parent frame] [style '(auto-hscroll
> auto-vscroll)]))
> (for-each
>   (λ (a)
>     (new canvas%
>          [parent panel] [min-height 150] [min-width 150]
>          [paint-callback (λ (c dc)
>                            (when (= a 0) (set! counter (add1 counter)))
>                            (define-values (w h) (send dc get-size))
>                            ; uncomment the following line to see the effect on
> expensive rendering:
>                            ; (plot/dc (function (λ (x) (sin (* 4 x))) -1 1) dc
> 0 0 w h )
>                            (send dc draw-text (format "~a" counter) 0 0))]))
>   '(0 1 2 3 4 5 6 7 8 9 10))
> (send frame show #t)
> Nik

Posted on the users mailing list.