Updated 2014-01-28 00:31:16 by RLE

TIP#262 proposes that frames should have an option for setting a background image. This Page was started so some graphical examples of frames with background images could be displayed along with a discussion of the proposed change.

ET The TIP#262 can be found here http://tip.tcl.tk/262.html

After this was published, it became apparent that nested frames might present a problem. I think that having a -transparent option for frames might enhance this. Below is a screenshot of 2 sets of nested frames with buttons, where the upper set is how they would look without images and without the ability to set a frame transparent. The bottom half shows how this could look with a background image and a frame (enclosing the 3 buttons) that has been set to be transparent. Since this is not yet implemented, the below image is merely my photoshop'd version of what it might look like.

Note that the image has been tiled. It was created in photoshop, from a pattern, and then repeated as needed to fill the frame. This would allow one to create small pattern files that could also be inlined as code without being thousands of lines of text. The tile option would let one resize the window and as many repetitions of the pattern as needed would be rendered to fill the new frame size.

To implement this using the tip, (and an option -transparent not yet included in the tip) should be like so:
 Frame11 configure -backgroundimage $apattern -tile 1
 Frame8  configure -transparent 1 -borderwidth 0

which would take an image, tile it (repeat it) as needed to fill the frame, and then make Frame8 transparent so the buttons appear to hover over the background.

Note: Frame11 and Frame8 are command aliases to frames. I use Visual Tcl for this which generates command aliases to each widget that can then be used to configure the widget.

Frame8 was created inside Frame11 to organize the layout of the 3 buttons using the pack manager. In order to be completely transparent, the border width would need to be 0. If not 0, then it would draw a frame, based on style, as before, but the interior of the frame would still be transparent. I haven't completely thought this out yet, however.

MG (Excuse the rambling, just woke up) If it's possible to add a -transparent option like that for frames, why not go a step further: add a transparent color which all widgets can accept as their -background color. I assume that if code is added so that frames could be transparent, it wouldn't take much to apply it to other widgets. (Of course, I could be totally wrong, so if anyone who actually knows could correct me...)

One thing I noticed in your images, btw: Frame5 (the non-transparent counterpart of Frame8) has a raised relief, with a fairly heavy border, but Frame8 doesn't. Would the borders still show up for transparent frames? (Since it's not difficult to turn the borders off when you don't want them, that would seem to make more sense, to me...) Oh, and another thought: although the TIP doesn't mention it, could/would these options be added to [toplevel] widgets as well as frames? That would probably be equally useful.

ET The discussion on the core list seems to be how one would make these frames transparent on the 3 major system, windows, linux/unix, macos. So far, windows seems do-able, macos with some changes to a different API. Haven't heard from the linux/unix guys yet. I was wondering myself if the transparent color that is part of gif images was actually implemented.

Frame5 did have the raised relief, but not for any particular reason - just an option click in visual-tcl where I often just try different settings to see their effect. I would think that a -borderwidth 0 on a transparent frame would make it completely transparent, while a positive value would still render the borders the same as if -transparent was not on - but I don't know exactly how they'd look if the interior was transparent. It might work out or the two options together might clash. But with border 0, I would think the style (raised, relief, etc.) would in effect be canceled.

I usually have at least one frame at the top of my heirarchy inside all my toplevels, so couldn't we get the effect applied to a toplevel simply by applying this to the outermost frame in a toplevel, rather than changing the toplevel code itself. In the example, Frame1 and Frame11 could be inside a frame just below the toplevel, which could have border 0.

Incidentally, this -transparent option could also be more than a boolean; maybe a float, where 0. and 1. would be off/on but there could be semi-transparency with a value, say 0.5. I didn't suggest this yet as I really have no clue how difficult any of this would be to implement. But perhaps on a system that could not implement partial transparency, the floating value would simply be rounded to 0 or 1.

