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