Forum: Ruby Placing Sets of Ruby/Tk Widgets

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
David B. (Guest)
on 2006-04-02 20:25
After a whole day of frustrating "experimentation" with no good results,
I was ready to give up and ask this question:

How do I place two vertical sets of widgets (inside of a left and right
frame), two horizontal set of widgets (inside of a top and bottom frame)
and one set of rectanges in a square grid (inside of a middle center
canvas in a middle center frame) to control the location of my "sets"?

But then I got angry (both with myself and Ruby/Tk) and became
determined to figure it out without asking.

It took me hours and hours, but I fainally "nailed" it!  The source of
my frustration was not realizing that the (:x,:y) coordinates were
relative to the parent widgets' origin (in my example these are TkRoot
and TkFrames).

If you want to take a look (where I've use :background, :borderwidth and
:relief options to make the frames and canvas stand out), here is the
Ruby code:

require "tk"
root=TkRoot.new(:title=>'Ruby/Tk Geometry, Frame, Canvas, ' + \
  'and Widget Meanderings', :geometry=>'705x700')

packer1 = { :fill=>:none }

#  Note:  These (x,y) coordinates are relative to the parent widget's
#  (TkRoot's or TkFrame's) origin
placer1 = { :x=>0, :y=>0 };	placer2 = { :x=>0, :y=>600 }
placer3 = { :x=>0, :y=>40 };	placer4 = { :x=>100, :y=>100 };
placer5 = { :x=>600, :y=>100 };	placer6 = { :x=>0, :y=>100 }

topFrame = TkFrame.new(root, :width=>705, :height=>100, \
  :borderwidth=>5, :relief=>:groove, :background=>:pink).place(placer1)
topFrameButton1 = TkButton.new(topFrame, :text=>'TFButton 1').\
  place(placer1)

middleLeftFrame = TkFrame.new(root, :width=>100, :height=>500, \
  :borderwidth=>5, :relief=>:groove, :background=>:cyan).place(placer6)
middleLeftFrameButton1 = TkButton.new(middleLeftFrame, :text=>\
  'MLFButton 1').place(placer1)
middleLeftFrameButton2 = TkButton.new(middleLeftFrame, :text=>\
  'MLFButton 2').place(placer3)

middleCenterFrame = TkFrame.new(root, :width=>500, :height=>500, \
  :borderwidth=>5, :relief=>:groove, :background=>:blue).place(placer4)
middleCenterCanvas = TkCanvas.new(middleCenterFrame, :width=>477, \
  :height=>477, :borderwidth=>5, :relief=>:groove,
:background=>:yellow).\
  pack(packer1)
middleCenterCanvasButton1 = TkButton.new(middleCenterCanvas, :text=>\
  'MCCButton 1').place(placer1)

middleRightFrame = TkFrame.new(root, :width=>105, :height=>500, \
  :borderwidth=>5, :relief=>:groove, :background=>:green).place(placer5)
middleRightFrameButton1 = TkButton.new(middleRightFrame, :text=>\
  'MRFButton 1').place(placer1)

bottomFrame = TkFrame.new(root, :width=>705, :height=>100, \
  :borderwidth=>5, :relief=>:groove,
:background=>:orange).place(placer2)
bottomFrameButton1 = TkButton.new(bottomFrame, :text=>'BFButton 1').\
  place(placer1)

ev_quit = TkVirtualEvent.new('Control-c', 'Control-q', 'q')
Tk.root.bind(ev_quit, proc{Tk.exit}).focus
Tk.mainloop
Hidetoshi NAGAI (Guest)
on 2006-04-03 09:12
(Received via mailing list)
From: David B. <removed_email_address@domain.invalid>
Subject: Placing Sets of Ruby/Tk Widgets
Date: Mon, 3 Apr 2006 01:25:46 +0900
Message-ID: <removed_email_address@domain.invalid>
> But then I got angry (both with myself and Ruby/Tk) and became
> determined to figure it out without asking.
>
> It took me hours and hours, but I fainally "nailed" it!  The source of
> my frustration was not realizing that the (:x,:y) coordinates were
> relative to the parent widgets' origin (in my example these are TkRoot
> and TkFrames).

Please cool down. :-)
Probably, Pack geometry manager is enough for your case.

In many cases, Pack geometry manager is good choice.
In many cases of others (e.g. layout a widget with both of a horizontal
and a vertical scrollbar), Grid geometry manager is suitable.
And in extremely rase case, Place geometry manager (or layout on the
canvas widget) is necessary.