Also, -transparent would be a feature of frames, independent of the imaging capability. This would give a feeling of inheritance to inner frames that would then inherit their parent frames color. Then if one wanted to effect all the colors of a set of nested frames with the same color, one could just change the outermost frames color.

I would also think that all the other options, like expand, fill, etc. would work as expected. It seems logical that the rendering of styles would be in two parts, the interiors and the borders. There's also the internal and external padding that should be straightforward to implement also.

MG When I said as a color, I didn't really mean related to images, just as a simpler way to add transparency to all widgets. It would be good, for instance, to be able to give label widgets a transparent background, so that they took on the background color of the frame (or toplevel) they were packed in automatically.

I've also seen requests (and bits of code) on the Wiki for tiled background images in text and canvas widgets, so I wonder: is there any reason this TIP was limited to frame widgets? Is there something that makes it simple(r) to add these into frames than into (some/all) other kinds of widgets? Or would it theoretically be quite easy to have transparent or bg-imaged widgets of all types, once it's coded for frames?

ET I was thinking that if I could just make frames look jazy, I'd be able to better show off some Tcl/Tk gui programs I've been writing. One often needs to justify using Tcl/Tk. All I keep hearing is XML this, Java that, Python shmithon etc.

I thought if I could just have better looking backgrounds, that could really spice up my gui scripts. The frame idea came to me when I was struggling to jazz up a "master control panel" I had written, and wanted to have a chrome background behind some widgets in a frame. In my business, it's often how cool the thing looks that sells the project. Functionality comes second when you have only a few seconds to impress some high placed political types.

I looked around, found the wiki entry on tiled backgrounds but it all seemed relatively difficult to implement involving a lot of code with canvases.

So, I asked myself, what's the smallest Tcl/Tk change that would get me what I was after, and background images in frames seemed to fit the bill. Since other widgets had background images (like button) I figured this must not be too difficult to implement. Later, the -transparent idea seemed to add almost as much as the imaging itself, but I haven't yet figured out how to change a published TIP.

It could be the way I program. Since I can add frames with no effort using visual-tcl, I tend to use them around almost every widget, just in case I want to later add something next to it without messing up other widget placement. I find the place and grid managers to be problematic and difficult to work with and so by using many frames and the pack manager I can always get what I want. I'm just a sort of frame type of guy :)

DKF: If frames support background images, so should toplevels. After all, those two widgets are virtually the same thing.

ET It's been brought to my attention that a canvas can do pretty much everything a frame can, and it supports a background image. So, if this is the case, I might suggest a withdrawl of this tip and instead create a tip that proposes that a canvas background image could be transparent as I've discussed above. I also did the tiling with the code example (by Aric Bills) from tiled image to tile a jpg file I created from a photoshop pattern. Then I made an inline -data string from the file. The tiling reduced an inline image -data set from over 2000 lines of text to about 200. Quite acceptable for inlining.

On the other hand, doing this within frames might still be a preferable way to go for beginners who might be put off by the complexity of canvases. I guess it would be up to the implementers to decide which was best.

There's also a package called Paved Widgets that support most of this request. I've asked the poster who mentioned this if it supported transparent images (he replied as how it did not), as I'd still need to do framing with a paved::canvas and would need the transparency.

This is beginning to converge down to a few ideas.

  • use canvas instead of frame to get a background image
  • use the tiling repeat feature of image copy
  • write a new tip suggesting transparency option for a canvas and/or a frame (and text widget, surely)
  • implement the first 2 in Tcl code, but the hard one is the transparency

Without the transparency, placement would be difficult as nested frames or canvases would obscure the background image.

I had considered suggesting a hack on frame whereby using the -backgroundimage on a frame command would just invoke canvas behind the scenes. This could get confusing, or it could be a way to implement this as a frame so the novice programmer wouldn't have to think about all the canvas features to get a background image into a frame. But maybe it'd just be better to go with a few library proc's instead.

