Tk: how to dynamically remove / add widgets?

I have a handle on a frame and a widget in that frame:

@problem = TkFrame.new(root).pack('side'=>'right', 'expand'=>'yes',

‘fill’=>‘x’, ‘padx’=>’.5c’, ‘pady’=>’.5c’)
@a = TkLabel.new(problem){width 2; height 1}

Everything is up and runnning.

On a certain event I want to modify the frame
e.g. remove the widget @a, add another widget @b.

How do I do this?

Thanks.

Hi,

···

From: “Its Me” itsme213@hotmail.com
Subject: tk: how to dynamically remove / add widgets?
Date: Sun, 25 Apr 2004 06:04:06 +0900
Message-ID: eCAic.21996$hR1.16476@fe2.texas.rr.com

On a certain event I want to modify the frame
e.g. remove the widget @a, add another widget @b.

Use ‘bind’ method.
The follwing is a sample of binding.

It will be included in the sample directry of the renewal

version of Ruby/Tk.


#!/usr/bin/env ruby

require ‘tk’

class Button_clone < TkLabel
def initialize(*args)
@command = nil
if args[-1].kind_of?(Hash)
keys = _symbolkey2str(args.pop)
@command = keys.delete(‘command’)
args.push(keys)
end

super(*args)

self.configure(:highlightthickness=>1, 
	   :padx=>'3m', :pady=>'1m', 
	   :relief=>'raised')

self.bind('Enter', proc{self.background(self.activebackground)})
self.bind('Leave', proc{
	self.background(self.highlightbackground)
	self.relief('raised')
      })

self.bind('ButtonPress-1', proc{self.relief('sunken')})
self.bind('ButtonRelease-1', proc{
	self.relief('raised')
	@command.call if @command
      })

end

def command(cmd = Proc.new)
@command = cmd
end
end

TkLabel.new(:text=><<EOT).pack
This is a sample of ‘event binding’.
The first button is a normal button widget.
And the second one is a normal label widget
but with some bindings like a button widget.
EOT

lbl = TkLabel.new(:foreground=>‘red’).pack(:pady=>3)

v = TkVariable.new(0)

TkFrame.new{|f|
TkLabel.new(f, :text=>'click count : ').pack(:side=>:left)
TkLabel.new(f, :textvariable=>v).pack(:side=>:left)
}.pack

TkButton.new(:text=>‘normal Button widget’,
:command=>proc{
puts ‘button is clicked!!’
lbl.text ‘button is clicked!!’
v.numeric += 1
}){
pack(:fill=>:x, :expand=>true)
}

Button_clone.new(:text=>‘Label with Button binding’,
:command=>proc{
puts ‘label is clicked!!’
lbl.text ‘label is clicked!!’
v.numeric += 1
}){
pack(:fill=>:x, :expand=>true)
}

Tk.mainloop


Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

Thanks …

“Hidetoshi NAGAI” nagai@ai.kyutech.ac.jp wrote in message

Use ‘bind’ method.
The follwing is a sample of binding.
self.bind(‘Enter’, proc{self.background(self.activebackground)})

This seems to be about binding and re-binding the callbacks on a widget.

What I want to do is actually remove widgets and add new widget to some
containing frame.

Any way to do that?

it’s tricky to do without making the parent re-size:

require ‘tk’
require ‘tkencoding’ unless %r/^8.[1-9]/o =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK

