diff options
author | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-07-12 23:08:32 +0000 |
---|---|---|
committer | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-07-12 23:08:32 +0000 |
commit | ed6ce8b43b6f25df1d4809ac799de4dd1c85c1f3 (patch) | |
tree | 09bc05d679d0f224a29fee44d10beea321bdc0b5 /ext/tk/sample | |
parent | e13fb8029b87943ab8af2211226b7c9347d3976d (diff) | |
download | ruby-ed6ce8b43b6f25df1d4809ac799de4dd1c85c1f3.tar.gz |
* 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/widget | 7 | ||||
-rw-r--r-- | ext/tk/sample/demos-jp/widget | 8 | ||||
-rw-r--r-- | ext/tk/sample/editable_listbox.rb | 131 | ||||
-rw-r--r-- | ext/tk/sample/menubar3.rb | 72 | ||||
-rw-r--r-- | ext/tk/sample/multi-ip_sample.rb | 3 | ||||
-rw-r--r-- | ext/tk/sample/safe-tk.rb | 23 | ||||
-rw-r--r-- | ext/tk/sample/scrollframe.rb | 20 | ||||
-rw-r--r-- | ext/tk/sample/tkalignbox.rb | 44 | ||||
-rw-r--r-- | ext/tk/sample/tkballoonhelp.rb | 90 | ||||
-rw-r--r-- | ext/tk/sample/tkcombobox.rb | 121 | ||||
-rw-r--r-- | ext/tk/sample/tktextframe.rb | 251 |
11 files changed, 581 insertions, 189 deletions
diff --git a/ext/tk/sample/demos-en/widget b/ext/tk/sample/demos-en/widget index 9a0605d8b9..250c589116 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 132953f32d..dfaa9c004e 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 553d400e24..7a9ad4450b 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 0000000000..129cfd779b --- /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 8150e69c73..eccf0201f8 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 e2408480d1..148548efb2 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 ab7a9ce24b..6a9381d465 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 dd82b50360..fb1b58f458 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 fc99753b81..a9bd371db6 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 941f7cc4cb..59db565f06 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 d50f2e5d88..b2b40c9138 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 |