Qt教程一 —— 第九章:你可以使用加农炮了




在这个例子中我们开始画一个蓝色可爱的小加农炮.只cannon.cpp和上一章不同。

一行一行地解说



t9/cannon.cpp




void CannonField::paintEvent( QPaintEvent * ) { QPainter p( this );


我们现在开始认真地使用QPainter。我们创建一个绘画工具来操作这个窗口部件。


p.setBrush( blue );


当一个QPainter填满一个矩形、圆或者其它无论什么,它会用它的画刷填满这个图形。这里我们把画刷设置为蓝色。(我们也可以使用一个调色板。)


p.setPen( NoPen );


并且QPainter使用画笔来画边界。这里我们设置为NoPen,就是说我们在边界上什么都不画,蓝色画刷会在我们画的东西的边界内画满全部。


p.translate( 0, rect().bottom() );


QPainter::translate()函数转化QPainter的坐标系统,比如,它通过偏移谅来移动。这里我们设置窗口部件的左下角为(0,0)。x和y的方向没有改变,比如,窗口部件中的所有y坐标现在都是负数(请看坐标系统获得有关Qt的坐标系统更多的信息。)


p.drawPie( QRect(-35, -35, 70, 70), 0, 90*16 );


drawPie()函数使用一个开始角度和弧长在一个指定的矩形内画一个饼型图。角度的度量用的是一度的十六分之一。零度在三点的位置。画的方向是顺时针的。这里我们在窗口部件的左下角画一个四分之一圆。这个饼图被蓝色充满,并且没有边框。


p.rotate( -ang );


QPainter::rotate()函数绕QPainter坐标系统的初始位置旋转它。旋转的参数是一个按度数给定的浮点数(不是一个像上面那样给的十六分之一的度数)并且是顺时针的。这里我们顺时针旋转ang度数。


p.drawRect( QRect(33, -4, 15, 8) );


QPainter::drawRect()函数画一个指定的矩形。这里我们画的是加农炮的炮筒。

很难想象当坐标系统被转换之后(转化、旋转、缩放或者修剪)的绘画结果。

在这种情况下,坐标系统先被转化后被旋转。如果矩形QRect(33, -4, 15, 8)被画到这个转化后的坐标系统中,它看起来会是这样:




注意矩形被CannonField窗口部件的边界省略了一部分。当我们选装坐标系统,以60度为例,矩形会以(0,0)为圆心被旋转,也就是左下角,因为我们已经转化了坐标系统。结果会是这样:




我们做完了,除了我们还没有解释为什么Windows在这个时候没有发抖。


int main( int argc, char **argv ) { QApplication::setColorSpec( QApplication::CustomColor ); QApplication a( argc, argv );


我们告诉Qt我们在这个程序中想使用一个不同的颜色分配策略。这里没有单一正确的颜色分配策略。因为这个程序使用了不常用的黄色,但不是很多颜色,CustomColor最好。这里有几个其它的分配策略,你可以在QApplication::setColorSpec()文档中读到它们。

通常情况下你可以忽略这一点,因为默认的是好的。偶尔一些使用常用颜色的应用程序看起来比较糟糕,因而改变分配策略通常会有所帮助。

行为



当滑块被操作的时候,所画的加农炮的角度会因此而变化。

Quit中的字母Q现在有下划线,并且Alt+Q会实现你所要的。如果你不知道这些,你一定是没有做第八章中的练习。

你也要注意加农炮的闪烁让人很烦,特别是在一个比较慢的机器上。我们将会在下一章修正这一点。

(请看编译来学习如何创建一个makefile和连编应用程序。)

练习



设置一个不同的画笔代替NoPen。设置一个调色板的画刷。

试着用“Q&uit”或者“Qu&it”作为按钮的文本来提到“&Quit”。发生了什么?

现在你可以进行第十章了。

/****************************************************************
**
** Definition of LCDRange class, Qt tutorial 8
**
****************************************************************/

#ifndef LCDRANGE_H
#define LCDRANGE_H

#include <q3vbox.h>

class QSlider;


class LCDRange : public Q3VBox
{
    Q_OBJECT
public:
    LCDRange( QWidget *parent=0, const char *name=0 );

    int value() const;

public slots:
    void setValue( int );
    void setRange( int minVal, int maxVal );

signals:
    void valueChanged( int );

private:
    QSlider  *slider;
};


#endif // LCDRANGE_H



/****************************************************************
**
** Implementation of LCDRange class, Qt tutorial 8
**
****************************************************************/

#include "lcdrange.h"

#include <qslider.h>
#include <qlcdnumber.h>

LCDRange::LCDRange( QWidget *parent, const char *name )
        : Q3VBox( parent, name )
{
    QLCDNumber *lcd  = new QLCDNumber( 2, this, "lcd"  );
    slider = new QSlider( Qt::Orientation::Horizontal, this, "slider" );
    slider->setRange( 0, 99 );
    slider->setValue( 0 );
    connect( slider, SIGNAL(valueChanged(int)),
             lcd, SLOT(display(int)) );
    connect( slider, SIGNAL(valueChanged(int)),
             SIGNAL(valueChanged(int)) );

    setFocusProxy( slider );
}

int LCDRange::value() const
{
    return slider->value();
}

void LCDRange::setValue( int value )
{
    slider->setValue( value );
}

void LCDRange::setRange( int minVal, int maxVal )
{
    if ( minVal < 0 || maxVal > 99 || minVal > maxVal ) {
      qWarning( "LCDRange::setRange(%d,%d)\n"
               "\tRange must be 0..99\n"
               "\tand minVal must not be greater than maxVal",
               minVal, maxVal );
      return;
    }
    slider->setRange( minVal, maxVal );
}



/****************************************************************
**
** Definition of CannonField class, Qt tutorial 8
**
****************************************************************/

#ifndef CANNON_H
#define CANNON_H

#include <qwidget.h>


class CannonField : public QWidget
{
    Q_OBJECT
public:
    CannonField( QWidget *parent=0, const char *name=0 );

    int angle() const { return ang; }
    QSizePolicy sizePolicy() const;

public slots:
    void setAngle( int degrees );

signals:
    void angleChanged( int );

protected:
    void paintEvent( QPaintEvent * );
	void paintEvent0( QPaintEvent * );

private:
    int ang;
};


#endif // CANNON_H



/****************************************************************
**
** Implementation CannonField class, Qt tutorial 9
**
****************************************************************/

#include "cannon.h"
#include <qpainter.h>


CannonField::CannonField( QWidget *parent, const char *name )
        : QWidget( parent, name )
{
    ang = 45;
    setPalette( QPalette( QColor( 250, 250, 0) ) );
}


void CannonField::setAngle( int degrees )
{
    if ( degrees < 5 )
        degrees = 5;
    if ( degrees > 70 )
        degrees = 70;
    if ( ang == degrees )
        return;
    ang = degrees;
    repaint();
    emit angleChanged( ang );
}

/*
    QString s = "Angle = " + QString::number( ang );
    QPainter p( this );
    p.drawText( 100, 100, s );
*/
void CannonField::paintEvent( QPaintEvent * paintEvt)
{
	QString s = "Angle = " + QString::number( ang );
    QPainter p( this );
    p.drawText( 100, 100, s );

	paintEvent0(paintEvt );
}

void CannonField::paintEvent0( QPaintEvent * )
{
    QPainter p( this );
/*
    void setBrush(const QBrush &brush);
    void setBrush(Qt::BrushStyle style);
*/
	//p.setBackgroundColor(QColor().blue());
    //p.setBrush( blue );
	   //painter.setPen( QPen( Qt::black, 5, Qt::SolidLine) ); 
   //painter.setBrush( QBrush( Qt::red, Qt::Dense1Pattern) ); 
	p.setBrush( QBrush( Qt::blue, Qt::SolidPattern) ); 
/*
    void setPen(const QColor &color);
    void setPen(const QPen &pen);
    void setPen(Qt::PenStyle style);
*/

    p.setPen(Qt::PenStyle::NoPen );

    p.translate( 0, rect().bottom() );
    p.drawPie( QRect(-35, -35, 70, 70), 0, 90*16 );
    p.rotate( -ang );
    p.drawRect( QRect(33, -4, 15, 8) );
}


QSizePolicy CannonField::sizePolicy() const
{
    return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
}



/*
#include <QtCore/QCoreApplication>

int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);

	return a.exec();
}
*/
/****************************************************************
**
** Qt tutorial 9
**
****************************************************************/

#include <qapplication.h>
#include <qpushbutton.h>
#include <qlcdnumber.h>
#include <qfont.h>
#include <qlayout.h>

#include "lcdrange.h"
#include "cannon.h"


class MyWidget: public QWidget
{
public:
    MyWidget( QWidget *parent=0, const char *name=0 );
};


MyWidget::MyWidget( QWidget *parent, const char *name )
        : QWidget( parent, name )
{
    QPushButton *quit = new QPushButton( "&Quit", this, "quit" );
    quit->setFont( QFont( "Times", 18, QFont::Bold ) );

    connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );

    LCDRange *angle = new LCDRange( this, "angle" );
    angle->setRange( 5, 70 );

    CannonField *cannonField = new CannonField( this, "cannonField" );

    QObject::connect( angle, SIGNAL(valueChanged(int)),
             cannonField, SLOT(setAngle(int)) );
    QObject::connect( cannonField, SIGNAL(angleChanged(int)),
             angle, SLOT(setValue(int)) );

    QGridLayout *grid = new QGridLayout( this, 2, 2, 10 );
    grid->addWidget( quit, 0, 0 );
    grid->addWidget( angle, 1, 0, Qt::AlignTop );
    grid->addWidget( cannonField, 1, 1 );
    grid->setColStretch( 1, 10 );

    angle->setValue( 60 );
    angle->setFocus();
}

int main( int argc, char **argv )
{
    QApplication::setColorSpec( QApplication::CustomColor );
    QApplication a( argc, argv );

    MyWidget w;
    w.setGeometry( 100, 100, 500, 355 );
    a.setMainWidget( &w );
    w.show();
    return a.exec();
}