• 12599阅读
  • 1回复

【文档翻译】Analog Clock 实例(4) [复制链接]

上一主题 下一主题
离线gongyh
 

只看楼主 倒序阅读 楼主  发表于: 2005-09-06
Analog Clock Example
类似时钟的例子展现了怎么画一个自定义的widget。
这个例子也示范了怎么样转变和放缩QPainter的一部分,使制作自定义widget更容易。
AnalogClock类的定义
AnaalogClock类提供一个时钟小部件,其中有时针,分针,它们能自动的更新在很短的时间
内。我们的QWideget子类用标准的paintEvent函数绘制出钟表的表面:
  class AnalogClock : public QWidget
  {
    Q_OBJECT

  public:
    AnalogClock(QWidget *parent = 0);

  protected:
    void paintEvent(QPaintEvent *event);
  };
AnalogClock 类的执行
  AnalogClock::AnalogClock(QWidget *parent)
    : QWidget(parent)
  {
    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(1000);

    setWindowTitle(tr("Analog Clock"));
    resize(200, 200);
  }
当widget被构造的时候,我们保持秒钟的轨迹,我让timer放出timeout()信号,连接widget的update(),这样
clock表面被更新当timer发射timeout()信号的时候.
最后,我们调整这个widge的大小,使它显示合适的大小.
void AnalogClock::paintEvent(QPaintEvent *)
  {
    static const int hourHand[6] = { 7, 8, -7, 8, 0, -40 };
    static const int minuteHand[6] = { 7, 8, -7, 8, 0, -70 };
    QColor hourColor(127, 0, 127);
    QColor minuteColor(0, 127, 127, 191);

    int side = qMin(width(), height());
    QTime time = QTime::currentTime();
当widget内容得到更新的时候,就是说,update()调用的时候,paintEvent()被调用。它发生在widge第一次显示的时候,隐蔽,暴露是,但是,当它执行widge的update()函数时也能被调用,我们连接timer的
timeout()信号到它的slot,它至少每5秒钟就被调用一次。
在我们建立画笔,绘制clock时,我们首先建立两个数组坐标点,两个QColors ,它们被用在做时针,和
分针。它的分针有一个alpha组成(191),意味作它75%透明。

我们可以决定widget大小小些,以至于时钟适合在部件widget中,在绘制之前决定当前时间是很有用的。
QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(width() / 2, height() / 2);
    painter.scale(side / 200.0, side / 200.0);
用Qpainter绘制自定义的widgets,Painters能被用于绘画任何的QPaintDevice 但是他们通常被用于
widgets上,因此我们通过painter的构造函数得到widget的实例。

我们调用painter.setRenderHint(QPainter::Antialiasing);这使得画出平滑的斜线。它被移到widget的
中心作为开始点,在widget中有运行刻度,我们使用比例因素,让我们使用x,y坐标在-100和100之间,
它保证了在winget里,大小比widget大小更小。

为了使我们的代码简单,我们将画一个固定位置的时钟表面鱼鳞刻度,使它在widget的中心。

这个画柄关系着所有的转化在paint事件中,并且保证每一样事物在正确的位置,使用画柄通常比手动绘制自定义的widget容易。
我们首先绘制时针,使用一个公式来反时针旋转坐标轴系统一定的度数。即,表现出指针顺时针旋转必要的度数。
    painter.setPen(Qt::NoPen);
    painter.setBrush(hourColor);
我们设置Pen为Qt::NoPen,因为我们不想要边框,我使用彩色实心画刷来显示时针。画刷被用来填充多边形和别的几何图形。
    painter.save();
    painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
    painter.drawConvexPolygon(QPolygon(3, hourHand));
    painter.restore();

我们在变换矩阵保存和恢复之间旋转时针,分针的位置应该没有考虑之前旋转。
    painter.setPen(hourColor);

    for (int i = 0; i < 12; ++i) {
        painter.drawLine(88, 0, 96, 0);
        painter.rotate(30.0);
    }
我们绘制一个标记在每个小时时钟的位置。我们绘制每个标记然后旋转坐标系统,准备绘制下一个
标记。
    painter.setPen(Qt::NoPen);
    painter.setBrush(minuteColor);

    painter.save();
    painter.rotate(6.0 * (time.minute() + time.second() / 60.0));
    painter.drawConvexPolygon(QPolygon(3, minuteHand));
    painter.restore();
分针的被旋转跟时针相同的方法。
    painter.setPen(minuteColor);

    for (int j = 0; j < 60; ++j) {
        if ((j % 5) != 0)
          painter.drawLine(92, 0, 96, 0);
        painter.rotate(6.0);
    }
  }
再一次我在时钟的周围绘制上标记,它是代表着分钟,我们隔5分钟 绘制一个标记在时针的上面。

The Analog Clock example shows how to draw the contents of a custom widget.


