QT学习8:准备战斗
cannon.h:
#ifndef CANNONFIELD_H_
#define CANNONFIELD_H_
#include <QWidget.h>
class CannonField : public QWidget
{
Q_OBJECT
public:
CannonField(QWidget *parent=NULL, const char *name=NULL);
int angle() const {return ang;}
QSizePolicy sizePolicy() const;
public slots:
void setAngle(int degrees);
signals:
void angleChanged(int);
protected:
//-------------------------------------
// 虚函数,在update() repaint()时,界面从隐藏到显示,尺寸改变,内容改变等都会被自动
// 调用,它本身已自动开启双缓冲,所以不会引起闪烁
//-------------------------------------
void paintEvent(QPaintEvent *);
private:
int ang;
};
#endif
cannon.cpp:
#include "CannonField.h"
#include <QPainter.h>
CannonField::CannonField(QWidget *parent, const char *name)
:QWidget(parent, name)
{
ang = 45;
//所有Qt窗口部件都拥有一个调色板并使用它绘制自己.
setPalette(QPalette(QColor(250, 0, 0)));
}
void CannonField::setAngle(int degrees)
{
if (degrees<5)
{
degrees = 5;
}
if (degrees>70)
{
degrees = 70;
}
if (ang == degrees)
{
return;
}
ang = degrees;
//--------------------------------------
// 被调用后,立即执行重绘,因此repaint是最快的
// 但不能放在paintEvent中调用,不然会死循环.
// update()跟repaint()比较,update则更加有优越性。
// update()调用之后并不是立即重绘,而是将重绘事件放入主消息循环中,
// 由main的event loop来统一调度的(其实也是比较快的)。
// update在调用paintEvent之前,还做了很多优化,如果update被调用了很多次,
// 最后这些update会合并到一个大的重绘事件加入到消息队列,
// 最后只有这个大的update被执行一次。同时也避免了repaint()中所提到的死循环
// -- hgy notes.
//--------------------------------------
repaint();
emit angleChanged(ang);
}
void CannonField::paintEvent(QPaintEvent *)
{
// -------------------------------------
// QPaintEvent包含一个必须被刷新的窗口部件的区域
// QPainter默认只能在paintEvent里面调用
// -------------------------------------
QString s = "Angle = " + QString::number(ang);
QPainter p(this);
p.drawText(200, 200, s);
}
QSizePolicy CannonField::sizePolicy() const
{
return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
LCDRange.h :
#ifndef LCDRANGE_H_
#define LCDRANGE_H_
#include <QWidget.h>
class QSlider;
class LCDRange:public QWidget
{
Q_OBJECT
public:
LCDRange(QWidget* parent=NULL, const char *name=NULL);
int value() const;
public slots:
void setValue(int);
void setRange(int minVal, int maxVal);
signals://信号只声明,不能定义.
void valueChanged(int);
private:
QSlider *slider;
};
#endif//LCDRANGE_H_
LCDRange.cpp:
#include "LCDRange.h"
#include <QSlider.h>
#include <QLCDNumber.h>
#include <QVBoxLayout>
LCDRange::LCDRange(QWidget* parent, const char *name)
:QWidget(parent, name)
{
QLCDNumber *lcd = new QLCDNumber(2, this);
slider = new QSlider(Qt::Orientation::Horizontal, this);
slider->setRange(0, 99);
slider->setValue(0);
//别把display(int)写成Display(int)了,不然不会响应的,而且你就算写成display1,
//编译器也不会报错,只是不响应
//
connect(slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)));
//信号-->类的信号-->
connect(slider, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)));
QVBoxLayout *vlayout = new QVBoxLayout;
vlayout->addWidget(lcd);
vlayout->addWidget(slider);
setLayout(vlayout);
}
int LCDRange::value() const
{
return slider->value();
}
void LCDRange::setValue(int value)
{
//qWarning("setValue\n");
slider->setValue(value);
}
void LCDRange::setRange(int minVal, int maxVal)
{
if (minVal<0
|| maxVal>99
|| minVal>maxVal)
{
//和TRACE相似.
qWarning("LCDRange::setRange(%d, %d)\n\t"
"Range must be 0...99\n\t"
"and minVal must not be greater than maxVal",
minVal, maxVal);
return;
}
slider->setRange(minVal, maxVal);
}
main:
#include "qtlesson.h"
#include <QtGui/QApplication>
#include <QPushButton.h>
#include <QFont.h>
#include <QVBoxLayout>
#include <QGridLayout>
#include "LCDRange.h"
#include "CannonField.h"
class MyWidget : public QWidget
{
public:
MyWidget(QWidget *parent=NULL, const char *name=NULL);
};
MyWidget::MyWidget(QWidget* parent, const char *name)
{
QPushButton *quit = new QPushButton("Quit", this);
quit->setFont(QFont(("Times"), 18, QFont::Bold));
connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
LCDRange *angle = new LCDRange(this);
angle->setRange(5, 70);
CannonField *cannonField = new CannonField(this);
connect(angle, SIGNAL(valueChanged(int)), cannonField, SLOT(setAngle(int)));
//connect(cannonField, SIGNAL(angleChanged(int)), angle, SLOT(setValue(int)));
//2X2, 10 pixel border
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获得键盘焦点,这样默认情况下键盘输入会到达LCDRange窗口部件
angle->setFocus();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWidget w;
w.setGeometry(100, 100, 500, 355);
a.setMainWidget(&w);
w.show();
return a.exec();
}
1.paintEvent()是一个虚函数,子类可以对父类的paintEvent进行重写。当调用update(),repaint()的时候,paintEvent()会被调用,另外,当界面有任何改变的时候,paintEvent()也会被调用,这种界面的改变包括界面从隐藏到显示,界面尺寸改变,当然还包括界面内容改变的时候会被调用。paintEvent()是已经被高度优化过的函数,它本身已经自动开启并实现了双缓冲(X11系统需要手动去开启双缓冲),因此Qt中重绘不会引起任何闪烁
2.QPainter默认只能在paintEvent里面调用
浙公网安备 33010602011771号