summaryrefslogtreecommitdiff
path: root/ext/tk/sample
diff options
context:
space:
mode:
authornagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-07-12 23:08:32 +0000
committernagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-07-12 23:08:32 +0000
commited6ce8b43b6f25df1d4809ac799de4dd1c85c1f3 (patch)
tree09bc05d679d0f224a29fee44d10beea321bdc0b5 /ext/tk/sample
parente13fb8029b87943ab8af2211226b7c9347d3976d (diff)
* ext/tk/extconf.rb: New strategy for searching Tcl/Tk libraries.
* ext/tk/*: Support new features of Tcl/Tk8.6b1 and minor bug fixes. ( [KNOWN BUG] Ruby/Tk on Ruby 1.9 will not work on Cygwin. ) * ext/tk/*: Unify sources between Ruby 1.8 & 1.9. Improve default_widget_set handling. * ext/tk/*: Multi-TkInterpreter (multi-tk.rb) works on Ruby 1.8 & 1.9. ( [KNOWN BUG] On Ruby 1.8, join to a long term Thread on Tk callbacks may freeze. On Ruby 1.9, cannot create a second master interpreter (creating slaves are OK); supported master interpreter is the default master interpreter only. ) * ext/tk/lib/tkextlib/*: Update supported versions of Tk extensions. Tcllib 1.8/Tklib 0.4.1 ==> Tcllib 1.11.1/Tklib 0.5 BWidgets 1.7 ==> BWidgets 1.8 TkTable 2.9 ==> TkTable 2.10 TkTreeCtrl 2005-12-02 ==> TkTreeCtrl 2.2.9 Tile 0.8.0/8.5.1 ==> Tile 0.8.3/8.6b1 IncrTcl 2005-02-14 ==> IncrTcl 2008-12-15 TclX 2005-02-07 ==> TclX 2008-12-15 Trofs 0.4.3 ==> Trofs 0.4.4 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24063 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/tk/sample')
-rw-r--r--ext/tk/sample/demos-en/widget7
-rw-r--r--ext/tk/sample/demos-jp/widget8
-rw-r--r--ext/tk/sample/editable_listbox.rb131
-rw-r--r--ext/tk/sample/menubar3.rb72
-rw-r--r--ext/tk/sample/multi-ip_sample.rb3
-rw-r--r--ext/tk/sample/safe-tk.rb23
-rw-r--r--ext/tk/sample/scrollframe.rb20
-rw-r--r--ext/tk/sample/tkalignbox.rb44
-rw-r--r--ext/tk/sample/tkballoonhelp.rb90
-rw-r--r--ext/tk/sample/tkcombobox.rb121
-rw-r--r--ext/tk/sample/tktextframe.rb251
11 files changed, 581 insertions, 189 deletions
diff --git a/ext/tk/sample/demos-en/widget b/ext/tk/sample/demos-en/widget
index 9a0605d..250c589 100644
--- a/ext/tk/sample/demos-en/widget
+++ b/ext/tk/sample/demos-en/widget
@@ -170,9 +170,12 @@ else
}
scr.command(proc{|*args| txt.yview(*args)})
# txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both', 'padx'=>1)
- txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both')
+# txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both')
# textFrame.pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>2)
textFrame.pack('expand'=>'yes', 'fill'=>'both')
+ # $root.withdraw.deiconify
+ Tk.update_idletasks
+ txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both')
statusBar = TkFrame.new($root) {|f|
if $tk_version =~ /^4.*/
@@ -1035,7 +1038,7 @@ end
#
def aboutBox
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo',
- 'message'=>"Ruby/Tk widget demonstration Ver.1.7.0-en\n\n" +
+ 'message'=>"Ruby/Tk widget demonstration Ver.1.7.1-en\n\n" +
"based on demos of Tk8.1 -- 8.5 " +
"( Copyright of Tcl/Tk demos:: " +
"(c) 1996-1997 Sun Microsystems, Inc. / " +
diff --git a/ext/tk/sample/demos-jp/widget b/ext/tk/sample/demos-jp/widget
index 132953f..dfaa9c0 100644
--- a/ext/tk/sample/demos-jp/widget
+++ b/ext/tk/sample/demos-jp/widget
@@ -190,10 +190,14 @@ else
yscrollcommand proc{|first,last| scr.set first,last}
}
scr.command(proc{|*args| txt.yview(*args)})
+
# txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both', 'padx'=>1)
- txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both')
+# txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both')
# textFrame.pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>2)
textFrame.pack('expand'=>'yes', 'fill'=>'both')
+ # $root.withdraw.deiconify
+ Tk.update_idletasks
+ txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both')
statusBar = TkFrame.new($root) {|f|
if $tk_version =~ /^4.*/
@@ -1070,7 +1074,7 @@ end
#
def aboutBox
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo',
- 'message'=>"Ruby/Tk ウィジェットデモ Ver.1.7.0-jp\n\n" +
+ 'message'=>"Ruby/Tk ウィジェットデモ Ver.1.7.1-jp\n\n" +
"based on demos of Tk8.1 -- 8.5 " +
"( Copyright of Tcl/Tk demos:: " +
"(c) 1996-1997 Sun Microsystems, Inc. / " +
diff --git a/ext/tk/sample/editable_listbox.rb b/ext/tk/sample/editable_listbox.rb
index 553d400..7a9ad44 100644
--- a/ext/tk/sample/editable_listbox.rb
+++ b/ext/tk/sample/editable_listbox.rb
@@ -1,5 +1,5 @@
#
-# Editable_TkListbox class
+# Tk::RbWidget::Editable_Listbox class
#
# When "DoubleClick-1" on a listbox item, the entry box is opend on the
# item. And when hit "Return" key on the entry box after modifying the
@@ -10,19 +10,106 @@
#
require 'tk'
-class Editable_TkListbox < TkListbox
- def _ebox_placer(coord_y)
- idx = self.nearest(coord_y)
- x, y, w, h = self.bbox(idx)
+module Tk
+ module RbWidget
+ class Editable_Listbox < TkListbox
+ end
+ end
+end
+
+
+class Tk::RbWidget::Editable_Listbox < TkListbox
+ #------------------------------------
+ BindTag = TkBindTag.new_by_name(self.to_s.gsub(/::/, '#'))
+
+ BindTag.bind('FocusIn', :widget){|w|
+ w.instance_eval{
+ if idx = @ebox.pos
+ see(idx) if bbox(idx).empty?
+ @ebox.focus(true)
+ end
+ }
+ }
+
+ BindTag.bind('Double-1', :widget, :y){|w, y|
+ w.instance_eval{ _ebox_placer(nearest(y)) }
+ }
+
+ BindTag.bind('Return', :widget){|w|
+ w.instance_eval{
+ if idx = index(:active)
+ _ebox_placer(idx)
+ end
+ }
+ }
+ #------------------------------------
+
+ def configure(*args)
+ ret = super
+
+ case cget(:state)
+ when 'normal'
+ # do nothing
+ when 'disabled'
+ _ebox_erase
+ else # unknown
+ # do nothing
+
+ end
+
+ ret
+ end
+
+ def _ebox_move(idx)
+ return nil if cget(:state) == 'disabled'
+ x, y, w, h = bbox(idx)
+ return nil unless y && h
@ebox.place(:x => 0, :relwidth => 1.0,
- :y => y - self.selectborderwidth,
- :height => h + 2 * self.selectborderwidth)
+ :y => y - selectborderwidth,
+ :height => h + 2 * selectborderwidth)
@ebox.pos = idx
- @ebox.value = self.listvariable.list[idx]
@ebox.focus
end
- private :_ebox_placer
+ def _ebox_placer(idx)
+ return nil unless _ebox_move(idx)
+ @ebox.value = listvariable.list[idx]
+ @ebox.xview_moveto(self.xview[0])
+ end
+
+ def _ebox_erase
+ @ebox.place_forget
+ @ebox.pos = nil
+ end
+ private :_ebox_move, :_ebox_placer, :_ebox_erase
+
+ def _setup_ebox_bindings
+ # bindings for entry
+ @ebox.bind('Return'){
+ list = listvariable.list
+ list[@ebox.pos] = @ebox.value if @ebox.pos
+ listvariable.value = list
+ _ebox_erase
+ focus
+ }
+
+ @ebox.bind('Escape'){ _ebox_erase }
+ end
+ def _setup_listbox_bindings
+ # bindings for listbox
+ tags = bindtags
+ bindtags(tags.insert(tags.index(self) + 1, self.class::BindTag))
+ end
+ private :_setup_ebox_bindings, :_setup_listbox_bindings
+
+ def yview(*args)
+ if !@ebox.pos || bbox(@ebox.pos).empty?
+ @ebox.place_forget
+ else
+ _ebox_move(@ebox.pos)
+ end
+ super
+ end
def create_self(keys)
super(keys)
@@ -32,38 +119,30 @@ class Editable_TkListbox < TkListbox
end
@ebox = TkEntry.new(self){
- @pos = -1
+ @pos = nil
def self.pos; @pos; end
def self.pos=(idx); @pos = idx; end
}
- @ebox.bind('Return'){
- list = self.listvariable.list
- list[@ebox.pos] = @ebox.value
- self.listvariable.value = list
- @ebox.place_forget
- @ebox.pos = -1
- }
-
- @ebox.bind('Escape'){
- @ebox.place_forget
- @ebox.pos = -1
- }
-
- self.bind('Double-1', '%y'){|y| _ebox_placer(y) }
+ _setup_ebox_bindings
+ _setup_listbox_bindings
end
end
if $0 == __FILE__
+ #lbox0 = TkListbox.new.pack(:side=>:left)
+ #lbox0.insert(:end, 0,1,2,3,4,5,6,7,8,9,0,1,2,3)
+
scr = TkScrollbar.new.pack(:side=>:right, :fill=>:y)
- lbox1 = Editable_TkListbox.new.pack(:side=>:left)
- lbox2 = Editable_TkListbox.new.pack(:side=>:left)
+ lbox1 = Tk::RbWidget::Editable_Listbox.new.pack(:side=>:left)
+ lbox2 = Tk::RbWidget::Editable_Listbox.new.pack(:side=>:left)
scr.assign(lbox1, lbox2)
lbox1.insert(:end, *%w(a b c d e f g h i j k l m n))
lbox2.insert(:end, 0,1,2,3,4,5,6,7,8,9,0,1,2,3)
+
Tk.mainloop
end
diff --git a/ext/tk/sample/menubar3.rb b/ext/tk/sample/menubar3.rb
new file mode 100644
index 0000000..129cfd7
--- /dev/null
+++ b/ext/tk/sample/menubar3.rb
@@ -0,0 +1,72 @@
+#
+# menubar sample 3 : vertical layout menubar; use frame and menubuttons
+#
+
+require 'tk'
+
+radio_var = TkVariable.new('y')
+
+menu_spec = [
+ [['&File', true], # when underline option is ture, '&' index is the position
+ {:label=>'Open', :command=>proc{puts('Open clicked')}, :underline=>0},
+ '---',
+ ['Check_A', TkVariable.new(true), 6],
+ {:type=>'checkbutton', :label=>'Check_B',
+ :variable=>TkVariable.new, :underline=>6},
+ '---',
+ ['Radio_X', [radio_var, 'x'], /[XYZ]/, '', {:foreground=>'black'}],
+ ['Radio_Y', [radio_var, 'y'], /[XYZ]/],
+ ['Radio_Z', [radio_var, 'z'], /[XYZ]/], # use Regexp for underline position
+ '---',
+ ['cascade', [
+ ['sss', proc{p 'sss'}, 0],
+ ['ttt', proc{p 'ttt'}, 0],
+ ['uuu', proc{p 'uuu'}, 0],
+ ['vvv', proc{p 'vvv'}, 0],
+ ],
+ 0, '',
+ {:font=>'Courier 16 italic',
+ :menu_config=>{:font=>'Times -18 bold', :foreground=>'black'}}],
+ '---',
+ ['Quit', proc{exit}, 0]],
+
+ [['Edit', 0],
+ ['Cut', proc{puts('Cut clicked')}, 2],
+ ['Copy', proc{puts('Copy clicked')}, 0],
+ ['Paste', proc{puts('Paste clicked')}, 0]],
+
+ [['Help', 0, {:menu_name=>'help'}],
+ ['About This', proc{puts('Ruby/Tk menubar sample 3')}, "This"]]
+ # use string index for underline position
+]
+
+layout_proc = 'vertical'
+# The following procedure is same to 'layout_proc'=>'vertical'
+=begin
+layout_proc = proc{|parent, mbtn|
+ mbtn.direction :right
+ mbtn.pack(:side=>:top, :fill=>:x)
+
+ menu = mbtn.menu
+ cmd = proc{|m, dir|
+ Tk::Menu::TkInternalFunction.next_menu(m, dir) rescue nil
+ # ignore error when the internal function doesn't exist
+ }
+ menu.bind('Tab', cmd, :widget, 'forward')
+ menu.bind('Alt-Tab', cmd, :widget, 'backward')
+}
+=end
+
+menubar = TkMenubar.new(nil, menu_spec,
+ 'layout_proc'=>layout_proc,
+ 'tearoff'=>false,
+ 'foreground'=>'grey40',
+ 'activeforeground'=>'red',
+ 'font'=>'Helvetia 12 bold')
+menubar.pack('side'=>'left', 'fill'=>'y')
+
+TkText.new(:wrap=>'word').pack.insert('1.0', 'This sample script generates "Menu Sidebar".
+If "::tk::MenuNextMenuon" function is available your Tcl/Tk library, you will be able to move to the next menu by Tab key on the posted menu, or the previous menu by Alt + Tab key.
+Please read the sample source, and check how to override default configure options of menu entries on a menu_spec. Maybe, on windows, this menubar does not work properly about keyboard shortcuts. Then, please use "menu" option of root/toplevel widget (see sample/menubar3.rb).')
+
+Tk.mainloop
diff --git a/ext/tk/sample/multi-ip_sample.rb b/ext/tk/sample/multi-ip_sample.rb
index 8150e69..eccf020 100644
--- a/ext/tk/sample/multi-ip_sample.rb
+++ b/ext/tk/sample/multi-ip_sample.rb
@@ -19,7 +19,6 @@ cmd = Proc.new{|txt|
else
root = TkRoot.new(:title=>'timer sample')
end
-
label = TkLabel.new(:parent=>root, :relief=>:raised, :width=>10) \
.pack(:side=>:bottom, :fill=>:both)
@@ -48,6 +47,7 @@ cmd = Proc.new{|txt|
b_start = TkButton.new(:text=>'Start', :state=>:disabled) {
pack(:side=>:left, :fill=>:both, :expand=>true)
}
+
b_stop = TkButton.new(:text=>'Stop', :state=>:normal) {
pack('side'=>'left', 'fill'=>'both', 'expand'=>'yes')
}
@@ -80,6 +80,7 @@ safe_slave2.eval_proc(cmd, 'safe2') # label -> .w00020
cmd.call('master') # label -> .w00024
#second_master = MultiTkIp.new(&cmd)
+#second_master = MultiTkIp.new(:safe=>2){p [:second_master, $SAFE]}
TkTimer.new(2000, -1, proc{p ['safe1', safe_slave1.deleted?]}).start
TkTimer.new(2000, -1, proc{p ['safe2', safe_slave2.deleted?]}).start
diff --git a/ext/tk/sample/safe-tk.rb b/ext/tk/sample/safe-tk.rb
index e240848..148548e 100644
--- a/ext/tk/sample/safe-tk.rb
+++ b/ext/tk/sample/safe-tk.rb
@@ -11,13 +11,16 @@ TkFrame.new(:borderwidth=>2, :height=>3,
:relief=>:sunken).pack(:fill=>:x, :expand=>true,
:padx=>10, :pady=>7)
+safe0_p = proc{|*args| p args}
+
###############################
puts "---- create a safe slave IP with Ruby's safe-level == 1 ----------"
-ip = MultiTkIp.new_safe_slave(1)
+ip = MultiTkIp.new_safe_slave(1){|*args| safe0_p["safe_slave safe_level == #{$SAFE}", args]}
puts "\n---- create procs ----------"
puts 'x = proc{p [\'proc x\', "$SAFE==#{$SAFE}"]; exit}'
+#x = proc{p ['proc x', "$SAFE==#{$SAFE}"]; exit}
x = proc{p ['proc x', "$SAFE==#{$SAFE}"]; exit}
TkLabel.new(:text=>'x = proc{p [\'proc x\', "$SAFE==#{$SAFE}"]; exit}',
:anchor=>:w).pack(:fill=>:x)
@@ -46,7 +49,9 @@ p lbl = ip.eval_proc{
:command=>proc{l.text($SAFE)}).pack(:fill=>:x, :padx=>5)
TkButton.new(:text=>':command=>x', :command=>x).pack(:fill=>:x, :padx=>5)
TkButton.new(:text=>':command=>proc{exit}',
- :command=>proc{exit}).pack(:fill=>:x, :padx=>5)
+ :command=>proc{
+ safe0_p["'exit' is called at $SAFE=#{$SAFE}"];exit}
+ ).pack(:fill=>:x, :padx=>5)
TkFrame.new(:borderwidth=>2, :height=>3,
:relief=>:sunken).pack(:fill=>:x, :expand=>true,
:padx=>10, :pady=>7)
@@ -68,10 +73,24 @@ p ip.eval_proc(proc{
TkButton.new(:text=>':command=>proc{y.call(l)}',
:command=>proc{y.call(l)}).pack(:fill=>:x,
:padx=>5)
+ TkButton.new(:text=>':command=>proc{Proc.new(&y).call(l)}',
+ :command=>proc{
+ Proc.new(&y).call(l)
+ }).pack(:fill=>:x, :padx=>5)
+ TkButton.new(:text=>':command=>proc{MultiTkIp._proc_on_current_safelevel(y).call(l)}',
+ :command=>proc{
+ MultiTkIp._proc_on_current_safelevel(y).call(l)
+ }).pack(:fill=>:x, :padx=>5)
+if Object.const_defined?(:RubyVM) && ::RubyVM.class == Class
TkButton.new(:text=>':command=>proc{Thread.new(l, &y).value}',
:command=>proc{
Thread.new(l, &y).value
}).pack(:fill=>:x, :padx=>5)
+else
+ # KNOWN BUG::
+ # Current multi-tk.rb cannot support long term threads on callbacks.
+ # Such a thread freezes the Ruby/Tk process.
+end
TkButton.new(:text=>':command=>proc{z.call}',
:command=>proc{z.call}).pack(:fill=>:x, :padx=>5)
TkFrame.new(:borderwidth=>2, :height=>3,
diff --git a/ext/tk/sample/scrollframe.rb b/ext/tk/sample/scrollframe.rb
index ab7a9ce..6a9381d 100644
--- a/ext/tk/sample/scrollframe.rb
+++ b/ext/tk/sample/scrollframe.rb
@@ -1,11 +1,11 @@
#
-# Tk::ScrollFrame class
+# Tk::RbWidget::ScrollFrame class
#
# This widget class is a frame widget with scrollbars.
# The ScrollFrame doesn't propagate the size of embedded widgets.
# When it is configured, scrollregion of the container is changed.
#
-# Scrollbars can be toggled by Tk::ScrollFrame#vscroll & hscroll.
+# Scrollbars can be toggled by Tk::RbWidget::ScrollFrame#vscroll & hscroll.
# If horizontal or virtical scrollbar is turned off, the horizontal
# or virtical size of embedded widgets is propagated.
#
@@ -13,7 +13,7 @@
#
require 'tk'
-class Tk::ScrollFrame < TkFrame
+class Tk::RbWidget::ScrollFrame < TkFrame
include TkComposite
DEFAULT_WIDTH = 200
@@ -209,7 +209,8 @@ end
# test
if __FILE__ == $0
- f = Tk::ScrollFrame.new(:scrollbarwidth=>10, :width=>300, :height=>200)
+ f = Tk::RbWidget::ScrollFrame.new(:scrollbarwidth=>10,
+ :width=>300, :height=>200)
f.pack(:expand=>true, :fill=>:both)
TkButton.new(f, :text=>'foo button', :command=>proc{puts 'foo'}).pack
@@ -220,17 +221,26 @@ if __FILE__ == $0
# f.hscroll(false)
+ # add a text widget
Tk.after(3000){
t = TkText.new(f).pack(:expand=>true, :fill=>:both)
- t.insert(:end, 'Here is a text widget')
+ t.insert(:end, "An example of Tk::RbWidget::ScrollFrame widget.\n\n")
+ t.insert(:end, "Here is a text widget.\n")
+ t.insert(:end, "Please resize the application window, ")
+ t.insert(:end, "and try the scrollbars ")
+ t.insert(:end, "to move the view of packed widgets.\n")
}
+ # remove a vertical scrollbar, and then the scrollframe is not scrollable.
Tk.after(6000){ f.vscroll(false) }
+ # add a vertical scrollbar, and make the scrollframe scrollable.
Tk.after(9000){ f.vscroll(true) }
+ # remove a horizontal scrollbar, and then the scrollframe is not scrollable.
Tk.after(12000){ f.hscroll(false) }
+ # add a horizontal scrollbar, and make the scrollframe scrollable.
Tk.after(15000){ f.hscroll(true) }
Tk.mainloop
diff --git a/ext/tk/sample/tkalignbox.rb b/ext/tk/sample/tkalignbox.rb
index dd82b50..fb1b58f 100644
--- a/ext/tk/sample/tkalignbox.rb
+++ b/ext/tk/sample/tkalignbox.rb
@@ -10,10 +10,17 @@
require 'tk'
-class TkAlignBox < TkFrame
+module Tk
+ module RbWidget
+ class AlignBox < TkFrame
+ end
+ end
+end
+
+class Tk::RbWidget::AlignBox < TkFrame
def initialize(*args)
- if self.class == TkAlignBox
- fail RuntimeError, "TkAlignBox is an abstract class"
+ if self.class == Tk::RbWidget::AlignBox
+ fail RuntimeError, "Tk::AlignBox is an abstract class"
end
@padx = 0
@pady = 0
@@ -31,12 +38,12 @@ class TkAlignBox < TkFrame
end
def _set_framesize
- fail RuntimeError, "TkAlignBox is an abstract class"
+ fail RuntimeError, "Tk::AlignBox is an abstract class"
end
private :_set_framesize
def _place_config(widget, idx, cnt)
- fail RuntimeError, "TkAlignBox is an abstract class"
+ fail RuntimeError, "Tk::AlignBox is an abstract class"
end
private :_place_config
@@ -117,7 +124,7 @@ class TkAlignBox < TkFrame
attr_accessor :propagate
end
-class TkHBox < TkAlignBox
+class Tk::RbWidget::HBox < Tk::RbWidget::AlignBox
def _set_framesize
bd = self.borderwidth
self.width((@max_width + 2*@padx) * @widgets.size + 2*bd)
@@ -134,9 +141,9 @@ class TkHBox < TkAlignBox
end
private :_place_config
end
-TkHLBox = TkHBox
+Tk::RbWidget::HLBox = Tk::RbWidget::HBox
-class TkHRBox < TkHBox
+class Tk::RbWidget::HRBox < Tk::RbWidget::HBox
def _place_config(widget, idx, cnt)
widget.place_in(self,
'relx'=>(cnt - idx - 1)/cnt, 'x'=>@padx,
@@ -147,7 +154,7 @@ class TkHRBox < TkHBox
private :_place_config
end
-class TkVBox < TkAlignBox
+class Tk::RbWidget::VBox < Tk::RbWidget::AlignBox
def _set_framesize
bd = self.borderwidth
self.width(@max_width + 2*@padx + 2*bd)
@@ -164,9 +171,9 @@ class TkVBox < TkAlignBox
end
private :_place_config
end
-TkVTBox = TkVBox
+Tk::RbWidget::VTBox = Tk::RbWidget::VBox
-class TkVBBox < TkVBox
+class Tk::RbWidget::VBBox < Tk::RbWidget::VBox
def _place_config(widget, idx, cnt)
widget.place_in(self,
'relx'=>0, 'x'=>@padx,
@@ -181,31 +188,34 @@ end
# test
################################################
if __FILE__ == $0
- f = TkHBox.new(:borderwidth=>3, :relief=>'ridge').pack
+ f = Tk::RbWidget::HBox.new(:borderwidth=>3, :relief=>'ridge').pack
f.add(TkButton.new(f, :text=>'a'),
TkButton.new(f, :text=>'aa', :font=>'Helvetica 16'),
TkButton.new(f, :text=>'aaa'),
TkButton.new(f, :text=>'aaaa'))
- f = TkHBox.new(:borderwidth=>3, :relief=>'ridge',
- :padx=>7, :pady=>3, :background=>'yellow').pack
+ f = Tk::RbWidget::HBox.new(:borderwidth=>3, :relief=>'ridge',
+ :padx=>7, :pady=>3, :background=>'yellow').pack
f.add(TkButton.new(f, :text=>'a'),
TkButton.new(f, :text=>'aa', :font=>'Helvetica 16'),
TkButton.new(f, :text=>'aaa'),
TkButton.new(f, :text=>'aaaa'))
- f = TkVBox.new(:borderwidth=>5, :relief=>'groove').pack
+ f = Tk::RbWidget::VBox.new(:borderwidth=>5,
+ :relief=>'groove').pack(:fill=>:y, :expand=>true)
f.add(TkButton.new(f, :text=>'a'),
TkButton.new(f, :text=>'aa', :font=>'Helvetica 30'),
TkButton.new(f, :text=>'aaa'),
TkButton.new(f, :text=>'aaaa'))
- f = TkHRBox.new(:borderwidth=>3, :relief=>'raised').pack(:fill=>:x)
+ f = Tk::RbWidget::HRBox.new(:borderwidth=>3,
+ :relief=>'raised').pack(:fill=>:x)
f.add(TkButton.new(f, :text=>'a'),
TkButton.new(f, :text=>'aa'),
TkButton.new(f, :text=>'aaa'))
- f = TkVBBox.new(:borderwidth=>3, :relief=>'ridge').pack(:fill=>:x)
+ f = Tk::RbWidget::VBBox.new(:borderwidth=>3,
+ :relief=>'ridge').pack(:fill=>:x)
f.propagate = false
f.height 100
f.add(TkFrame.new(f){|ff|
diff --git a/ext/tk/sample/tkballoonhelp.rb b/ext/tk/sample/tkballoonhelp.rb
index fc99753..a9bd371 100644
--- a/ext/tk/sample/tkballoonhelp.rb
+++ b/ext/tk/sample/tkballoonhelp.rb
@@ -7,11 +7,21 @@
# please try to use the Tix extension of Tcl/Tk under Ruby/Tk.
#
# The interval time to display a balloon help is defined 'interval' option
-# (default is 1000ms).
+# (default is 750ms).
#
require 'tk'
-class TkBalloonHelp<TkLabel
+module Tk
+ module RbWidget
+ class BalloonHelp<TkLabel
+ end
+ end
+end
+class Tk::RbWidget::BalloonHelp<TkLabel
+ DEFAULT_FOREGROUND = 'black'
+ DEFAULT_BACKGROUND = 'white'
+ DEFAULT_INTERVAL = 750
+
def _balloon_binding(interval)
@timer = TkAfter.new(interval, 1, proc{show})
def @timer.interval(val)
@@ -50,10 +60,13 @@ class TkBalloonHelp<TkLabel
@command = keys.delete('command')
- @interval = keys.delete('interval'){1000}
+ @interval = keys.delete('interval'){DEFAULT_INTERVAL}
_balloon_binding(@interval)
- @label = TkLabel.new(@frame, 'background'=>'bisque').pack
+ # @label = TkLabel.new(@frame, 'background'=>'bisque').pack
+ @label = TkLabel.new(@frame,
+ 'foreground'=>DEFAULT_FOREGROUND,
+ 'background'=>DEFAULT_BACKGROUND).pack
@label.configure(_symbolkey2str(keys)) unless keys.empty?
@path = @label
end
@@ -118,41 +131,42 @@ end
if __FILE__ == $0
TkButton.new('text'=>'This button has a balloon help') {|b|
pack('fill'=>'x')
- TkBalloonHelp.new(b, 'text'=>' Message ')
+ Tk::RbWidget::BalloonHelp.new(b, 'text'=>' Message ')
}
TkButton.new('text'=>'This button has another balloon help') {|b|
pack('fill'=>'x')
- TkBalloonHelp.new(b, 'text'=>'configured message',
- 'interval'=>200, 'font'=>'courier',
- 'background'=>'gray', 'foreground'=>'red')
+ Tk::RbWidget::BalloonHelp.new(b,
+ 'text'=>"CONFIGURED MESSAGE\nchange colors, and so on",
+ 'interval'=>200, 'font'=>'courier',
+ 'background'=>'gray', 'foreground'=>'red')
}
sb = TkScrollbox.new.pack(:fill=>:x)
sb.insert(:end, *%w(aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm))
=begin
# CASE1 : command takes no arguemnt
- bh = TkBalloonHelp.new(sb, :interval=>500,
- :relief=>:ridge, :background=>'white',
- :command=>proc{
- y = TkWinfo.pointery(sb) - TkWinfo.rooty(sb)
- bh.text "current index == #{sb.nearest(y)}"
- })
+ bh = Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
+ :relief=>:ridge, :background=>'white',
+ :command=>proc{
+ y = TkWinfo.pointery(sb) - TkWinfo.rooty(sb)
+ bh.text "current index == #{sb.nearest(y)}"
+ })
=end
=begin
# CASE2 : command takes 2 arguemnts
- bh = TkBalloonHelp.new(sb, :interval=>500,
- :relief=>:ridge, :background=>'white',
- :command=>proc{|x, y|
- bh.text "current index == #{sb.nearest(y)}"
- })
+ bh = Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
+ :relief=>:ridge, :background=>'white',
+ :command=>proc{|x, y|
+ bh.text "current index == #{sb.nearest(y)}"
+ })
=end
=begin
# CASE3 : command takes 3 arguemnts
- TkBalloonHelp.new(sb, :interval=>500,
- :relief=>:ridge, :background=>'white',
- :command=>proc{|x, y, bhelp|
- bhelp.text "current index == #{sb.nearest(y)}"
- })
+ Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
+ :relief=>:ridge, :background=>'white',
+ :command=>proc{|x, y, bhelp|
+ bhelp.text "current index == #{sb.nearest(y)}"
+ })
=end
=begin
# CASE4a : command is a Proc object and takes 4 arguemnts
@@ -160,16 +174,16 @@ if __FILE__ == $0
bhelp.text "current index == #{parent.nearest(y)}"
}
- TkBalloonHelp.new(sb, :interval=>500,
- :relief=>:ridge, :background=>'white',
- :command=>cmd)
+ Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
+ :relief=>:ridge, :background=>'white',
+ :command=>cmd)
sb2 = TkScrollbox.new.pack(:fill=>:x)
sb2.insert(:end, *%w(AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK LLL MMM))
- TkBalloonHelp.new(sb2, :interval=>500,
- :padx=>5, :relief=>:raised,
- :background=>'gray25', :foreground=>'white',
- :command=>cmd)
+ Tk::RbWidget::BalloonHelp.new(sb2, :interval=>500,
+ :padx=>5, :relief=>:raised,
+ :background=>'gray25', :foreground=>'white',
+ :command=>cmd)
=end
#=begin
# CASE4b : command is a Method object and takes 4 arguemnts
@@ -178,16 +192,16 @@ if __FILE__ == $0
end
cmd = self.method(:set_msg)
- TkBalloonHelp.new(sb, :interval=>500,
- :relief=>:ridge, :background=>'white',
- :command=>cmd)
+ Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
+ :relief=>:ridge, :background=>'white',
+ :command=>cmd)
sb2 = TkScrollbox.new.pack(:fill=>:x)
sb2.insert(:end, *%w(AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK LLL MMM))
- TkBalloonHelp.new(sb2, :interval=>500,
- :padx=>5, :relief=>:raised,
- :background=>'gray25', :foreground=>'white',
- :command=>cmd)
+ Tk::RbWidget::BalloonHelp.new(sb2, :interval=>500,
+ :padx=>5, :relief=>:raised,
+ :background=>'gray25', :foreground=>'white',
+ :command=>cmd)
#=end
Tk.mainloop
diff --git a/ext/tk/sample/tkcombobox.rb b/ext/tk/sample/tkcombobox.rb
index 941f7cc..59db565 100644
--- a/ext/tk/sample/tkcombobox.rb
+++ b/ext/tk/sample/tkcombobox.rb
@@ -1,11 +1,20 @@
#
-# tkcombobox.rb : TkAutoScrollbox & TkCombobox
+# tkcombobox.rb : auto scrollbox & combobox
#
# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
#
require 'tk'
-class TkAutoScrollbox < TkListbox
+module Tk
+ module RbWidget
+ class AutoScrollListbox < TkListbox
+ end
+ class Combobox < TkEntry
+ end
+ end
+end
+
+class Tk::RbWidget::AutoScrollListbox
include TkComposite
@@up_bmp = TkBitmapImage.new(:data=><<EOD)
@@ -221,17 +230,7 @@ end
################################################
-# don't use Ttk widget
-Object.instance_eval{remove_const :TkCombobox} if Object.autoload? :TkCombobox
-
-# if you want to use the 'default_widget_set' selector,
-#class TkCombobox < TkEntry; end
-#Tk.__set_toplevel_aliases__(:Tk, TkCombobox, :TkCombobox)
-
-
-################################################
-
-class TkCombobox < TkEntry
+class Tk::RbWidget::Combobox < TkEntry
include TkComposite
@@down_btn_bmp = TkBitmapImage.new(:data=><<EOD)
@@ -251,6 +250,7 @@ static unsigned char up_arrow_bits[] = {
EOD
def _button_proc(dir = true)
+ return if @ent.state == 'disabled'
@btn.relief(:sunken)
x = @frame.winfo_rootx
y = @frame.winfo_rooty
@@ -275,9 +275,10 @@ EOD
@top.grab
begin
- @var.tkwait
- if (idx = @var.to_i) >= 0
- @ent.value = @lst.get(idx)
+ @wait_var.tkwait
+ if (idx = @wait_var.to_i) >= 0
+ # @ent.value = @lst.get(idx)
+ _set_entry_value(@lst.get(idx))
end
@top.withdraw
@btn.relief(:raised)
@@ -297,18 +298,65 @@ EOD
@btn.bind('1', proc{_button_proc(true)})
@btn.bind('3', proc{_button_proc(false)})
- @lst.bind('1', proc{|y| @var.value = @lst.nearest(y)}, '%y')
- @lst.bind('Return', proc{@var.value = @lst.curselection[0]})
+ @lst.bind('1', proc{|y| @wait_var.value = @lst.nearest(y)}, '%y')
+ @lst.bind('Return', proc{@wait_var.value = @lst.curselection[0]})
cancel = TkVirtualEvent.new('2', '3', 'Escape')
- @lst.bind(cancel, proc{@var.value = -1})
+ @lst.bind(cancel, proc{@wait_var.value = -1})
end
private :_init_bindings
+ def _set_entry_value(val)
+ @ent.textvariable.value = val
+ end
+ private :_set_entry_value
+
+ #----------------------------------------------------
+
+ def _state_control(value = None)
+ if value == None
+ # get
+ @ent.state
+ else
+ # set
+ @ent.state(value.to_s)
+ case value = @ent.state # regulate 'state' string
+ when 'normal', 'readonly'
+ @btn.state 'normal'
+ when 'disabled'
+ @btn.state 'disabled'
+ else
+ # unknown : do nothing
+ end
+ end
+ end
+ private :_state_control
+
+ def __methodcall_optkeys # { key=>method, ... }
+ {'state' => :_state_control}
+ end
+ private :__methodcall_optkeys
+
+ #----------------------------------------------------
+
+ def _textvariable_control(var = None)
+ if var == None
+ # get
+ ((var = @ent.textvariable) === @default_var)? nil: var
+ else
+ # set
+ @var = var
+ tk_send('configure', '-textvariable', (@var)? var: @default_var)
+ end
+ end
+ private :_textvariable_control
+
+ #----------------------------------------------------
+
def initialize_composite(keys={})
keys = _symbolkey2str(keys)
- @btn = TkLabel.new(@frame, :relief=>:raised, :borderwidth=>3,
+ @btn = TkLabel.new(@frame, :relief=>:raised, :borderwidth=>2,
:image=>@@down_btn_bmp).pack(:side=>:right,
:ipadx=>2, :fill=>:y)
@ent = TkEntry.new(@frame).pack(:side=>:left)
@@ -322,16 +370,21 @@ EOD
startwait = keys.delete('startwait'){300}
interval = keys.delete('interval'){150}
- @lst = TkAutoScrollbox.new(@top,
- :startwait=>startwait,
- :interval=>interval).pack(:fill=>:both,
- :expand=>true)
+ @lst = Tk::RbWidget::AutoScrollListbox.new(@top, :scrollbar=>true,
+ :startwait=>startwait,
+ :interval=>interval)
+ @lst.pack(:fill=>:both, :expand=>true)
@ent_list = []
- @var = TkVariable.new
+ @wait_var = TkVariable.new
+ @var = @default_var = TkVariable.new
+
+ @ent.textvariable @default_var
_init_bindings
+ option_methods('textvariable' => :_textvariable_control)
+
delegate('DEFAULT', @ent)
delegate('height', @lst)
delegate('relief', @frame)
@@ -340,6 +393,8 @@ EOD
delegate('arrowrelief', @lst)
delegate('arrowborderwidth', @lst)
+ delegate('state', false)
+
if mode = keys.delete('scrollbar')
scrollbar(mode)
end
@@ -405,10 +460,14 @@ end
# test
################################################
if __FILE__ == $0
+# e0 = Tk::RbWidget::Combobox.new.pack
+# e0.values(%w(aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu))
+
v = TkVariable.new
- e = TkCombobox.new(:height=>7, :scrollbar=>true, :textvariable=>v,
- :arrowrelief=>:flat, :arrowborderwidth=>0,
- :startwait=>400, :interval=>200).pack
+ e = Tk::RbWidget::Combobox.new(:height=>7, :scrollbar=>true,
+ :textvariable=>v,
+ :arrowrelief=>:flat, :arrowborderwidth=>0,
+ :startwait=>400, :interval=>200).pack
e.values(%w(aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu))
#e.see(e.list_index('end') - 2)
e.value = 'cc'
@@ -421,8 +480,10 @@ if __FILE__ == $0
TkFrame.new(:relief=>:raised, :borderwidth=>2,
:height=>3).pack(:fill=>:x, :expand=>true, :padx=>5, :pady=>3)
- l = TkAutoScrollbox.new(nil, :relief=>:groove, :borderwidth=>4,
- :width=>20).pack(:fill=>:both, :expand=>true)
+ l = Tk::RbWidget::AutoScrollListbox.new(nil, :relief=>:groove,
+ :borderwidth=>4,:height=>7,
+ :width=>20).pack(:fill=>:both,
+ :expand=>true)
(0..20).each{|i| l.insert('end', "line #{i}")}
TkFrame.new(:relief=>:ridge, :borderwidth=>3){
diff --git a/ext/tk/sample/tktextframe.rb b/ext/tk/sample/tktextframe.rb
index d50f2e5..b2b40c9 100644
--- a/ext/tk/sample/tktextframe.rb
+++ b/ext/tk/sample/tktextframe.rb
@@ -5,9 +5,53 @@
#
require 'tk'
-class TkTextFrame < TkText
+module Tk::ScrollbarComposite
include TkComposite
+ def component_construct_keys
+ # If a component requires options for construction,
+ # return an Array of option-keys.
+ []
+ end
+ private :component_construct_keys
+
+ def create_component(keys={})
+ # This method must return the created component widget.
+ end
+ private :create_component
+
+ def component_delegates
+ # if want to override defalut option-methods or delegates,
+ # please define here.
+ end
+ private :component_delegates
+
+ def define_delegates
+ # option methods for scrollbars
+ option_methods([:scrollbarwidth, :get_scrollbarwidth])
+
+ # set receiver widgets for configure methods (with alias)
+ delegate_alias('scrollbarrelief', 'relief', @h_scroll, @v_scroll)
+ delegate_alias('framebackground', 'background',
+ @frame, @h_scroll, @v_scroll)
+ delegate_alias('activeframebackground', 'activebackground',
+ @h_scroll, @v_scroll)
+
+ # set receiver widgets for configure methods
+ delegate('DEFAULT', @component)
+ delegate('troughcolor', @h_scroll, @v_scroll)
+ delegate('repeatdelay', @h_scroll, @v_scroll)
+ delegate('repeatinterval', @h_scroll, @v_scroll)
+ delegate('borderwidth', @frame)
+ delegate('relief', @frame)
+
+ component_delegates
+ end
+ private :define_delegates
+
+ DEFAULT_VSCROLL = true
+ DEFAULT_HSCROLL = true
+
def initialize_composite(keys={})
keys = _symbolkey2str(keys)
@@ -15,55 +59,123 @@ class TkTextFrame < TkText
@v_scroll = TkScrollbar.new(@frame, 'orient'=>'vertical')
@h_scroll = TkScrollbar.new(@frame, 'orient'=>'horizontal')
- # create a text widget
- @text = TkText.new(@frame, 'wrap'=>'none')
+ # create a component
+ construct_keys = {}
+ ((component_construct_keys.map{|k| k.to_s}) & keys.keys).each{|k|
+ construct_keys[k] = keys.delete(k)
+ }
+
+ # create a component (the component must be scrollable)
+ @component = create_component(construct_keys)
# set default receiver of method calls
- @path = @text.path
+ @path = @component.path
# assign scrollbars
- @text.xscrollbar(@h_scroll)
- @text.yscrollbar(@v_scroll)
+ @component.xscrollbar(@h_scroll)
+ @component.yscrollbar(@v_scroll)
# allignment
TkGrid.rowconfigure(@frame, 0, 'weight'=>1, 'minsize'=>0)
TkGrid.columnconfigure(@frame, 0, 'weight'=>1, 'minsize'=>0)
- @text.grid('row'=>0, 'column'=>0, 'sticky'=>'news')
+ @component.grid('row'=>0, 'column'=>0, 'sticky'=>'news')
# scrollbars ON
- vscroll(keys.delete('vscroll'){true})
- hscroll(keys.delete('hscroll'){true})
-
- # set background of the text widget
-=begin
- color = keys.delete('textbackground')
- textbackground(color) if color
-=end
- # please check the differences of the following definitions
+ vscroll(keys.delete('vscroll'){self.class::DEFAULT_VSCROLL})
+ hscroll(keys.delete('hscroll'){self.class::DEFAULT_HSCROLL})
+
+ # do configure
+ define_delegates
+
+ # do configure
+ configure keys unless keys.empty?
+ end
+ private :initialize_composite
+
+ # get/set width of scrollbar
+ def get_scrollbarwidth
+ @v_scroll.width
+ end
+ def set_scrollbarwidth(width)
+ @v_scroll.width(width)
+ @h_scroll.width(width)
+ end
+ alias :scrollbarwidth :set_scrollbarwidth
+
+ def hook_vscroll_on(*args); end
+ def hook_vscroll_off(*args); end
+ def hook_hscroll_on(*args); end
+ def hook_hscroll_off(*args); end
+ private :hook_vscroll_on,:hook_vscroll_off,:hook_hscroll_on,:hook_hscroll_off
+
+ # vertical scrollbar : ON/OFF
+ def vscroll(mode, *args)
+ st = TkGrid.info(@v_scroll)
+ if mode && st.size == 0 then
+ @v_scroll.grid('row'=>0, 'column'=>1, 'sticky'=>'ns')
+ hook_vscroll_on(*args)
+ elsif !mode && st.size != 0 then
+ @v_scroll.ungrid
+ hook_vscroll_off(*args)
+ end
+ self
+ end
+
+ # horizontal scrollbar : ON/OFF
+ def hscroll(mode, *args)
+ st = TkGrid.info(@h_scroll)
+ if mode && st.size == 0 then
+ @h_scroll.grid('row'=>1, 'column'=>0, 'sticky'=>'ew')
+ hook_hscroll_on(*args)
+ elsif !mode && st.size != 0 then
+ @h_scroll.ungrid
+ hook_hscroll_off(*args)
+ end
+ self
+ end
+end
+
+################################################
+
+class TkTextFrame < TkText
+ include Tk::ScrollbarComposite
+
+ # def component_construct_keys; []; end
+ # private :component_construct_keys
+
+ def create_component(keys={})
+ # keys has options which are listed by component_construct_keys method.
+ @text = TkText.new(@frame, 'wrap'=>'none')
+ @text.configure(keys) unless keys.empty?
+
+ # option methods for component
option_methods(
- [:scrollbarwidth, :get_scrollbarwidth],
[:textbackground, nil, :textbg_info],
:textborderwidth,
:textrelief
)
- # set receiver widgets for configure methods (with alias)
- delegate_alias('scrollbarrelief', 'relief', @h_scroll, @v_scroll)
+ # return the created componet
+ @text
+ end
+ private :create_component
- # set receiver widgets for configure methods
- delegate('DEFAULT', @text)
- delegate('background', @frame, @h_scroll, @v_scroll)
- delegate('activebackground', @h_scroll, @v_scroll)
- delegate('troughcolor', @h_scroll, @v_scroll)
- delegate('repeatdelay', @h_scroll, @v_scroll)
- delegate('repeatinterval', @h_scroll, @v_scroll)
- delegate('borderwidth', @frame)
- delegate('relief', @frame)
+ # def component_delegates; end
+ # private :component_delegates
- # do configure
- configure keys unless keys.empty?
+ def hook_hscroll_on(wrap_mode=nil)
+ if wrap_mode
+ wrap wrap_mode
+ else
+ wrap 'none' # => self.wrap('none')
+ end
+ end
+ def hook_hscroll_off(wrap_mode)
+ wrap wrap_mode # => self.wrap(wrap_mode)
+ end
+ def hscroll(mode, wrap_mode="char")
+ super
end
- private :initialize_composite
# set background color of text widget
def textbackground(color = nil)
@@ -103,47 +215,13 @@ class TkTextFrame < TkText
def textrelief(type)
@text.relief(type)
end
-
- # get/set width of scrollbar
- def get_scrollbarwidth
- @v_scroll.width
- end
- def set_scrollbarwidth(width)
- @v_scroll.width(width)
- @h_scroll.width(width)
- end
- alias :scrollbarwidth :set_scrollbarwidth
-
- # vertical scrollbar : ON/OFF
- def vscroll(mode)
- st = TkGrid.info(@v_scroll)
- if mode && st.size == 0 then
- @v_scroll.grid('row'=>0, 'column'=>1, 'sticky'=>'ns')
- elsif !mode && st.size != 0 then
- @v_scroll.ungrid
- end
- self
- end
-
- # horizontal scrollbar : ON/OFF
- def hscroll(mode, wrap_mode="char")
- st = TkGrid.info(@h_scroll)
- if mode && st.size == 0 then
- @h_scroll.grid('row'=>1, 'column'=>0, 'sticky'=>'ew')
- wrap 'none' # => self.wrap('none')
- elsif !mode && st.size != 0 then
- @h_scroll.ungrid
- wrap wrap_mode # => self.wrap(wrap_mode)
- end
- self
- end
end
-
################################################
# test
################################################
if __FILE__ == $0
+ TkLabel.new(:text=>'TkTextFrame is an example of Tk::ScrollbarComposite module.').pack
f = TkFrame.new.pack('fill'=>'x')
#t = TkTextFrame.new.pack
t = TkTextFrame.new(:textborderwidth=>3,
@@ -158,5 +236,46 @@ if __FILE__ == $0
'command'=>proc{t.hscroll(true)}).pack('side'=>'left')
TkButton.new(f, 'text'=>'hscr OFF',
'command'=>proc{t.hscroll(false)}).pack('side'=>'left')
+
+ ############################################
+
+ # Tk.default_widget_set = :Ttk
+
+ TkFrame.new.pack(:pady=>10)
+ TkLabel.new(:text=>'The following is another example of Tk::ScrollbarComposite module.').pack
+
+ #----------------------------------
+ class ScrListbox < TkListbox
+ include Tk::ScrollbarComposite
+
+ DEFAULT_HSCROLL = false
+
+ def create_component(keys={})
+ TkListbox.new(@frame, keys)
+ end
+ private :create_component
+ end
+ #----------------------------------
+
+ f = TkFrame.new.pack(:pady=>5)
+ lbox = ScrListbox.new(f).pack(:side=>:left)
+ lbox.value = %w(aa bb cc dd eeeeeeeeeeeeeeeeeeeeeeeeee ffffffffff gg hh ii jj kk ll mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm nn oo pp qq)
+ fb = TkFrame.new(f).pack(:expand=>true, :fill=>:y, :padx=>5)
+ TkButton.new(fb, 'text'=>'lbox hscr OFF',
+ 'command'=>proc{lbox.hscroll(false)}).pack(:side=>:bottom,
+ :fill=>:x)
+ TkButton.new(fb, 'text'=>'lbox hscr ON',
+ 'command'=>proc{lbox.hscroll(true)}).pack(:side=>:bottom,
+ :fill=>:x)
+ TkFrame.new(fb).pack(:pady=>5, :side=>:bottom)
+ TkButton.new(fb, 'text'=>'lbox vscr OFF',
+ 'command'=>proc{lbox.vscroll(false)}).pack(:side=>:bottom,
+ :fill=>:x)
+ TkButton.new(fb, 'text'=>'lbox vscr ON',
+ 'command'=>proc{lbox.vscroll(true)}).pack(:side=>:bottom,
+ :fill=>:x)
+
+ ############################################
+
Tk.mainloop
end