學習筆記之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"的資源文件,添加相應圖片資源。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章