How to create simple calculator in Ruby Shoes

17 Apr 2014

Posted by Milos Dolobac

In this tutorial you will learn how to create simple calculator in Ruby GUI toolkit Shoes that looks like this:

how to make calculator in ruby</img>

Because original Shoes is outdated and new Shoes 4 isn’t released yet, we’ll use Green Shoes in this tutorial.

How to install Shoes

Before you can install green_shoes you have to install ruby. I’ve included instructions about how to install ruby in previous post.

If you have ruby installed by rvm, just install green_shoes with rubygems:

$ gem install green_shoes

If you have trouble with installation, you have to install ruby gtk2.

Running shoes

To run we need to add green_shoes gem to our ruby file.

Go to your favorite text editor, create new file calculator.rb and type this code:

calculator.rb

require 'green_shoes'

Shoes.app(title: "My calculator", width: 200, height: 240) do
end

Go to the terminal and run green shoes:

ruby calculator.rb

You should see something like this:

how to run shoes</img>

Adding basic template for app

Let’s add template for our calculator. We need to add place for number field, clear button and remaining buttons.

require 'green_shoes'

Shoes.app(title: "My calculator", width: 200, height: 240) do
  flow width: 200, height: 240 do
    flow width: 0.7, height: 0.2 do
      background rgb(0, 157, 228)
    end

    flow width: 0.3, height: 0.2 do
    end

    flow width: 1.0, height: 0.8 do
      background rgb(139, 206, 236)
    end
  end
end

If you run shoes again, you should see something like this:

calculator template</img>

Let’s look at what we’ve done. First we’ve created flow, that copy size of screen.

flow width: 200, height: 240 do

Our app is divided into three parts: number field, clear button and remaining buttons, so we’ve created three different flows to match it.

flow width: 0.7, height: 0.2 do
  background rgb(0, 157, 228)
end

Here we used floating points to match size of flow. If you type 0.7 it means 70% width of screen and if you type 0.2 it means 20% size. Then we’ve used background method to change color of the flow.

Ok we’ve done with preparations, let’s create some buttons.

Adding calculator buttons

First we need to add number field:

require 'green_shoes'

Shoes.app(title: "My calculator", width: 200, height: 240) do
  number_field = nil
  @number = 0
  flow width: 200, height: 240 do
    flow width: 0.7, height: 0.2 do
      background rgb(0, 157, 228)
      number_field = para @number, margin: 10
    end
    
    flow width: 0.3, height: 0.2 do
    end    

    flow width: 1.0, height: 0.8 do
      background rgb(139, 206, 236)
    end
  end
end

So if you run code you should number 0 in number field:

how to create number field for calculator</img>

Let’s take a look at code:

number_field = nil
  @number = 0

Here we’ve set two variables. Variable number_field is for displaying number field. In variable @number we set actual value of number in the number field.

number_field = para @number, margin: 10

Here we’ve changed number field to para. Para is method in shoes for displaying text or numbers in screen. We’ve used @number to set para to 0, but it can be anything you like. After that we’ve set margin to all sizes.

Adding Clr Button

Now we have to add clr button. To add button type something like this:

require 'green_shoes'

Shoes.app(title: "My calculator", width: 200, height: 240) do
  number_field = nil
  @number = 0
  flow width: 200, height: 240 do
    flow width: 0.7, height: 0.2 do
      background rgb(0, 157, 228)
      number_field = para @number, margin: 10
    end
    
    flow width: 0.3, height: 0.2 do
      button 'Clr', width: 1.0, height: 1.0 do
      end
    end    

    flow width: 1.0, height: 0.8 do
      background rgb(139, 206, 236)
    end
  end
end

how to add clear button</img>

button 'Clr', width: 1.0, height: 1.0 do
end

So here we’ve added button with name Clr and set it’s width and height to size of flow.

Adding remaining buttons

We need to add all buttons what we need. Add this code into your app.

require 'green_shoes'

Shoes.app(title: "My calculator", width: 200, height: 240) do
  number_field = nil
  @number = 0
  flow width: 200, height: 240 do
    flow width: 0.7, height: 0.2 do
      background rgb(0, 157, 228)
      number_field = para @number, margin: 10
    end
    
    flow width: 0.3, height: 0.2 do
      button 'Clr', width: 1.0, height: 1.0 do
      end
    end    

    flow width: 1.0, height: 0.8 do
      background rgb(139, 206, 236)
      %w(7 8 9 + 4 5 6 - 1 2 3 / 0 . = *).each do |btn|
        button btn, width: 50, height: 50 do
        end
      end      
    end
  end
