qt 绘制消息框_【Qt开发】Qt在QLabel(QWidget)鼠标绘制直线和矩形框

说实话,原本我是没有打算放一个很大的例子的,一则比较复杂,二来或许须要不少次才能说得完。不过,如今已经说完了绘图部分,因此计划仍是上一个这样的例子。这里我会只作出一个简单的画板程序,大致上就是可以画直线和矩形吧。这样,我计划分红两种实现,一是使用普通的QWidget做为画板,第二则是使用Graphcis View Framework来实现。由于前面有朋友说不大明白Graphics View的相关内容,因此计划如此。

好了,如今先来看看咱们的主体框架。咱们的框架仍是使用Qt Creator建立一个Gui Application工程。

简单的main()函数就再也不赘述了,这里首先来看MainWindow。顺便说一下,我通常不会使用ui文件,因此这些内容都是手写的。首先先来看看最终的运行结果:

或许很简单,可是至少咱们可以把前面所说的各类知识串连起来,这也就达到目的了。

如今先来看看MainWindow的代码:

mainwindow.h

#ifndef MAINWINDOW_H 

#define MAINWINDOW_H 

 

#include  

 

#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

mainwindow.cpp

#include 

"mainwindow.h"

 

MainWindow::MainWindow(QWidget *parent) 

        : QMainWindow(parent) 

        QToolBar *bar = 

this->addToolBar(

"Tools");

        QActionGroup *group = 

new QActionGroup(bar);

 

        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); 

        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); 

}

应该说,从以往的学习中能够看出,这里的代码没有什么奇怪的了。咱们在MainWindow类里面声明了一个信号,changeCurrentShape(Shape::Code),用于按钮按下后通知画图板。注意,QActio的triggered()信号是没有参数的,所以,咱们须要在QAction的槽函数中从新emit咱们本身定义的信号。构造函数里面建立了两个QAction,一个是drawLineAction,一个是drawRectAction,分别用于绘制直线和矩形。MainWindow的中心组件是PainWidget,也就是咱们的画图板。下面来看看PaintWidget类:

paintwidget.h

#ifndef PAINTWIDGET_H 

#define PAINTWIDGET_H 

 

#include  

#include  

#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 shapeList; 

}; 

 

#endif 

// PAINTWIDGET_H

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); 

        } 

        

if(shape) {

                shape->paint(painter); 

        } 

 

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->setStart(

event->pos());

                shape->setEnd(

event->pos());

        } 

 

void PaintWidget::mouseMoveEvent(QMouseEvent *

event)

        

if(shape && !perm) {

                shape->setEnd(

event->pos());

                update(); 

        } 

 

void PaintWidget::mouseReleaseEvent(QMouseEvent *

event)

        perm = 

true;

}

PaintWidget类定义了一个slot,用于接收改变后的新的ShapeCode。最主要的是,PaintWidget重定义了三个关于鼠标的事件:mousePressEvent,mouseMoveEvent和mouseReleaseEvent。

咱们来想象一下如何绘制一个图形:图形的绘制与鼠标操做息息相关。以画直线为例,首先咱们须要按下鼠标,肯定直线的第一个点,因此在mousePressEvent里面,咱们让shape保存下start点。而后在鼠标按下的状态下移动鼠标,此时,直线就会发生变化,其实是直线的终止点在随着鼠标移动,因此在mouseMoveEvent中咱们让shape保存下end点,而后调用update()函数,这个函数会自动调用paintEvent()函数,显示出咱们绘制的内容。最后,当鼠标松开时,图形绘制完毕,咱们将一个标志位置为true,此时说明这个图形绘制完毕。

为了保存咱们曾经画下的图形,咱们使用了一个List。每次按下鼠标时,都会把图形存入这个List。能够看到,咱们在paintEvent()函数中使用了foreach遍历了这个List,绘制出历史图形。foreach是Qt提供的一个宏,用于遍历集合中的元素。

最后咱们来看看Shape类。

shape.h

#ifndef SHAPE_H 

#define SHAPE_H 

 

#include  

 

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

shape.cpp

#include 

"shape.h"

 

Shape::Shape() 

}

Shape类最重要的就是保存了start和end两个点。为何只要这两个点呢?由于咱们要绘制的是直线和矩形。对于直线来讲,有了两个点就能够肯定这条直线,对于矩形来讲,有了两个点做为左上角的点和右下角的点也能够肯定这个矩形,所以咱们只要保存两个点,就足够保存这两种图形的位置和大小的信息。paint()函数是Shape类的一个纯虚函数,子类都必须实现这个函数。咱们如今有两个子类:Line和Rect,分别定义以下:

line.h

#ifndef LINE_H 

#define LINE_H 

 

#include 

"shape.h"

 

class Line :

public Shape

public:

        Line(); 

 

        

void paint(QPainter &painter);

}; 

 

#endif 

// LINE_H

line.cpp

#include 

"line.h"

 

Line::Line() 

 

void Line::paint(QPainter &painter)

        painter.drawLine(start, end); 

}

rect.h

#ifndef RECT_H 

#define RECT_H 

 

#include 

"shape.h"

 

class Rect :

public Shape

public:

        Rect(); 

 

        

void paint(QPainter &painter);

}; 

 

#endif 

// RECT_H

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()); 

}

使用paint()函数,根据两个点的数据,Line和Rect均可以绘制出它们自身来。此时就能够看出,咱们之因此要创建一个Shape做为父类,由于这两个类有几乎彻底类似的数据对象,而且从语义上来讲,Line、Rect与Shape也彻底是一个is-a的关系。若是你想要添加颜色等的信息,彻底能够在Shape类进行记录。这也就是类层次结构的好处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值