« 時計をつくる10 | トップページ | Twitterクライアントをつくる5 »

2010年11月 8日 (月)

Twitterクライアントをつくる4

いろいろハマりすぎて先に進めておりません。
とりあえずアプリっぽく取得したついーとを表示することができております。

今回ハマったのはWx::ScrolledWindowのスクロールバー表示とスクロールとストリームからのWx::Imageの処理。

取得したついーとをこんなカンジで表示するようにしました。

1

まず一つ一つのついーとをボタンやテキストの入ったフォームをPanelにしてこれを再利用しようと目論む。wxFormBuilderで野暮ったいがとりあえずのPanelができたので追加してみるがうまく動かない。画面が小さかったり自動リサイズされなかったりヘンな表示になる。GUIをコードで組んでみたことがあまりなかったのでSizerの動きがイマイチ理解できていなかったようだ。

Wx::ScrolledWindowは初めて使用してみたが意外とすんなりいかなかった。
スクロールバーをPanelを追加した分、画面の大きさによって自動的に表示させたかったのだがFrameをリサイズした時だけしか表示してくれない。Sizerを使った場合はWindow#set_virtual_size_hintsで大きさを指定してあげればよいかと思ったが指定しただけでは表示してくれない。send_size_eventも無効。fit_insideでやっと自動的に出るようになった。ヨカッタ。

ユーザのアイコンを表示させるためにuriを元にダウンロードしてWx::ImageからBitmapを作成する処理をしているんですが、このダウンロードした状態(ストリーム)からWx::Imageで読み込んだときに画像のフォーマットが判別できず苦労しました。
一旦ファイルでセーブしてそれを読み込ませればフォーマットを正しく自動判別してくれるのだがストリームからWx::BITMAP_TYPE_ANYで読み込むと自動認識できないようでload_streamが働かない。

おそらくアイコンはGIFだったりJPEGだったりPNGするのでWx::BITMAP_TYPE_ANYで自動判別してもらいたいところですが一旦ファイルに落とすしか無いのか。いやそれだと負けだ。ということでググる。
他の処理系だとImageFromStreamのようなメソッドがあるようなのですが、wxRubyには見当たらない。ではWx::Imageはどうやって判別しているのかな、とソースを見てみるとWx::Bitmapのハッシュを使っているようです。そっちを見てみると

  1.   # Allow wxRuby to guess the type of an image file from its extension.
  2.   BITMAP_TYPE_GUESS = {
  3.     'bmp'  => Wx::BITMAP_TYPE_BMP,
  4.     'gif'  => Wx::BITMAP_TYPE_GIF,
  5.     'ico'  => Wx::BITMAP_TYPE_ICO,
  6.     'jpeg' => Wx::BITMAP_TYPE_JPEG,
  7.     'jpg'  => Wx::BITMAP_TYPE_JPEG,
  8.     'pbm'  => Wx::BITMAP_TYPE_PNM,
  9.     'pcx'  => Wx::BITMAP_TYPE_PCX,
  10.     'pgm'  => Wx::BITMAP_TYPE_PNM,
  11.     'png'  => Wx::BITMAP_TYPE_PNG,
  12.     'pnm'  => Wx::BITMAP_TYPE_PNM,
  13.     'ppm'  => Wx::BITMAP_TYPE_PNM,
  14.     'tga'  => Wx::BITMAP_TYPE_TGA,
  15.     'tif'  => Wx::BITMAP_TYPE_TIF,
  16.     'tiff' => Wx::BITMAP_TYPE_TIF,
  17.     'xbm'  => Wx::BITMAP_TYPE_XBM,
  18.     'xpm'  => Wx::BITMAP_TYPE_XPM
  19.   }
  20.  

ファイルの拡張子で判別している?
一応拡張子を存在しないモノに変えてみて試したら正しく画像処理されているので拡張子だけに頼っているわけではなさそうだが、この方式は使えそう。

  1.   icon_url = URI.parse(status.user.profile_image_url)
  2.   tBITMAP_TYPE_GUESS = Wx::Bitmap::BITMAP_TYPE_GUESS
  3.   imgtype = tBITMAP_TYPE_GUESS[File.extname(icon_url.to_s).sub(/^./, '').downcase]
  4.  
  5.   open(icon_url, 'rb') do |i|
  6.     icon.load_stream(i, imgtype)
  7.     # p icon.ok?
  8.   end
  9.  

