Ruby GUI Toolkits Feb 9, 2020 Available GUI toolkits The Tk GUI toolkit is a part of the Ruby distribution Other toolkits are FXRuby, GTK+, FLTK, Gt, probably others Tk is badly documented, does not support native widgets, and is generally regarded as ugly However, Tk is perfectly functional and easily available
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 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 Wait for event Dispatch event Quit 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 oneyou 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) end Tk.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 Javas layout managers Ruby has three geometry managers: grid, place, and pack pack is like Javas FlowLayout; things are put into it in the order they are defined grid is like Javas 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 dont 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 dont 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-preview Select 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 >1 Successfully installed wxruby2-preview-0.0.40-i686darwin8.8.2 HelloWorld in wxRuby2
require 'rubygems' require 'wx' include Wx # Extend the Wx::App class class 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 dont 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 end end include Wx
Using a BoxSizer # Code from previous slide goes here class 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() end end MyApp.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 dont care much about appearance You have several choices if you want something better than Tk This situation may change as Ruby becomes increasingly popular The End