学习笔记之Qt4的2D绘图

1.  Qt4中的2D绘图部分称为Arthur绘图。它由3个主要的类支撑起整个框架:

(1)      QPainter:用来执行具体的绘画操作。

(2)      QPaintDevice:是QPainter用来绘图的绘图设备。

(3)      QPaintEngine:提供不同类型设备的接口。

2.  Qpainter类能够绘制:

(1)      基本的图形:点、线、矩形、多边形等。

(2)      复杂的图形:如绘图路径。

3.  使用绘图路径(QpaintPath)的优点是复杂形状的图形只用生成一次,以后再绘制时只需要调用QPainter::drawPath()就可以了。QPaintPath对象可以用来填充、绘制轮廓。

4.  线和轮廓使用画笔(QPen)进行绘制,画刷(QBrush)进行填充。

5.  画笔的属性包括:

(1)      画笔风格(PenStyle):它在在Qt中使用Qt::PenStyle定义了6种画笔风格,分别为:

a.      Qt::SolidLine

b.      Qt::DashLine

c.      Qt::DotLine

d.      Qt::DashDotLine

e.      Qt::DashDotDotLine

f.       Qt::CustomDashLine

默认为Qt::SolidLine。还有一种风格为Qt::NoPen,使用它时QPainter不绘制线。

若要使用自定义风格的线风格(Qt::CustomDashLine),则需要使用QPen的setDashPattern()函数来实现自定义风格。

(2)      线宽(Width)

(3)      颜色(color)

(4)      端点风格(CapStyle):它决定了线的端点样式,但只对线宽大于等于1的线有效,对装饰笔绘制的线无效。用枚举类型Qt::PenCapStyle表示,分别为以下三种:

a.      Qt::SquareCap

b.      ,Qt::FlatCap

c.      Qt::RoundCap。

(5)      连接风格(JoinStyle):它指两条线如何连接,仅对线宽大于等于1的线有效,对装饰笔绘制的线无效。Qt定义了4种连接方式,用枚举类型Qt::PenStyle表示,分别为:

a.      Qt::MiterJoin

b.      Qt::bevelJoin

c.      Qt::RoundJoin

d.      Qt::SvgMiterJoin

6.  penWidthSpinBox->setSpecialValueText(tr("0 (cosmetic pen)"));

setSpecialValueText()函数是QSpinBox类的特殊用法,用来在QSpinBox中显示文字而不是默认的数值。

7.  画刷的属性包括:

(1)      填充颜色:在Qt中颜色使用QColor类表示。它支持RGB,HSV,CMYK颜色模型。QColor还支持alpha混合的轮廓和填充(可以实现透明效果),QColor类与平台、设备无关(通过QColormap类与硬件进行映射)。它还可以使用SVG 1.0中定义的任何颜色名为参数初始化。

(2)      填充模式(风格):它由Qt::BrushStyle枚举变量定义,包括以下几种填充模式:

a.       基本模式填充:包括各种点、线组合的模式。

b.      渐变模式填充

c.       纹理填充

8.  Qt4还提供了渐变填充的画刷。渐变填充包括两个要素:颜色的变化以及路径的变化。在Qt中指定了三种渐变填充,它们都是从QGradient继承而来。三种填充渐变如下:

(1)      线性渐变(QLinearGradient):起点(x,y),终点(x1,y1)

(2)      圆形渐变(QRadicalGradient):圆心(x,y),半径,焦点(x1,y1)

(3)      圆锥渐变(QConicalGradient):圆心(x,y),开始角

9. 双缓冲绘图:在绘图过程中,一个缓冲区绘制临时内容,一个缓冲区保存绘制好的内容,最后进行合并。在交互绘制过程中,程序将图像缓冲区复制到临时缓冲区,并在临时缓冲区上绘制,绘制完毕再将结果复制到图像缓冲区。

在Qt4种,所有窗口部件默认都是用双缓冲进行绘图,可以减轻绘制的闪烁感。


