Archive:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11 (zh CN): Difference between revisions
(Created page with '{{Template:I18n/Language Navigation Bar_(zh_CN)|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}} {{TutorialBrowser_(zh_CN)| series=[[Development/Tutorials/Qt4_Ruby_Tutoria...') |
m (AnneW moved page Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11 (zh CN) to Archive:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11 (zh CN) without leaving a redirect: Obsolete) |
||
(2 intermediate revisions by one other user not shown) | |||
Line 30: | Line 30: | ||
'''<tt>CannonField</tt>''' 现在有射击能力了。 | '''<tt>CannonField</tt>''' 现在有射击能力了。 | ||
< | <syntaxhighlight lang="ruby"> | ||
include Math | include Math | ||
</ | </syntaxhighlight> | ||
我们含入(include)'''<tt>Math</tt>''',因为我们需要 '''<tt>sin()</tt>''' 和 '''<tt>cos()</tt>''' 函数。 | 我们含入(include)'''<tt>Math</tt>''',因为我们需要 '''<tt>sin()</tt>''' 和 '''<tt>cos()</tt>''' 函数。 | ||
< | <syntaxhighlight lang="ruby"> | ||
@timerCount = 0 | @timerCount = 0 | ||
Line 45: | Line 45: | ||
@shootAngle = 0 | @shootAngle = 0 | ||
@shootForce = 0 | @shootForce = 0 | ||
</ | </syntaxhighlight> | ||
我们初始化新的私有变量,并且连接 [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] 讯号到 '''<tt>moveShot()</tt>''' 槽。我们将在每次定时器超时(times out)时移动炮弹。 | 我们初始化新的私有变量,并且连接 [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] 讯号到 '''<tt>moveShot()</tt>''' 槽。我们将在每次定时器超时(times out)时移动炮弹。 | ||
Line 51: | Line 51: | ||
'''<tt>timerCount</tt>''' 会不断追踪发射后经过的时间。'''<tt>shootAngle</tt>''' 是加农炮发射时的角度,而 '''<tt>shootForce</tt>''' 是加农炮发射时的力量。 | '''<tt>timerCount</tt>''' 会不断追踪发射后经过的时间。'''<tt>shootAngle</tt>''' 是加农炮发射时的角度,而 '''<tt>shootForce</tt>''' 是加农炮发射时的力量。 | ||
< | <syntaxhighlight lang="ruby"> | ||
def shoot() | def shoot() | ||
if @autoShootTimer.isActive() | if @autoShootTimer.isActive() | ||
Line 62: | Line 62: | ||
@autoShootTimer.start(5) | @autoShootTimer.start(5) | ||
end | end | ||
</ | </syntaxhighlight> | ||
除非有炮弹在空中,否则这个函式会发射炮弹。'''<tt>timerCount</tt>''' 重设为零。'''<tt>shootAngle</tt>''' 和 '''<tt>shootForce</tt>''' 变量会被设定为当前加农炮的角度和力量。最后,我们启动定时器。 | 除非有炮弹在空中,否则这个函式会发射炮弹。'''<tt>timerCount</tt>''' 重设为零。'''<tt>shootAngle</tt>''' 和 '''<tt>shootForce</tt>''' 变量会被设定为当前加农炮的角度和力量。最后,我们启动定时器。 | ||
< | <syntaxhighlight lang="ruby"> | ||
def moveShot() | def moveShot() | ||
region = Qt::Region.new(shotRect()) | region = Qt::Region.new(shotRect()) | ||
Line 80: | Line 80: | ||
update(region) | update(region) | ||
end | end | ||
</ | </syntaxhighlight> | ||
'''<tt>moveShot()</tt>''' 是一个移动炮弹的槽,当[http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer]启动后,每5毫秒被呼叫一次。 | '''<tt>moveShot()</tt>''' 是一个移动炮弹的槽,当[http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer]启动后,每5毫秒被呼叫一次。 | ||
Line 96: | Line 96: | ||
最后,我们重绘 [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]。这将发出只有一、两个矩形需要更新的单一的绘图事件。 | 最后,我们重绘 [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]。这将发出只有一、两个矩形需要更新的单一的绘图事件。 | ||
< | <syntaxhighlight lang="ruby"> | ||
def paintEvent(event) | def paintEvent(event) | ||
painter = Qt::Painter.new(self) | painter = Qt::Painter.new(self) | ||
Line 107: | Line 107: | ||
painter.end() | painter.end() | ||
end | end | ||
</ | </syntaxhighlight> | ||
绘图事件函式比起前面的章节已经简化。大部分的逻辑操作已经移动到新的 '''<tt>paintShot()</tt>''' 和 '''<tt>paintCannon()</tt>''' 函式。 | 绘图事件函式比起前面的章节已经简化。大部分的逻辑操作已经移动到新的 '''<tt>paintShot()</tt>''' 和 '''<tt>paintCannon()</tt>''' 函式。 | ||
< | <syntaxhighlight lang="ruby"> | ||
def paintShot(painter) | def paintShot(painter) | ||
painter.setPen(Qt::NoPen) | painter.setPen(Qt::NoPen) | ||
Line 117: | Line 117: | ||
painter.drawRect(shotRect()) | painter.drawRect(shotRect()) | ||
end | end | ||
</ | </syntaxhighlight> | ||
这个私有函式画出一个黑色填充矩形作为炮弹。 | 这个私有函式画出一个黑色填充矩形作为炮弹。 | ||
Line 123: | Line 123: | ||
我们省略了 '''<tt>paintCannon()</tt>''' 的实作,它和前面章节 [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] 的重新实作相同。 | 我们省略了 '''<tt>paintCannon()</tt>''' 的实作,它和前面章节 [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] 的重新实作相同。 | ||
< | <syntaxhighlight lang="ruby"> | ||
def shotRect() | def shotRect() | ||
gravity = 4.0 | gravity = 4.0 | ||
Line 142: | Line 142: | ||
return result | return result | ||
end | end | ||
</ | </syntaxhighlight> | ||
这个私有函式计算炮弹的中心点,并且返回封装炮弹的矩形。除了随时间推移而增加的 '''<tt>timerCount</tt>''' 外,它还使用加农炮起始的力量和角度。 | 这个私有函式计算炮弹的中心点,并且返回封装炮弹的矩形。除了随时间推移而增加的 '''<tt>timerCount</tt>''' 外,它还使用加农炮起始的力量和角度。 | ||
Line 154: | Line 154: | ||
唯一增加的是 '''Shoot''' 按钮。 | 唯一增加的是 '''Shoot''' 按钮。 | ||
< | <syntaxhighlight lang="ruby"> | ||
shoot = Qt::PushButton.new(tr('&Shoot')) | shoot = Qt::PushButton.new(tr('&Shoot')) | ||
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold)) | shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold)) | ||
</ | </syntaxhighlight> | ||
在建构子中,我们建立并设定了 '''Shoot''' 按钮,就像我们为 '''Quit''' 按钮作的。 | 在建构子中,我们建立并设定了 '''Shoot''' 按钮,就像我们为 '''Quit''' 按钮作的。 | ||
< | <syntaxhighlight lang="ruby"> | ||
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()')) | connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()')) | ||
</ | </syntaxhighlight> | ||
连接 '''Shoot''' 按钮的 '''<tt>clicked()</tt>''' 讯号,到'''<tt>CannonField</tt>''' 的 '''<tt>shoot()</tt>''' 槽。 | 连接 '''Shoot''' 按钮的 '''<tt>clicked()</tt>''' 讯号,到'''<tt>CannonField</tt>''' 的 '''<tt>shoot()</tt>''' 槽。 |
Latest revision as of 15:53, 23 June 2013
Template:I18n/Language Navigation Bar (zh CN)
Template:TutorialBrowser (zh CN)
Giving It a Shot
档案:
概览
在这个范例中,我们引入一个定时器来实现动画的射击。
一行一行的浏览
CannonField 现在有射击能力了。
include Math
我们含入(include)Math,因为我们需要 sin() 和 cos() 函数。
@timerCount = 0
@autoShootTimer = Qt::Timer.new(self)
connect(@autoShootTimer, SIGNAL('timeout()'),
self, SLOT('moveShot()'))
@shootAngle = 0
@shootForce = 0
我们初始化新的私有变量,并且连接 Qt::Timer::timeout() 讯号到 moveShot() 槽。我们将在每次定时器超时(times out)时移动炮弹。
timerCount 会不断追踪发射后经过的时间。shootAngle 是加农炮发射时的角度,而 shootForce 是加农炮发射时的力量。
def shoot()
if @autoShootTimer.isActive()
return
end;
@timerCount = 0
@shootAngle = @currentAngle
@shootForce = @currentForce
@autoShootTimer.start(5)
end
除非有炮弹在空中,否则这个函式会发射炮弹。timerCount 重设为零。shootAngle 和 shootForce 变量会被设定为当前加农炮的角度和力量。最后,我们启动定时器。
def moveShot()
region = Qt::Region.new(shotRect())
@timerCount += 1
shotR = shotRect()
if shotR.x() > width() || shotR.y() > height()
@autoShootTimer.stop()
else
region = region.unite(Qt::Region.new(shotR))
end
update(region)
end
moveShot() 是一个移动炮弹的槽,当Qt::Timer启动后,每5毫秒被呼叫一次。
它的工作是计算新的位置、更新屏幕上的炮弹到新的位置,并且在必要时停止定时器。
首先,我们建立一个 Qt::Region 来保留旧的 shotRect()。Qt::Region 有保留任何区域种类的能力,而我们将在这里用它来简化绘图。shotRect() 会返回炮弹现在位置的矩形。这在稍后会详细解释。
然后我们递增 timerCount,它影响炮弹沿弹道移动的每一步。
接下来,我们取得新的炮弹矩形。
如果炮弹已经越过 widget 右侧或底部边界,那么我们停止定时器,否则我们加入新的 shotRect() 到 Qt::Region。
最后,我们重绘 Qt::Region。这将发出只有一、两个矩形需要更新的单一的绘图事件。
def paintEvent(event)
painter = Qt::Painter.new(self)
paintCannon(painter)
if @autoShootTimer.isActive()
paintShot(painter)
end
painter.end()
end
绘图事件函式比起前面的章节已经简化。大部分的逻辑操作已经移动到新的 paintShot() 和 paintCannon() 函式。
def paintShot(painter)
painter.setPen(Qt::NoPen)
painter.setBrush(Qt::Brush.new(Qt::black))
painter.drawRect(shotRect())
end
这个私有函式画出一个黑色填充矩形作为炮弹。
我们省略了 paintCannon() 的实作,它和前面章节 Qt::Widget::paintEvent() 的重新实作相同。
def shotRect()
gravity = 4.0
time = @timerCount / 20.0
velocity = @shootForce
radians = @shootAngle * 3.14159265 / 180.0
velx = velocity * cos(radians)
vely = velocity * sin(radians)
x0 = (@barrelRect.right() + 5.0) * cos(radians)
y0 = (@barrelRect.right() + 5.0) * sin(radians)
x = x0 + velx * time
y = y0 + vely * time - 0.5 * gravity * time * time
result = Qt::Rect.new(0, 0, 6, 6)
result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))
return result
end
这个私有函式计算炮弹的中心点,并且返回封装炮弹的矩形。除了随时间推移而增加的 timerCount 外,它还使用加农炮起始的力量和角度。
这个公式使用的是重力场中无摩擦运动的标准牛顿公式。为简单起见,我们选择忽略任何爱因斯坦效应(Einstein effect)。
我们在y坐标向上增加的坐标系统中计算中心点。在我们计算出中心点后,我们建构一个大小为6×6的 Qt::Rect 并移动它的中心点到算出的中心点之上。藉由相同的操作,我们把这个点转换成 widget 的坐标系统(参阅坐标系统)。
唯一增加的是 Shoot 按钮。
shoot = Qt::PushButton.new(tr('&Shoot'))
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
在建构子中,我们建立并设定了 Shoot 按钮,就像我们为 Quit 按钮作的。
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))
连接 Shoot 按钮的 clicked() 讯号,到CannonField 的 shoot() 槽。
执行应用程序
加农炮可以射击,但没有东西会被射中。
练习
使炮弹变成一个填满的圆。[提示:Qt::Painter::drawEllipse() 可能会有帮助。]
当炮弹在空中时,改变加农炮的颜色。