diff options
author | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2003-10-14 19:36:09 +0000 |
---|---|---|
committer | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2003-10-14 19:36:09 +0000 |
commit | 6bd9229984446b774d5d3edb3275277eb61041bd (patch) | |
tree | 9e5c7c56784535e5fdeff156c50b3f756b0aff16 | |
parent | 6d9c20d6a33d00db831ddb02209ea7e32db8fa45 (diff) | |
download | ruby-6bd9229984446b774d5d3edb3275277eb61041bd.tar.gz |
ext/tk/sample/demos-en/entry3.rb, ext/tk/sample/demos-jp/entry3.rb :
* new demo-scripts
ext/tk/sample/demos-en/widget, ext/tk/sample/demos-jp/widget :
* add entries for 'entry3.rb'
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4766 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | ext/tk/sample/demos-en/entry3.rb | 198 | ||||
-rw-r--r-- | ext/tk/sample/demos-en/widget | 8 | ||||
-rw-r--r-- | ext/tk/sample/demos-jp/entry3.rb | 202 | ||||
-rw-r--r-- | ext/tk/sample/demos-jp/widget | 7 |
5 files changed, 419 insertions, 4 deletions
@@ -1,3 +1,11 @@ +Wed Oct 15 04:31:51 2003 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp> + + * ext/tk/sample/demos-en/entry3.rb, ext/tk/sample/demos-jp/entry3.rb : + new demo-scripts + + * ext/tk/sample/demos-en/widget, ext/tk/sample/demos-jp/widget : + add entries for 'entry3.rb' + Wed Oct 15 04:31:47 2003 Akinori MUSHA <knu@iDaemons.org> * test/digest/test_digest.rb: Moved from ext/digest/test.rb. diff --git a/ext/tk/sample/demos-en/entry3.rb b/ext/tk/sample/demos-en/entry3.rb new file mode 100644 index 0000000000..44f788225c --- /dev/null +++ b/ext/tk/sample/demos-en/entry3.rb @@ -0,0 +1,198 @@ +# entry3.rb -- +# +# This demonstration script creates several entry widgets whose +# permitted input is constrained in some way. It also shows off a +# password entry. +# +# based on Tcl/Tk8.4.4 widget demos + +if defined?($entry3_demo) && $entry3_demo + $entry3_demo.destroy + $entry3_demo = nil +end + +$entry3_demo = TkToplevel.new {|w| + title("Constrained Entry Demonstration") + iconname("entry3") + positionWindow(w) +} + +TkLabel.new($entry3_demo, + :font=>$font, :wraplength=>'5i', :justify=>:left, + :text=><<EOL).pack(:side=>:top) +Four different entries are displayed below. You can add characters \ +by pointing, clicking and typing, though each is constrained in what \ +it will accept. The first only accepts integers or the empty string \ +(checking when focus leaves it) and will flash to indicate any \ +problem. The second only accepts strings with fewer than ten \ +characters and sounds the bell when an attempt to go over the limit \ +is made. The third accepts US phone numbers, mapping letters to \ +their digit equivalent and sounding the bell on encountering an \ +illegal character or if trying to type over a character that is not \ +a digit. The fourth is a password field that accepts up to eight \ +characters (silently ignoring further ones), and displaying them as \ +asterisk characters. +EOL + +TkFrame.new($entry3_demo){|f| + pack(:side=>:bottom, :fill=>:x, :pady=>'2m') + + TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ + $entry3_demo.destroy + $entry3_demo = nil + }).pack(:side=>:left, :expand=>true) + + TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ + showCode 'entry3' + }).pack(:side=>:left, :expand=>true) +} + +# focusAndFlash -- +# Error handler for entry widgets that forces the focus onto the +# widget and makes the widget flash by exchanging the foreground and +# background colours at intervals of 200ms (i.e. at approximately +# 2.5Hz). +# +# Arguments: +# widget - entry widget to flash +# fg - Initial foreground colour +# bg - Initial background colour +# count - Counter to control the number of times flashed +def focusAndFlash(widget, fg, bg, count=5) + return if count <= 0 + TkTimer.new(200, count, + proc{widget.configure(:foreground=>bg, :background=>fg)}, + proc{widget.configure(:foreground=>fg, :background=>bg)} + ).start + widget.focus(true) +end + +l1 = TkLabelFrame.new($entry3_demo, :text=>"Integer Entry") +TkEntry.new(l1, :validate=>:focus, + :vcmd=>[ + proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P' + ]) {|e| + invalidcommand [proc{|w| focusAndFlash(w, e.fg, e.bg)}, '%W'] + pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') +} + +l2 = TkLabelFrame.new($entry3_demo, :text=>"Length-Constrained Entry") +TkEntry.new(l2, :validate=>:key, :invcmd=>proc{Tk.bell}, + :vcmd=>[proc{|s| s.length < 10}, '%P'] + ).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') + +### PHONE NUMBER ENTRY ### +# Note that the source to this is quite a bit longer as the behaviour +# demonstrated is a lot more ambitious than with the others. + +# Initial content for the third entry widget +entry3content = TkVariable.new("1-(000)-000-0000") + +# Mapping from alphabetic characters to numbers. +$phoneNumberMap = {} +Hash[*(%w(abc 2 def 3 ghi 4 jkl 5 mno 6 pqrs 7 tuv 8 wxyz 9))].each{|chars, n| + chars.split('').each{|c| + $phoneNumberMap[c] = n + $phoneNumberMap[c.upcase] = n + } +} + +# phoneSkipLeft -- +# Skip over fixed characters in a phone-number string when moving left. +# +# Arguments: +# widget - The entry widget containing the phone-number. +def phoneSkipLeft(widget) + idx = widget.index('insert') + if idx == 8 + # Skip back two extra characters + widget.cursor = idx - 2 + elsif idx == 7 || idx == 12 + # Skip back one extra character + widget.cursor = idx - 1 + elsif idx <= 3 + # Can't move any further + Tk.bell + Tk.callback_break + end +end + +# phoneSkipRight -- +# Skip over fixed characters in a phone-number string when moving right. +# +# Arguments: +# widget - The entry widget containing the phone-number. +# add - Offset to add to index before calculation (used by validation.) +def phoneSkipRight(widget, add = 0) + idx = widget.index('insert') + if (idx + add == 5) + # Skip forward two extra characters + widget.cursor = idx + 2 + elsif (idx + add == 6 || idx + add == 10) + # Skip forward one extra character + widget.cursor = idx + 1 + elsif (idx + add == 15 && add == 0) + # Can't move any further + Tk.bell + Tk.callback_break + end +end + +# validatePhoneChange -- +# Checks that the replacement (mapped to a digit) of the given +# character in an entry widget at the given position will leave a +# valid phone number in the widget. +# +# widget - entry widget to validate +# vmode - The widget's validation mode +# idx - The index where replacement is to occur +# char - The character (or string, though that will always be +# refused) to be overwritten at that point. + +def validatePhoneChange(widget, vmode, idx, char) + return true if idx == nil + Tk.after_idle(proc{widget.configure(:validate=>vmode, + :invcmd=>proc{Tk.bell})}) + if !(idx<3 || idx==6 || idx==7 || idx==11 || idx>15) && char =~ /[0-9A-Za-z]/ + widget.delete(idx) + widget.insert(idx, $phoneNumberMap[char] || char) + Tk.after_idle(proc{phoneSkipRight(widget, -1)}) + return true + end + return false +end + + +l3 = TkLabelFrame.new($entry3_demo, :text=>"US Phone-Number Entry") +TkEntry.new(l3, :validate=>:key, :invcmd=>proc{Tk.bell}, + :textvariable=>entry3content, + :vcmd=>[ + proc{|w,v,i,s| validatePhoneChange(w,v,i,s)}, + "%W %v %i %S" + ]){|e| + # Click to focus goes to the first editable character... + bind('FocusIn', proc{|d,w| + if d != "NotifyAncestor" + w.cursor = 3 + Tk.after_idle(proc{w.selection_clear}) + end + }, '%d %W') + bind('Left', proc{|w| phoneSkipLeft(w)}, '%W') + bind('Right', proc{|w| phoneSkipRight(w)}, '%W') + pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') +} + +l4 = TkLabelFrame.new($entry3_demo, :text=>"Password Entry") +TkEntry.new(l4, :validate=>:key, :show=>'*', + :vcmd=>[ + proc{|s| s.length <= 8}, + '%P' + ]).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') + +TkFrame.new($entry3_demo){|f| + lower + TkGrid.configure(l1, l2, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew) + TkGrid.configure(l3, l4, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew) + TkGrid.columnconfigure(f, [0,1], :uniform=>1) + pack(:fill=>:both, :expand=>true) +} diff --git a/ext/tk/sample/demos-en/widget b/ext/tk/sample/demos-en/widget index b6b63d644b..2c13a5e493 100644 --- a/ext/tk/sample/demos-en/widget +++ b/ext/tk/sample/demos-en/widget @@ -238,9 +238,13 @@ txt.insert('end', "1. Without scrollbars.\n", tag_demo, "demo-entry1") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. With scrollbars.\n", tag_demo, "demo-entry2") txt.insert('end', " \n ", tag_demospace) -txt.insert('end', "3. Spin-boxes. (if supported)\n", tag_demo, "demo-spin") +txt.insert('end', + "3. Validated entries and password fields. (if supported)\n", + tag_demo, "demo-entry3") txt.insert('end', " \n ", tag_demospace) -txt.insert('end', "4. Simple Rolodex-like form.\n", tag_demo, "demo-form") +txt.insert('end', "4. Spin-boxes. (if supported)\n", tag_demo, "demo-spin") +txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "5. Simple Rolodex-like form.\n", tag_demo, "demo-form") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") diff --git a/ext/tk/sample/demos-jp/entry3.rb b/ext/tk/sample/demos-jp/entry3.rb new file mode 100644 index 0000000000..4c0b24e28c --- /dev/null +++ b/ext/tk/sample/demos-jp/entry3.rb @@ -0,0 +1,202 @@ +# entry3.rb -- +# +# This demonstration script creates several entry widgets whose +# permitted input is constrained in some way. It also shows off a +# password entry. +# +# based on Tcl/Tk8.4.4 widget demos + +if defined?($entry3_demo) && $entry3_demo + $entry3_demo.destroy + $entry3_demo = nil +end + +$entry3_demo = TkToplevel.new {|w| + title("Constrained Entry Demonstration") + iconname("entry3") + positionWindow(w) +} + +TkLabel.new($entry3_demo, + :font=>$font, :wraplength=>'5i', :justify=>:left, + :text=><<EOL).pack(:side=>:top) +以下には4種類のエントリボックスが表示されています.各エントリボックスは,\ +マウスクリックで選択し文字を打ち込むことが可能ですが,それぞれがどのような\ +入力を受け付けることができるかには制約が設けられています.\ +一つめのエントリボックスは整数と見なされる文字列か入力文字がない空の状態か\ +の場合だけを受け付け,問題がある場合はエントリボックスが点滅します\ +(フォーカスが去る時にチェックされます).\ +二つめのエントリボックスは,入力された文字列の長さが\ +10文字未満の場合だけを受け付け,制限を越えて書き込もうとしたときには\ +ベルを鳴らして知らせます.\ +三つめはアメリカの電話番号を受け付けるエントリボックスです.\ +アルファベットは,電話機のダイヤル上で対応づけられている数字に変換されます.\ +不適切な文字が入力されたり数字以外の文字の位置に数字を入力しようとしたり\ +した場合には警告のベルが鳴ります.\ +四つめのエントリボックスは,8文字までの入力を受け付ける\ +パスワードフィールドです(8文字以上は特に警告を出すことなく無視されます).\ +入力された文字はアスタリスク記号に置き換えて表示されます. +EOL + +TkFrame.new($entry3_demo){|f| + pack(:side=>:bottom, :fill=>:x, :pady=>'2m') + + TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ + $entry3_demo.destroy + $entry3_demo = nil + }).pack(:side=>:left, :expand=>true) + + TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ + showCode 'entry3' + }).pack(:side=>:left, :expand=>true) +} + +# focusAndFlash -- +# Error handler for entry widgets that forces the focus onto the +# widget and makes the widget flash by exchanging the foreground and +# background colours at intervals of 200ms (i.e. at approximately +# 2.5Hz). +# +# Arguments: +# widget - entry widget to flash +# fg - Initial foreground colour +# bg - Initial background colour +# count - Counter to control the number of times flashed +def focusAndFlash(widget, fg, bg, count=5) + return if count <= 0 + TkTimer.new(200, count, + proc{widget.configure(:foreground=>bg, :background=>fg)}, + proc{widget.configure(:foreground=>fg, :background=>bg)} + ).start + widget.focus(true) +end + +l1 = TkLabelFrame.new($entry3_demo, :text=>"Integer Entry") +TkEntry.new(l1, :validate=>:focus, + :vcmd=>[ + proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P' + ]) {|e| + invalidcommand [proc{|w| focusAndFlash(w, e.fg, e.bg)}, '%W'] + pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') +} + +l2 = TkLabelFrame.new($entry3_demo, :text=>"Length-Constrained Entry") +TkEntry.new(l2, :validate=>:key, :invcmd=>proc{Tk.bell}, + :vcmd=>[proc{|s| s.length < 10}, '%P'] + ).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') + +### PHONE NUMBER ENTRY ### +# Note that the source to this is quite a bit longer as the behaviour +# demonstrated is a lot more ambitious than with the others. + +# Initial content for the third entry widget +entry3content = TkVariable.new("1-(000)-000-0000") + +# Mapping from alphabetic characters to numbers. +$phoneNumberMap = {} +Hash[*(%w(abc 2 def 3 ghi 4 jkl 5 mno 6 pqrs 7 tuv 8 wxyz 9))].each{|chars, n| + chars.split('').each{|c| + $phoneNumberMap[c] = n + $phoneNumberMap[c.upcase] = n + } +} + +# phoneSkipLeft -- +# Skip over fixed characters in a phone-number string when moving left. +# +# Arguments: +# widget - The entry widget containing the phone-number. +def phoneSkipLeft(widget) + idx = widget.index('insert') + if idx == 8 + # Skip back two extra characters + widget.cursor = idx - 2 + elsif idx == 7 || idx == 12 + # Skip back one extra character + widget.cursor = idx - 1 + elsif idx <= 3 + # Can't move any further + Tk.bell + Tk.callback_break + end +end + +# phoneSkipRight -- +# Skip over fixed characters in a phone-number string when moving right. +# +# Arguments: +# widget - The entry widget containing the phone-number. +# add - Offset to add to index before calculation (used by validation.) +def phoneSkipRight(widget, add = 0) + idx = widget.index('insert') + if (idx + add == 5) + # Skip forward two extra characters + widget.cursor = idx + 2 + elsif (idx + add == 6 || idx + add == 10) + # Skip forward one extra character + widget.cursor = idx + 1 + elsif (idx + add == 15 && add == 0) + # Can't move any further + Tk.bell + Tk.callback_break + end +end + +# validatePhoneChange -- +# Checks that the replacement (mapped to a digit) of the given +# character in an entry widget at the given position will leave a +# valid phone number in the widget. +# +# widget - entry widget to validate +# vmode - The widget's validation mode +# idx - The index where replacement is to occur +# char - The character (or string, though that will always be +# refused) to be overwritten at that point. + +def validatePhoneChange(widget, vmode, idx, char) + return true if idx == nil + Tk.after_idle(proc{widget.configure(:validate=>vmode, + :invcmd=>proc{Tk.bell})}) + if !(idx<3 || idx==6 || idx==7 || idx==11 || idx>15) && char =~ /[0-9A-Za-z]/ + widget.delete(idx) + widget.insert(idx, $phoneNumberMap[char] || char) + Tk.after_idle(proc{phoneSkipRight(widget, -1)}) + return true + end + return false +end + + +l3 = TkLabelFrame.new($entry3_demo, :text=>"US Phone-Number Entry") +TkEntry.new(l3, :validate=>:key, :invcmd=>proc{Tk.bell}, + :textvariable=>entry3content, + :vcmd=>[ + proc{|w,v,i,s| validatePhoneChange(w,v,i,s)}, + "%W %v %i %S" + ]){|e| + # Click to focus goes to the first editable character... + bind('FocusIn', proc{|d,w| + if d != "NotifyAncestor" + w.cursor = 3 + Tk.after_idle(proc{w.selection_clear}) + end + }, '%d %W') + bind('Left', proc{|w| phoneSkipLeft(w)}, '%W') + bind('Right', proc{|w| phoneSkipRight(w)}, '%W') + pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') +} + +l4 = TkLabelFrame.new($entry3_demo, :text=>"Password Entry") +TkEntry.new(l4, :validate=>:key, :show=>'*', + :vcmd=>[ + proc{|s| s.length <= 8}, + '%P' + ]).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') + +TkFrame.new($entry3_demo){|f| + lower + TkGrid.configure(l1, l2, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew) + TkGrid.configure(l3, l4, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew) + TkGrid.columnconfigure(f, [0,1], :uniform=>1) + pack(:fill=>:both, :expand=>true) +} diff --git a/ext/tk/sample/demos-jp/widget b/ext/tk/sample/demos-jp/widget index bda80d5541..3dd285a489 100644 --- a/ext/tk/sample/demos-jp/widget +++ b/ext/tk/sample/demos-jp/widget @@ -261,10 +261,13 @@ txt.insert('end', "1. スクロールバーなし\n", tag_demo, "demo-entry1") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. スクロールバーあり\n", tag_demo, "demo-entry2") txt.insert('end', " \n ", tag_demospace) -txt.insert('end', "3. スピンボックス (機能に対応したバージョンのTkが必要)\n", +txt.insert('end', "3. 認証処理付きのエントリボックスとパスワードフィールド (機能に対応したバージョンのTkが必要)\n", + tag_demo, "demo-entry3") +txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "4. スピンボックス (機能に対応したバージョンのTkが必要)\n", tag_demo, "demo-spin") txt.insert('end', " \n ", tag_demospace) -txt.insert('end', "4. 簡単なフォーム\n", tag_demo, "demo-form") +txt.insert('end', "5. 簡単なフォーム\n", tag_demo, "demo-form") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") |