2D绘图实例:

1、用qt creator创建一个名为basicdraw的empty qt project工程;
2、在工程中添加相应文件,代码如下:

palette.h

#ifndef PALETTE_H
#define PALETTE_H

#include<QtGui>
#include "previewlabel.h"
#include "qpenstydelegate.h"

class QLabel;
class QSpinBox;
class QComboBox;
class Palette:public QWidget
{
    Q_OBJECT
public:
    Palette(QWidget *parent=0);
signals:
    void penChanged(QPen& pen);
    void brushChanged(QBrush& brush);
private slots:
    void penChanged();
    void brushChanged();
private:
    QLabel *penColorLabel;//画笔颜色
    QLabel *penWidthLabel;//画笔线宽
    QLabel *penStyleLabel;//画笔风格
    QLabel *brushColorLabel;//画刷颜色
    QLabel *brushStyleLabel;//画刷风格
    PreviewLabel *preLabel;//预览取
    QSpinBox *penWidthSpinBox;
    QComboBox *penColorComboBox;
    QComboBox *penStyleComboBox;
    QComboBox *brushColorComboBox;
    QComboBox *brushStyleComboBox;

    void createColorComboBox(QComboBox *comboBox);
    void createStyleComboBox();
};

#endif // PALETTE_H

 
 

palette.cpp

#include "palette.h"


Palette::Palette(QWidget *parent)
    :QWidget(parent)
{
    //画笔颜色
    penColorComboBox=new QComboBox;
    createColorComboBox(penColorComboBox);
    penColorLabel=new QLabel(tr("Pen Color:"));
    penColorLabel->setBuddy(penColorComboBox);

    //画笔线宽
    penWidthSpinBox=new QSpinBox;
    penWidthSpinBox->setRange(0,20);
    //设置线宽初始值
    penWidthSpinBox->setSpecialValueText(tr("0(cosmetic pen)"));

    penWidthLabel=new QLabel(tr("pen &width"));
    penWidthLabel->setBuddy(penWidthSpinBox);

    //画笔样式
    createStyleComboBox();

    penStyleLabel=new QLabel(tr("&pen Style:"));
    penStyleLabel->setBuddy(penStyleComboBox);

    //画刷颜色
    brushColorComboBox=new QComboBox;
    createColorComboBox(brushColorComboBox);

    brushColorLabel=new QLabel(tr("Brush Color:"));
    brushColorLabel->setBuddy(brushColorComboBox);

    //画刷填充样式
    brushStyleComboBox=new QComboBox;
    brushStyleComboBox->addItem(tr("None"),Qt::NoBrush);
    brushStyleComboBox->addItem(tr("Linear Gradient"),Qt::LinearGradientPattern);
    brushStyleComboBox->addItem(tr("Radial Gradient"),Qt::RadialGradientPattern);
    brushStyleComboBox->addItem(tr("Conical Gradient"),Qt::ConicalGradientPattern);
    brushStyleComboBox->addItem(tr("Texture"),Qt::TexturePattern);

    brushStyleLabel=new QLabel(tr("&Brush Style:"));
    brushStyleLabel->setBuddy(brushStyleComboBox);

    //预览区
    preLabel=new PreviewLabel(this);

    //连接信号与槽
    connect(penColorComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(penChanged()));
    connect(penWidthSpinBox,SIGNAL(valueChanged(int)),this,SLOT(brushChanged()));
    connect(penStyleComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(penChanged()));
    connect(brushColorComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(brushChanged()));
    connect(brushStyleComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(brushChanged()));
    connect(this,SIGNAL(penChanged(QPen&)),preLabel,SLOT(penChanged(QPen&)));
    connect(this,SIGNAL(brushChanged(QBrush&)),preLabel,SLOT(brushChanged(QBrush&)));

    //布局
    QGridLayout *mainLayout=new QGridLayout;
    mainLayout->addWidget(penColorLabel,0,0,Qt::AlignRight);
    mainLayout->addWidget(penColorComboBox,0,1);
    mainLayout->addWidget(penWidthLabel,1,0,Qt::AlignRight);
    mainLayout->addWidget(penWidthSpinBox,1,1);
    mainLayout->addWidget(penStyleLabel,2,0,Qt::AlignRight);
    mainLayout->addWidget(penStyleComboBox,2,1);
    mainLayout->addWidget(brushStyleLabel,3,0,Qt::AlignRight);
    mainLayout->addWidget(brushStyleComboBox,3,1);
    mainLayout->addWidget(brushColorLabel,4,0,Qt::AlignRight);
    mainLayout->addWidget(brushColorComboBox,4,1);
    mainLayout->addWidget(preLabel,5,0,6,2);
    setLayout(mainLayout);

    penChanged();
    brushChanged();

    setWindowTitle(tr("Basic Drawing"));
}