ということでuriを解析してファイルの拡張子でフォーマットタイプを判別するようにしてみました。今度はいいカンジで動いています。

Reloadするとついーとを拾って画面を更新します。まだついーとが重複してしまいますが次で直したい。

恒例のソース晒し

  1. begin
  2.   require 'rubygems'
  3. rescue LoadError
  4. end
  5. require 'open-uri'
  6.  
  7. require 'wx'
  8. require 'twitter'
  9. require 'watir'
  10. # require 'vapir'
  11. # require 'vapir-ie'
  12. # require "watir-vapir"
  13.  
  14. require './WTC.rb'
  15.  
  16. # Authentication info file for Oauth
  17. OAUTH_ACCESS_FILE   = File.join( File.dirname(__FILE__), "..", "config", "oauth_access.yml")
  18. OAUTH_CONSUMER_FILE = File.join( File.dirname(__FILE__), "..", "config", "oauth_consumer.yml")
  19.  
  20. class WxrubyTweetClient < WTC
  21.   def initialize(parent = nil)
  22.     super()
  23.  
  24.     # Init time line manager
  25.     @tlmgr = Timeline_Manager.new('Home')
  26.     add_tab('Home')
  27.  
  28.     # Event handler
  29.     evt_tool(m_tool_reload){|event| on_tool_reload}
  30.     evt_tool(m_tool_tweet) {|event| on_tool_tweet}
  31.     evt_tool(m_tool_group) {|event| on_tool_group}
  32.  
  33.     # Avoid to freeze GUI
  34.     Wx::Timer.every(10) { sleep(0.01) }
  35.  
  36.     @consumer = load_consumer_file()
  37.     login()
  38.   end
  39.  
  40.   # Load consumer key/sercret from file
  41.   def load_consumer_file()
  42.     consumer = Hash.new
  43.     if File.exist?(OAUTH_CONSUMER_FILE)
  44.       # Load consumer key/secret file
  45.       begin
  46.         File.open(OAUTH_CONSUMER_FILE,'r') do |f|
  47.           consumer = YAML.load(f)
  48.         end
  49.       rescue => e
  50.         puts 'consumer file load err: ', e, e.backtrace
  51.         exit
  52.       end
  53.     else
  54.       puts "#{OAUTH_CONSUMER_FILE} is not exist", __LINE__
  55.       exit
  56.     end
  57.  
  58.     if (consumer["oauth_consumer"].has_key?("key") &&
  59.         consumer["oauth_consumer"].has_key?("secret"))
  60.       # Set Consumer key/secret
  61.       Twitter::Client.configure do |conf|
  62.         conf.oauth_consumer_token = consumer["oauth_consumer"]["key"]
  63.         conf.oauth_consumer_secret = consumer["oauth_consumer"]["secret"]
  64.       end
  65.       return consumer
  66.     else
  67.       puts "Consumer key/secret are not exists in #{OAUTH_CONSUMER_FILE}", __LINE__
  68.       exit
  69.     end
  70.   end
  71.  
  72.   # Request access token
  73.   def req_access_token()
  74.     consumer = OAuth::Consumer.new(
  75.         @consumer["oauth_consumer"]["key"],
  76.         @consumer["oauth_consumer"]["secret"],
  77.         :site => 'http://twitter.com'
  78.     )
  79.  
  80.     request_token = consumer.get_request_token
  81.  
  82.     # Launch browser to get PIN code
  83.     begin
  84.       # browser = Vapir::IE.new
  85.       # browser = Vapir::Browser.new
  86.       browser = Watir::Browser.new
  87.       browser.goto(request_token.authorize_url)
  88.     rescue => e
  89.       p e, e.backtrace
  90.       puts 'Browser related issue happened'
  91.       exit
  92.     end
  93.  
  94.     oauth_verifier = Wx::get_text_from_user("Input PIN from twitter.com")
  95.     exit if oauth_verifier.empty?
  96.  
  97.     access_token = request_token.get_access_token(
  98.       :oauth_verifier => oauth_verifier
  99.     )
  100.  
  101.     return {"key" => access_token.token, "secret" => access_token.secret}
  102.   end
  103.  
  104.   # Login Twitter.com
  105.   def login()
  106.     if File.exist?(OAUTH_ACCESS_FILE)
  107.       begin
  108.         File.open(OAUTH_ACCESS_FILE,'r') do |f|
  109.           access = YAML.load(f)
  110.           @twit = Twitter::Client.new(access)
  111.         end
  112.       rescue => e
  113.         puts 'oauth_access file load err: ', e, __LINE__
  114.         exit
  115.       end
  116.     else
  117.       begin
  118.         access = Hash.new
  119.         access["oauth_access"] = req_access_token()
  120.         # @twit = Twitter::Client.new
  121.         # @twit.authenticate?(access["oauth_access"]["key"], access["oauth_access"]["secret"])
  122.         @twit = Twitter::Client.new(access)
  123.         File.open(OAUTH_ACCESS_FILE,'w') do |f|
  124.           YAML.dump(access,f)
  125.         end
  126.       rescue => e
  127.         p e, e.backtrace
  128.         puts 'Oauth err, try again...'
  129.         retry
  130.       end
  131.     end
  132.   end
  133.  
  134.   # Add new TAB to Notebook
  135.   def add_tab(name)
  136.     spanel = Wx::ScrolledWindow.new(m_notebook1, :size => Wx::DEFAULT_SIZE, :style => Wx::VSCROLL)
  137.     spanel.set_scroll_rate(0,15)
  138.     spanel.label = name
  139.     spanel.sizer = @tlmgr.add_tl(name)
  140.     m_notebook1.add_page(spanel, name)
  141.     return spanel
  142.   end
  143.  
  144.   # Event handler
  145.   def on_tool_reload
  146.     panel = m_notebook1.page(m_notebook1.get_selection)
  147.     public_timeline = @twit.timeline_for(:me) do |status|
  148.     # public_timeline = @twit.my(:timeline) do |status|
  149.       # p status.to_hash
  150.       @tlmgr.add_status(panel, status)
  151.     end
  152.   end
  153.  
  154.   def on_tool_tweet
  155.     msg = m_textctrl_tweet.value
  156.     status = @twit.status(:post, msg) if not msg.empty?
  157.   end
  158.  
  159.   def on_tool_group
  160.   end
  161.  
  162. end
  163.  
  164. class Timeline_Manager
  165.   # attr_reader :tl_name
  166.  
  167.   def initialize(name)
  168.     @tl_name = Hash.new
  169.     add_tl(name)
  170.   end
  171.  
  172.   def add_tl(name)
  173.     @tl_name[name] = Wx::BoxSizer.new(Wx::VERTICAL)
  174.     return @tl_name[name]
  175.   end
  176.  
  177.   # Add status to notebook tab
  178.   def add_status(panel, status)
  179.     sizer = Wx::BoxSizer.new(Wx::VERTICAL)
  180.     state_panel = WTCpanel.new(panel)
  181.  
  182.     # Get user icon
  183.     icon = Wx::Image.new
  184.     begin
  185.       icon_url = URI.parse(status.user.profile_image_url)
  186.       tBITMAP_TYPE_GUESS = Wx::Bitmap::BITMAP_TYPE_GUESS
  187.       imgtype = tBITMAP_TYPE_GUESS[File.extname(icon_url.to_s).sub(/^./, '').downcase]
  188.  
  189.       open(icon_url, 'rb') do |i|
  190.         icon.load_stream(i, imgtype)
  191.         # p icon.ok?
  192.       end
  193.     rescue => e
  194.       icon = Wx::Image.from_bitmap(Wx::NULL_BITMAP)
  195.       # p e, e.backtrace
  196.     end
  197.  
  198.     # Set up tweet and user info
  199.     state_panel.user_name.label   = status.user.screen_name
  200.     state_panel.icon.bitmap_label = icon.to_bitmap
  201.     state_panel.tweet.write_text(status.text)
  202.  
  203.     # Add status to time line
  204.     sizer.add_item(state_panel, :proportion => 0, :flag => Wx::EXPAND | Wx::ALL)
  205.     @tl_name[panel.label].add_item(sizer, :proportion => 0, :flag => Wx::EXPAND | Wx::ALL)
  206.     panel.fit_inside
  207.   end
  208.  
  209.   # Get sizer for time line
  210.   def sizer(name)
  211.     @tl_name[name]
  212.   end
  213. end
  214.  
  215. class App < Wx::App
  216.   def on_init
  217.     f =  ::WxrubyTweetClient.new
  218.     f.show
  219.   end
  220. end
  221. if not defined?(Ocra)
  222.   App.new.main_loop
  223. end