This example also demonstrates how the transformation and scaling features of QPainter can be used to make drawing custom widgets easier.

AnalogClock Class Definition
The AnalogClock class provides a clock widget with hour and minute hands that is automatically updated every few seconds. We subclass QWidget and reimplement the standard paintEvent() function to draw the clock face:

  class AnalogClock : public QWidget
  {
    Q_OBJECT

  public:
    AnalogClock(QWidget *parent = 0);

  protected:
    void paintEvent(QPaintEvent *event);
  };
AnalogClock Class Implementation
  AnalogClock::AnalogClock(QWidget *parent)
    : QWidget(parent)
  {
    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(1000);

    setWindowTitle(tr("Analog Clock"));
    resize(200, 200);
  }
When the widget is constructed, we set up a one-second timer to keep track of the current time, and we connect it to the standard update() slot so that the clock face is updated when the timer emits the timeout() signal.

Finally, we resize the widget so that it is displayed at a reasonable size.

  void AnalogClock::paintEvent(QPaintEvent *)
  {
    static const int hourHand[6] = { 7, 8, -7, 8, 0, -40 };
    static const int minuteHand[6] = { 7, 8, -7, 8, 0, -70 };
    QColor hourColor(127, 0, 127);
    QColor minuteColor(0, 127, 127, 191);

    int side = qMin(width(), height());
    QTime time = QTime::currentTime();
The paintEvent() function is called whenever the widget's contents need to be updated. This happens when the widget is first shown, and when it is covered then exposed, but it is also executed when the widget's update() slot is called. Since we connected the timer's timeout() signal to this slot, it will be called at least once every five seconds.

Before we set up the painter and draw the clock, we first define two lists of coordinates and two QColors that will be used for the hour and minute hands. The minute hand's color has an alpha component of 191, meaning that it's 75% opaque.

We also determine the length of the widget's shortest side so that we can fit the clock face inside the widget. It is also useful to determine the current time before we start drawing.

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(width() / 2, height() / 2);
    painter.scale(side / 200.0, side / 200.0);
The contents of custom widgets are drawn with a QPainter. Painters can be used to draw on any QPaintDevice, but they are usually used with widgets, so we pass the widget instance to the painter's constructor.

We call QPainter::setRenderHint() with QPainter::Antialiasing to turn on antialiasing. This makes drawing of diagonal lines much smoother.

The translation moves the origin to the center of the widget, and the scale operation ensures that the following drawing operations are scaled to fit within the widget. We use a scale factor that let's us use x and y coordinates between -100 and 100, and that ensures that these lie within the length of the widget's shortest side.

To make our code simpler, we will draw a fixed size clock face that will be positioned and scaled so that it lies in the center of the widget.

The painter takes care of all the transformations made during the paint event, and ensures that everything is drawn correctly. Letting the painter handle transformations is often easier than performing manual calculations just to draw the contents of a custom widget.


We draw the hour hand first, using a formula that rotates the coordinate system counterclockwise by a number of degrees determined by the current hour and minute. This means that the hand will be shown rotated clockwise by the required amount.

    painter.setPen(Qt::NoPen);
    painter.setBrush(hourColor);
We set the pen to be Qt::NoPen because we don't want any outline, and we use a solid brush with the color appropriate for displaying hours. Brushes are used when filling in polygons and other geometric shapes.

    painter.save();
    painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
    painter.drawConvexPolygon(QPolygon(3, hourHand));
    painter.restore();
We save and restore the transformation matrix before and after the rotation because we want to place the minute hand without having to take into account any previous rotations.

    painter.setPen(hourColor);

    for (int i = 0; i < 12; ++i) {
        painter.drawLine(88, 0, 96, 0);
        painter.rotate(30.0);
    }
We draw markers around the edge of the clock for each hour. We draw each marker then rotate the coordinate system so that the painter is ready for the next one.

    painter.setPen(Qt::NoPen);
    painter.setBrush(minuteColor);

    painter.save();
    painter.rotate(6.0 * (time.minute() + time.second() / 60.0));
    painter.drawConvexPolygon(QPolygon(3, minuteHand));
    painter.restore();
The minute hand is rotated in a similar way to the hour hand.

    painter.setPen(minuteColor);

    for (int j = 0; j < 60; ++j) {
        if ((j % 5) != 0)
          painter.drawLine(92, 0, 96, 0);
        painter.rotate(6.0);
    }
  }
Again, we draw markers around the edge of the clock, but this time to indicate minutes. We skip multiples of 5 to avoid drawing minute markers on top of hour markers.


[ 此贴被XChinux在2005-09-06 10:28重新编辑 ]
打工不是一辈子的事!
离线ok2005
只看该作者 1楼 发表于: 2005-11-14
有启发~~~~~~~~~~~~~~~~~~
快速回复
限100 字节
 
上一个 下一个