QT与很多GUI库不同(如MFC),它不能随时随地地在界面上画图,只能在界面类的painterEvent中画图,如此一来,想在绘制QT界面时使用状态模式(GOF的23种设计模式之一)就有点困难了,作为解决方案,我先把要界面上的图片绘制在一张图片上(QPixmap),然后再在painterEvent中将Pixmap“画”到界面上。以下是这种方法的一个小例子。
截图:
源代码:
#include <QtGui>
//状态类的基类,定义了各个公用接口,
//其中,SetPixmap是一个纯虚接口
class BasePen
{
protected:
//这三个类成员理应是BasePen的私有成员,然后通过接口访问
//我这里为了方便,直接把它们设为保护成员了
QPixmap m_Pixmap;
QPoint m_StartPoint;
QPoint m_EndPoint;
virtual void SetPixmap() = 0;
public:
BasePen()
{
m_StartPoint = m_EndPoint = QPoint(0, 0);
m_Pixmap = QPixmap(500, 500);
}
void SetStartPoint(QPoint point) { m_StartPoint = point; }
void SetEndPoint(QPoint point)
{
m_EndPoint = point;
SetPixmap();
}
QPixmap GetPixmap() { return m_Pixmap; }
};
//矩形类,在界面上画一个红色的矩形
class RectPen : public BasePen
{
protected:
void SetPixmap()
{
m_Pixmap.fill(Qt::white);
QPainter painter(&m_Pixmap);
QRect rect(m_StartPoint, m_EndPoint);
painter.setPen(Qt::red);
painter.drawRect(rect);
}
};
//直线类,在界面上画一条蓝色的直线
class LinePen : public BasePen
{
protected:
void SetPixmap()
{
m_Pixmap.fill(Qt::white);
QPainter painter(&m_Pixmap);
painter.setPen(Qt::blue);
painter.drawLine(m_StartPoint, m_EndPoint);
}
};
//圆形类,在界面上画一个绿色的椭圆
class CirclePen : public BasePen
{
protected:
void SetPixmap()
{
m_Pixmap.fill(Qt::white);
QPainter painter(&m_Pixmap);
QRect rect(m_StartPoint, m_EndPoint);
painter.setPen(Qt::green);
painter.drawEllipse(rect);
}
};
class Widget : public QWidget
{
Q_OBJECT
private:
bool m_MouseDown;
BasePen *m_BasePen;
RectPen *m_RectPen;
LinePen *m_LinePen;
CirclePen *m_CirclePen;
//在界面上放三个按钮,用来控制画图状态
QRadioButton *m_LineButton;
QRadioButton *m_RectButton;
QRadioButton *m_CircleButton;
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
public:
Widget(QWidget *parent = 0);
~Widget();
private slots:
void ClickedLineButton() { m_BasePen = m_LinePen; }
void ClickedRectButton() { m_BasePen = m_RectPen; }
void ClickedCircleButton() { m_BasePen = m_CirclePen; }
};
Widget::Widget(QWidget *parent /* = 0 */)
: QWidget(parent)
{
m_MouseDown = false;
m_RectPen = new RectPen;
m_LinePen = new LinePen;
m_CirclePen = new CirclePen;
m_LineButton = new QRadioButton("Line", this);
m_RectButton = new QRadioButton("Rect", this);
m_CircleButton = new QRadioButton("Circle", this);
m_LineButton->move(10, 10);
m_RectButton->move(100, 10);
m_CircleButton->move(200, 10);
connect(m_LineButton, SIGNAL(clicked()), this, SLOT(ClickedLineButton()));
connect(m_RectButton, SIGNAL(clicked()), this, SLOT(ClickedRectButton()));
connect(m_CircleButton, SIGNAL(clicked()), this, SLOT(ClickedCircleButton()));
m_BasePen = m_LinePen;
m_LineButton->setChecked(true);
setFixedSize(500, 500);
}
Widget::~Widget()
{
delete m_LinePen;
delete m_RectPen;
delete m_CirclePen;
}
void Widget::mousePressEvent(QMouseEvent *event)
{
if( event->button() == Qt::LeftButton )
{
m_MouseDown = true;
m_BasePen->SetStartPoint(event->pos());
}
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if( m_MouseDown )
{
m_BasePen->SetEndPoint(event->pos());
update();
}
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
if( event->button() == Qt::LeftButton )
{
m_MouseDown = false;
}
}
void Widget::paintEvent(QPaintEvent *event)
{
QPixmap temp = m_BasePen->GetPixmap();
QPainter painter(this);
painter.drawPixmap(0, 0, temp);
}
#include "main.moc"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Widget *ww = new Widget;
ww->show();
return app.exec();
}