Linux 版 (精华区)
发信人: tcpip (高级草包), 信区: Linux
标 题: Qt tutorial 10------Smooth as Silk
发信站: 哈工大紫丁香 (2000年06月11日12:51:16 星期天), 转信
第十章: Smooth as Silk
在这个例子中,我们引入绘画位图来去掉闪烁.同时,我们增加了力量控制.
lcdrange.h 包含了LCDRange类的定义.
lcdrange.cpp 包含了LCDRange类的实现.
cannon.h 包含了CannonField类的定义.
cannon.cpp包含CannonField类的实现.
main.cpp 包含MyWidget 和 main.
Makefile contains some rules for generating the meta object information
necessary for signal/slot creation.
代码逐行解释
cannon.h
CannonField现在在角度基础上增加了力量值.
int angle() const { return ang; }
int force() const { return f; }
public slots:
void setAngle( int degrees );
void setForce( int newton );
signals:
void angleChanged( int );
void forceChanged( int );
在象角度一样的提供力量的接口.
private:
void paintCannon( QPainter * );
QRect cannonRect() const;
我们把实现描绘的代码单独地放在一个函数里面.并且把cannon的大小
也包装在一个单独的函数里.
int ang;
int f;
};
力量值存储在整型变量 f里.
cannon.cpp
#include
我们包括了QPixmap(位图类)的定义.
CannonField::CannonField( QWidget *parent, const char *name )
: QWidget( parent, name )
{
ang = 45;
f = 0;
}
力量(f)初始化为零.
void CannonField::setAngle( int degrees )
{
if ( degrees < 5 )
degrees = 5;
if ( degrees > 70 )
degrees = 70;
if ( ang == degrees )
return;
ang = degrees;
repaint( cannonRect(), FALSE );
emit angleChanged( ang );
}
我们对setAngle()函数做了轻微的改动.它仅仅重画控件包含cannon
的那部分区域.变元FALSE表明指定的矩形区域在paint事件被发送
到控件之前不会被擦除.
void CannonField::setForce( int newton )
{
if ( newton < 0 )
newton = 0;
if ( f == newton )
return;
f = newton;
emit forceChanged( f );
}
setForce()函数的实现和setAngle()相似.不同的是我们不需要显示力量值
,因此不需要重绘控件.
void CannonField::paintEvent( QPaintEvent *e )
{
QRect updateR = e->rect();
QPainter p;
p.begin( this );
if ( updateR.intersects( cannonRect() ) )
paintCannon( &p );
p.end();
}
我们现在对paint事件进行了优化:仅仅重绘控件需要更新的部分.
首先,我们从QPaintEvent取得需要更新的矩形参数.然后开始绘制控件.
我们检查更新的矩形是否和cannon矩形相交.如果相交,我们就绘制
cannon.注意:我们为paintCannon()函数传递了一个指向painter的指针.
const QRect barrel_rect(33, -4, 15, 8);
我们把炮管的矩形定义为常量.
void CannonField::paintCannon( QPainter *p )
{
QRect cr = cannonRect();
首先,我们取得cannon的包围的矩形并且存储在 cr.里面.
QPixmap pix( cr.size() );
这里,我们遇到了一个新的类:QPixmap. QPixmap 是与屏幕无关的 paint device which
is handy for flicker-free
painting.利用它,可以很容易得到 这里,我们创建了一个
位图,其大小和cannon的尺寸是一样的.我们需要在此位图里绘制大炮,
然后使用一项操作把此位图移动到屏幕上.这个技术称为双缓冲.实际上
是颤动调动(removes flickering
不知合适否?).
QPainter tmp;
我们创建一临时性的painter tmp来绘制位图.
pix.fill( this, cr.topLeft() );
完成了在上面的创建,位图是被任意的象素填补的.这样,我们要先使用
控件的背景来填补.在指定了位图的放置位置后,就可以用各种背景来妥
善处理(实例background pixmaps).
tmp.begin( &pix );
tmp.setBrush( blue );
tmp.setPen( NoPen );
这里,我们开始在位图上绘画.象前章一样,我们设置了蓝色的的刷子和隐形的
画笔.这一次,我们使用了便洁的方法.setPen() and setBrush()
是QPainter的重载函数.
tmp.translate( 0, pix.height() - 1 );
tmp.drawPie( QRect( -35,-35, 70, 70 ), 0, 90*16 );
tmp.rotate( -ang );
tmp.drawRect( barrel_rect );
tmp.end();
这些代码和前面的例子类似.唯一的不同是转化:现在是相对于位图的高度,并且我们
把炮筒的矩形移到了一个常量里面.
p->drawPixmap( cr.topLeft(), pix );
最后,我们调用drawPixmap()快速的把位图 显示在屏幕上.
QRect CannonField::cannonRect() const
{
QRect r( 0, 0, 50, 50 );
r.moveBottomLeft( rect().bottomLeft() );
return r;
}
这个函数以控件的坐标系为准返回cannon包含的矩形.首先,我们创建
了一个50X50大小的矩形,然后,我们设置它的左下角等于控件的左下角.
rect()函数以控件的坐标系为基准返回控件
包含的矩形区域的大小(比如:左上角是(0,0)).
main.cpp
class MyWidget : public QWidget
{
public:
MyWidget( QWidget *parent=0, const char *name=0 );
protected:
void resizeEvent( QResizeEvent * );
private:
QPushButton *quit;
LCDRange *angle;
LCDRange *force;
CannonField *cannonField;
};
我们增加了第二个LCDRange用来设置力量大小.
force = new LCDRange( this, "force" );
force->setRange( 10, 50 );
force->setGeometry( 10, angle->y() + angle->height() + 10, 75, 130 );
我们把 force LCDRange控件放在angle控件的下面,并指定其范围 为 10...50.
connect( force,SIGNAL(valueChanged(int)), cannonField,SLOT(setForce(int)));
connect( cannonField,SIGNAL(forceChanged(int)), force,SLOT(setValue(int)));
我们把force控件连接到 cannonField控件上,就象连接 angle控件一样.
force->setValue( 25 );
初始化力量值为 25.
程序行为
现在,我们可以使用力量控制,并且画面不再闪烁.
练习
使炮筒的尺寸大小依赖于力量的大小.
把大炮放在右下角.
你现在可以进入 第十一章了.
[上一章] [下一章] [教程目录]
Copyright ?1999 Troll Tech
Trademarks
Qt version 1.44
-- "这一千多年没写诗了?"
"写了, 不过只写了两句." "千年得两句, 一定是万古丽句了. 念来听听."
"好吧, 我现丑了" 太白星清了清嗓子, 浑厚的男中音在天庭响起:大海啊, 都是水;
骏马啊, 四条腿;
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: tcpip.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.583毫秒