2D drawing of Qt4 of study notes

1. The 2D drawing part in Qt4 is called Arthur drawing. It is supported by 3 main classes:

(1)       QPainter : used to perform specific painting operations.

(2)       QPaintDevice : is a drawing device used by QPainter for drawing.

(3)       QPaintEngine : Provides interfaces for different types of equipment.

2. The Qpainter class can draw:

(1) Basic graphics: points, lines, rectangles, polygons, etc.

(2) Complex graphics: such as drawing paths.

3. The advantage of using the drawing path (QpaintPath) is that complex shapes are only generated once, and you only need to call QPainter::drawPath() when drawing them later . QPaintPath objects can be used to fill and draw outlines.

4. Contour line and use brushes (QPen) plotted, brushes (QBrush) is filled.

5. The attributes of the brush include:

(1)       PenStyle : It uses Qt::PenStyle to define 6 pen styles in Qt , namely:

a.      Qt::SolidLine

b.      Qt::DashLine

c.      Qt::DotLine

d. Qt :: DashDotLine

e.      Qt::DashDotDotLine

f.       Qt::CustomDashLine

The default is Qt::SolidLine. There is another style called Qt::NoPen, QPainter does not draw lines when using it.

If you want to use a custom style line style (Qt::CustomDashLine), you need to use the setDashPattern() function of QPen to implement the custom style.

(2)       Width

(3)       Color

(4)       CapStyle : It determines the end style of the line, but it is only valid for lines with a line width greater than or equal to 1, and is invalid for lines drawn by decorative pens. Expressed by the enumerated type Qt::PenCapStyle , there are three types:

a.      Qt::SquareCap

b.      ,Qt::FlatCap

c.      Qt::RoundCap。

(5)       Join Style : It refers to how two lines are connected. It is only valid for lines with a line width greater than or equal to 1, and is invalid for lines drawn by decorative pens. Qt defines 4 connection methods, represented by the enumerated type Qt::PenStyle , which are:

a.      Qt::MiterJoin

b.      Qt::bevelJoin

c.      Qt::RoundJoin

d.      Qt::SvgMiterJoin

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

The setSpecialValueText() function is a special usage of the QSpinBox class, used to display text in QSpinBox instead of the default value.

7. The attributes of the brush include:

(1)       Fill color : The color in Qt is represented by the QColor class. It supports RGB, HSV, CMYK color models. QColor also supports alpha blending of outlines and fills (transparency effects can be achieved), and the QColor class is platform- and device-independent (mapping with the hardware through the QColormap class). It can also be initialized with any color name defined in SVG 1.0.

(2)       Filling mode (style): It is defined by the Qt::BrushStyle enumeration variable, including the following filling modes:

a. Basic pattern filling : including patterns of various combinations of points and lines.

b. Gradient pattern fill

c. Texture filling

8. Qt4 also provides a gradient fill brush. Gradient filling includes two elements: the change of color and the change of path. Three gradient fills are specified in Qt, and they all inherit from the QGradient class . The three fill gradients are as follows:

(1) Linear gradient (QLinearGradient) : starting point (x, y), end point (x1, y1)

(2)       QRadicalGradient : center (x, y), radius, focus (x1, y1)

(3) Conical gradient (QConicalGradient) : center (x, y), starting angle

9. Double-buffer drawing: During the drawing process, one buffer draws temporary content, one buffer saves the drawn content, and finally merges. In the interactive drawing process, the program copies the image buffer to the temporary buffer, and draws on the temporary buffer, and then copies the result to the image buffer after drawing.

In Qt4, all widgets use double buffering for drawing by default, which can reduce the flicker of drawing.


2D drawing examples:

1. Use qt creator to create an empty qt project called basicdraw;
2. add corresponding files to the project, the code is as follows:

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

}


Note: Also create a new resource file named "images" and add corresponding image resources.



Guess you like

Origin blog.csdn.net/youarenotme/article/details/58587075