WPF 為 .NET Framework 圖形子系統,支援富媒體、動畫、資料視覺化。本文以類比鐘面應用展示 IronRuby 與 WPF 深度整合。
require 'WindowsBase'
require 'PresentationFramework'
require 'PresentationCore'
require 'System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
class Clock
CLOCK_WIDTH = 150; CLOCK_HEIGHT = 150
LABEL_HEIGHT = CLOCK_HEIGHT / 7; LABEL_WIDTH = CLOCK_WIDTH / 7
RADIUS = CLOCK_WIDTH / 2; RADS = Math::PI / 180
MIN_LOCATIONS = {}; HOUR_LOCATIONS = {}
def run!
plot_locations
@window = System::Windows::Window.new
@window.background = System::Windows::Media::Brushes.LightGray
@window.width = CLOCK_WIDTH * 2; @window.height = CLOCK_HEIGHT * 2
@window.resize_mode = System::Windows::ResizeMode.NoResize
@canvas = System::Windows::Controls::Canvas.new
@canvas.width = CLOCK_WIDTH; @canvas.height = CLOCK_HEIGHT
@minute_hand = System::Windows::Shapes::Line.new
@minute_hand.stroke = System::Windows::Media::Brushes.Black
@minute_hand.stroke_thickness = 1
@minute_hand.x1 = CLOCK_WIDTH / 2; @minute_hand.y1 = CLOCK_HEIGHT / 2
@hour_hand = System::Windows::Shapes::Line.new
@hour_hand.stroke = System::Windows::Media::Brushes.Black
@hour_hand.stroke_thickness = 3
@hour_hand.x1 = CLOCK_WIDTH / 2; @hour_hand.y1 = CLOCK_HEIGHT / 2
@canvas.children.add(@minute_hand)
@canvas.children.add(@hour_hand)
plot_face; plot_labels; plot_hands
@window.content = @canvas
System::Windows::Application.new.run(@window)
end
def plot_locations
(0..60).each do |i|
a = i * 6
x = (RADIUS * Math.sin(a * RADS)).to_i + CLOCK_WIDTH / 2
y = CLOCK_HEIGHT / 2 - (RADIUS * Math.cos(a * RADS)).to_i
coords = [x, y]
HOUR_LOCATIONS[i/5] = coords if i % 5 == 0
MIN_LOCATIONS[i] = coords
end
end
def plot_face
extra_x = CLOCK_WIDTH * 0.15; extra_y = CLOCK_HEIGHT * 0.15
face = System::Windows::Shapes::Ellipse.new
face.fill = System::Windows::Media::Brushes.White
face.width = CLOCK_WIDTH + extra_x; face.height = CLOCK_HEIGHT + extra_y
face.margin = System::Windows::Thickness.new(-extra_x/2, -extra_y/2, 0, 0)
face.stroke = System::Windows::Media::Brushes.Gray; face.stroke_thickness = 1
System::Windows::Controls::Canvas.set_z_index(face, -1)
@canvas.children.add(face)
end
def plot_labels
HOUR_LOCATIONS.each_pair do |p, coords|
next if p == 0
lbl = System::Windows::Controls::Label.new
lbl.horizontal_content_alignment = System::Windows::HorizontalAlignment.Center
lbl.width = LABEL_WIDTH; lbl.height = LABEL_HEIGHT
lbl.content = p.to_s
lbl.margin = System::Windows::Thickness.new(coords[0] - LABEL_WIDTH/2, coords[1] - LABEL_HEIGHT/2, 0, 0)
lbl.padding = System::Windows::Thickness.new(0,0,0,0)
@canvas.children.add(lbl)
end
end
def plot_hands
time = Time.now
hours = time.hour; minutes = time.min
return if @minutes && minutes == @minutes
@hours = hours >= 12 ? hours - 12 : hours
@minutes = minutes == 0 ? 60 : minutes
@minute_hand.dispatcher.begin_invoke(
System::Windows::Threading::DispatcherPriority.Render,
System::Action.new {
@minute_hand.x2 = MIN_LOCATIONS[@minutes][0]
@minute_hand.y2 = MIN_LOCATIONS[@minutes][1]
@hour_hand.x2 = HOUR_LOCATIONS[@hours][0]
@hour_hand.y2 = HOUR_LOCATIONS[@hours][1]
})
end
end
clock = Clock.new
timer = System::Timers::Timer.new
timer.interval = 1000
timer.elapsed { clock.plot_hands }
timer.enabled = true
clock.run!
.new 直接建構 CLR 物件。set_z_index)。timer.elapsed { clock.plot_hands } 對應 timer.Elapsed += ...,支援 method(:tick)、proc、lambda 多重訂閱。XamlReader.parse(File.read('xaml')) 直接建構物件樹,find_name 取得命名元素。class Programmer < MyClassLibrary::Person 並擴充方法。include System::Windows::Shapes 或 WinForms = System::Windows::Forms 別名。IronRuby 賦予 .NET 動態語言表達力,配合 WPF 圖形能力,極適合資料視覺化快速原型。雖專案已停更,但其互操作設計思想仍具參考價值。