void Palette::penChanged()
{
    QPen pen;
    int width=penWidthSpinBox->value();
    pen.setWidth(width);

    QColor color=penColorComboBox->itemData(
                penColorComboBox->currentIndex(),Qt::UserRole).value<QColor>();
    pen.setColor(color);

    Qt::PenStyle penStyle=(Qt::PenStyle)penStyleComboBox->itemData(
                penStyleComboBox->currentIndex(),Qt::UserRole).toInt();
    pen.setStyle(penStyle);

    emit penChanged(pen);
}

void Palette::createColorComboBox(QComboBox *comboBox)
{
    QPixmap pix(16,16);

    QPainter pt(&pix);
    pt.fillRect(0,0,16,16,Qt::black);
    comboBox->addItem(QIcon(pix),tr("black"),Qt::black);
    pt.fillRect(0,0,16,16,Qt::red);
    comboBox->addItem(QIcon(pix),tr("red"),Qt::red);
    pt.fillRect(0,0,16,15,Qt::green);
    comboBox->addItem(QIcon(pix),tr("green"),Qt::green);
    pt.fillRect(0,0,16,16,Qt::blue);
    comboBox->addItem(QIcon(pix),tr("blue"),Qt::blue);
    pt.fillRect(0,0,16,16,Qt::yellow);
    comboBox->addItem(QIcon(pix),tr("yellow"),Qt::yellow);
    pt.fillRect(0,0,16,16,Qt::cyan);
    comboBox->addItem(QIcon(pix),tr("cyan"),Qt::cyan);
    pt.fillRect(0,0,16,16,Qt::magenta);
    comboBox->addItem(QIcon(pix),tr("magenta"),Qt::magenta);
}

void Palette::createStyleComboBox()
{
    penStyleComboBox=new QComboBox;
    penStyleComboBox->setItemDelegate(
                new QPenStyDelegate((QObject *)penStyleComboBox));
    penStyleComboBox->addItem(tr("Solid"),Qt::SolidLine);
    penStyleComboBox->addItem(tr("Dash"),Qt::DashLine);
    penStyleComboBox->addItem(tr("Dot"),Qt::DotLine);
    penStyleComboBox->addItem(tr("Dash Dot"),Qt::DashDotLine);
    penStyleComboBox->addItem(tr("Dash Dot DOt"),Qt::DashDotDotLine);
    penStyleComboBox->addItem(tr("None"),Qt::NoPen);

}

