1# -*- coding: utf-8 -*- 2# 3# animated label widget demo (called by 'widget') 4# 5# based on Tcl/Tk8.5a2 widget demos 6 7# toplevel widget が存在すれば削除する 8if defined?($anilabel_demo) && $anilabel_demo 9 $anilabel_demo.destroy 10 $anilabel_demo = nil 11end 12 13# demo 用の toplevel widget を生成 14$anilabel_demo = TkToplevel.new {|w| 15 title("Animated Label Demonstration") 16 iconname("anilabel") 17 positionWindow(w) 18} 19 20base_frame = TkFrame.new($anilabel_demo).pack(:fill=>:both, :expand=>true) 21 22# label 生成 23msg = TkLabel.new(base_frame) { 24 font $font 25 wraplength '4i' 26 justify 'left' 27 text "下には4つのアニメーションラベルが表示されています。左側にあるラベルは、内部のテキストメッセージをスクロールしたように見せることで動きを付けています。右側のラベルは、表示するイメージを変化させることで動きを与えています。" 28} 29msg.pack('side'=>'top') 30 31# frame 生成 32TkFrame.new(base_frame) {|frame| 33 TkButton.new(frame) { 34 #text '了解' 35 text '閉じる' 36 command proc{ 37 tmppath = $anilabel_demo 38 $anilabel_demo = nil 39 tmppath.destroy 40 } 41 }.pack('side'=>'left', 'expand'=>'yes') 42 43 TkButton.new(frame) { 44 text 'コード参照' 45 command proc{showCode 'anilabel'} 46 }.pack('side'=>'left', 'expand'=>'yes') 47 48}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') 49 50# label demo 用フレーム生成 51f_left = TkLabelFrame.new(base_frame, :text=>'Scrolling Texts') 52f_right = TkLabelFrame.new(base_frame, :text=>'GIF Image') 53Tk.pack(f_left, f_right, 'side'=>'left', 'expand'=>'yes', 'fill'=>'both', 54 'padx'=>10, 'pady'=>10) 55 56# animated label 57class AnimatedTextLabel < TkLabel 58 def initialize(*args) 59 super(*args) 60 @timer = TkTimer.new{ _animation_callback } 61 @timer.loop_exec = -1 62 # bind('Destroy'){ @timer.stop } 63 @btag = TkBindTag.new('Destroy'){ @timer.stop } 64 self.bindtags_unshift(@btag) 65 end 66 67 def _animation_callback() 68 txt = self.text 69 self.text = (txt[1..-1] << txt[0]) 70 end 71 private :_animation_callback 72 73 def start(interval) 74 @timer.set_interval(interval) 75 @timer.start 76 end 77 78 def stop 79 @timer.stop 80 end 81end 82 83# animated image 84class AnimatedImageLabel < AnimatedTextLabel 85 def initialize(*args) 86 super(*args) 87 @destroy_image = false 88 @btag.bind_append('Destroy'){ 89 if @destroy_image 90 begin 91 self.image.delete 92 rescue 93 end 94 end 95 } 96 end 97 attr_accessor :destroy_image 98 99 def _animation_callback() 100 img = self.image 101 102 fmt = img.format 103 if fmt.kind_of?(Array) 104 if fmt[1].kind_of?(Hash) 105 # fmt == ['GIF', {'index'=>idx}] 106 idx = fmt[1]['index'] 107 else 108 # fmt == ['GIF', '-index', idx] :: Ruby1.8.2 returns this. 109 idx = fmt[2] 110 end 111 elsif fmt.kind_of?(String) && fmt =~ /GIF -index (\d+)/ 112 idx = $1.to_i 113 else 114 idx = -1 115 end 116 117 begin 118 img.format("GIF -index #{idx + 1}") 119 rescue => e 120 img.format("GIF -index 0") 121 end 122 end 123 private :_animation_callback 124end 125 126# label ������ 127l1 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:ridge, 128 :font=>{:family=>'Courier', :size=>10}) 129l2 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:groove, 130 :font=>{:family=>'Courier', :size=>10}) 131l3 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:flat, 132 :font=>{:family=>'Courier', :size=>10}, :width=>18) 133Tk.pack(l1, l2, l3, 134 :side=>:top, :expand=>true, :anchor=>:w, :padx=>10, :pady=>10) 135 136limg = AnimatedImageLabel.new(f_right, :borderwidth=>0) 137limg.pack(:side=>:top, :expand=>true, :padx=>10, :pady=>10) 138 139# base64-encoded animated GIF file 140tclPowerdData = <<EOD 141 R0lGODlhKgBAAPQAAP//////zP//AP/MzP/Mmf/MAP+Zmf+ZZv+ZAMz//8zM 142 zMyZmcyZZsxmZsxmAMwzAJnMzJmZzJmZmZlmmZlmZplmM5kzM2aZzGZmzGZm 143 mWZmZmYzZmYzMzNmzDMzZgAzmSH+IE1hZGUgd2l0aCBHSU1QIGJ5IExARGVt 144 YWlsbHkuY29tACH5BAVkAAEALAAAAAAqAEAAAAX+YCCOZEkyTKM2jOm66yPP 145 dF03bx7YcuHIDkGBR7SZeIyhTID4FZ+4Es8nQyCe2EeUNJ0peY2s9mi7PhAM 146 ngEAMGRbUpvzSxskLh1J+Hkg134OdDIDEB+GHxtYMEQMTjMGEYeGFoomezaC 147 DZGSHFmLXTQKkh8eNQVpZ2afmDQGHaOYSoEyhhcklzVmMpuHnaZmDqiGJbg0 148 qFqvh6UNAwB7VA+OwydEjgujkgrPNhbTI8dFvNgEYcHcHx0lB1kX2IYeA2G6 149 NN0YfkXJ2BsAMuAzHB9cZMk3qoEbRzUACsRCUBK5JxsC3iMiKd8GN088SIyT 150 0RAFSROyeEg38caDiB/+JEgqxsODrZJ1BkT0oHKSmI0ceQxo94HDpg0qsuDk 151 UmRAMgu8OgwQ+uIJgUMVeGXA+IQkzEeHGvD8cIGlDXsLiRjQ+EHroQhea7xY 152 8IQBSgYYDi1IS+OFBCgaDMGVS3fGi5BPJpBaENdQ0EomKGD56IHwO39EXiSC 153 Ysgxor5+Xfgq0qByYUpiXmwuoredB2aYH4gWWda0B7SeNENpEJHC1ghi+pS4 154 AJpIAwWvKPBi+8YEht5EriEqpFfMlhEdkBNpx0HUhwypx5T4IB1MBg/Ws2sn 155 wV3MSQOkzI8fUd48Aw3dOZto71x85hHtHijYv18Gf/3GqCdDCXHNoICBobSo 156 IqBqJLyCoH8JPrLgdh88CKCFD0CGmAiGYPgffwceZh6FC2ohIIklnkhehTNY 157 4CIHHGzgwYw01ujBBhvAqKOLLq5AAk9kuSPkkKO40NB+h1gnypJIIvkBf09a 158 N5QIRz5p5ZJXJpmlIVhOGQA2TmIJZZhKKmmll2BqyWSXWUrZpQtpatlmk1c2 159 KaWRHeTZEJF8SqLDn/hhsOeQgBbqAh6DGqronxeARUIIACH5BAUeAAAALAUA 160 LgAFAAUAAAUM4CeKz/OV5YmqaRkCACH5BAUeAAEALAUALgAKAAUAAAUUICCK 161 z/OdJVCaa7p+7aOWcDvTZwgAIfkEBR4AAQAsCwAuAAkABQAABRPgA4zP95zA 162 eZqoWqqpyqLkZ38hACH5BAUKAAEALAcALgANAA4AAAU7ICA+jwiUJEqeKau+ 163 r+vGaTmac63v/GP9HM7GQyx+jsgkkoRUHJ3Qx0cK/VQVTKtWwbVKn9suNunc 164 WkMAIfkEBQoAAAAsBwA3AAcABQAABRGgIHzk842j+Yjlt5KuO8JmCAAh+QQF 165 CgAAACwLADcABwAFAAAFEeAnfN9TjqP5oOWziq05lmUIACH5BAUKAAAALA8A 166 NwAHAAUAAAUPoPCJTymS3yiQj4qOcPmEACH5BAUKAAAALBMANwAHAAUAAAUR 167 oCB+z/MJX2o+I2miKimiawgAIfkEBQoAAAAsFwA3AAcABQAABRGgIHzfY47j 168 Q4qk+aHl+pZmCAAh+QQFCgAAACwbADcABwAFAAAFEaAgfs/zCV9qPiNJouo7 169 ll8IACH5BAUKAAAALB8ANwADAAUAAAUIoCB8o0iWZggAOw== 170EOD 171 172l1.text('* Slow Animation *').start(300) 173l2.text('* Fast Animation *').start(80) 174l3.text('This is a longer scrolling text in a widget that will not show the whole message at once. ').start(150) 175 176limg.destroy_image = true 177limg.image(TkPhotoImage.new(:format=>'GIF', :data=>tclPowerdData)).start(100) 178