« 時計をつくる2 | トップページ | 時計をつくる4 »

2009年5月 9日 (土)

時計をつくる3

前回ジャギってしまった時針をWx::GraphicsContextのメソッドを使って
アンチエイリアスを効かせて描いてみます。

どうやらGCDCからGraphicsContextをgetして描画することが出来るようですが、ドキュメントにそのようなメソッドが書かれていないのでDCからGraphicsContextを生成して描くことにします。

GraphicsContextには便利そうなメソッドがいっぱいありそうです。これらを使って他の部分も書き換えてみます。

GraphicsContextの基本的な使い方は、ココココを見ると以下のように使うらしい。

......
# Create GraphicsPath from GraphicsContext
path = gc.create_path

# Save GraphicsMatrix
mt   = gc.get_transform

# Add Path Something
path.add_circle(0, 0, radius)

# Pen Setting
gc.set_pen(pen)

# Draw It
gc.draw_path(path)

# Restore GraphicsMatrix
gc.set_transform(mt)
......

GraphicsContextを使って描画する場合、まずWx::GraphicsContext.create(Wx::DC)でGraphicsContextを生成する。次にGraphicsPathの生成を行う。GraphicsPathで形を設定して、GraphicsPenで描画に使用するペンの設定、GraphicsContextのdrawメソッドで最後に描画をおこなう。

この前後で、GraphicsMatrixの待避と戻しを行っておかないと座標やらスケールやらカラーが保持されたままになってしまうようだ。これは不具合があって、GraphicsPathごとにPenの設定を保持することが出来ないようなのでGraphicsPathをdrawするごとにPenの設定が必要になる。だから待避と戻しを行っておかないとGraphicsPathの色の塗り分けが出来なくなる。

これでとりあえず針が綺麗に描画できるようになった。次は、針を動かす部分。
GraphicsContextのrotateメソッドを使用することにした。ラジアンを指定するだけでアフィン変換しれくれるので座標計算が不要になった。

できたコードは以下。

  1. require 'rubygems'
  2. require 'wx'
  3. require 'RTC.rb'
  4.  
  5. class RubyThroughClock < RTC
  6.   def initialize(parent = nil)
  7.     super()
  8.  
  9.     evt_paint(){drawClock()}
  10.     m_spinctrl1.evt_spinctrl(m_spinctrl1.get_id()){|event| updateHour(event)}
  11.     m_spinctrl2.evt_spinctrl(m_spinctrl2.get_id()){|event| updateMin(event)}
  12.  
  13.     # structure for testing
  14.     @time = Struct.new('Time', :hour, :min).new
  15.     @time.hour = 0
  16.     @time.min = 0
  17.   end
  18.  
  19.   def updateHour(event)
  20.     @time.hour = @m_spinctrl1.get_value
  21.     drawClock()
  22.   end
  23.  
  24.   def updateMin(event)
  25.     @time.min = @m_spinctrl2.get_value
  26.     drawClock()
  27.   end
  28.  
  29.   def drawClock()
  30.     paint do |dc|
  31.     #paint_buffered do |dc|
  32.  
  33.       # Create Graphics Context
  34.       gc = Wx::GraphicsContext.create(dc)
  35.  
  36.       # Set background color
  37.       dc.set_background_mode(Wx::TRANSPARENT)
  38.       dc.set_background(Wx::NULL_BRUSH)
  39.  
  40.       # Clear DC
  41.       dc.clear
  42.  
  43.       # Get current time
  44.       #time = Time.now
  45.       time = @time
  46.  
  47.       # Draw the current time
  48.       time_str = "%02d" % time.hour.to_s + ':' + "%02d" % time.min.to_s
  49.       dc.draw_text(time_str, 5, dc.size.height - 30)
  50.  
  51.       # Offset X Y position
  52.       gc.translate(dc.size.width / 2, dc.size.height / 2)
  53.  
  54.       # Draw Circle
  55.       drawCircle(gc, dc.size.height / 2, Wx::Pen.new(Wx::RED, 8))
  56.  
  57.       # Draw Hour hand
  58.       hand = [ [0, dc.size.height / 30], [-5, 0], [0, -dc.size.height / 4], [5, 0] ]
  59.       drawHand(gc, hand, Wx::WHITE_BRUSH, Math::PI * ( 30 * (time.hour % 12)) / 180)
  60.  
  61.       # Draw Min hand
  62.       hand = [ [0, dc.size.height / 30], [-5, 0], [0, -dc.size.height / 2], [5, 0] ]
  63.       drawHand(gc, hand, Wx::BLUE_BRUSH, Math::PI * ( 6 * time.min ) / 180)
  64.  
  65.       end
  66.   end
  67.  
  68.   def drawHand(gc, hand, brush, radians)
  69.     path = gc.create_path
  70.     mt   = gc.get_transform
  71.  
  72.     # Set Hand Polygon
  73.     hand.each do |xy|
  74.       path.add_line_to_point(xy[0], xy[1])
  75.     end
  76.     path.close_subpath
  77.  
  78.     # Move Hand
  79.     gc.rotate(radians)
  80.  
  81.     # Pen Setting
  82.     gc.set_pen(Wx::Pen.new(Wx::BLACK, 1))
  83.  
  84.     # Brush Setting
  85.     gc.set_brush(brush)
  86.     gc.fill_path(path)
  87.     #gc.fill_path(path, Wx::WINDING_RULE)
  88.     #gc.stroke_path(path)
  89.     #gc.draw_path(path)
  90.  
  91.     gc.set_transform(mt)
  92.   end
  93.  
  94.   def drawCircle(gc, radius, pen)
  95.     path = gc.create_path
  96.     mt   = gc.get_transform
  97.  
  98.     # Set Path
  99.     path.add_circle(0, 0, radius)
  100.  
  101.     # Pen Setting
  102.     gc.set_pen(pen)
  103.  
  104.     # Draw Circle
  105.     gc.draw_path(path)
  106.  
  107.     gc.set_transform(mt)
  108.   end
  109.  
  110.  
  111. end
  112.  
  113.  
  114. class App < Wx::App
  115.   def on_init
  116.     f =  ::RubyThroughClock.new
  117.     f.show
  118.   end
  119. end
  120. App.new.main_loop
  121.  

実行結果。針が綺麗になりました。動きもちゃんとしています。

01_2

|

« 時計をつくる2 | トップページ | 時計をつくる4 »

時計をつくる」カテゴリの記事

コメント

コメントを書く



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




トラックバック

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

この記事へのトラックバック一覧です: 時計をつくる3:

« 時計をつくる2 | トップページ | 時計をつくる4 »