end

how to add buttons in shoes</img>

%w(7 8 9 + 4 5 6 - 1 2 3 / 0 . = *).each do |btn|
  button btn, width: 50, height: 50 do
  end

We’ve added all buttons to array with %w method and added every button to each loop, then we’ve set height and width of the buttons.

Running Buttons

So our buttons are now displayed, but if you click at them they don’t work. Let’s fix it. Go to flow with clr button and add code some code:

require 'green_shoes'

Shoes.app(title: "My calculator", width: 200, height: 240) do
  number_field = nil
  @number = 0
  flow width: 200, height: 240 do
    flow width: 0.7, height: 0.2 do
      background rgb(0, 157, 228)
      number_field = para @number, margin: 10
    end
    
    flow width: 0.3, height: 0.2 do
      button 'Clr', width: 1.0, height: 1.0 do
        @number = 0
        number_field.replace(@number)
      end
    end    

    flow width: 1.0, height: 0.8 do
      background rgb(139, 206, 236)
      %w(7 8 9 + 4 5 6 - 1 2 3 / 0 . = *).each do |btn|
        button btn, width: 50, height: 50 do
        end
      end      
    end
  end
end
@number = 0
number_field.replace(@number)

Here we’ve added block of code to button, that every time button Clr is pressed variable @number is set to 0. Then we use special ruby method replace to change actual value of number_field to 0. Maybe it doesn’t seems to work, but try change value of variable @number to any other number and then press clr. It should change to zero.

Ok we’ve added functionality to Clr button let’s move on numbers:

require 'green_shoes'

Shoes.app(title: "My calculator", width: 200, height: 240) do
  number_field = nil
  @number = 0
  flow width: 200, height: 240 do
    flow width: 0.7, height: 0.2 do
      background rgb(0, 157, 228)
      number_field = para @number, margin: 10
    end
    
    flow width: 0.3, height: 0.2 do
      button 'Clr', width: 1.0, height: 1.0 do
        @number = 0
        number_field.replace(@number)
      end
    end    

    flow width: 1.0, height: 0.8 do
      background rgb(139, 206, 236)
      %w(7 8 9 + 4 5 6 - 1 2 3 / 0 . = *).each do |btn|
        button btn, width: 50, height: 50 do
          case btn
            when /[0-9]/ 
              @number = @number.to_i * 10 + btn.to_i
          end
          number_field.replace(@number)    
        end
      end      
    end
  end
end

If you try your calculator in shoes, you should be able to use numbers.

case btn
  when /[0-9]/ 
    @number = @number.to_i * 10 + btn.to_i
end
number_field.replace(@number)

Here we used case statement with when to catch clicks on numbers. We’ve replaced value of variable @number with value of our buttons.

Adding operations

We have working number buttons, but what to do with operators.

require 'green_shoes'

Shoes.app(title: "My calculator", width: 200, height: 240) do
  number_field = nil
  @number = 0
  @op = nil
  @previous = 0
  
  flow width: 200, height: 240 do
    flow width: 0.7, height: 0.2 do
      background rgb(0, 157, 228)
      number_field = para @number, margin: 10
    end
    
    flow width: 0.3, height: 0.2 do
      button 'Clr', width: 1.0, height: 1.0 do
        @number = 0
        number_field.replace(@number)
      end
    end    

    flow width: 1.0, height: 0.8 do
      background rgb(139, 206, 236)
      %w(7 8 9 + 4 5 6 - 1 2 3 / 0 . = *).each do |btn|
        button btn, width: 50, height: 50 do
          case btn
            when /[0-9]/ 
              @number = @number.to_i * 10 + btn.to_i
            
            when '='
              @number = @previous.send(@op, @number)
            else
              @previous, @number = @number, nil
              @op = btn
          end
          number_field.replace(@number)    
        end
      end      
    end
  end
end
@op = nil
@previous = 0

First we need to add two variables, @previous and @op right after variable @number. We’ll use @op for actual operations and previous to catch previous number.

when '='
  @number = @previous.send(@op, @number)
else
  @previous, @number = @number, nil
  @op = btn

We’ve set value of @op to our operator buttons and save value of actual number to variable @previous. Then we’ve used ruby send method, that when equals button is pressed, it calculate expressions for us.

We’re done with our calculator. See you next time.

comments powered by Disqus