void Palette::brushChanged()
{
    QBrush brush;
    \
    QColor color=brushColorComboBox->itemData(
                brushColorComboBox->currentIndex(),
                Qt::UserRole).value<QColor>();

    Qt::BrushStyle style=Qt::BrushStyle(brushStyleComboBox->itemData(
                                            brushStyleComboBox->currentIndex(),
                                            Qt::UserRole).toInt());

    if(style==Qt::LinearGradientPattern)
    {
        QLinearGradient linearGradient(0,0,100,100);
        linearGradient.setColorAt(0.0,Qt::white);
        linearGradient.setColorAt(0.2,Qt::green);
        linearGradient.setColorAt(1.0,Qt::black);
        brush=linearGradient;
    }
    else if(style==Qt::RadialGradientPattern)
    {
        QRadialGradient radialGradient(50,50,50,70,70);
        radialGradient.setColorAt(0.0,Qt::white);
        radialGradient.setColorAt(0.2,Qt::green);
        radialGradient.setColorAt(1.0,Qt::black);
        brush=radialGradient;
    }
    else if(style==Qt::ConicalGradientPattern)
    {
        QConicalGradient conicalGradient(50,50,150);
        conicalGradient.setColorAt(0.0,Qt::white);
        conicalGradient.setColorAt(0.2,Qt::green);
        conicalGradient.setColorAt(1.0,Qt::black);
        brush=conicalGradient;
    }
    else if(style==Qt::TexturePattern)
    {
        brush=QBrush(QPixmap(":/images/ellipse.png"));
    }
    else
    {
        brush.setColor(color);
        brush.setStyle(style);
    }
    emit brushChanged(brush);
}


previewlabel.h

#ifndef PREVIEWLABEL_H
#define PREVIEWLABEL_H

#include<QtGui>
class PreviewLabel:public QLabel
{
    Q_OBJECT
public:
    PreviewLabel(QWidget *parent=0);

public slots:
    void penChanged(QPen& pen);
    void brushChanged(QBrush& brush);

protected:
    void paintEvent(QPaintEvent *event);

private:
    QPen curPen;
    QBrush curBrush;
};

#endif // PREVIEWLABEL_H


 
 

previewlabel.cpp

#include "previewlabel.h"

PreviewLabel::PreviewLabel(QWidget *parent)
    :QLabel(parent)
{

}
void PreviewLabel::penChanged(QPen &pen)
{
    curPen=pen;
    update();
}
void PreviewLabel::brushChanged(QBrush &brush)
{
    curBrush=brush;
    update();
}
void PreviewLabel::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setPen(curPen);
    painter.setBrush(curBrush);
    painter.drawRect(rect().x()+10,rect().y()+10,rect().width()-20,rect().height()-20);
}

qpenstydelegate.h

#ifndef QPENSTYDELEGATE_H
#define QPENSTYDELEGATE_H

#include<QtGui>

class QPenStyDelegate:public QAbstractItemDelegate
{
    Q_OBJECT
public:
    QPenStyDelegate(QObject *parent=0);

    void paint(QPainter *painter,
               const QStyleOptionViewItem &option,
               const QModelIndex &index) const;
    QSize sizeHint(const QStyleOptionViewItem &option,
                   const QModelIndex &index) const;
};

#endif // QPENSTYDELEGATE_H


qpenstydelegate.cpp

#include "qpenstydelegate.h"

QPenStyDelegate::QPenStyDelegate(QObject *parent)
    :QAbstractItemDelegate(parent)
{

}

void QPenStyDelegate::paint(QPainter *painter,
                                 const QStyleOptionViewItem &option,
                                 const QModelIndex &index)const
{
    QString text=index.data(Qt::DisplayPropertyRole).toString();
    Qt::PenStyle penStyle=(Qt::PenStyle)index.data(Qt::UserRole).toInt();
    QRect r=option.rect;

    if(option.state & QStyle::State_Selected)
    {
            painter->save();
            painter->setBrush(option.palette.highlight());
            painter->setPen(Qt::NoPen);
            painter->drawRect(option.rect);
            painter->setPen(QPen(option.palette.highlightedText(),2,penStyle));
     }
            else
            painter->setPen(penStyle);
            painter->drawLine(0,r.y()+r.height()/2,
                              r.right(),r.y()+r.height()/2);
            if(option.state & QStyle::State_Selected)
            painter->restore();
}

 QSize QPenStyDelegate::sizeHint(const QStyleOptionViewItem &option,
                                 const QModelIndex &index) const
    {
            return QSize(100,30);
}


