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毫秒