XRC

  1. <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
  2. <resource xmlns="http://www.wxwindows.org/wxxrc" version="2.3.0.1">
  3.   <object class="wxFrame" name="MyFrame1" subclass="WTC">
  4.     <style>wxCAPTION|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU|wxTAB_TRAVERSAL</style>
  5.     <size>500,407</size>
  6.     <title>wxRuby Tweet Client</title>
  7.     <centered>1</centered>
  8.     <object class="wxPanel" name="m_panel4">
  9.       <style>wxTAB_TRAVERSAL</style>
  10.       <object class="wxBoxSizer">
  11.         <orient>wxVERTICAL</orient>
  12.         <object class="sizeritem">
  13.           <option>0</option>
  14.           <flag>wxEXPAND|wxALL</flag>
  15.           <border>5</border>
  16.           <object class="wxBoxSizer">
  17.             <orient>wxVERTICAL</orient>
  18.             <object class="sizeritem">
  19.               <option>0</option>
  20.               <flag>wxEXPAND</flag>
  21.               <border>5</border>
  22.               <object class="wxToolBar" name="m_toolBar1">
  23.                 <style>wxTB_HORIZONTAL</style>
  24.                 <bitmapsize></bitmapsize>
  25.                 <margins></margins>
  26.                 <packing>1</packing>
  27.                 <separation>5</separation>
  28.                 <object class="tool" name="m_tool_reload">
  29.                   <label>tool</label>
  30.                   <tooltip></tooltip>
  31.                   <longhelp></longhelp>
  32.                   <bitmap>../icon/eleganticons/images/Refresh.png</bitmap>
  33.                 </object>
  34.                 <object class="tool" name="m_tool_tweet">
  35.                   <label>Tweet</label>
  36.                   <tooltip>Tweet!</tooltip>
  37.                   <longhelp></longhelp>
  38.                   <bitmap>../icon/eleganticons/images/Speech-Bubble.png</bitmap>
  39.                 </object>
  40.                 <object class="tool" name="m_tool_dm">
  41.                   <label>Reply</label>
  42.                   <tooltip>Reply</tooltip>
  43.                   <longhelp></longhelp>
  44.                   <bitmap>../icon/eleganticons/images/Mail.png</bitmap>
  45.                 </object>
  46.                 <object class="tool" name="m_tool_group">
  47.                   <label>Group</label>
  48.                   <tooltip>Add Group</tooltip>
  49.                   <longhelp></longhelp>
  50.                   <bitmap>../icon/eleganticons/images/Person-group-add.png</bitmap>
  51.                 </object>
  52.                 <object class="tool" name="m_tool_search">
  53.                   <label>Search</label>
  54.                   <tooltip>Search</tooltip>
  55.                   <longhelp></longhelp>
  56.                   <bitmap>../icon/eleganticons/images/Search.png</bitmap>
  57.                 </object>
  58.                 <object class="tool" name="m_tool_setting">
  59.                   <label>Setting</label>
  60.                   <tooltip>Settings</tooltip>
  61.                   <longhelp></longhelp>
  62.                   <bitmap>../icon/eleganticons/images/Config.png</bitmap>
  63.                 </object>
  64.               </object>
  65.             </object>
  66.           </object>
  67.         </object>
  68.         <object class="sizeritem">
  69.           <option>0</option>
  70.           <flag>wxEXPAND|wxALL</flag>
  71.           <border>5</border>
  72.           <object class="wxBoxSizer">
  73.             <orient>wxVERTICAL</orient>
  74.             <object class="sizeritem">
  75.               <option>0</option>
  76.               <flag>wxEXPAND</flag>
  77.               <border>5</border>
  78.               <object class="wxPanel" name="m_panel1">
  79.                 <style>wxTAB_TRAVERSAL</style>
  80.                 <object class="wxBoxSizer">
  81.                   <orient>wxVERTICAL</orient>
  82.                   <object class="sizeritem">
  83.                     <option>0</option>
  84.                     <flag>wxEXPAND</flag>
  85.                     <border>5</border>
  86.                     <object class="wxTextCtrl" name="m_textCtrl_tweet">
  87.                       <style>wxTE_MULTILINE</style>
  88.                       <value></value>
  89.                       <maxlength>140</maxlength>
  90.                     </object>
  91.                   </object>
  92.                 </object>
  93.               </object>
  94.             </object>
  95.           </object>
  96.         </object>
  97.         <object class="sizeritem">
  98.           <option>1</option>
  99.           <flag>wxALL|wxEXPAND</flag>
  100.           <border>5</border>
  101.           <object class="wxBoxSizer">
  102.             <orient>wxVERTICAL</orient>
  103.             <object class="sizeritem">
  104.               <option>1</option>
  105.               <flag>wxEXPAND</flag>
  106.               <border>5</border>
  107.               <object class="wxNotebook" name="m_notebook1" />
  108.             </object>
  109.           </object>
  110.         </object>
  111.       </object>
  112.     </object>
  113.   </object>
  114.   <object class="wxPanel" name="MyPanel1" subclass="WTCpanel">
  115.     <style>wxTAB_TRAVERSAL</style>
  116.     <object class="wxBoxSizer">
  117.       <orient>wxHORIZONTAL</orient>
  118.       <object class="sizeritem">
  119.         <option>1</option>
  120.         <flag></flag>
  121.         <border>5</border>
  122.         <object class="wxBoxSizer">
  123.           <orient>wxHORIZONTAL</orient>
  124.           <object class="sizeritem">
  125.             <option>0</option>
  126.             <flag>wxEXPAND</flag>
  127.             <border>5</border>
  128.             <object class="wxBoxSizer">
  129.               <orient>wxVERTICAL</orient>
  130.               <object class="sizeritem">
  131.                 <option>0</option>
  132.                 <flag>wxALL</flag>
  133.                 <border>5</border>
  134.                 <object class="wxBitmapButton" name="icon">
  135.                   <style>wxBU_AUTODRAW</style>
  136.                   <bitmap />
  137.                   <default>0</default>
  138.                 </object>
  139.               </object>
  140.               <object class="sizeritem">
  141.                 <option>0</option>
  142.                 <flag>wxALL</flag>
  143.                 <border>5</border>
  144.                 <object class="wxStaticText" name="user_name">
  145.                   <label></label>
  146.                   <wrap>-1</wrap>
  147.                 </object>
  148.               </object>
  149.             </object>
  150.           </object>
  151.           <object class="sizeritem">
  152.             <option>1</option>
  153.             <flag>wxEXPAND</flag>
  154.             <border>5</border>
  155.             <object class="wxBoxSizer">
  156.               <orient>wxHORIZONTAL</orient>
  157.               <object class="sizeritem">
  158.                 <option>1</option>
  159.                 <flag>wxALL|wxEXPAND</flag>
  160.                 <border>5</border>
  161.                 <object class="wxTextCtrl" name="tweet">
  162.                   <style>wxTE_MULTILINE</style>
  163.                   <value></value>
  164.                   <maxlength>0</maxlength>
  165.                 </object>
  166.               </object>
  167.             </object>
  168.           </object>
  169.           <object class="sizeritem">
  170.             <option>0</option>
  171.             <flag>wxALL</flag>
  172.             <border>5</border>
  173.             <object class="wxBoxSizer">
  174.               <orient>wxVERTICAL</orient>
  175.               <object class="sizeritem">
  176.                 <option>0</option>
  177.                 <flag>wxEXPAND</flag>
  178.                 <border>5</border>
  179.                 <object class="wxButton" name="m_button2">
  180.                   <style>wxBU_EXACTFIT</style>
  181.                   <label>Follow</label>
  182.                   <default>0</default>
  183.                 </object>
  184.               </object>
  185.               <object class="sizeritem">
  186.                 <option>0</option>
  187.                 <flag>wxEXPAND</flag>
  188.                 <border>5</border>
  189.                 <object class="wxButton" name="m_button1">
  190.                   <style>wxBU_EXACTFIT</style>
  191.                   <label>RT</label>
  192.                   <default>0</default>
  193.                 </object>
  194.               </object>
  195.               <object class="sizeritem">
  196.                 <option>0</option>
  197.                 <flag>wxEXPAND</flag>
  198.                 <border>5</border>
  199.                 <object class="wxButton" name="m_button3">
  200.                   <style>wxBU_EXACTFIT</style>
  201.                   <label>Favarite</label>
  202.                   <default>0</default>
  203.                 </object>
  204.               </object>
  205.               <object class="sizeritem">
  206.                 <option>0</option>
  207.                 <flag>wxEXPAND</flag>
  208.                 <border>5</border>
  209.                 <object class="wxButton" name="m_button4">
  210.                   <style>wxBU_EXACTFIT</style>
  211.                   <label>Reply</label>
  212.                   <default>0</default>
  213.                 </object>
  214.               </object>
  215.             </object>
  216.           </object>
  217.         </object>
  218.       </object>
  219.     </object>
  220.   </object>
  221. </resource>
  222.  