I think that it is not difficult to study Pack geometry manager.
Its strategy of layout is simple but working very well.
The following is rewrite-version of your example with Pack.
Please see that there is no coordinate except putting a widget on
a canvas widget and there are minimum controls to fix the widget size.
-----------------------------------------------------------------------
require 'tk'

root=TkRoot.new(:title=>'Ruby/Tk Geometry, Frame, Canvas, ' +
                'and Widget Meanderings', :geometry=>'705x700')

#-----------------------------------
topFrame = TkFrame.new(root, :height=>100, :borderwidth=>5,
:relief=>:groove,
                       :background=>:pink).pack(:fill=>:x,
:expand=>false)
topFrame.pack_propagate(false) # if you must keep the height of the
frame.

topFrameButton1 = TkButton.new(topFrame, :text=>'TFButton 1')
topFrameButton1.pack(:side=>:left, :anchor=>:nw)

#-----------------------------------
middleFrame = TkFrame.new(root).pack(:fill=>:both, :expand=>true)

#-----------------------------------
middleLeftFrame = TkFrame.new(middleFrame, :width=>100, :borderwidth=>5,
                              :relief=>:groove, :background=>:cyan)
middleLeftFrame.pack(:side=>:left, :fill=>:y, :expand=>false)

middleLeftFrameButton1 = TkButton.new(middleLeftFrame, :text=>'MLFButton
1')
middleLeftFrameButton1.pack(:fill=>:x, :expand=>false)

middleLeftFrameButton2 = TkButton.new(middleLeftFrame, :text=>'MLFButton
2')
middleLeftFrameButton2.pack(:fill=>:x, :expand=>false)

#-----------------------------------
middleCenterFrame = TkFrame.new(middleFrame, :borderwidth=>5,
                                :relief=>:groove, :background=>:blue)
middleCenterFrame.pack(:side=>:left, :fill=>:both, :expand=>true)

middleCenterCanvas = TkCanvas.new(middleCenterFrame, :borderwidth=>5,
                                  :relief=>:groove,
:background=>:yellow)
middleCenterCanvas.pack(:fill=>:both, :expand=>true, :padx=>5, :pady=>5)

middleCenterCanvasButton1 = TkButton.new(middleCenterCanvas,
                                         :text=>'MCCButton 1')

# ??? Do you want to put the button "ON" the canvas?
# middleCenterCanvasButton1.place(:x=>0,:y=>0)
canvasButton1Win = TkcWindow.new(middleCenterCanvas, [0, 0],
:anchor=>:nw,
                                 :window=>middleCenterCanvasButton1)

#-----------------------------------
middleRightFrame = TkFrame.new(middleFrame, :width=>105,
:borderwidth=>5,
                               :relief=>:groove, :background=>:green)
middleRightFrame.pack(:side=>:left, :fill=>:y, :expand=>false)

middleRightFrameButton1 = TkButton.new(middleRightFrame,
:text=>'MRFButton 1')
middleRightFrameButton1.pack(:fill=>:x, :expand=>false)

#-----------------------------------
bottomFrame = TkFrame.new(root, :height=>100,
                          :borderwidth=>5, :relief=>:groove,
                          :background=>:orange).pack(:fill=>:x,
:expand=>false)
bottomFrame.pack_propagate(false) # if you must keep the height of the
frame.

bottomFrameButton1 = TkButton.new(bottomFrame, :text=>'BFButton 1',
:command=>proc{p root.geometry}
)
bottomFrameButton1.pack(:side=>:left, :anchor=>:nw)

#-----------------------------------
ev_quit = TkVirtualEvent.new('Control-c', 'Control-q', 'q')
Tk.root.bind(ev_quit, proc{Tk.exit}).focus
Tk.mainloop
David B. (Guest)
on 2006-04-03 17:10
Hidetoshi NAGAI wrote:
>
> Please cool down. :-)
> Probably, Pack geometry manager is enough for your case.
>
> -----------------------------------------------------------------------
> bottomFrameButton1 = TkButton.new(bottomFrame, :text=>'BFButton 1',
> :command=>proc{p root.geometry}
> )


Wow!  Once again, brute force must bow to finesse!

I did not notice the pack_propagate() method, before.  That was key.

Also, what does the bottomFrameButton1's "{:command=>{p root.geometry}"
do?  And why did you NOT use it in the topFrameButton1?

Thanks.

P.S.  Yes, I will cool down.  (:>)
David B. (Guest)
on 2006-04-03 17:30
David B. wrote:
> Also, what does the bottomFrameButton1's "{:command=>{p root.geometry}"
> do?  And why did you NOT use it in the topFrameButton1?
>

Oh, you're just printing out the geometry when the button is clicked.
Bingo!
This topic is locked and can not be replied to.