Call method from a TK object

Please can someone tell my why the code that follows works when the
"tick" and “zero” methods are nested inside “gui” , but when I move
the “tick” and “zero” methods out of gui - into a top level class
methods, the calls to tick from within the $stop object gets a “local
method not found” error? (You need TK libs to run)

This script generates a counter with start and stop buttons.

class StopWatch

@@seconds=0
@@hundredths=0
@@stopped=TRUE
 $heading = "Ticker"
···

#------------------------------------------------------------------------------
public

	def initialize(head)
		$heading = head
		gui $heading
		root = Tk.root
		root.bind "Control-c", proc{root.destroy}
		root.bind "Control-q", proc{root.destroy}
		Tk.root.focus
		Tk.mainloop
	end

#------------------------------------------------------------------------------
private

	def gui(head)
	
		require "tk"

		$title = TkLabel.new {
  			text head 
  			relief 'raised'
  			width 20
  			font 'courier'
  			pack('side'=>'top', 'fill'=>'both')
		}

		$label = TkLabel.new {
  			text '0.00' 
  			relief 'raised'
  			width 10
  			font 'verdana'
  			pack('side'=>'bottom', 'fill'=>'both')
		}

		$start = TkButton.new {
  			text 'Start'
  			command proc {
    			$stop.text "Stop"
    			if @@stopped
      				@@stopped = FALSE
      				tick
    			end
  			}

pack(‘side’=>‘left’,‘fill’=>‘both’,‘expand’=>‘yes’)
}

		$stop = TkButton.new {	
  			text 'Stop'
  			command proc{
    			text "Zero"
    			if @@stopped then
					zero
        			text 'Stop'
    			end
    			@@stopped = TRUE
  			}

pack(‘side’=>‘right’,‘fill’=>‘both’,‘expand’=>‘yes’)
}

# the following two methods do not work when NOT nested inside

the gui method as they are now
# starts the timer
def tick
if @@stopped then return end
Tk.after 50, proc{tick}
@@hundredths+=5
if @@hundredths >= 100
@@hundredths=0
@@seconds+=1
end
$label.text format("%d.%02d", @@seconds,
@@hundredths)
end

        # resets timer to zero
        def zero
	        @@seconds=0
	        @@hundredths=0
	        $label.text format("%d.%02d", @@seconds,

@@hundredths)
end

	end

end

#------------------------------------------------------------------------------

run app

