Ruby-FLTK Guide
Last Updated: 01-Sep-2001
Content-Type: ISO-2022-JP

$BCm0U(B: $B$3$N%I%-%e%a%s%H$K$OL$<BAuItJ,$K$D$$$F$b=q$+$l$F$$$^$9!%(B
      $B$^$?!$1Q8lHG$H$O<c43J8>O$,$3$H$J$kItJ,$,$"$j$^$9!%(B

0. $B$O$8$a$K(B

Ruby/FLTK$B$O(BFLTK GUI$B%D!<%k%-%C%H$r(BRuby$B$+$i;H$&$?$a$N3HD%%i%$%V%i%j$G$9!%(B
FLTK$B$OHs>o$K7Z$$%D!<%k%-%C%H$G!$>/$J$$%a%b%j$GF0$/$3$H$rA@$$!$$=$7$F!$4p(B
$BK\E*$J%&%#%8%C%H$@$1$rDs6!$7$F$$$^$9!%(BFLTK$B$N%$%Y%s%H%b%G%k$OHs>o$KC1=c$J(B
$B$b$N$H$J$C$F$*$j!$(BRuby$B$K$*$$$F$bF1$8$/C1=c$J$b$N$H$J$C$F$$$^$9!%(B
$B%U%)%s%H$d?'$r;XDj$9$kJ}K!$b$^$?Hs>o$K$9$C$-$j$HC1=c$J$b$N$H$J$C$F$$$^$9!%(B
FLTK$B$K$*$1$k%*%V%8%'%/%H;X8~$N%b%G%k$O!$$=$N$^$^(BRuby$B3HD%%i%$%V%i%j$NCf$K(B
$B$bH?1G$5$l$F$$$^$9!%(B

FLTK$B5Z$S(BRuby/FLTK$B$G$OB?>/0lHLE*$G$J$$L>A0$,;H$o$l$F$*$j!$Nc$($P!$%i%8%*%\(B
$B%?%s$O(BRoundButton$B$K(BRADIO_BUTTON$B$H$$$&%?%$%W$rM?$($k$3$H$G<B8=$G$-!$%A%'%C(B
$B%/%\%C%/%9$O(BCheckButton$B$H$$$&%/%i%9$K$h$C$F<B8=$5$l$F$$$^$9!%4pK\$H$J$k%3(B
$B%s%F%J%/%i%9$r(BGroup$B$H8F$S!$$=$7$F!$%j%9%H%&%#%8%C%H$O(BBrowser$B$H8F$P$l$F$$$^(B
$B$9!%$=$N$?$a!$$b$7FC<l$JMQES$N%&%#%8%C%H$,M_$7$$>l9g$O!$<+J,$GC5$7$F2<$5$$!%(B

FLTK$B$O!$(BWin32$B$H(BX$B$NN>J}$GF0:n2DG=$G$9!%(BMac$BHG$O&BHG$N$h$&$G$9!%$7$+$7$J$,$i!$(B
$B;dC#$O3+H/4D6-$H$7$F(BLinux$B$r;H$C$F$$$^$9!%(B

1. Ruby-FLTK $B$H(B C++ FLTK

$B2DG=$J8B$j(BFLTK$B$N(BAPI$B$OD>@\3HD%%i%$%V%i%j$KH?1G$5$l$F$$$^$9!%$=$N$?$a!$4{B8(B
$B$N(BFLTK$B$N%I%-%e%a%s%H$d%5%s%W%k$O;29M$H$7$F;H$&$3$H$,$G$-$^$9!%$=$3$G!$$3$3(B
$B$G$O!$(BRuby/FLTK$B$H(BC++ FLTK$B$N0c$$$r=R$Y$^$9!%(B

Ruby/FLTK$B$O(B"FLTK"$B$H$$$&L>A0$N%b%8%e!<%k$+$i9=@.$5$l$F$$$^$9!%$3$N%b%8%e!<%k(B
$B$NCf$K!$(BFLTK$B$K$*$1$k%/%i%9!$%a%=%C%I!$Dj?t$J$I$,4^$^$l$F$$$^$9!%$3$N$?$a!$(B
"Fl_", "Fl::", "fl_" $B$H$$$&%W%l%U%#%C%/%9$O(BRuby/FLTK$B$G$O;HMQ$7$F$$$^$;$s!%(B
$BNc$($P!$(BFl_Widget$B$O(BFLTK::Widget$B$H$$$&%/%i%9$K$h$C$F<B8=$5$l$F$$$F!$(B
FL_MAJOR_VERSION$B$H$$$&Dj?t$O(BFLTK::MAJOR_VERSION$B$H$J$C$F$$$^$9!%(B

$B%/%i%9L>$+$i$O%"%s%@!<%9%3%"$,$9$Y$F<h$j=|$+$l$F$$$^$9!%$=$N$?$a!$Nc$($P!$(B
Fl_Round_Button$B$H$$$&(BFLTK$B$N%/%i%9$O!$(BFLTK::RoundButton$B$H$J$C$F$$$^$9!%(B
FLTK::event_key$B$N$h$&$K!$4X?t$d%a%=%C%I$N%"%s%@!<%9%3%"$O$=$N$^$^;D$7$F$$(B
$B$^$9!%(B

FLTK::Group$B$N(Binitialize$B%a%=%C%I$G$O!$%V%m%C%/$rM?$($k$H<+F0E*$K(Bbegin()$B$H(B
end()$B$r8F$S$^$9!%0J2<$N(B2$B$D$N%3!<%I$OEy2A$J$b$N$G$9!%(B

  -- using begin() and end() --
  win = FLTK::Window.new(...)
  begin
    win.begin()
    # some codes
  ensure
    win.end()
  end

  -- using a block with initialize() --
  FLTK::Window.new(...){|win|
    # some codes
  }

$B$$$/$D$+$N(BFLTK$B$N%a%=%C%IL>$O!$(BRuby$B$N%-!<%o!<%I$H>WFM$9$k$?$a<!$NDL$j$KL>A0(B
$B$rJQ$($F$$$^$9!%(B

	Fl_Button::type		-> FLTK::Button#button_type
                                   FLTK::Button#buttontype
	Fl_Group::end		-> FLTK::Group#group_end
                                   FLTK::Group#groupend

$B$3$3$G!$%"%s%@!<%9%3%"$,F~$C$F$$$k$b$N$HF~$C$F$$$J$$$b$N$N$K$OA4$/0c$$$O(B
$B$"$j$^$;$s!%(B

Ruby$B$N%W%m%0%i%_%s%0%9%?%$%k$K=>$C$F!$CM$r<hF@$9$k%a%=%C%I$H!$@_Dj$9$k%a%=(B
$B%C%I$O$3$H$J$kL>A0$G%"%/%;%9$7$^$9!%Nc$($P!$(BFLTK::Widget#label$B$N>l9g!$(B
w.label("stuff")$B$"$k$$$O(Bw.label = "stuff"$B$G%i%Y%kL>$r@_Dj$7!$(Bw.label$B$G%i%Y%k(B
$B$r<hF@$7$^$9!%$^$?!$(BFLTK::Widget#visible$B$N$h$&$K%V!<%kCM$rJV$9$b$N$O!$(Bvisible?
$B$H$$$&JLL>$r@_$1$F$$$^$9!%(B

$B$^$?!$$"$k(BFLTK$B$N4X?t$O!$J8;zNs$H$=$ND9$5$rEO$9I,MW$,$"$j$^$9$,!$(BRuby$B$G$OJ8;z(B
$BNs$ND9$5$r$o$6$o$6EO$9I,MW$,$"$j$^$;$s!%(B


2. Ruby/FLTK$B$N3HD%(B

FLTK$B$O@~$dJ8;z!$?^7A$rIA$/$?$a$K%0%m!<%P%k4X?t$rDs6!$7$F$$$^$9!%$3$l$i$N4X(B
$B?t$O%&%#%8%C%H$KFCDj$5$l$F$$$k$b$N$G$O$"$j$^$;$s!%$=$N$?$a!$4p=`E@(B(0,0)$B$O(B
$B>o$K8=:_IA2h$7$F$$$k(BGroup$B%&%#%8%C%H$N:8>e$H$J$C$F$$$^$9!%$=$N$?$a!$$=$l$>(B
$B$l$N%&%#%8%C%HFb$G$O!$$=$N%&%#%8%C%H$N0LCV(B(x,y)$B$+$i$N%*%U%;%C%H$r$H$kI,MW(B
$B$,$"$j$^$9!%(B

Ruby-FLTK$B$G$O!$(BFLTK::Drawable$B$H$$$&%/%i%9$,$"$j!$(BGDK$B$K$*$1$k(B"Drawable"$B!$(B
Java$B$K$*$1$k(B"GraphicsContext"$B$"$k$$$O!$(BWin32$B$G$O(B"DC"$B$H$$$&$b$N$K;w$F$$$k(B
$B$b$N$G$9!%6&$K%*%U%;%C%H$r<+F0E*$K@_Dj$9$k$?$a!$$3$l$i$rMxMQ$9$k$3$H$G!$(B
$B3Z$KIA2h$r9T$J$&$3$H$,$G$-$^$9!%(B
(sample7.rb$B$,(BDrawable$B$rMQ$$$?%5%s%W%k$G$9!%(B)

[$BL$<BAu(B]
FLTK$B$K$*$1$k%$%Y%s%H=hM}$O(Bstatic$B$JJQ?t$G%-%e!<$r<B8=$9$k$3$H$K$h$C$F9T$J$C(B
$B$F$$$^$9!%$=$N$?$a!$%$%Y%s%H$r%-%e!<$+$i<hF@$9$k$H!$$=$l$>$l$N%$%Y%s%H$K4X(B
$B$9$k>\:Y$O<:$o$l$F$7$^$$$^$9!%(B
Ruby/FLTK$B$G$O!$(BFLTK::Event$B%/%i%9$K$h$C$F!$$9$Y$F$N%$%Y%s%H$K4X$9$k>\:Y$rJ](B
$B;}$7$h$&$H9M$($F$$$^$9!%(B

FLTK$B$G$O!$$4$/8B$i$l$?%l%$%"%&%H%^%M!<%8%c$N$_$r%5%]!<%H$7$F$$$^$9!%8=:_$O!$(B
$B%T%/%;%k$r85$K$7$F%l%$%"%&%H$r7h$a$k$h$&$K$J$C$F$$$^$9!%:#8e$N(BFLTK$B$G$O!$$h(B
$B$j6/NO$J%l%$%"%&%H%^%M!<%8%c$rK>$`$H$3$m$G$9!%(B
Ruby/FLTK$B$O>/$J$$$J$,$i$b!$$3$N$h$&$J8=:_$N>u67$r2r7h$9$k$?$a$N5!G=$r;}$C$F(B
$B$$$^$9!%$^$:!$$9$Y$F$N%&%#%8%C%H$OBg$-$/J,$1$F(B2$B$DJ}K!$K$h$C$F@8@.$9$k$3$H(B
$B$,$G$-$^$9!%(BFLTK$B$GMQ$$$i$l$F$$$k$h$&$J(B (x,y,w,h) $B$"$k$$$O(B (x,y,w,h,label)
$B$r;XDj$7$F@8@.$9$kJ}K!$H!$(B(w,h) $B$H(B (w,h,label) $B$@$1$r;XDj$7$F@8@.$9$kJ}K!(B
$B$G$9!%8e<T$N>l9g!$(Bx $B$H(B y $B$NCM$O(B 0 $B$H$7$F$$$^$9!%(BFLTK::Pack$B$NCf$K%&%#%8%C%H(B
$B$rCV$-$?$$$H$-$K$O!$$3$N(B x $B$H(B y $B$NCM$OL5;k$5$l$k$N$G!$8e<T$NJ}K!$,E,$7$F$$(B
$B$k$H9M$($^$9!%(B

3. FLTK Events, Action Callbacks, and Drawing

FLTK$B$O!$%7%9%F%`%$%Y%s%H$H!$%3!<%k%P%C%/$r6hJL$7$F$$$^$9!%%7%9%F%`%$%Y%s%H(B
$B$O!$%^%&%9$d%-!<%\!<%I$NF0:n$d!$%U%)!<%+%9!$3h@-2=$J$I$N%$%Y%s%H$r4^$_$^$9!%(B
$B%3!<%k%P%C%/$O!$%&%#%8%C%H$N>uBV$,JQ2=$9$k$H$-$K8F$S=P$5$l$^$9!%Nc$($P!$%\(B
$B%?%s$,2!$5$l$?$J$I$NA`:n$K$h$C$F5/$3$kJQ2=$G$9!%(B

3.1 $B%$%Y%s%H(B

$B%$%Y%s%H$r=hM}$9$k$?$a$K!$$=$l$>$l$N%&%#%8%C%H%/%i%9$G$O(Bhandle$B$H$$$&%a%=%C%I(B
$B$,Dj5A$5$l$F$$$J$1$l$P$J$j$^$;$s!%(Bhandle$B%a%=%C%I$O%$%Y%s%H%3!<%I$r<u$1<h$k$?(B
$B$a$K0z?t$r0l$D;}$A$^$9!%%$%Y%s%H%3!<%I$O!$Nc$($P!$(BFLTK::RELEASE$B$J$I$NDj?t$H(B
$B$7$FDj5A$5$l$F$$$^$9!%(B

$BB?$/$N%$%Y%s%H$O!$4XO"$9$k(BGroup$B$XAw$i$l$^$9!%Nc$($P!$%^%&%9$N0\F0$rCN$i$;$k(B
$B%$%Y%s%H(B(FLTK::MOVE)$B$O!$%^%&%9%]%$%s%?$N2<$K$"$k(BGroup$B$XDLCN$5$l$^$9!%(B
$B$"$k%$%Y%s%H$O!$D>@\%&%#%8%C%H$KDLCN$5$l$^$9!%Nc$($P!$%-!<%\!<%I%$%Y%s%H$O!$(B
$B%U%)!<%+%9$5$l$F$$$k%&%#%8%C%H$K$N$_Aw$i$l$^$9!%(B

$B%*!<%P!<%i%$%I$5$l$?(Bhandle$B%a%=%C%I$O!$$b$7%$%Y%s%H$r<uM}$7$?$J$i(Btrue$B$rJV$7!$(B
$B$b$7<uM}$7$J$$$N$G$"$l$P(Bfalse$B$rJV$5$J$1$l$P$J$j$^$;$s!%(B
false$B$rJV$7$?>l9g!$B>$N%&%#%8%C%H$J$I$KEO$5$l$^$9!%(B
$BNc$($P!$%F%-%9%H$rI=<($9$k$h$&$J%&%#%8%C%H$O%-!<%\!<%I%$%Y%s%H$rL5;k$7$^$9!%(B
$B$=$N$?$a!$$=$N%&%#%8%C%H$r4^$`%&%#%s%I%&$J$I$K%$%Y%s%H$OEO$5$l$^$9!%(B

3.2 $B%3!<%k%P%C%/(B

$B$=$l$>$l$N%&%#%8%C%H$K$O!$(Bcallback$B%a%=%C%I$r;H$C$F!$0l$D$@$1%3!<%k%P%C%/$r;}(B
$B$?$;$k$3$H$,$G$-$^$9!%(Bcallback$B%a%=%C%I$O<g$K<!$N(B2$B$D=q<0$G8F$S=P$9$3$H$,$G$-$^(B
$B$9!%(B

   (a) callback(proc, data = nil)
   (b) callback(data = nil){|widget,data| ... }

(a)$B$G$O%3!<%k%P%C%/$,8F$S=P$5$l$k$H(B proc.call(widget,data) $B$,<B9T$5$l$^$9!%(B
$B$3$3$G!$(Bwidget$B$O%3!<%k%P%C%/$r;}$C$F$$$k%&%#%8%C%H$N$3$H$G$9!%(B
(b)$B$O%V%m%C%/ItJ,$r(Bproc$B$H$9$k$H!$(Bcallback(proc, data) $B$HF1$8$G$9!%(B
$B%3!<%k%P%C%/$O!$(BFLTK::WHEN_NEVER$B$J$I$NDj?t$K$h$C$F%U%#%k%?$9$k$3$H$b$G$-$^$9!%(B
$B$^$?!$(BRuby/FLTK$B$NFCD'$H$7$F!$(BButton$B%/%i%9$O%*%V%8%'%/%H@8@.;~$K%V%m%C%/$r;}$?(B
$B$;$k$3$H$K$h$C$F%3!<%k%P%C%/$r;}$?$;$k$3$H$,$G$-$^$9!%(B

   b = FLTK::Button.new(100,30,"QUIT"){ ... }

$B$3$l$O!$<!$N$b$N$HEy2A$J%3!<%I$G$9!%(B

   b = FLTK::Button.new(100,30,"QUIT")
   b.callback{ ... }


3.3 $BIA2h(B

$B%\%?%s$d%i%Y%k$N$h$&$J4pK\E*$J%&%#%8%C%H$O<+J,<+?H$rIA2h$7$^$9!%$7$+$7!$(B
$BIA2hJ}K!$r8D?M$G;XDj$7$?$$>l9g$,$"$j$^$9!%C1=c$JNc$H$7$F!$%&%#%8%C%H$K(B
$B@~$d?^7A$r=q$$$FFH<+$N%&%#%8%C%H$r:n@.$9$k$J$I$,$"$j$^$9!%(B
$BB?$/$N(BGUI$B%D!<%k%-%C%H$HF1$8$/!$%&%#%8%C%H$,=E$J$C$?$j!$$"$k$$$O=E$J$C$F(B
$B$$$?ItJ,$,8=$l$?$j$9$k>l9g$O:FIA2h$r9T$J$$$^$9!%(BFLTK$B$G$O$3$N$h$&$JIA2h(B
$B$O(B draw $B%a%=%C%I$K$h$C$F9T$J$o$l$^$9!%(B

$BIaDL!$(BFLTK::Widget$B%/%i%9$N%5%V%/%i%9$r:n@.$7$F!$FH<+$N%&%#%8%C%H$r:n@.(B
$B$9$k$H;W$$$^$9!%$3$N$H$-IA2h%a%=%C%I(B draw $B$bF1;~$K:FDj5A$9$k$3$H$,$G$-(B
$B$^$9!%(Bdraw$B%a%=%C%I$NFbIt$G$O!$(BFLTK::line$B$d(BFLTK::pie$B$J$I$N$h$&$J!$(BFLTK$B%b(B
$B%8%e!<%k$N$9$Y$F$NIA2h4X?t$r<B9T$9$k$3$H$,$G$-$^$9!%(B

  class MyWidget < FLTK::Widget
    def draw()
      FLTK::color(FLTK::BLACK)
      FLTK::line(x + 10, y + 10, x + w - 10, y + h - 10)
    end
  end

$B$3$3$G!$(Bx,y,w,h$B$H$$$&$N$O(BFLTK::Widget$B$N%a%=%C%I$G!$(B(x,y)$B$O%&%#%8%C%H$N:8(B
$B>e$N0LCV$r<hF@$7!$(B(w,h)$B$GI}$H9b$5$r<hF@$9$k$3$H$,$G$-$^$9!%(B
FLTK$B%b%8%e!<%k$KDj5A$5$l$F$$$kIA2h4X?t$K$*$$$F0LCV$r;XDj$9$k$?$a$K$O!$(B
$B%&%#%s%I%&$N:8>e$r(B(0,0)$B$H$7$F9M$($J$1$l$P$J$j$^$;$s!%$D$^$j!$%&%#%s%I%&$N(B
$BCf$K$"$k%&%#%8%C%HFbIt$K?^7A$d@~$r=q$-$?$$>l9g$K$O!$%*%U%;%C%H$r7W;;$7$J(B
$B$1$l$P$J$j$^$;$s!%(B
$B$3$N7W;;$rKh2s9T$J$&$N$OB?>/LLE]$G$9$N$G!$$h$jNI$$J}K!$H$7$F$O(BFLTK::Drawable
$B%b%8%e!<%k$r:n@.$7$?%5%V%/%i%9$K(Binclude$B$7$F3F%&%#%8%C%H$KFC2=$7$?IA2h%a%=%C(B
$B%I$rDI2C$9$k$3$H$G$9!%(B

  class MyWidget < FLTK::Widget
    include FLTK::Drawable
    def draw()
      color(FLTK::BLACK)
      line(10,10,w-10,h-10)
    end
  end

$B$b$7!$?F%/%i%9$N(B draw $B%a%=%C%I$r8F$S$?$1$l$P!$(Bsuper() $B$r;H$&$@$1$G$9!%(B


4. $B%l%$%"%&%H4IM}(B

FLTK still has roots in the pixel-placement approach to laying out GUI 
screens. It expects that you know how large each widget should be, and 
you can position them accordingly. However, there are some layout 
capabilities you can use.

First, a Group object can automatically resize its children when it 
changes size. Each Group can contain a single "resizable" widget, and 
the placement of other widgets relative to that resizable widget will 
determine how those other widgets get resized. This is described somewhat 
in the C++ FLTK manual. [We should have a good sample for this!]

Second, Pack objects can be combined to create surprisingly complex 
layouts. A Pack object contains either a horizontal or vertical stack of 
widgets, similar to a Box object in Java or GTK+. A Pack object will 
automatically position its children to avoid overlapping, so when you 
create objects within a Pack, you can specify a position of (0,0) for 
all of them.

By nesting Pack objects, you can achieve most layouts that would be 
required of a typical forms application. You might have a horizontal 
Pack that contains just two other Packs. The left Pack could contain a 
vertical stack of field labels, while the right Pack could contain a 
vertical stack of actual data fields.

FLTK also has a very advanced interactive design tool named FLUID. 
There are versions available that output Perl and Python code, so it 
should be possible to have it generate Ruby code, if someone is 
interested enough to try.

5. Sample Programs

$B8=:_%5%s%W%k%W%m%0%i%`$O(Bsamples$B%G%#%l%/%H%j$K$"$j$^$9!%(B
