Part 05 简易画板的实现(Qt)
——2012.02.13
0. 本次学习Qt时主要方法:分析代码,理清实现画板功能的思路,弄清各类间的关系。
1. 编写学习笔记主要形式:展示程序功能,展示程序类的功能关系分析图,展示(经修改的)程序代码。
2. 主要参考学习资料: Qt Assistant与Qt学习之路(31)(豆子空间)。
3. 本Part内容:了解QPainter,QPointer,QEvent类的使用,认识Center Widget中功能的实现方法。
011 Program –paintApp(Widget)
01. 展示程序功能
程序有一工具栏,有一画板,刚开始时,画板为空,鼠标指向工具栏第二个选项,在状态栏中有“Draw a rectangle”的提示字样。
按下鼠标,拖动,释放,可以得出一个矩形于画板中显示,当多次画时,历史痕迹不会消去。
现在开始选中工具栏的第一项,Draw a Line.
与上次操作一样,按下鼠标,拖动,释放,可以得出一个直线于画板中显示,当然,每次所画图形如果发生重叠,新画的图形会将旧的图形覆盖。
02. 展示程序类的功能关系分析图
03. 程序代码
# MyApp.pro
TARGET = MyApp
TEMPLATE = app
SOURCES += \
main.cpp \
mainwindow.cpp \
paintwidget.cpp \
line.cpp \
shape.cpp \
rect.cpp
HEADERS += \
mainwindow.h \
paintwidget.h \
line.h \
shape.h \
rect.h
RESOURCES += res.qrc
// main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.setWindowTitle(QObject::tr("Paint Application"));
w.setWindowIcon(QIcon(":/main.png"));
w.resize(800, 600);
w.show();
return app.exec();
}
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui>
#include "shape.h"
#include "paintwidget.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
signals:
void changeCurrentShape(Shape::Code newShape);
private slots:
void drawLineActionTriggered();
void drawRectActionTriggered();
};
#endif // MAINWINDOW_H
// PaintWidget.h
#ifndef PAINTWIDGET_H
#define PAINTWIDGET_H
#include <QtGui>
#include <QDebug>
#include "shape.h"
#include "line.h"
#include "rect.h"
class PaintWidget : public QWidget
{
Q_OBJECT
public:
PaintWidget(QWidget *parent = 0);
public slots:
void setCurrentShape(Shape::Code s)
{
if(s != currShapeCode)
{
currShapeCode = s; // 设定形状
}
}
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private:
Shape::Code currShapeCode;
Shape *shape;
bool perm;
QList<Shape*> shapeList;
};
#endif // PAINTWIDGET_H
// shape.h
#ifndef SHAPE_H
#define SHAPE_H
#include <QtGui>
class Shape
{
public:
enum Code
{
Line,
Rect
};
Shape();
void setStart(QPoint s)
{
start = s;
}
void setEnd(QPoint e)
{
end = e;
}
QPoint startPoint()
{
return start;
}
QPoint endPoint()
{
return end;
}
void virtual paint(QPainter & painter) = 0;
protected:
QPoint start;
QPoint end;
};
#endif // SHAPE_H
// Line.h
#ifndef LINE_H
#define LINE_H
#include "shape.h"
class Line : public Shape
{
public:
Line();
void paint(QPainter &painter);
};
#endif // LINE_H
// rect.h
#ifndef RECT_H
#define RECT_H
#include "shape.h"
class Rect : public Shape
{
public:
Rect();
void paint(QPainter &painter);
};
#endif // RECT_H
// mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
// 设置工具栏
QToolBar *bar = this->addToolBar("Tools");
QActionGroup *group = new QActionGroup(bar);
// 设置Line动作
QAction *drawLineAction = new QAction("Line", bar);
drawLineAction->setIcon(QIcon(":/line.png"));
drawLineAction->setToolTip(tr("Draw a line."));
drawLineAction->setStatusTip(tr("Draw a line."));
drawLineAction->setCheckable(true);
drawLineAction->setChecked(true);
group->addAction(drawLineAction);
bar->addAction(drawLineAction);
// 设置Rect动作
QAction *drawRectAction = new QAction("Rectangle", bar);
drawRectAction->setIcon(QIcon(":/rect.png"));
drawRectAction->setToolTip(tr("Draw a rectangle."));
drawRectAction->setStatusTip(tr("Draw a rectangle."));
drawRectAction->setCheckable(true);
group->addAction(drawRectAction);
bar->addAction(drawRectAction);
// 设置状态栏
QLabel *statusMsg = new QLabel;
statusBar()->addWidget(statusMsg);
// 设置中心部件
PaintWidget *paintWidget = new PaintWidget(this);
setCentralWidget(paintWidget);
// 信号连接
connect(drawLineAction, SIGNAL(triggered()), this, SLOT(drawLineActionTriggered()));
connect(drawRectAction, SIGNAL(triggered()), this, SLOT(drawRectActionTriggered()));
connect(this, SIGNAL(changeCurrentShape(Shape::Code)), paintWidget, SLOT(setCurrentShape(Shape::Code)));
}
void MainWindow::drawLineActionTriggered()
{
emit changeCurrentShape(Shape::Line); // 设定形状为线形,发射信号
}
void MainWindow::drawRectActionTriggered()
{
emit changeCurrentShape(Shape::Rect); // 设定形状为Rectangle矩形,发射信号
}
// paintwidget.cpp
#include "paintwidget.h"
PaintWidget::PaintWidget(QWidget *parent)
: QWidget(parent), currShapeCode(Shape::Line), shape(NULL), perm(false)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
void PaintWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setBrush(Qt::white);
painter.drawRect(0, 0, size().width(), size().height());
foreach(Shape * shape, shapeList) // 这里遍历容器可以保留历史痕迹
{
shape -> paint(painter);
}
return;
}
void PaintWidget::mousePressEvent(QMouseEvent *event)
{
switch(currShapeCode)
{
case Shape::Line:
{
shape = new Line;
break;
}
case Shape::Rect:
{
shape = new Rect;
break;
}
}
if(shape != NULL)
{
perm = false;
shapeList << shape;
shape -> setStart(event->pos());
shape -> setEnd(event->pos());
}
}
void PaintWidget::mouseMoveEvent(QMouseEvent *event)
{
if(shape && !perm)
{
shape->setEnd(event->pos());
update(); // void QWidget::update() [slot]
// Updates the widget unless updates are disabled or the widget is hidden.
// This function does not cause an immediate repaint;
// instead it schedules a paint event for processing when Qt returns to the main event loop.
// This permits Qt to optimize for more speed and less flicker than a call to repaint() does.
// Calling update() several times normally results in just one QWidget:paintEvent() call.
}
}
void PaintWidget::mouseReleaseEvent(QMouseEvent *event)
{
perm = true;
}
// shape.cpp
#include "shape.h"
Shape::Shape()
{
}
// line.cpp
#include "line.h"
Line::Line()
{
}
void Line::paint(QPainter &painter)
{
painter.drawLine(start, end);
}
// rect.cpp
#include "rect.h"
Rect::Rect()
{
}
void Rect::paint(QPainter &painter)
{
painter.drawRect(start.x(), start.y(),
end.x() - start.x(), end.y() - start.y());
}