form.h

#ifndef FORM_H
#define FORM_H

#include<QtGui>

class Form:public QWidget
{
    Q_OBJECT
public:
    Form(QWidget *parent=0);
    enum ShapeType
    {
        Line,
        Polyline,
        Rectangle,
        Polygone,
        Arc,
        Pie,
        Chord,
        Ellipse,
        Text
    };
    void setShape(ShapeType shape);

public slots:
    void fontChanged(const QFont& font);
    void penChanged(QPen& pen);
    void brushChanged(QBrush& brush);

protected:
    bool bDrawing;
    int x,y,w,h;
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *event);

private:
    QImage bufferImage; //绘图缓冲区
    QImage tempImage; //临时缓冲区
    ShapeType curShape; //当前图形种类
    QPen curPen;        //当前画笔
    QBrush curBrush;    //当前画刷
    QFont textFont;     //字体
    int thickness;

    void paint(QImage& image);

};

#endif // FORM_H


form.cpp

#include "form.h"

Form::Form(QWidget *parent)
    :QWidget(parent)
{
    //关闭窗口部件的双缓冲
    setAttribute(Qt::WA_NoBackground);
    bDrawing=false;
    curShape=Ellipse;

    resize(800,600);
    bufferImage=QImage(width(),height(),
                       QImage::Format_ARGB32_Premultiplied);
    bufferImage.fill(qRgb(255,255,255));
    tempImage=QImage(width(),height(),
                     QImage::Format_ARGB32_Premultiplied);
}

//设置当前绘图的图形种类
void Form::setShape(ShapeType shape)
{
    curShape=shape;
}

//当鼠标按下时,进入交互绘图状态
void Form::mousePressEvent(QMouseEvent *event)
{
    bDrawing=true;
    x=event->x();
    y=event->y();
}
//当鼠标移动时将图形缓冲区中的内容复制到临时缓冲区,并绘制临时的反馈图形
void Form::mouseMoveEvent(QMouseEvent *event)
{
    w=event->x()-x;
    h=event->y()-y;
    tempImage=bufferImage;
    paint(tempImage);
}

//当鼠标释放时,在绘图缓冲区上绘制图形
void Form::mouseReleaseEvent(QMouseEvent *event)
{
    bDrawing=false;
    paint(bufferImage);
}

//根据当前是否在绘图,在不同的缓冲区上绘制图形
void Form::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    if(bDrawing)
        painter.drawImage(QPoint(0,0),tempImage);
    else
        painter.drawImage(QPoint(0,0),bufferImage);
}

//实际的绘图函数,实现不同形状的绘图
void Form::paint(QImage &image)
{
    QPainter painter(&image);
    painter.setPen(curPen);
    painter.setBrush(curBrush);
    switch(curShape)
    {
    case Rectangle:
        painter.drawRect(x,y,w,h);
        break;
    case Ellipse:
        painter.drawEllipse(x,y,w,h);
        break;
    case Text:
        QFontMetrics metrics(textFont);
        QRect rect=metrics.boundingRect(textFont.family());
        painter.setFont(textFont);
        painter.translate(x,y);
        painter.scale(w/rect.width(),h/rect.height());
        painter.drawText(0,rect.height(),textFont.family());
        break;
    }
    update();
}

//绘图要素的改变
void Form::fontChanged(const QFont &font)
{
    textFont=font;
}

void Form::penChanged(QPen &pen)
{
    curPen=pen;
}

void Form::brushChanged(QBrush &brush)
{
    curBrush=brush;
}


mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include<QMainWindow>
#include<QActionGroup>
#include<QFontComboBox>
#include"form.h"
#include"palette.h"

