Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10

Jump to: navigation, search


Contents

Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10


Smooth as Silk
Tutorial Series   Qt4 Ruby Tutorial
Previous   Tutorial 9 - With Cannon You Can
What's Next   Tutorial 11 - Giving It a Shot
Further Reading   n/a

Smooth as Silk

Qt4 Ruby Tutorial Screenshot 10.png

Files:

Overview

In this example, we add a force control.

Line by Line Walkthrough

cannon.rb

The CannonField now has a force value in addition to the angle.

signals 'angleChanged(int)', 'forceChanged(int)'
slots 'setAngle(int)', 'setForce(int)'
</code>
 
The interface to the force follows the same practice as for the angle.
 
<syntaxhighlight lang="ruby">
def initialize(parent = nil)
  super()
 
  @currentAngle = 45
  @currentForce = 0
 
  setPalette(Qt::Palette.new(Qt::Color.new(250, 250, 200)))
  setAutoFillBackground(true)
end
</code>
 
The force '''<tt>@currentForce</tt>''' is initialized to zero.
 
<syntaxhighlight lang="ruby">
def setAngle(angle)
  if angle < 5
    angle = 5
  elsif angle > 70
    angle = 70
  end
 
  if @currentAngle == angle
    return
  end
 
  @currentAngle = angle
  update(cannonRect())
  emit angleChanged(@currentAngle)
end
</code>
 
We have made a slight change in the '''<tt>setAngle()</tt>''' function. It repaints only the portion of the widget that contains the cannon.
 
<syntaxhighlight lang="ruby">
def setForce(force)
  if force < 0
    force = 0
  end
  if @currentForce == force
    return
  end
 
  @currentForce = force
  emit forceChanged(@currentForce)
end
</code>
 
The implementation of '''<tt>setForce()</tt>''' is quite similar to that of '''<tt>setAngle()</tt>'''. The only difference is that because we don't show the force value, we don't need to repaint the widget.
 
<syntaxhighlight lang="ruby">
def paintEvent(event)
  painter = Qt::Painter.new(self)
 
  painter.setPen(Qt::NoPen)
  painter.setBrush(Qt::Brush.new(Qt::blue))
 
  painter.translate(0, height())
  painter.drawPie(Qt::Rect.new(-35, -35, 70, 70), 0, 90 * 16)
  painter.rotate(-@currentAngle)
  painter.drawRect(Qt::Rect.new(30, -5, 20, 10))
  painter.end()
end
</code>
 
We paint as in Chapter 9.
 
<syntaxhighlight lang="ruby">
def cannonRect()
  result = Qt::Rect.new(0, 0, 50, 50)
  result.moveBottomLeft(rect().bottomLeft())
  return result
end
</code>
 
The '''<tt>cannonRect()</tt>''' function returns the rectangle enclosing the cannon in widget coordinates. First we create a rectangle with the size 50 x 50 and then move it so its bottom-left corner is equal to the widget's own bottom-left corner.
 
The [http://doc.qt.nokia.com/latest/qwidget.html#rect-prop Qt::Widget::rect()] function returns the widget's enclosing rectangle in the widget's own coordinates. The top-left corner of the rectangle is always (0, 0).
 
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]'''
 
The constructor is mostly the same, but some new bits have been added.
 
<syntaxhighlight lang="ruby">
force = LCDRange.new()
force.setRange(10, 50)
</code>
 
We add a second '''<tt>LCDRange</tt>''', which will be used to set the force.
 
<syntaxhighlight lang="ruby">
connect(force, SIGNAL('valueChanged(int)'),
         cannonField, SLOT('setForce(int)'))
connect(cannonField, SIGNAL('forceChanged(int)'),
         force, SLOT('setValue(int)'))
</code>
 
We connect the '''<tt>force</tt>''' widget and the '''<tt>cannonField</tt>''' widget, just like we did for the '''<tt>angle</tt>''' widget.
 
<syntaxhighlight lang="ruby">
leftLayout = Qt::VBoxLayout.new()
leftLayout.addWidget(angle)
leftLayout.addWidget(force)
 
gridLayout = Qt::GridLayout.new()
gridLayout.addWidget(quit, 0, 0)
gridLayout.addLayout(leftLayout, 1, 0)
gridLayout.addWidget(cannonField, 1, 1, 2, 1)
gridLayout.setColumnStretch(1, 10)
</code>
 
In Chapter 9, we put '''<tt>angle</tt>''' in the lower-left cell of the layout. Now we want to have two widgets in that cell, so we make a vertical box, put the vertical box in the grid cell, and put each of '''<tt>angle</tt>''' and '''<tt>range</tt>''' in the vertical box.
 
<syntaxhighlight lang="ruby">
force.setValue(25)
</code>
 
We initialize the force value to 25.
 
=== Running the Application ===
We now have a force control.
 
=== Exercises ===
Make the size of the cannon barrel be dependent on the force.
 
Put the cannon in the bottom-right corner.
 
Try adding a better keyboard interface. For example, make + and - increase and decrease the force and enter shoot. If you're bothered by the way the '''<tt>Left</tt>''' and '''<tt>Right</tt>''' keys work, change that too. [Hint: Reimplement [http://doc.qt.nokia.com/latest/qwidget.html#keyPressEvent Qt::Widget::keyPressEvent()].]
 
[[Category:Ruby]]

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal