学习笔记之Qt4的2D绘图 爱被打了一巴掌 2022-07-12 16:25 255阅读 0赞 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"的资源文件,添加相应图片资源。
相关 Qt学习笔记之2D绘图 一、概要 Qt中提供了强大的2D绘图系统,可以使用相同的API在屏幕和绘图设备上进行绘制,它主要基于`QPainter`、`QPaintDevice`和`QPaintEn 逃离我推掉我的手/ 2023年07月05日 10:05/ 0 赞/ 4 阅读
相关 【Qt】2D绘图之双缓冲绘图 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 绘制矩形 04. 青旅半醒/ 2022年11月13日 00:48/ 0 赞/ 224 阅读
相关 【Qt】2D绘图之涂鸦板 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 程序设计(基本功能) Dear 丶/ 2022年11月12日 15:59/ 0 赞/ 180 阅读
相关 【Qt】2D绘图之绘图中其它问题 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 重绘事件 04. 怼烎@/ 2022年11月12日 14:57/ 0 赞/ 203 阅读
相关 【Qt】2D绘图之绘制图片 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 简单绘制图片 04 - 日理万妓/ 2022年11月12日 10:58/ 0 赞/ 223 阅读
相关 【Qt】2D绘图之坐标系统 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. Qt坐标系统 04 约定不等于承诺〃/ 2022年11月12日 09:52/ 0 赞/ 214 阅读
相关 【Qt】2D绘图之渐变填充 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 线性渐变 04. 刺骨的言语ヽ痛彻心扉/ 2022年11月12日 09:45/ 0 赞/ 233 阅读
相关 学习笔记之Qt4的2D绘图 1. Qt4中的2D绘图部分称为Arthur绘图。它由3个主要的类支撑起整个框架: (1) QPainter:用来执行具体的绘画操作。 (2) QPa 爱被打了一巴掌/ 2022年07月12日 16:25/ 0 赞/ 256 阅读
还没有评论,来说两句吧...