The following example program demonstrates a resizeable window with a few canvases. One outer canvas and two inner canvases. Of the two inner ones, one has 2 labels and the other 2 buttons. The one with buttons has a slate texture for the background. This works because the buttons are not in a frame (or canvas) of their own nested inside the canvas.
    # procedure from Aric Bills wiki example
    proc {initBackground} {canvas sourceImage} {
        package require Img 
        set tiledImage [image create photo]
        $canvas create image 0 0  -anchor nw  -image $tiledImage  -tags {backgroundBitmap}
        $canvas lower backgroundBitmap
        if {0} {
            proc {tile} {canvas sourceImage tiledImage} {
                $tiledImage copy $sourceImage  -to 0 0 [winfo width $canvas] [winfo height $canvas]
            bind $canvas <Configure> [list tile $canvas $sourceImage $tiledImage]
            bind $canvas <Destroy> [list image delete $sourceImage $tiledImage]
            tile $canvas $sourceImage $tiledImage
        } else {  
            # avoid needing a tile proc  
            bind $canvas <Configure> "$tiledImage copy $sourceImage  -to 0 0 \[winfo width $canvas\] \[winfo height $canvas\]"
            bind $canvas <Destroy> [list image delete $sourceImage $tiledImage]
            $tiledImage copy $sourceImage  -to 0 0 [winfo width $canvas] [winfo height $canvas]   
    proc {main} {argc argv} {
            global  vTcl
            package require Img
            #wm withdraw .
            wm geometry . 400x400+30+30
            initBackground .can61.can66 [myback]
            #console show
    proc {myback} {} {
    set backg [image create photo -data {
        return $backg
       set base ""
       canvas $base.can61 \
            -borderwidth 2 -closeenough 1.0 -height 264 -relief ridge -width 378 
        canvas $base.can61.can62 \
            -borderwidth 2 -closeenough 1.0 -height 264 -highlightthickness 9 \
            -relief ridge -width 378 
        label $base.can61.can62.lab64 \
            -text label1 
        label $base.can61.can62.lab65 \
            -text label2 
        canvas $base.can61.can66 \
            -closeenough 1.0 -height 264 -relief groove -width 378 
        button $base.can61.can66.but67 \
            -background #009900 -borderwidth 6 -foreground #ffff00 -pady 0 \
            -text button1 
        button $base.can61.can66.but75 \
            -background #ff0000 -borderwidth 6 -foreground #ffffff -pady 0 \
            -text exit -command exit
        pack $base.can61 \
            -in . -anchor center -expand 1 -fill both -side top 
        pack $base.can61.can62 \
            -in $base.can61 -anchor center -expand 1 -fill both -side top 
        pack $base.can61.can62.lab64 \
            -in $base.can61.can62 -anchor center -expand 1 -fill none -side top 
        pack $base.can61.can62.lab65 \
            -in $base.can61.can62 -anchor center -expand 1 -fill none -side top 
        pack $base.can61.can66 \
            -in $base.can61 -anchor center -expand 1 -fill both -side top 
        pack $base.can61.can66.but67 \
            -in $base.can61.can66 -anchor center -expand 1 -fill none -side top 
        pack $base.can61.can66.but75 \
            -in $base.can61.can66 -anchor center -expand 1 -fill none -side top 
    main $argc $argv

Here's what it looks like, but also with a second background picture below it. The bricks are only about 30% more data and tile nicely, while the slate doesn't look so good because of the effort to make the data set so small.

(embedded image link broken 2012-01-27)

uniquename 2014jan27

For those who do not have the facilities or time to implement the code above (and to fix the dead external-image-link above), here is a locally stored image of the Tk GUI produced by the code above.

This example uses 'label' and 'button' widgets on a canvas --- the buttons on a tiled background image. For an example of 'scale' and 'entry' widgets on a canvas, see the wiki page titled Widgets on a canvas. For another example of putting a tiled image on a canvas, see the wiki page titled tiled image.