Re: Noob alert: trouble resizing canvas when app window is manually resized



John Wallace wrote:
I've been trying on and off for a day or three to get a simple Tcl/Tk app
using a canvas to behave "intuitively" when the app's main window is
manually resized. Specifically, the ideal result would be the canvas (and
its contents) is redrawn to fill the new size of window, whether it be
larger or smaller than before. The following code example and embedded
comments hopefully provide more detail, maybe even *sufficient* detail, to
help identify what I want, what I'm seeing, and how my current code might be
improved (which might include throwing it away :)).

I'm new to Tcl/Tk and don't have any local experts to consult. Although I'm
new, I've got the rest of my real app working OK(ish), just the canvas stuff
has me baffled for now, and I'd like this to look right for the real end
users. I have done the RTFM thing (specifically, Welch's "Practical
Programming" book, and the FAQ, and the Wiki, and the newsgroup and...) and
cannot find anything to quite match; related stuff is either too trivial to
help or too huge to cut down, with little in between in terms of simple (but
working) relevant examples. This is probably one of those "it's so trivial
it's obvious" cases but it's not currently obvious to me, hence the "small
reproducer" included here.

In case it's relevant, my environment is newly-installed TCL8.4 on
not-so-new Win2K.

OK, a couple of things.

first - you are getting the size of the main window "." to calulate
the size of your oval, but you are not allowing the canvas to resize with
the window itself (try setting the background color of the canvas and
you can see what is going on). To fix this, add -exand 1 -fill both to
your pack command and it should grow/shrink with he window.

second - you don't need to destroy and recreate the canvas every time you
want to redraw - create and pack it once at startup, then in you draw routine
you have a couple of options:
a) .c delete all ;# remove current contents
.c create oval .... ;# draw new oval
or
b) draw it *once* and save the id
set id [.c create oval ....]
then each time you need to change it, just use the coords subcommand
.c coords $id 50 50 [expr $xpixels - 50] [expr $ypixels - 50]
note that this assumes you declare id global so it saves the state


third .c is a widget path name, not a variable. so you don't need to declare it global


Bruce



All input gratefully received, though as we're heading for a holiday weekend
here in the UK I may not be able to say "thank you" for a day or two.
Regards
John

# Simple but unsatisfactory example of canvases and resizes
# Improvements are needed:
# (1) "First redraw" issue
# (2) "Tall narrow" ovals are truncated within the window
# (3) Clicking Redraw sometimes increases the size (circumstances unclear)
# Sample output from 'puts' below:
# x: 256 y: 192 resizes: 0
# <first redraw changes size unexpectedly?>
# x: 200 y: 200 resizes: 0
# <click "ReDraw" between the following >
# x: 204 y: 227 resizes: 6
# x: 208 y: 231 resizes: 10
# x: 212 y: 235 resizes: 14
# x: 216 y: 239 resizes: 18
# x: 220 y: 243 resizes: 22
# <manually resize the window - make it taller - then click ReDraw >
# x: 224 y: 646 resizes: 67 <-- Only top third or so of oval is drawn

proc main { } {
global .c xpixels ypixels
bind . <Configure> newsize
# Initial default sizes
set xpixels [expr [winfo screenwidth .] / 4]
set ypixels [expr [winfo screenheight .] / 4]
# Do canvas with oval
doCanvas
# Initial canvas/oval is the expected size but first "redraw" makes
# it change more than expected, then redraw works as expected.
# Doing a redraw right here hides that behaviour from the user.
reDoCanvas
}
#####################################
proc doCanvas { } {
global .c xpixels ypixels resizes
puts "x: $xpixels y: $ypixels resizes: $resizes"
canvas .c -background white -width $xpixels -height $xpixels
.c create oval 50 50 [expr $xpixels - 50] [expr $ypixels - 50] -fill green
pack .c
}
######################################
proc reDoCanvas { } {
global .c xpixels ypixels
set xpixels [winfo width .]
set ypixels [winfo height .]
pack forget .c
destroy .c
doCanvas
}
#######################################
proc newsize { } {
global resizes
incr resizes
}

frame .f1
button .f1.drawplot -command reDoCanvas -text "ReDraw"
pack .f1.drawplot -side left
pack .f1
set resizes 0
main


.