class MainWindow:public QMainWindow
{
    Q_OBJECT
public:
    MainWindow();
private slots:
    void draw(QAction* action);//绘制当前图形的种类

private:
    void createActions();
    void createMenus();
    void createToolBars();
    void createStatusBar();
    void CreateDockWindows();

    Palette *paletteWidget;
    Form *form;

    QMenu *drawMenu;
    QToolBar *drawToolBar;
    QFontComboBox *fontCmb;

    //不同图形的QAction
    QAction *rectangleAct;
    QAction *ellipseAct;
    QAction *textAct;
    QActionGroup *drawActGroup;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include<QtGui>

MainWindow::MainWindow()
{
    resize(800,600);
    form=new Form(this);
    setCentralWidget(form);

    createActions();
    createMenus();
    createToolBars();
    createStatusBar();
    CreateDockWindows();
}

//绘制当前图形的种类
void MainWindow::draw(QAction* action)
{
    if(action==rectangleAct)
        form->setShape(Form::Rectangle);
    if(action==ellipseAct)
        form->setShape(Form::Ellipse);
    else if(action==textAct)
        form->setShape(Form::Text);
}

//创建不同图形的QAction,并将所有绘图的QAction归到一个QActionGroup中
void MainWindow::createActions()
{
    rectangleAct=new QAction(QIcon(":/images/rectangle.png"),
                            tr("&rectangle"),this);
    rectangleAct->setCheckable(true);

    ellipseAct=new QAction(QIcon(":/images/ellipse.png"),
                           tr("&Ellipse"),this);
    ellipseAct->setCheckable(true);
    ellipseAct->setCheckable(true);

    textAct=new QAction(QIcon(":/images/text.png"),
                        tr("&Text"),this);
    textAct->setCheckable(true);

    drawActGroup=new QActionGroup(this);
    drawActGroup->addAction(rectangleAct);
    drawActGroup->addAction(ellipseAct);
    drawActGroup->addAction(textAct);

    connect(drawActGroup,SIGNAL(triggered(QAction*)),this,
                                SLOT(draw(QAction*)));
}

//创建菜单
void MainWindow::createMenus()
{
    drawMenu=menuBar()->addMenu(tr("&Draw"));
    drawMenu->addAction(rectangleAct);
    drawMenu->addAction(ellipseAct);
    drawMenu->addAction(textAct);
}

//创建工具条
void MainWindow::createToolBars()
{
    drawToolBar=addToolBar(tr("Draw"));
    drawToolBar->addAction(rectangleAct);
    drawToolBar->addAction(ellipseAct);
    drawToolBar->addSeparator();//
    drawToolBar->addAction(textAct);
    fontCmb=new QFontComboBox(drawToolBar);
    drawToolBar->addWidget(fontCmb);
    connect(fontCmb,SIGNAL(currentFontChanged(const QFont&)),form,
                           SLOT(fontChanged(const QFont&)));
            fontCmb->setCurrentFont(font());
}
//创建状态条
void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}
//创建调色板
void MainWindow::CreateDockWindows()
{
    QDockWidget *dock=new QDockWidget(tr("Palette"),this);
    dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    paletteWidget=new Palette(dock);
    dock->setWidget(paletteWidget);
    addDockWidget(Qt::LeftDockWidgetArea,dock);

    connect(paletteWidget,SIGNAL(penChanged(QPen&)),form,
            SLOT(penChanged(QPen&)));
    connect(paletteWidget,SIGNAL(brushChanged(QBrush&)),form,
            SLOT(brushChanged(QBrush&)));
}


main.cpp

#include<QApplication>
#include<QtGui>
#include<QTextCodec>
#include"mainwindow.h"

int main(int argc,char *argv[])
{
    QApplication app(argc,argv);
    QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
    MainWindow mainwindow;
    mainwindow.show();
    return app.exec();

}


注:还要新建一个名为"images"的资源文件,添加相应图片资源。



猜你喜欢

转载自blog.csdn.net/youarenotme/article/details/58587075