1 A parte de desenho 2D no Qt4 é chamada de desenho de Arthur. É suportado por 3 classes principais:
(1) QPainter : usado para realizar operações de pintura específicas.
(2) QPaintDevice : é o dispositivo de desenho usado pelo QPainter para desenhar.
(3) QPaintEngine : Fornece interfaces para diferentes tipos de equipamentos.
2 A classe Qpainter pode desenhar:
(1) Gráficos básicos: pontos, linhas, retângulos, polígonos, etc.
(2) Gráficos complexos: como traçar caminhos.
3 - A vantagem de usar o caminho de desenho (QpaintPath) é que as formas complexas são geradas apenas uma vez e você só precisa chamar QPainter :: drawPath () ao desenhá-las posteriormente . Os objetos QPaintPath podem ser usados para preencher e desenhar contornos.
4 - Contorne a linha e use pincéis (QPen) traçados, pincéis (QBrush) são preenchidos.
5 Os atributos do pincel incluem:
(1) PenStyle : usa Qt :: PenStyle para definir 6 estilos de caneta em Qt , a saber:
uma. Qt :: SolidLine
b. Qt :: DashLine
c. Qt :: DotLine
d. Qt :: DashDotLine
e. Qt :: DashDotDotLine
f. Qt :: CustomDashLine
O padrão é Qt :: SolidLine. Existe outro estilo chamado Qt :: NoPen, o QPainter não desenha linhas ao usá-lo.
Se você quiser usar um estilo de linha de estilo personalizado (Qt :: CustomDashLine), você precisa usar a função setDashPattern () de QPen para implementar o estilo personalizado.
(2) Largura
(3) Cor
(4) CapStyle : Determina o estilo do final da linha, mas só é válido para linhas com largura de linha maior ou igual a 1, e é inválido para linhas desenhadas por canetas decorativas. Expresso pelo tipo enumerado Qt :: PenCapStyle , existem três tipos:
uma. Qt :: SquareCap
b. , Qt :: FlatCap
c. Qt :: RoundCap。
(5) Estilo de União : Refere-se à forma como duas linhas são conectadas, só é válido para linhas com largura maior ou igual a 1, mas inválido para linhas desenhadas por canetas decorativas. Qt define 4 métodos de conexão, representados pelo tipo enumerado Qt :: PenStyle , que são:
uma. Qt :: MiterJoin
b. Qt :: bevelJoin
c. Qt :: RoundJoin
d. Qt :: SvgMiterJoin
6. penWidthSpinBox -> setSpecialValueText (tr ( "0 (caneta cosmética)" ));
A função setSpecialValueText () é um uso especial da classe QSpinBox, usada para exibir texto em QSpinBox em vez do valor padrão.
7 Os atributos do pincel incluem:
(1) Cor de preenchimento : A cor em Qt é representada pela classe QColor . Suporta modelos de cores RGB, HSV, CMYK . QColor também suporta mistura alfa de contornos e preenchimentos (efeitos de transparência podem ser alcançados), e a classe QColor é independente de plataforma e dispositivo (mapeamento com o hardware por meio da classe QColormap). Ele também pode ser inicializado com qualquer nome de cor definido em SVG 1.0.
(2) Modo de preenchimento (estilo): É definido pela variável de enumeração Qt :: BrushStyle , incluindo os seguintes modos de preenchimento:
a. Preenchimento de padrão básico : incluindo padrões de várias combinações de pontos e linhas.
b. Preenchimento de padrão de gradiente
c. Preenchimento de textura
8 Qt4 também fornece um pincel de preenchimento gradiente. O preenchimento gradiente inclui dois elementos: a mudança de cor e a mudança de caminho. Três preenchimentos de gradiente são especificados em Qt, e todos eles herdam da classe QGradient . Os três gradientes de preenchimento são os seguintes:
(1) QLinearGradient : ponto inicial (x, y), ponto final (x1, y1)
(2) QRadicalGradient : centro (x, y), raio, foco (x1, y1)
(3) Gradiente cônico (QConicalGradient) : centro (x, y), ângulo inicial
9 Desenho de buffer duplo: no processo de desenho, um buffer desenha o conteúdo temporário, outro salva o conteúdo desenhado e, finalmente, mescla. No processo de desenho interativo, o programa copia o buffer de imagem para o buffer temporário e desenha no buffer temporário e, a seguir, copia o resultado para o buffer de imagem após o desenho.
No Qt4, todos os widgets usam buffer duplo para desenho por padrão, o que pode reduzir a oscilação do desenho.
Exemplos de desenho 2D:
1. Use qt creator para criar um projeto qt vazio chamado basicdraw;
2. adicione os arquivos correspondentes ao projeto, o código é o seguinte:
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();
}
Observação: crie também um novo arquivo de recurso denominado "imagens" e adicione os recursos de imagem correspondentes.