Linux 版 (精华区)
发信人: pilot (〓〓★〓〓), 信区: Linux
标 题: Qt Tutorial 7
发信站: 紫 丁 香 (Thu May 11 16:01:08 2000), 转信
(Qt Tutorial 6 已经有少许改动,see 6284)
Subject Qt tutorial 7-------"One Thing Leads to Another"
Posted by kensou
Translated by Pilot-=?=-
第七章: One Thing Leads to Another
这个例程演示了如何使用signal/slot机制来创建自定义的组件,以及如何使用更复杂的手
段把它们连接在一起.现在源代码被分成了几个文件.
lcdrange.h LCDRange类定义
/****************************************************************
**
** Definition of LCDRange class, Qt tutorial 7
**
****************************************************************/
#ifndef LCDRANGE_H
#define LCDRANGE_H
#include <qwidget.h>
class QScrollBar;
class QLCDNumber;
class LCDRange : public QWidget
{
Q_OBJECT
public:
LCDRange( QWidget *parent=0, const char *name=0 );
int value() const;
public slots:
void setValue( int );
signals:
void valueChanged( int );
protected:
void resizeEvent( QResizeEvent * );
private:
QScrollBar *sBar;
QLCDNumber *lcd;
};
#endif // LCDRANGE_H
lcdrange.cpp LCDRange实现文件
/****************************************************************
**
** Implementation of LCDRange class, Qt tutorial 7
**
****************************************************************/
#include "lcdrange.h"
#include <qscrollbar.h>
#include <qlcdnumber.h>
LCDRange::LCDRange( QWidget *parent, const char *name )
: QWidget( parent, name )
{
lcd = new QLCDNumber( 2, this, "lcd" );
lcd->move( 0, 0 );
sBar = new QScrollBar( 0, 99, // range
1, 10, // line/page steps
0, // inital value
QScrollBar::Horizontal, // orientation
this, "scrollbar" );
connect( sBar, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)) );
connect( sBar, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)) );
}
int LCDRange::value() const
{
return sBar->value();
}
void LCDRange::setValue( int value )
{
sBar->setValue( value );
}
void LCDRange::resizeEvent( QResizeEvent * )
{
lcd->resize( width(), height() - 16 - 5 );
sBar->setGeometry( 0, lcd->height() + 5, width(), 16 );
}
main.cpp MyWidget类以及main函数.
/****************************************************************
**
** Qt tutorial 7
**
****************************************************************/
#include <qapplication.h>
#include <qpushbutton.h>
#include <qscrollbar.h>
#include <qlcdnumber.h>
#include <qfont.h>
#include "lcdrange.h"
class MyWidget : public QWidget
{
public:
MyWidget( QWidget *parent=0, const char *name=0 );
protected:
void resizeEvent( QResizeEvent * );
private:
QPushButton *quit;
LCDRange *value[16];
};
MyWidget::MyWidget( QWidget *parent, const char *name )
: QWidget( parent, name )
{
setMinimumSize( 200, 300 );
quit = new QPushButton( "Quit", this, "quit" );
quit->setGeometry( 10, 10, 75, 30 );
quit->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
for( int i = 0 ; i < 16 ; i++ ) {
value[i] = new LCDRange( this );
if ( i > 0 )
connect( value[i], SIGNAL(valueChanged(int)),
value[i - 1], SLOT(setValue(int)) );
}
}
void MyWidget::resizeEvent( QResizeEvent * )
{
int valueWidth = (width() - 20)/4;
int valueHeight = (height() - 65)/4;
for( int i = 0 ; i < 16 ; i++ )
value[i]->setGeometry( 10 + (i%4)*valueWidth, 55 + (i/4)*valueHeight,
valueWidth - 5, valueHeight - 5 );
}
int main( int argc, char **argv )
{
QApplication a( argc, argv );
MyWidget w;
w.setGeometry( 100, 100, 400, 400 );
a.setMainWidget( &w );
w.show();
return a.exec();
}
Makefile Make文件,包含了支持signal/slot的内容
#############################################################################
# $Id: Makefile,v 2.6 1998/02/27 14:03:19 hanord Exp $
#
# Win32 Makefile, requires Microsoft nmake.
#
# Copyright (C) 1998 by Troll Tech AS. All rights reserved.
#
#############################################################################
PROJECT = t7
!INCLUDE $(QTDIR)\Makefile.inc
逐行解释
lcdrange.h:
这个文件基本上是从第六章的mian.cpp发展来的,改动如下:
#ifndef LCDRANGE_H
#define LCDRANGE_H
这是一个正统的C条件编译语句,其目的是避免同一个头文件被包含多次.把#ifndef写进每
个头文件是个很好的习惯.
#include <qwidget.h>
class QScrollBar;
class QLCDNumber;
包含了qwidget.h,LCDRange继承自QWidget,父类的声明文件是必需的.实际上qwidget.h已
经被qpushbutton.h隐含的包含了.
因为类声明中只有QScrollBar,QLCDNumber的指针而不需要其定义,所以只需简单的声明它
们的类名,这样可以减轻编译器的工作.
class LCDRange : public QWidget
{
Q_OBJECT
public:
LCDRange( QWidget *parent=0, const char *name=0 );
注意Q_OBJECT,使用signal/slot的类必须包含Q_OBJECT宏.Q_OBJECT宏定义了在二进制文
件中实现了的(signal/slot)函数.
int value() const;
public slots:
void setValue( int );
signals:
void valueChanged( int );
这三个成员构成了程序中widget与其他组件之间的接口.在这之前LCDRange还没有定义接
口.value()是一个public函数用以读取LCDRange的值.setValue()是第一个我们自定义的
slot,而valueChanged()是第一个自定义的signal.
Slot必须以正常方式定义(一个slot也就是一个C++成员函数).Signal是在二进制目标文件
(meta object file)中实现的,遵循C++ Protected函数规则,也就是说,只能被定义它们的
类或者继承的子类调用.
lcdrange.cpp:
这个文件基本上是从第六章的mian.cpp发展来的,改动如下:
connect( sBar, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)) );
connect( sBar, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)) );
这些代码摘自LCDRange的构造函数.
第一个connect函数在上一章已经见过了,现在注意第二个:它把sBar的valueChanged()信
号与自身的valueChanged链接起来.三个参数的connect()可以把一个对象中的signal,
slot链接起来.
这里并没有敲错,signal确实可以与另一个signal链接起来,当第一个signal发出时,第
二个signal跟着发出.
现在让我们看看当用户使用滚动条是会发生什么:当滚动条移动时发出valueChanged()
信号,而valueChanged()信号同时链接到lcd的diaplay()事件(slot)和LCDRange的
valueChanged()信号.
于是,当sBar的valueChanged()信号发出时,LCDRange的valueChanged()信号同时发出,
于是,QLCDNumber::display()被调用并显示新的数字.
注意,你无法做到精确保证signal的发出顺序.
int LCDRange::value() const
{
return sBar->value();
}
这个函数简单的返回滚动条的当前值.
void LCDRange::setValue( int value )
{
sBar->setValue( value );
}
这个函数使用setValue()设置滚动条的当前值,因为滚动条的数值与LCD的显示数字链
接所以LCD的数字会自动刷新.如果设置滚动条数值的时候超出了其有效值范围会自动
进行调整.
main.cpp:
for( int i = 0 ; i < 16 ; i++ )
{
value[i] = new LCDRange( this );
if ( i > 0 )
connect( value[i], SIGNAL(valueChanged(int)),
value[i - 1], SLOT(setValue(int)) );
}
虽然LCDRange被分成了两个文件,但这里才是main.cpp中真正有变化的地方.上一章中我
们创建了16个LCDRange对象,现在,我们使用signal/slot机制把它们链接起来.把每一个
LCDRange的valueChanged()信号与前一个LCDRange的setValue()事件链接起来,于是每当
LCDRange发出valueChanged()信号时又触发了下一个valueChanged()信号(你会吃惊吗?
至少我不会),这样我们得到了一个"signal/slot链".
程序行为
刚启动时这个程序与上一章的程序表现没有两样,但如果你试着动一动右下角的滚动条
的话...
练习
使用右下角的的滚动条把所有的LCD设置成30.然后用第二排最右边的滚动条把上一半LCD
设置成29.再用第二排从右边数第二个滚动条把前七个LCD设置成30.
现在点击一下右下角滚动条的左箭头.看看会发生什么?为什么??
你现在可以进入第八章了.
--
〓〓★〓〓
比别人飞的更高,更快,更强!
※ 修改:.pilot 于 May 13 20:47:18 修改本文.[FROM: dns.mtlab.hit.ed]
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: dns.mtlab.hit.ed]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.726毫秒