210 likes | 656 Views
Ruby GUI Toolkits. Available GUI toolkits. The Tk GUI toolkit is a part of the Ruby distribution Tk is badly documented, does not support native widgets, and is generally regarded as ugly However, Tk is perfectly functional and easily available
E N D
Available GUI toolkits • The Tk GUI toolkit is a part of the Ruby distribution • Tk is badly documented, does not support native widgets, and is generally regarded as ugly • However, Tk is perfectly functional and easily available • Other toolkits are FXRuby, GTK+, FLTK, Gt, probably others • All have some significant disadvantages • My less-than-extensive research (about an hour's worth) leads me to think that wxRuby2 is the best choice • Advantages: Fairly stable, mature, cross-platform, native look-and-feel, good selection of widgets • Disadvantage: C++ oriented • The home page is at http://wxruby.rubyforge.org/wiki/wiki.pl • Download from RubyForge at http://rubyforge.org/frs/?group_id=35
Wait for event Dispatch event Quit Modern event-driven programs • Multiple sources of input • mouse clicks • keyboard • timers • external events • In all modern languages, this is handled with an event loop
Java hides the event loop • The event loop is built into Java GUIs • Interacting with a GUI component (such as a button) causes an event to occur • An Event is an object • You create Listeners for interesting events • The Listener gets the Event as a parameter • In Ruby, the event loop is not built in • However, Ruby GUI systems provide one—you just have to use it
“Hello world” in Tk • require 'tk'root = TkRoot.new { title 'Our first Tk App' }label = TkLabel.new(root) do text 'Hello, world!' pack("padx" => 90)endTk.mainloop • All subsequent widgets will be contained by root • The block uses instance_eval; the title method belongs to the newly created instance • pack is a geometry manager; it takes a hash as an argument • The mainloop is the event handler
Geometry managers • Geometry managers are like Java’s layout managers • Ruby has three geometry managers: grid, place, and pack • pack is like Java’s FlowLayout; things are put into it in the order they are defined • grid is like Java’s GridbagLayout, and is complex • place specifies pixel coordinates, and is tedious • pack is the best compromise for ordinary use
Allocation rectangle • Every Ruby widget has an allocation rectangle, and is put somewhere inside that rectangle • Here are the options for the hash argument to pack: • The 'side' option tells where the allocation rectangle goes in the container--'top' (default), 'bottom', 'left', or 'right' • The 'expand' option tells whether the allocation rectangle should be expanded to fill the remaining space--the value is either '0' (default, meaning don’t expand) or '1' • The 'anchor' option tells where the widget goes in the allocation rectangle--'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', or 'center' • The 'fill' option tells how to stretch the widget to fill the container--'none' (default), 'x', 'y', or 'both' • The 'padx' and 'pady' options specify margins • The default is pixels • You can suffix a number with a letter: i for inches, p for points, m for millimeters, or c for centimeters
Packing example I • require 'tk' • root = TkRoot.new() { title "Packing Example" } • button = TkButton.new(root) { text "First, rightmost" }button.pack("side"=>"right", "fill"=>"y") • entry = TkEntry.new(root).pack("side"=>"top", "fill"=>"x")entry.insert(0, "Entry on the top") • label = TkLabel.new() { text "to the right" }label.pack("side"=>"right")
Packing example II • image = TkPhotoImage.new('file'=>"background.gif", 'height'=>50)img_label = TkLabel.new(root) { image image }.pack("anchor"=>"e") • text = TkText.new(root) { width 20; height 5 }.pack("side"=>"left")text.insert('end', "Left in canvas") • TkMessage.new(root) { text "Message in the Bottom" }.pack("side"=>"bottom") • Tk.mainloop()
Event handling example • require 'tk'root = TkRoot.new() { title "Click the Button" }button = TkButton.new(root) { text "Hello..." command proc { puts "...world!" }}button.pack()Tk.mainloop() • This brings up a window with a button labeled “Hello...” • When the button is clicked, “...world!” is printed to the console
RubyGems • RubyGems is a standardized way of installing, upgrading, and removing Ruby packages • It uses a centralized repository, so you don’t even have to know where to download packages from • If you installed InstantRails, you already have RubyGems • Example: • C:\ruby\InstantRails\rails_apps>gem install wxruby2-previewSelect which gem to install for your platform (i386-mswin32) 1. wxruby2-preview 0.0.40 (i686-darwin8.8.2) 2. wxruby2-preview 0.0.40 (i386-mswin32) 3. wxruby2-preview 0.0.40 (powerpc-darwin7.9.0) 4. wxruby2-preview 0.0.40 (i686-linux) 5. Skip this gem 6. Cancel installation> 1Successfully installed wxruby2-preview-0.0.40-i686-darwin8.8.2
“HelloWorld” in wxRuby2 • require 'rubygems'require 'wx'include Wx# Extend the Wx::App classclass HelloWorld < App # Define what the application is going to do when it starts def on_init # Make a frame with the title "Hello World" helloframe = Frame.new(nil, -1, "Hello World") # Put the text "Hello World" in that frame StaticText.new(helloframe,-1,"Hello World")# Make the window appear helloframe.show() end end# Make the program actually do it!HelloWorld.new.main_loop
Using wxRuby2 • A tutorial for wxRuby2 is at http://wxruby.rubyforge.org/wiki/wiki.pl?WxRuby_Tutorial • Some of the examples don’t work as printed • The following code, at the beginning of the file, seems to solve the problem: • begin require 'wx'rescue LoadError => no_wx_err begin require 'rubygems' require 'wx' rescue LoadError raise no_wx_err endendinclude Wx
Using a BoxSizer • # Code from previous slide goes hereclass MyApp < Wx::App def on_init() frame = Wx::Frame.new(nil, -1, 'Sizer happiness') frame.set_client_size(Wx::Size.new(200,200)) sizer = Wx::BoxSizer.new(Wx::VERTICAL) text = Wx::TextCtrl.new(frame, -1, 'Type in here', Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE, Wx::TE_MULTILINE) sizer.add(text, 1, Wx::GROW|Wx::ALL, 2) button = Wx::Button.new(frame, -1, 'Click on this') sizer.add(button, 0, Wx::ALIGN_RIGHT, 2) frame.set_sizer(sizer) frame.show() endendMyApp.new.main_loop()
Comments • Ruby has no real “Ruby-like” GUI system • Tk is the default if you are OK with just basic functionality and don’t care much about appearance • You have several choices if you want something better than Tk • This situation may change as Ruby becomes increasingly popular