class Widget
attr :widget
def initialize master
@master = master
end
end
class FooWindow < Widget
def initialize master
super
@widget = TkLabel.new @master, ‘text’=>‘foo’
end
end
class BarWindow < Widget
def initialize master
super
@widget = TkLabel.new @master, ‘text’=>‘bar’
end
end
class Gui < Widget
def initialize master = TkRoot.new
super
init_geometry
build_widget
build_button_bar
build_window_frame
build_windows
grid_configure
end
def init_geometry
case @master
when TkRoot, TkWindow, Tk::Wm
@width = @master.winfo_screenwidth * 0.42
@height = @master.winfo_screenheight * 0.42
@master.configure ‘width’=>@width, ‘height’=>@height
@master.geometry ‘+50+50’
else
@width = @master.width
@height = @master.height
end
end
def build_widget
@widget = TkFrame.new @master
@widget.place ‘relx’=>0, ‘rely’=>0, ‘relwidth’=>1, ‘relheight’=>1
end
def build_button_bar
@button_frame = TkFrame.new @widget
@button_frame.grid ‘sticky’=>‘ew’
@foo_button = TkButton.new @button_frame, ‘text’=>‘foo’
@foo_button.configure ‘command’=>lambda{set_window @foo_window}
@foo_button.pack
@bar_button = TkButton.new @button_frame, ‘text’=>‘bar’
@bar_button.configure ‘command’=>lambda{set_window @bar_window}
@bar_button.pack
end
def build_window_frame
@window_frame = TkFrame.new @widget
@window_frame.grid ‘sticky’=>‘nsew’
end
def build_windows
@foo_window = FooWindow.new @window_frame
@bar_window = BarWindow.new @window_frame
end
def grid_configure
TkGrid.rowconfigure @widget, 1, ‘weight’=>1
TkGrid.columnconfigure @widget, 0, ‘weight’=>1
end
def set_window widget
@window.place_forget if @window
@window = widget.widget
@window.place ‘relx’=>0, ‘rely’=>0,
‘relwidth’=>1, ‘relheight’=>1,
‘in’=>@window_frame
end
end

Gui.new
Tk.mainloop

the key bit is the set_window method…

-a

setwidget.rb (2.14 KB)

···

On Sun, 25 Apr 2004, Its Me wrote:

Thanks …

“Hidetoshi NAGAI” nagai@ai.kyutech.ac.jp wrote in message

Use ‘bind’ method.
The follwing is a sample of binding.
self.bind(‘Enter’, proc{self.background(self.activebackground)})

This seems to be about binding and re-binding the callbacks on a widget.

What I want to do is actually remove widgets and add new widget to some
containing frame.

Any way to do that?

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

Hi,

···

From: “Its Me” itsme213@hotmail.com
Subject: Re: tk: how to dynamically remove / add widgets?
Date: Mon, 26 Apr 2004 00:09:06 +0900
Message-ID: gsQic.23285$hR1.12603@fe2.texas.rr.com

This seems to be about binding and re-binding the callbacks on a widget.
What I want to do is actually remove widgets and add new widget to some
containing frame.

I intend to show that a callback for a widget can control another
widget. In other words, you can pack/unpack some widgets in a
callback procedure. If you hate the frame size is changed when packing
some widgets in the frame, you must set TkPack.propagate to false.
Please see the following sample script, and compare the difference
of propagate mode (true/false).

#!/usr/bin/env ruby
require ‘tk’

TkLabel.new(:text=>“Please click the bottom frame”).pack

f = TkFrame.new(:width=>400, :height=>100, :background=>‘yellow’,
:relief=>‘ridge’, :borderwidth=>5).pack

TkPack.propagate(f, false) # <== important!!

list = (1…3).collect{|n|
TkButton.new(f, :text=>“button-#{‘X’*n}”){
command proc{
puts “button-#{‘X’*n}”
self.unpack
}
}
}

f.bind(‘1’, proc{
w = list.shift
w.unpack
list.push(w)
list[0].pack(:anchor=>:center)
})

Tk.mainloop


Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

Perfect! Thank you very much.

I don’t have rdoc documentation working so this is more guesswork that it
should be.

“Hidetoshi NAGAI” nagai@ai.kyutech.ac.jp wrote in message

···

I intend to show that a callback for a widget can control another
widget. In other words, you can pack/unpack some widgets in a
callback procedure. If you hate the frame size is changed when packing
some widgets in the frame, you must set TkPack.propagate to false.
Please see the following sample script, and compare the difference
of propagate mode (true/false).

#!/usr/bin/env ruby
require ‘tk’

TkLabel.new(:text=>“Please click the bottom frame”).pack

f = TkFrame.new(:width=>400, :height=>100, :background=>‘yellow’,
:relief=>‘ridge’, :borderwidth=>5).pack

TkPack.propagate(f, false) # <== important!!

list = (1…3).collect{|n|
TkButton.new(f, :text=>“button-#{‘X’*n}”){
command proc{
puts “button-#{‘X’*n}”
self.unpack
}
}
}

f.bind(‘1’, proc{
w = list.shift
w.unpack
list.push(w)
list[0].pack(:anchor=>:center)
})

Tk.mainloop


Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)