Archive:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 07 (zh CN)

From KDE TechBase
Revision as of 20:50, 29 June 2011 by Neverendingo (talk | contribs) (Text replace - "</code>" to "</syntaxhighlight>")

Template:I18n/Language Navigation Bar (zh CN)

Template:TutorialBrowser (zh CN)

One Thing Leads to Another

档案:

概览

这个范例展示如何建立具有讯号和槽的自定义 widget,以及如何用更复杂的方式将它们连接起来。这是第一次,原始码被分割在几个档案中。

一行一行的浏览

lcdrange.rb

这个档案主要是抄袭自第6章,这里只提出比较特别的改变。

signals 'valueChanged(int)'
slots 'setValue(int)'
def value()
  @slider.value()
end

def setValue(value)
  @slider.setValue(value)
end

这些构成了这个 widget 和程序中其他组件之间的接口。到目前为止,LCDRange 还没真的拥有一个 API。

value() 是一个存取 LCDRange 值的公开(public)函式、setValue() 是我们第一个自定义槽,而 valueChanged()是我们第一个自定义讯号。

Slot 必须用正规方式实作(槽也是一个 Ruby 成员函式)。讯号会被自动实作。讯号遵循 Ruby 保护(protected)函式的存取规则(换言之,只有定义他们的类别或继承的类别可以发出它们)。

LCDRange 的值发生改变时,valueChanged() 讯号就会被使用。

value() 的实作非常简单。它只是返回 slider 的值。

setValue() 的实作也同样简单。请注意,因为 slider 和 LCD number 连接,设定 slider 的值时,LCD number 也会自动更新。此外,如果超出规定范围,slider 会自动调整值。

connect(@slider, SIGNAL('valueChanged(int)'),
        lcd, SLOT('display(int)'))
connect(@slider, SIGNAL('valueChanged(int)'),
        self, SIGNAL('valueChanged(int)'))

第一个 QObject::connect() 呼叫与前几章看到的相同。第二个是新的,它连接 QAbstractSlider::valueChanged() 讯号到这个对象的 valueChanged() 讯号。是的,没错。讯号也可以连接到其他的讯号。当第一个讯号被发出时,第二个讯号也被发出。

让我们看看当使用者操作 slider 时,会发生什么事。当 slider 发现它的值已经改变,就会发出QAbstractSlider::valueChanged() 讯号。这个讯号连接到 Qt::LCDNumberQLCDNumber::display() 槽和 LCDRangevalueChanged() 讯号。

因此,当这个讯号发出时,LCDRange 也发出自己的 valueChanged() 讯号。此外,QLCDNumber::display() 被呼叫并显示新的数字。

请注意,你不能确定任何执行的特定顺序,LCDRange::valueChanged() 可能会在QLCDNumber::display() 被呼叫之前或之后发出。

t7.rb

previousRange = nil

for row in 0..2
  for column in 0..2
    lcdRange = LCDRange.new()
    grid.addWidget(lcdRange, row, column)
    unless previousRange.nil?
      connect(lcdRange, SIGNAL('valueChanged(int)'),
              previousRange, SLOT('setValue(int)'))
    end
    previousRange = lcdRange
  end
end

当我们建立9个 LCDRange 对象时,我们使用讯号与槽机制将它们连接在一起。每一个 LCDRangevalueChanged() 讯号都会连接到前一个的 setValue() 槽。因为每当 LCDRange 的值改变时,都会发出 valueChanged() 讯号,所以我们在这里建立一个讯号与槽的连锁反应。

执行应用程序

在启动时,这支程序的外观和前一章的一模一样。尝试操作右下角的 slider。

练习

使用右下角的 slider 来设定所有 LCD 为50。然后单击底部中间 slider 把手的左侧,设定除了最后一个所有的 LCD 为40。现在,使用左下角的 slider 来设定前七个 LCD 回到50。

按下右下角 slider 把手的左侧。会发生什么事?为什么这是正确的行为?