StopWatch.new(“BIT Ruby Stop Watch!”)

      $start = TkButton.new {

TkButton::new use #instance_eval, this mean that in the the block self is
$start

          text 'Start'
          command proc {
            $stop.text "Stop"
            if @@stopped
                @@stopped = FALSE
                tick

ruby try to call self.tick i.e. TkButton#tick and not StopWatch#tick, this
is why it give an error

      $stop = TkButton.new {
          text 'Stop'
          command proc{
            text "Zero"
            if @@stopped then
            zero

same here, it try to call TkButton#zero and not StopWatch#zero

                text 'Stop'
            end
            @@stopped = TRUE
          }

Guy Decoux

Nope, calling StopWatch.tick or StopWatch.zero doesnt work, “no such
method” (sic) error

···

On Fri, 9 Jan 2004 20:30:29 +0900, ts decoux@moulon.inra.fr wrote:

  	$start = TkButton.new {

TkButton::new use #instance_eval, this mean that in the the block self is
$start

			text 'Start'
			command proc {
  			$stop.text "Stop"
  			if @@stopped
    				@@stopped = FALSE
    				tick

ruby try to call self.tick i.e. TkButton#tick and not StopWatch#tick, this
is why it give an error

  	$stop = TkButton.new {	
			text 'Stop'
			command proc{
  			text "Zero"
  			if @@stopped then
  				zero

same here, it try to call TkButton#zero and not StopWatch#zero

      			text 'Stop'
  			end
  			@@stopped = TRUE
			}

Guy Decoux

Nope, calling StopWatch.tick or StopWatch.zero doesnt work, "no such
method" (sic) error

You make the confusion between StopWatch::tich (class method) and
StopWatch#tick (instance method). Try this (see 'self_orig = self')

svg% cat b.rb
#!/usr/bin/ruby
class StopWatch

   @@seconds=0
   @@hundredths=0
   @@stopped=TRUE
   $heading = "Ticker"
   
   def initialize(head)
      $heading = head
      gui $heading
      root = Tk.root
      root.bind "Control-c", proc{root.destroy}
      root.bind "Control-q", proc{root.destroy}
      Tk.root.focus
      Tk.mainloop
   end

   private
   def gui(head)
      
      require "tk"
      self_orig = self

      $title = TkLabel.new {
         text head
         relief 'raised'
         width 20
         font 'courier'
         pack('side'=>'top', 'fill'=>'both')
      }
      
      $label = TkLabel.new {
         text '0.00'
         relief 'raised'
         width 10
         font 'verdana'
         pack('side'=>'bottom', 'fill'=>'both')
      }

      $start = TkButton.new {
         text 'Start'
         command proc {
            $stop.text "Stop"
            if @@stopped
               @@stopped = FALSE
               self_orig.tick
            end
         }
         pack('side'=>'left','fill'=>'both','expand'=>'yes')
      }

      $stop = TkButton.new {
         text 'Stop'
         command proc{
            text "Zero"
            if @@stopped then
               self_orig.zero
               text 'Stop'
            end
            @@stopped = TRUE
         }

         pack('side'=>'right','fill'=>'both','expand'=>'yes')
      }
   end

   protected
   def tick
      if @@stopped then return end
      Tk.after 50, proc{tick}
      @@hundredths+=5
      if @@hundredths >= 100
         @@hundredths=0
         @@seconds+=1
      end
      $label.text format("%d.%02d", @@seconds, @@hundredths)
   end
      
   def zero
      @@seconds=0
      @@hundredths=0
      $label.text format("%d.%02d", @@seconds, @@hundredths)
   end
   
end

StopWatch.new("BIT Ruby Stop Watch!")

svg%

p.s. : public is useless with initialize (initialize is always private)

Guy Decoux

Thx for the help. Appreciated.

···

On Fri, 9 Jan 2004 21:27:22 +0900, ts decoux@moulon.inra.fr wrote:

Nope, calling StopWatch.tick or StopWatch.zero doesnt work, “no such
method” (sic) error

You make the confusion between StopWatch::tich (class method) and
StopWatch#tick (instance method). Try this (see ‘self_orig = self’)

svg% cat b.rb
#!/usr/bin/ruby
class StopWatch

@@seconds=0
@@hundredths=0
@@stopped=TRUE
$heading = “Ticker”

def initialize(head)
$heading = head
gui $heading
root = Tk.root
root.bind “Control-c”, proc{root.destroy}
root.bind “Control-q”, proc{root.destroy}
Tk.root.focus
Tk.mainloop
end

private
def gui(head)

 require "tk"
 self_orig = self

 $title = TkLabel.new {
    text head 
    relief 'raised'
    width 20
    font 'courier'
    pack('side'=>'top', 'fill'=>'both')
 }
 
 $label = TkLabel.new {
    text '0.00' 
    relief 'raised'
    width 10
    font 'verdana'
    pack('side'=>'bottom', 'fill'=>'both')
 }

 $start = TkButton.new {
    text 'Start'
    command proc {
       $stop.text "Stop"
       if @@stopped
          @@stopped = FALSE
          self_orig.tick
       end
    }
    pack('side'=>'left','fill'=>'both','expand'=>'yes')
 }

 $stop = TkButton.new {
    text 'Stop'
    command proc{
       text "Zero"
       if @@stopped then
          self_orig.zero
          text 'Stop'
       end
       @@stopped = TRUE
    }

    pack('side'=>'right','fill'=>'both','expand'=>'yes')
 }

end

protected
def tick
if @@stopped then return end
Tk.after 50, proc{tick}
@@hundredths+=5
if @@hundredths >= 100
@@hundredths=0
@@seconds+=1
end
$label.text format(“%d.%02d”, @@seconds, @@hundredths)
end

def zero
@@seconds=0
@@hundredths=0
$label.text format(“%d.%02d”, @@seconds, @@hundredths)
end

end

StopWatch.new(“BIT Ruby Stop Watch!”)

svg%

p.s. : public is useless with initialize (initialize is always private)

Guy Decoux