XRCからの生成物

  1.  
  2. # This class was automatically generated from XRC source. It is not
  3. # recommended that this file is edited directly; instead, inherit from
  4. # this class and extend its behaviour there. 
  5. #
  6. # Source file: noname.xrc
  7. # Generated at: 2010-11-06 15:57:28 +0900
  8.  
  9. class WTC < Wx::Frame
  10.  
  11.   attr_reader :m_panel4, :m_toolbar1, :m_tool_reload, :m_tool_tweet,
  12.               :m_tool_dm, :m_tool_group, :m_tool_search,
  13.               :m_tool_setting, :m_panel1, :m_textctrl_tweet,
  14.               :m_notebook1
  15.  
  16.   def initialize(parent = nil)
  17.     super()
  18.     xml = Wx::XmlResource.get
  19.     xml.flags = 2 # Wx::XRC_NO_SUBCLASSING
  20.     xml.init_all_handlers
  21.     xml.load("noname.xrc")
  22.     xml.load_frame_subclass(self, parent, "MyFrame1")
  23.  
  24.     finder = lambda do | x |
  25.       int_id = Wx::xrcid(x)
  26.       begin
  27.         Wx::Window.find_window_by_id(int_id, self) || int_id
  28.       # Temporary hack to work around regression in 1.9.2; remove
  29.       # begin/rescue clause in later versions
  30.       rescue RuntimeError
  31.         int_id
  32.       end
  33.     end
  34.  
  35.     @m_panel4 = finder.call("m_panel4")
  36.     @m_toolbar1 = finder.call("m_toolBar1")
  37.     @m_tool_reload = finder.call("m_tool_reload")
  38.     @m_tool_tweet = finder.call("m_tool_tweet")
  39.     @m_tool_dm = finder.call("m_tool_dm")
  40.     @m_tool_group = finder.call("m_tool_group")
  41.     @m_tool_search = finder.call("m_tool_search")
  42.     @m_tool_setting = finder.call("m_tool_setting")
  43.     @m_panel1 = finder.call("m_panel1")
  44.     @m_textctrl_tweet = finder.call("m_textCtrl_tweet")
  45.     @m_notebook1 = finder.call("m_notebook1")
  46.     if self.class.method_defined? "on_init"
  47.       self.on_init()
  48.     end
  49.   end
  50. end
  51.  
  52.  
  53.  
  54. # This class was automatically generated from XRC source. It is not
  55. # recommended that this file is edited directly; instead, inherit from
  56. # this class and extend its behaviour there. 
  57. #
  58. # Source file: noname.xrc
  59. # Generated at: 2010-11-06 15:57:28 +0900
  60.  
  61. class WTCpanel < Wx::Panel
  62.  
  63.   attr_reader :icon, :user_name, :tweet, :m_button2, :m_button1,
  64.               :m_button3, :m_button4
  65.  
  66.   def initialize(parent = nil)
  67.     super()
  68.     xml = Wx::XmlResource.get
  69.     xml.flags = 2 # Wx::XRC_NO_SUBCLASSING
  70.     xml.init_all_handlers
  71.     xml.load("noname.xrc")
  72.     xml.load_panel_subclass(self, parent, "MyPanel1")
  73.  
  74.     finder = lambda do | x |
  75.       int_id = Wx::xrcid(x)
  76.       begin
  77.         Wx::Window.find_window_by_id(int_id, self) || int_id
  78.       # Temporary hack to work around regression in 1.9.2; remove
  79.       # begin/rescue clause in later versions
  80.       rescue RuntimeError
  81.         int_id
  82.       end
  83.     end
  84.  
  85.     @icon = finder.call("icon")
  86.     @user_name = finder.call("user_name")
  87.     @tweet = finder.call("tweet")
  88.     @m_button2 = finder.call("m_button2")
  89.     @m_button1 = finder.call("m_button1")
  90.     @m_button3 = finder.call("m_button3")
  91.     @m_button4 = finder.call("m_button4")
  92.     if self.class.method_defined? "on_init"
  93.       self.on_init()
  94.     end
  95.   end
  96. end
  97.  
  98.  
  99.  

|

« 時計をつくる10 | トップページ | Twitterクライアントをつくる5 »

Twitterクライアントをつくる」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1201593/37569171

この記事へのトラックバック一覧です: Twitterクライアントをつくる4:

« 時計をつくる10 | トップページ | Twitterクライアントをつくる5 »