Qt圖形與圖片(Qt位置相關函數、Qt基礎圖形的繪制、雙緩沖機制、顯示SVG格式圖片)

此篇文章介紹幾種主要位置函數及其之間的區別,以及各種與位置相關函數的使用場合;然后,通過一個簡單繪圖工具實例,介紹利用QPainter和QPainterPath兩種方法繪制各種基礎圖形;最后,通過幾個實例介紹如何利用這些基礎的圖形來繪制更復雜的圖形。

Qt位置相關函數

區別概念

Qt提供了很多關于獲取窗體位置及顯示區域大小的函數,如x()、y()和pos()、rect()、size()、geometry()等,統稱為“位置相關函數”或“位置函數”。幾種主要位置函數及其之間的區別如下所示。
在這里插入圖片描述
其中,

  • x()、y()和pos()函數的作用都是獲得整個窗體左上角的坐標位置。
  • frameGeometry()函數與geometry ()函數相對應。frameGeometry()函數或獲得的是真個窗體的左頂點和長、寬值,而geometry ()函數獲得的是窗體內中央區域的左上頂點坐標及長、寬值。
  • 直接調用width()和height()函數獲得的是中央區域的長、寬值。
  • rect()、size()函數獲得的的結果也都是相對于窗體的中央區域而言的。size()函數獲得的是窗體得的長、寬值是相同的,都是窗體中央區域的長、寬值,rect()函數與geometry ()函數相同,返回一個QRect對象,,這兩個函數獲得的長、寬值是相同的,都是窗體中央區域的長、寬值,只是左上頂點的坐標值不一樣。geometry ()函數獲得的左上頂點坐標是相對于父窗體而言的坐標,而rect()函數獲得的左上頂點坐標始終為(0,0)。

在實際應用中,需要根據情況使用正確的位置信息函數以獲得準確的位置尺寸信息,尤其是在編寫對位置精度要求較高的程序(如地圖瀏覽程序)時,更應該注意函數的選擇,以避免產生不必要的誤差。

“實例”位置函數的應用

本節通過一個簡單的例子介紹QWidget提供的x()、y()、frameGeometry()、pos()、rect()、size()和geometry()等函數的使用場合。
創建一個Geometry項目,當改變對話框的大小或移動對話框時,調用各個函數所獲得的信息也相應地發生變化,從變化中可得知各函數之間的區別,效果如下圖所示。
在這里插入圖片描述
布局代碼如下:

Geometry::Geometry(QWidget *parent): QDialog(parent)
{setWindowTitle(tr("Geometry"));xLabel =new QLabel(tr("x():"));xValueLabel =new QLabel;yLabel =new QLabel(tr("y():"));yValueLabel =new QLabel;FrmLabel =new QLabel(tr("Frame:"));FrmValueLabel =new QLabel;posLabel =new QLabel(tr("pos():"));posValueLabel =new QLabel;geoLabel =new QLabel(tr("geometry():"));geoValueLabel =new QLabel;widthLabel =new QLabel(tr("width():"));widthValueLabel =new QLabel;heightLabel =new QLabel(tr("height():"));heightValueLabel =new QLabel;rectLabel =new QLabel(tr("rect():"));rectValueLabel =new QLabel;sizeLabel =new QLabel(tr("size():"));sizeValueLabel =new QLabel;mainLayout =new QGridLayout(this);mainLayout->addWidget(xLabel,0,0);mainLayout->addWidget(xValueLabel,0,1);mainLayout->addWidget(yLabel,1,0);mainLayout->addWidget(yValueLabel,1,1);mainLayout->addWidget(posLabel,2,0);mainLayout->addWidget(posValueLabel,2,1);mainLayout->addWidget(FrmLabel,3,0);mainLayout->addWidget(FrmValueLabel,3,1);mainLayout->addWidget(geoLabel,4,0);mainLayout->addWidget(geoValueLabel,4,1);mainLayout->addWidget(widthLabel,5,0);mainLayout->addWidget(widthValueLabel,5,1);mainLayout->addWidget(heightLabel,6,0);mainLayout->addWidget(heightValueLabel,6,1);mainLayout->addWidget(rectLabel,7,0);mainLayout->addWidget(rectValueLabel,7,1);mainLayout->addWidget(sizeLabel,8,0);mainLayout->addWidget(sizeValueLabel,8,1);updateLabel();
}

頁面數據刷新updateLabel函數邏輯如下:

void Geometry::updateLabel()
{QString xStr;                      	//獲得x()函數的結果并顯示xValueLabel->setText(xStr.setNum(x()));QString yStr;                      	//獲得y()函數的結果并顯示yValueLabel->setText(yStr.setNum(y()));QString frameStr;                   //獲得frameGeometry()函數的結果并顯示QString tempStr1,tempStr2,tempStr3,tempStr4;frameStr = tempStr1.setNum(frameGeometry().x())+","+tempStr2.setNum(frameGeometry().y())+","+tempStr3.setNum(frameGeometry().width())+","+tempStr4.setNum(frameGeometry().height());FrmValueLabel->setText(frameStr);QString positionStr;            	//獲得pos()函數的結果并顯示QString tempStr11,tempStr12;positionStr =tempStr11.setNum(pos().x())+","+tempStr12.setNum(pos().y());posValueLabel->setText(positionStr);QString geoStr;               		//獲得geometry()函數的結果并顯示QString tempStr21,tempStr22,tempStr23,tempStr24;geoStr =tempStr21.setNum(geometry().x())+","+tempStr22.setNum(geometry().y())+","+tempStr23.setNum(geometry().width())+","+tempStr24.setNum(geometry().height());geoValueLabel->setText(geoStr);QString wStr,hStr;                  //獲得width()、height()函數的結果并顯示widthValueLabel->setText(wStr.setNum(width()));heightValueLabel->setText(hStr.setNum(height()));QString rectStr;                    //獲得rect()函數的結果并顯示QString tempStr31,tempStr32,tempStr33,tempStr34;rectStr =tempStr31.setNum(rect().x())+","+tempStr32.setNum(rect().y())+","+tempStr33.setNum(/*rect().width()*/width())+","+tempStr34.setNum(height()/*rect().height()*/);rectValueLabel->setText(rectStr);QString sizeStr;                    //獲得size()函數的結果并顯示QString tempStr41,tempStr42;sizeStr =tempStr41.setNum(size().width())+","+tempStr42.setNum(size().height());sizeValueLabel->setText(sizeStr);
}

重新定義QWidget的moveEvent(QMoveEvent *event)函數,響應對話框的移動事件,使得窗體在被動時能夠同步更新各函數的顯示結果,具體代碼如下:

void Geometry::moveEvent(QMoveEvent *)
{updateLabel();
}

重新定義QWidget的resizeEvent(QResizeEvent *event)函數,響應對話框的大小調整事件,使得在窗體大小發生變化時,也能夠同步更新各函數的顯示結果,具體代碼如下:

void Geometry::resizeEvent(QResizeEvent *)
{updateLabel();
}

Qt基礎圖形的繪制

創建一個PaintEx項目,在設計頁面區分各種形狀及畫筆顏色、畫筆線寬、畫筆風格、畫筆頂帽、畫筆連接點、填充模式、鋪展效果、畫刷顏色、畫刷風格設置等。

繪圖框架設計

利用QPainter繪制各種圖形使用的框架的實例如下圖所示。
在這里插入圖片描述
此實例的具體實現包含兩個部分的內容:左側是用于畫圖的區域PaintArea類,右側是主窗口MainWidget類。
程序中,首先在PaintArea類中完成各種圖形顯示功能的Widget,重繪paintEvent函數。然后在主窗口MainWidget類中完成各種圖形參數的選擇。

繪圖區的實現

PaintArea類繼承自QWidget類,在類聲明中,首先聲明一個枚舉型數據Shape,列舉了所有本實例可能用到的圖形形狀;其次聲明setShape()函數用于設置形狀,setPen()函數用于設置畫筆,setBrush()函數用于設置畫刷,setFillRule()函數用于設置填充模式,以及重繪事件paintEvent()函數;最后聲明表示各種屬性的私有變量。
PaintArea類的構造函數用于完成初始化工作,設置圖形顯示區域的背景色及最小顯示尺寸,具體代碼如下:

PaintArea::PaintArea(QWidget *parent) : QWidget(parent)
{setPalette(QPalette(Qt::white));setAutoFillBackground(true);setMinimumSize(400,400);
}

其中,setPalette(QPalette(Qt::white))、setAutoFillBackground(true)完成對窗體背景色的設置,與下面的代碼效果一致:

QPalette p = palette();
p.setColor(QPalette::window, Qt::white);
setPalette(p);

setShape()函數可以設置形狀,setPen()函數可以涉資畫筆,setBrush()函數可以設置畫刷,setFillRule函數可以設置填充模式,具體代碼如下:

void PaintArea::setShape(Shape s)
{shape = s;update();
}
void PaintArea::setPen(QPen p)
{pen = p;update();
}
void PaintArea::setBrush(QBrush b)
{brush = b;update();
}
void PaintArea::setFillRule(Qt::FillRule rule)
{fillRule =rule;update();     //重畫繪制區窗體
}

PaintArea類的重繪函數代碼如下:

void PaintArea::paintEvent(QPaintEvent *)
{QPainter p(this);						//新建一個QPainter對象p.setPen(pen);							//設置QPainter對象的畫筆p.setBrush(brush);						//設置QPainter對象的畫刷QRect rect(50,100,300,200);static const QPoint points[4]={QPoint(150,100),QPoint(300,150),QPoint(350,250),QPoint(100,300)};int startAngle = 30*16;	int spanAngle = 120*16;QPainterPath path;                      //新建一個QPainterPath對象為畫路徑做準備path.addRect(150,150,100,100);path.moveTo(100,100);path.cubicTo(300,100,200,200,300,300);path.cubicTo(100,300,200,200,100,100);path.setFillRule(fillRule);switch(shape){case Line:                          //直線p.drawLine(rect.topLeft(),rect.bottomRight());break;case Rectangle:                     //長方形p.drawRect(rect);	break;case RoundRect:                     //圓角方形p.drawRoundedRect(rect, 20.0, 20.0); 	break;case Ellipse:                       //橢圓形p.drawEllipse(rect); 	break;case Polygon:                       //多邊形p.drawPolygon(points,4); 	break;case Polyline:                      //多邊線p.drawPolyline(points,4); 	break;case Points:                        //點p.drawPoints(points,4); 	break;case Arc:                            //弧p.drawArc(rect,startAngle,spanAngle);	 break;case Path:                           //路徑p.drawPath(path); 	break;case Text:                           //文字p.drawText(rect,Qt::AlignCenter,tr("Hello Qt!"));break;case Pixmap:                         //圖片p.drawPixmap(150,150,QPixmap("butterfly.png")); 	break;default: 	break;}
}
  • QRect rect(50,100,300,200):設定一個方形區域,為畫正方形、圓角正方形、橢圓等做準備。
  • static const QPoint points[4]={…}:創建一個QPoint數組,包含4個點,為畫多邊形、多邊形及點做準備。
  • int startAngle =3016:、int spanAngle = 12016:其中,startAngle 代表起始角,為弧形的起始點與圓心之間連線與水平方向的夾角;參數spanAngle表示的是跨度角,為弧形起點、終點分別于圓心連線之間的夾角(用QPainter畫弧形所使用的角度值,是以1/16°為單位,在畫弧時即1°用16表示。)

主窗口的實現

界面布局代碼如下:

MainWidget::MainWidget(QWidget *parent): QWidget(parent)
{paintArea =new PaintArea;shapeLabel =new QLabel(QStringLiteral("形狀:"));            //形狀選擇下拉列表框shapeComboBox =new QComboBox;shapeComboBox->addItem(QStringLiteral("Line"),PaintArea::Line);shapeComboBox->addItem(QStringLiteral("Rectangle"),PaintArea::Rectangle);shapeComboBox->addItem(QStringLiteral("RoundedRect"),PaintArea::RoundRect);shapeComboBox->addItem(QStringLiteral("Ellipse"),PaintArea::Ellipse);shapeComboBox->addItem(QStringLiteral("Polygon"),PaintArea::Polygon);shapeComboBox->addItem(QStringLiteral("Polyline"),PaintArea::Polyline);shapeComboBox->addItem(QStringLiteral("Points"),PaintArea::Points);shapeComboBox->addItem(QStringLiteral("Arc"),PaintArea::Arc);shapeComboBox->addItem(QStringLiteral("Path"),PaintArea::Path);shapeComboBox->addItem(QStringLiteral("Text"),PaintArea::Text);shapeComboBox->addItem(QStringLiteral("Pixmap"),PaintArea::Pixmap);connect(shapeComboBox,SIGNAL(activated(int)),this,SLOT(ShowShape (int)));penColorLabel =new QLabel(QStringLiteral("畫筆顏色:"));      //畫筆顏色選擇控件penColorFrame =new QFrame;penColorFrame->setFrameStyle(QFrame::Panel|QFrame::Sunken);penColorFrame->setAutoFillBackground(true);penColorFrame->setPalette(QPalette(Qt::blue));penColorBtn =new QPushButton(QStringLiteral("更改"));connect(penColorBtn,SIGNAL(clicked()),this,SLOT(ShowPenColor()));penWidthLabel =new QLabel(QStringLiteral("畫筆線寬:"));      //畫筆線寬選擇控件penWidthSpinBox =new QSpinBox;penWidthSpinBox->setRange(0,20);connect(penWidthSpinBox,SIGNAL(valueChanged(int)),this,SLOT (ShowPenWidth(int)));penStyleLabel =new QLabel(QStringLiteral("畫筆風格:"));      //畫筆風格選擇下拉列表框penStyleComboBox =new QComboBox;penStyleComboBox->addItem(QStringLiteral("SolidLine"),static_cast<int>(Qt::SolidLine));penStyleComboBox->addItem(QStringLiteral("DashLine"),static_cast<int>(Qt::DashLine));penStyleComboBox->addItem(QStringLiteral("DotLine"),static_cast<int>(Qt::DotLine));penStyleComboBox->addItem(QStringLiteral("DashDotLine"),static_cast<int>(Qt::DashDotLine));penStyleComboBox->addItem(QStringLiteral("DashDotDotLine"),static_cast<int>(Qt::DashDotDotLine));penStyleComboBox->addItem(QStringLiteral("CustomDashLine"),static_cast<int>(Qt::CustomDashLine));connect(penStyleComboBox,SIGNAL(activated(int)),this,SLOT (ShowPenStyle(int)));penCapLabel =new QLabel(QStringLiteral("畫筆頂帽:"));        //畫筆頂帽風格選擇下拉列表框penCapComboBox =new QComboBox;penCapComboBox->addItem(QStringLiteral("SquareCap"),Qt::SquareCap);penCapComboBox->addItem(QStringLiteral("FlatCap"),Qt::FlatCap);penCapComboBox->addItem(QStringLiteral("RoundCap"),Qt::RoundCap);connect(penCapComboBox,SIGNAL(activated(int)),this,SLOT (ShowPenCap (int)));penJoinLabel =new QLabel(QStringLiteral("畫筆連接點:"));//畫筆連接點風格選擇下拉列表框penJoinComboBox =new QComboBox;penJoinComboBox->addItem(QStringLiteral("BevelJoin"),Qt::BevelJoin);penJoinComboBox->addItem(QStringLiteral("MiterJoin"),Qt::MiterJoin);penJoinComboBox->addItem(QStringLiteral("RoundJoin"),Qt::RoundJoin);connect(penJoinComboBox,SIGNAL(activated(int)),this,SLOT (ShowPenJoin (int)));fillRuleLabel =new QLabel(QStringLiteral("填充模式:"));      //填充模式選擇下拉列表框fillRuleComboBox =new QComboBox;fillRuleComboBox->addItem(QStringLiteral("Odd Even"),Qt::OddEvenFill);fillRuleComboBox->addItem(QStringLiteral("Winding"),Qt::WindingFill);connect(fillRuleComboBox,SIGNAL(activated(int)),this,SLOT (ShowFillRule()));spreadLabel =new QLabel(QStringLiteral("鋪展效果:"));        //鋪展效果選擇下拉列表框spreadComboBox =new QComboBox;spreadComboBox->addItem(QStringLiteral("PadSpread"),QGradient::PadSpread);														 //(f)spreadComboBox->addItem(QStringLiteral("RepeatSpread"),QGradient:: RepeatSpread);spreadComboBox->addItem(QStringLiteral("ReflectSpread"),QGradient:: ReflectSpread);connect(spreadComboBox,SIGNAL(activated(int)),this,SLOT (ShowSpreadStyle()));brushColorLabel =new QLabel(QStringLiteral("畫刷顏色:"));    //畫刷顏色選擇控件brushColorFrame =new QFrame;brushColorFrame->setFrameStyle(QFrame::Panel|QFrame::Sunken);brushColorFrame->setAutoFillBackground(true);brushColorFrame->setPalette(QPalette(Qt::green));brushColorBtn =new QPushButton(QStringLiteral("更改"));connect(brushColorBtn,SIGNAL(clicked()),this,SLOT (ShowBrushColor()));brushStyleLabel =new QLabel(QStringLiteral("畫刷風格:"));	//畫刷風格選擇下拉列表框brushStyleComboBox =new QComboBox;brushStyleComboBox->addItem(QStringLiteral("SolidPattern"),static_cast<int>(Qt::SolidPattern));brushStyleComboBox->addItem(QStringLiteral("Dense1Pattern"),static_cast<int>(Qt::Dense1Pattern));brushStyleComboBox->addItem(QStringLiteral("Dense2Pattern"),static_cast<int>(Qt::Dense2Pattern));brushStyleComboBox->addItem(QStringLiteral("Dense3Pattern"),static_cast<int>(Qt::Dense3Pattern));brushStyleComboBox->addItem(QStringLiteral("Dense4Pattern"),static_cast<int>(Qt::Dense4Pattern));brushStyleComboBox->addItem(QStringLiteral("Dense5Pattern"),static_cast<int>(Qt::Dense5Pattern));brushStyleComboBox->addItem(QStringLiteral("Dense6Pattern"),static_cast<int>(Qt::Dense6Pattern));brushStyleComboBox->addItem(QStringLiteral("Dense7Pattern"),static_cast<int>(Qt::Dense7Pattern));brushStyleComboBox->addItem(QStringLiteral("HorPattern"),static_cast<int>(Qt::HorPattern));brushStyleComboBox->addItem(QStringLiteral("VerPattern"),static_cast<int>(Qt::VerPattern));brushStyleComboBox->addItem(QStringLiteral("CrossPattern"),static_cast<int>(Qt::CrossPattern));brushStyleComboBox->addItem(QStringLiteral("BDiagPattern"),static_cast<int>(Qt::BDiagPattern));brushStyleComboBox->addItem(QStringLiteral("FDiagPattern"),static_cast<int>(Qt::FDiagPattern));brushStyleComboBox->addItem(QStringLiteral("DiagCrossPattern"),static_cast<int>(Qt:: DiagCrossPattern));brushStyleComboBox->addItem(QStringLiteral("LinearGradientPattern"),static_cast<int>(Qt:: LinearGradientPattern));brushStyleComboBox->addItem(QStringLiteral("ConicalGradientPattern"),static_cast<int>(Qt:: ConicalGradientPattern));brushStyleComboBox->addItem(QStringLiteral("RadialGradientPattern"),static_cast<int>(Qt:: RadialGradientPattern));brushStyleComboBox->addItem(QStringLiteral("TexturePattern"),static_cast<int>(Qt::TexturePattern));connect(brushStyleComboBox,SIGNAL(activated(int)),this,SLOT (ShowBrush(int)));rightLayout =new QGridLayout;                   //控制面板的布局rightLayout->addWidget(shapeLabel,0,0);rightLayout->addWidget(shapeComboBox,0,1);rightLayout->addWidget(penColorLabel,1,0);rightLayout->addWidget(penColorFrame,1,1);rightLayout->addWidget(penColorBtn,1,2);rightLayout->addWidget(penWidthLabel,2,0);rightLayout->addWidget(penWidthSpinBox,2,1);rightLayout->addWidget(penStyleLabel,3,0);rightLayout->addWidget(penStyleComboBox,3,1);rightLayout->addWidget(penCapLabel,4,0);rightLayout->addWidget(penCapComboBox,4,1);rightLayout->addWidget(penJoinLabel,5,0);rightLayout->addWidget(penJoinComboBox,5,1);rightLayout->addWidget(fillRuleLabel,6,0);rightLayout->addWidget(fillRuleComboBox,6,1);rightLayout->addWidget(spreadLabel,7,0);rightLayout->addWidget(spreadComboBox,7,1);rightLayout->addWidget(brushColorLabel,8,0);rightLayout->addWidget(brushColorFrame,8,1);rightLayout->addWidget(brushColorBtn,8,2);rightLayout->addWidget(brushStyleLabel,9,0);rightLayout->addWidget(brushStyleComboBox,9,1);QHBoxLayout *mainLayout =new QHBoxLayout(this);  //整體的布局mainLayout->addWidget(paintArea);mainLayout->addLayout(rightLayout);mainLayout->setStretchFactor(paintArea,1);mainLayout->setStretchFactor(rightLayout,0);ShowShape(shapeComboBox->currentIndex());        //顯示默認的圖形
}
  • shapeComboBox->addItem(QStringLiteral(“Line”),PaintArea::Line):QComboBox的addItem函數可以僅插入文本,也可以同時插入文本相對應的具體數據,通常為枚舉類型數據,便于后面操作時確定選擇的是哪個數據。
  • penStyleComboBox->addItem(QStringLiteral(“SolidLine”), static_cast(Qt::SolidLine)):選用不同的參數,對應畫筆的不同風格,如下圖所示。
    在這里插入圖片描述
  • penCapComboBox->addItem(QStringLiteral(“SquareCap”),Qt::SquareCap):選用不同的參數,對應畫筆頂帽的不同風格,如下圖所示。
    在這里插入圖片描述
    其中,Qt::SquareCap表示在線條的頂點處是方形的,且線條繪制的區域包括了端點,并且再往外延伸半個線寬長度;Qt::FlatCap表示在線條的頂點處是方形的,但線條繪制區域不包括端點在內;Qt::RoundCap表示在線條的頂點處是圓形,且線條繪制區域包含了端點。
  • penJoinComboBox->addItem(QStringLiteral(“BevelJoin”),Qt::BevelJoin):選用不同的參數,對應畫筆連接點的不同風格,如下圖所示。
    在這里插入圖片描述
    其中,Qt::BevelJoin風格連接點是指兩條線的中心線頂點相匯,相接處依然保留線條各自的方形頂端;Qt::MiterJoin風格連接點是指兩條線的中心頂點相匯,相連處線條延長到線的外側匯集至點,形成一個尖頂的連接;Qt::RoundJoin風格連接點是指兩條線的中心線頂點相匯,相連處圓弧形連接。
  • fillRuleComboBox->addItem(QStringLiteral(“Odd Even”),Qt::OddEvenFill):Qt為QPainterPath類提供了兩種填充規則,分別是Qt::OddEvenFill和Qt::WindingFill,如下圖所示。這兩種填充規則在判定圖形中某一點處于內部還是外部時,判斷依據不同。
    在這里插入圖片描述
    其中,Qt::OddEvenFill填充規則判斷的依據是從圖形中某一點畫一條水平線到圖形外。若這條水平線與圖形邊線的交點數目為奇數,則說明此點位于圖形的內部;若交點數目為偶數,則此點位于圖形的外部,如下圖所示。
    在這里插入圖片描述
    而Qt::WindingFill填充規則的判斷依據則是從圖形中某一點畫一條水平線到圖形外,每個交點外邊線的方向可能向上,也可能向下,將這些交點數累加,方向相反的相互抵消,若最后結果不為0則說明此點在圖形內,若最后結果為0則說明在圖形外,如下圖所示。
    在這里插入圖片描述
    其中,邊線方向是由QPainterPath創建時根據描述的順序決定的。如果采用addRect()或addPolygon()等函數加入圖形,默認是按順時針方向。
  • spreadComboBox->addItem(QStringLiteral(“PadSpread”),QGradient::PadSpread):鋪展效果有三種,分別為QGradient::PadSpread、QGradient::RepeatSpread和QGradient::ReflectSpread。其中,PadSpread是默認的鋪展效果,也是最常見的鋪展效果,沒有被漸變覆蓋的區域填充單一的起始顏色或終止顏色;RepeatSpread效果與ReflectSpread效果只對線性漸變和圓形漸變起作用,如下圖所示。
    在這里插入圖片描述
    使用QGradient的setColorAt()函數設置起止的顏色,其中,第一個參數表示所設顏色點的位置,取值范圍為0.0~1.0,0.0表示起點,1.0表示終點;第二個參數表示該點的顏色值。除可設置起點和終點的顏色外,如有需要還可以設置中間任意位置的顏色,例如,setColorAt(0.3,Qt::white),設置起、終點之間1/3位置的顏色為白色。
  • brushStyleComboBox->addItem(QStringLiteral(“SolidPattern”), static_cast(Qt::SolidPattern)):選用不同的參數,對應畫刷的不同風格,如下圖所示。
    在這里插入圖片描述

ShowShape()槽函數,根據當前下拉列表框中選擇的選項,調用PaintArea類的setShape()函數設置PaintArea對象的形狀參數,具體代碼如下:

void MainWidget::ShowShape(int value)
{PaintArea::Shape shape = PaintArea::Shape(shapeComboBox->itemData(value,Qt::UserRole).toInt());paintArea->setShape(shape);
}

其中QComboBox類的itemData方法返回當前顯示的下拉列表框數據,是一個QVariant對象,此對象與控件初始化時插入枚舉型數據相關,調用QVariant類的toInt()函數獲得此數據在枚舉類型集合中的序號。
ShowPenColor()槽函數,利用標準顏色對話框QColorDialog獲取所選顏色,采用QFrame和QPushButton對象組合完成,QFrame對象負責顯示當前所選擇的顏色,QPushButton對象用于觸發標準顏色對話框進行顏色的選擇。
在此函數中獲得與畫筆相關的所有屬性值,包括畫筆顏色、畫筆線寬、畫筆風格、畫筆頂帽及畫筆連接點,共同構成QPen對象,并調用PaintArea對象的setPen()函數設置PaintArea對象的畫筆屬性。其他畫筆參數相關的響應函數完成的工作與此類似,具體代碼如下:

void MainWidget::ShowPenColor()
{QColor color = QColorDialog::getColor(static_cast<int>(Qt::blue));penColorFrame->setPalette(QPalette(color));int value = penWidthSpinBox->value();Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(),Qt::UserRole).toInt());Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(),Qt::UserRole).toInt());Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(),Qt::UserRole).toInt());paintArea->setPen(QPen(color,value,style,cap,join));
}

ShowPenWidth()槽函數的具體實現代碼如下:

void MainWidget::ShowPenWidth(int value)
{QColor color = penColorFrame->palette().color(QPalette::Window);Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(),Qt::UserRole).toInt());Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(),Qt::UserRole).toInt());Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(),Qt::UserRole).toInt());paintArea->setPen(QPen(color,value,style,cap,join));
}

ShowPenStyle()槽函數的具體實現代碼如下:

void MainWidget::ShowPenStyle(int styleValue)
{QColor color = penColorFrame->palette().color(QPalette::Window);int value = penWidthSpinBox->value();Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(styleValue,Qt::UserRole).toInt());Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(),Qt::UserRole).toInt());Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(),Qt::UserRole).toInt());paintArea->setPen(QPen(color,value,style,cap,join));
}

ShowPenCap()槽函數的具體實現代碼如下:

void MainWidget::ShowPenCap(int capValue)
{QColor color = penColorFrame->palette().color(QPalette::Window);int value = penWidthSpinBox->value();Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(),Qt::UserRole).toInt());Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(capValue,Qt::UserRole).toInt());Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(),Qt::UserRole).toInt());paintArea->setPen(QPen(color,value,style,cap,join));
}

ShowPenJoin()槽函數的具體實現代碼如下:

void MainWidget::ShowPenJoin(int joinValue)
{QColor color = penColorFrame->palette().color(QPalette::Window);int value = penWidthSpinBox->value();Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(),Qt::UserRole).toInt());Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(),Qt::UserRole).toInt());Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(joinValue,Qt::UserRole).toInt());paintArea->setPen(QPen(color,value,style,cap,join));
}

ShowFillRule()槽函數的具體實現代碼如下:

void MainWidget::ShowFillRule()
{Qt::FillRule rule = Qt::FillRule(fillRuleComboBox->itemData(fillRuleComboBox->currentIndex(),Qt::UserRole).toInt());paintArea->setFillRule(rule);
}

ShowSpreadStyle()槽函數的具體實現代碼如下:

void MainWidget::ShowSpreadStyle()
{spread = QGradient::Spread(spreadComboBox->itemData(spreadComboBox->currentIndex(),Qt::UserRole).toInt());
}

ShowBrushColor()槽函數,與設置畫筆顏色函數類似,但選定顏色后并不直接調用PaintArea對象的setBrush()函數,而是嗲用ShowBrush()函數設置顯示區的畫刷屬性,具體實現代碼如下:

void MainWidget::ShowBrushColor()
{QColor color = QColorDialog::getColor(static_cast<int>(Qt:: blue));brushColorFrame->setPalette(QPalette(color));ShowBrush(brushStyleComboBox->currentIndex());
}

ShowBrush()槽函數具體實現代碼如下:

void MainWidget::ShowBrush(int value)
{//獲得畫刷的顏色QColor color = brushColorFrame->palette().color(QPalette:: Window);Qt::BrushStyle style = Qt::BrushStyle(brushStyleComboBox-> itemData(value,Qt::UserRole).toInt());if(style == Qt::LinearGradientPattern)	{QLinearGradient linearGradient(0,0,400,400);linearGradient.setColorAt(0.0,Qt::white);linearGradient.setColorAt(0.2,color);linearGradient.setColorAt(1.0,Qt::black);linearGradient.setSpread(spread);paintArea->setBrush(linearGradient);}else if(style == Qt::RadialGradientPattern){QRadialGradient radialGradient(200,200,150,150,100);radialGradient.setColorAt(0.0,Qt::white);radialGradient.setColorAt(0.2,color);radialGradient.setColorAt(1.0,Qt::black);radialGradient.setSpread(spread);paintArea->setBrush(radialGradient);}else if(style == Qt::ConicalGradientPattern){QConicalGradient conicalGradient(200,200,30);conicalGradient.setColorAt(0.0,Qt::white);conicalGradient.setColorAt(0.2,color);conicalGradient.setColorAt(1.0,Qt::black);paintArea->setBrush(conicalGradient);}else if(style == Qt::TexturePattern){paintArea->setBrush(QBrush(QPixmap("butterfly.png")));}else{paintArea->setBrush(QBrush(color,style));}
}
  • Qt::BrushStyle style = Qt::BrushStyle(brushStyleComboBox-> itemData(
    value,Qt::UserRole).toInt()):獲得所選的畫刷風格,若選擇的是漸變或者紋理圖案,則需要進行一定處理。
  • if(style == Qt::LinearGradientPattern):
    主窗口的style變量值為Qt::LinearGradientPattern時,表明選擇的是圓形漸變。
    QLinearGradient(const QPointF &start, const QPointF &finalStop)創建線性漸變類對象需要兩個參數,分別表示起止點位置。
  • if(style == Qt::RadialGradientPattern):主窗口style變量值為Qt::RadialGradientPattern時,表明選擇的是圓形漸變。
    QRadialGradient(const QPointF &center, qreal radius, const QPointF &focalPoint)創建圓形漸變類對象需要三個參數,分別表示圓心位置、半徑值和焦點位置。QRadialGradient(const QPointF &center, qreal radius, const QPointF &focalPoint)表示以center為作為圓心和焦點位置,以center和focalPoint之間的距離radius為半徑,當然圓心和焦點的位置也可以不重合。
  • if(style == Qt::ConicalGradientPattern):主窗口的style變量值為Qt::ConicalGradientPattern時,表明選擇的是錐形漸變。
    QConicalGradient(const QPointF &center, qreal angle)創建錐形漸變類對象需要兩個參數,分別是錐形的頂點位置和漸變分界線與水平方向的夾角,如下圖所示。錐形漸變不需要設置鋪展效果,它的鋪展效果只能是QGradient::PadSpread (注意:錐形漸變的方向默認是逆時針方向)
    在這里插入圖片描述

雙緩沖機制

原理與設計

所謂雙緩沖機制,是指在繪制控件時,首先將要繪制的內容繪制在一個圖片中,再將圖片一次性地繪制到控件上。在早期地Qt本版中,若直接在控件上進行繪制工作,則在控件重繪時會產生閃爍地現象,控件重繪頻繁時,閃爍尤為明顯。雙緩沖機制可以有效地消除這種閃爍現象。自Qt5版本之后,QWidget控件已經能夠自動處理閃爍地問題。因此,在控件上直接繪圖時,不用再操心顯示的閃爍問題,但雙緩沖機制在很多場合仍然尤其用武之地。當所需繪制的內容比較復雜并需要頻繁刷新,或者每次只需要刷新整個控件的一小部分時,仍應盡量采用雙緩沖機制。

創建一個DrawWidget項目實現一個簡單的繪圖工具,可以選擇線型、線寬、顏色等基本要素,如下圖所示。QMainWindows對象作為主窗口,QToolBar對象作為工具欄,QWidget對象作為主窗口的中央窗體,也就是繪圖區。
在這里插入圖片描述
由于本實例是完成一個通過響應鼠標事件進行繪圖的功能,而這是在繪圖區窗體完成的,所以首先實現此窗體DrawWidget對鼠標事件進行重定義;然后實現可以選擇線型、線寬及顏色等基本要素的主窗口。

繪圖區的實現

DrawWidget類繼承自QWidget類,在類聲明中對鼠標事件mousePressEvent()和mouseMoveEvent()、重繪事件paintEvent()、尺寸變化事件resizeEvent()進行了重定義。setStyle()、setWidth()及setColor()函數主要用于為主窗口傳遞各種與繪圖有關的參數。

DrawWidget類布局代碼如下:

DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent)
{setAutoFillBackground(true);    	//對窗體背景色的設置setPalette(QPalette(Qt::white));pix =new QPixmap(size());           //此QPixmap對象用來準備隨時接收繪制的內容pix->fill(Qt::white);            	//填充背景色為白色setMinimumSize(600,400);            //設置繪制區窗體的最小尺寸
}

setStyle函數接收主窗口傳來的線型風格參數,setWidth函數接收主窗口傳來的線寬參數值,setColor函數接收主窗口傳來的畫筆顏色值。具體代碼如下:

void DrawWidget::setStyle(int s)
{style = s;
}
void DrawWidget::setWidth(int w)
{weight = w;
}
void DrawWidget::setColor(QColor c)
{color = c;
}

重定義鼠標按下事件mousePressEvent函數,在按下鼠標按鍵時,記錄當前的鼠標位置值startPos。

void DrawWidget::mousePressEvent(QMouseEvent *e)
{startPos = e->pos();
}

重定義鼠標事件mouseMoveEvent,鼠標移動事件在默認情況下,在刷表按鍵按下的同時拖拽鼠標時被觸發。
QWidget的mouseTracking屬性指示窗體是否追蹤鼠標,默認為false(不追蹤),即在至少有一個鼠標按鍵被按下的前提下移動鼠標才觸發mouseMoveEvent事件,可以通過setMouseTracking(bool enable)方法對該屬性值進行設置。如果設置的追蹤,則無論鼠標按鍵是否按下,只要鼠標移動,就會觸發mouseMoveEvent事件。在此事件處理函數中,完成QPixmap對象中繪圖的工作。具體代碼如下:

void DrawWidget::mouseMoveEvent(QMouseEvent *e)
{QPainter *painter = new QPainter;		//新建一個QPainter對象QPen pen;								//新建一個QPen對象pen.setStyle((Qt::PenStyle)style);	pen.setWidth(weight);					//設置畫筆的線寬值pen.setColor(color);					//設置畫筆的顏色painter->begin(pix);painter->setPen(pen);					//將QPen對象應用到繪制對象中//繪制從startPos到鼠標當前位置的直線painter->drawLine(startPos,e->pos());painter->end();startPos =e->pos();				//更新鼠標的當前位置,為下次繪制做準備update();						//重繪繪制區窗體
}
  • pen.setStyle((Qt::PenStyle)style):設置畫筆的線型,style表示當前選擇的線型是Qt::PenStyle枚舉數據的第幾個元素。
  • painter->begin(pix)、painter->end():以QPixmap對象為QPaintDevice參數繪制。在構造一個QPainter對象時,就立即開始對繪畫進行繪制。此構造QPainter對象是短時期的,如應定義在QWidget::paintEvent中,并只能調用一次。此構造函數調用開始于begin函數,并且在QPainter的析構函數中自動調用end函數。由于一個QPainter對象的初始化失敗時構造函數不能提供反饋信息,所以在繪制外部設備時應使用begin和end函數,如打印機等外部設備。
    下面是使用begin和end函數的一個例子:
void DrawWidget::paintEvent(QPaintEvent *)
{QPainter painter;painter->begin(this);painter->drawLine(...);painter->end();
}

類似下面的形式:

void DrawWidget::paintEvent(QPaintEvent *)
{QPainter painter(this);painter.drawLine(...;
}

重繪函數paintEvent完成繪制區窗體的更新工作,只需要用drawPixmap函數將用于接收圖形繪制的QPixmao對象繪制再繪制區窗體控件上。具體代碼如下:

void DrawWidget::paintEvent(QPaintEvent *)
{QPainter painter(this);painter.drawPixmap(QPoint(0,0),*pix);
}

調整繪制區大小函數resizeEvent,當窗體的大小發生改變時,效果看起來像是繪制區大小改變了,但實際能夠進行繪制的區域仍然沒有改變。因為繪圖的大小并沒有改變,還是原來繪制區窗口的大小,所以在窗體尺寸變化是應及時調整用于繪制的QPixmap對象的大小。具體代碼如下:

void DrawWidget::resizeEvent(QResizeEvent *event)
{if(height()>pix->height()||width()>pix->width()){QPixmap *newPix = new QPixmap(size());	//創建一個新的QPixmap對象newPix->fill(Qt::white);                //填充新QPixmap對象newPix的顏色為白色背景色QPainter p(newPix);p.drawPixmap(QPoint(0,0),*pix);         //在newPix中繪制原pix中的內容pix = newPix;                           //將newPix賦值給pix作為新的繪制圖形接收對象}QWidget::resizeEvent(event);                //完成其余的工作
}
  • if(height()>pix->height()||width()>pix->width()):判斷改變后的窗體長或寬是否大于原窗體的長和寬。若大于則進行相應的調整,否則直接調用QWidget的resizeEvent函數返回。
    clear函數完成繪制區的清楚工作,只需要調用一個新的、干凈的QPixmap對象來代替pix,并調用update函數重繪即可。具體代碼如下:
void DrawWidget::clear()
{QPixmap *clearPix =new QPixmap(size());clearPix->fill(Qt::white);pix = clearPix;update();
}

至此,一個能夠響應鼠標事件進行繪圖功能的窗體類DrawWidget已實現,可以進行接下來的工作,即在主窗口中應用此窗體類。

主窗口的實現

主窗口類MainWindow類繼承了QMainWindow類,只包含一個工具欄和一個中央窗體。首先,聲明一個構造函數、一個用于創建工具欄的函數createToolBar、一個用于進行選擇線型風格的槽函數ShowStyle和一個用于進行顏色選擇的槽函數ShowColor。然后,聲明一個DrawWidget類對象作為窗口的私有變量,以及聲明代表線型風格、線寬選擇、顏色選擇及清除按鈕的私有變量。
主界面構建代碼邏輯如下:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{drawWidget =new DrawWidget;     //新建一個DrawWidget對象setCentralWidget(drawWidget);	//新建的DrawWidget對象作為主窗口的中央窗體createToolBar();               	//實現一個工具欄setMinimumSize(600,400);      	//設置主窗口的最小尺寸ShowStyle();                    //初始化線型,設置控件中的當前值作為初始值drawWidget->setWidth(widthSpinBox->value());        //初始化線寬drawWidget->setColor(Qt::black);             		//初始化顏色
}

createToolBar實現一個工具函數功能代碼如下:

void MainWindow::createToolBar()
{QToolBar *toolBar = addToolBar("Tool");  				//為主窗口新建一個工具欄對象styleLabel =new QLabel(QStringLiteral("線型風格:"));   	//創建線型選擇控件styleComboBox =new QComboBox;styleComboBox->addItem(QStringLiteral("SolidLine"),static_cast<int>(Qt::SolidLine));styleComboBox->addItem(QStringLiteral("DashLine"),static_cast<int>(Qt::DashLine));styleComboBox->addItem(QStringLiteral("DotLine"),static_cast<int>(Qt::DotLine));styleComboBox->addItem(QStringLiteral("DashDotLine"),static_cast<int>(Qt::DashDotLine));styleComboBox->addItem(QStringLiteral("DashDotDotLine"),static_cast<int>(Qt::DashDotDotLine));//關聯相應的槽函數connect(styleComboBox,SIGNAL(activated(int)),this,SLOT(ShowStyle()));widthLabel =new QLabel(QStringLiteral("線寬:"));   //創建線寬選擇控件widthSpinBox =new QSpinBox;connect(widthSpinBox,SIGNAL(valueChanged(int)),drawWidget,SLOT (setWidth(int)));colorBtn =new QToolButton;                  //創建顏色選擇控件QPixmap pixmap(20,20);pixmap.fill(Qt::black);colorBtn->setIcon(QIcon(pixmap));connect(colorBtn,SIGNAL(clicked()),this,SLOT(ShowColor()));clearBtn =new QToolButton();               	//創建清除按鈕clearBtn->setText(QStringLiteral("清除"));connect(clearBtn,SIGNAL(clicked()),drawWidget,SLOT(clear()));toolBar->addWidget(styleLabel);toolBar->addWidget(styleComboBox);toolBar->addWidget(widthLabel);toolBar->addWidget(widthSpinBox);toolBar->addWidget(colorBtn);toolBar->addWidget(clearBtn);
}

改變線型參數的槽函數ShowStyle,通過調用DrawWidget類的setStyle函數將當前線型選擇控件中的線型參數傳給繪制區;設置畫筆顏色的槽函數ShowColor,通過調用DrawWidget類的setColor函數將用戶在標準顏色對話框中選擇的顏色值傳給繪制區。這兩個函數的具體代碼如下:

void MainWindow::ShowStyle()
{drawWidget->setStyle(styleComboBox->itemData(styleComboBox->currentIndex(),Qt::UserRole).toInt());
}void MainWindow::ShowColor()
{QColor color = QColorDialog::getColor(static_cast<int> (Qt::black), this);//使用標準顏色對話框QColorDialog獲得一個顏色值if(color.isValid()){//將新選擇的顏色傳給繪制區,用于改變畫筆的顏色值drawWidget->setColor(color);QPixmap p(20,20);p.fill(color);colorBtn->setIcon(QIcon(p));		//更新顏色選擇按鈕上的顏色顯示}
}

顯示Qt5 SVG格式圖片

SVG的英文全稱是Scalable Vector Graphics,即可縮放的矢量圖形。它是由萬維網聯盟在2000年8月制定的一種新的二維矢量圖形格式,也是規范中的網格矢量圖形標準,是一個開放的圖形標準。

SVG格式的特點如下:

  1. 基于XML。
  2. 采用文本來描述對象。
  3. 具有交互性和動態性。
  4. 完全支持DOM。

SVG相對于GIF、JPEG格式的優勢是,SVG是一種矢量圖形格式,比GIF、JPEG等柵格格式具有眾多優勢,如文件小,對于網絡而言,下載速度快;可任意縮放而不會破壞圖像的清晰度和細節;圖像中的文字獨立于圖像,文字保留可編輯和可搜尋的狀態,也沒有字體限制,用戶系統即使沒有安裝某一種字體,也可以看到與制作時完全相同的畫面等。正式基于其格式的各種優點及開放性,SVG得到了眾多組織和知名廠商的支持與認可,因此能夠迅速地開發和推廣應用。
Qt為SVG格式圖片地顯示與生成提供了專門的QtSvg模塊,此模塊中包含了與SVG圖片相關的所有類,主要有QSvgWidget、QSvgRender和QGraphicsSvgItem。

創建一個SVGTest項目,通過利用QSvgWidget類和QSvgRenderer類實現一個SVG圖片瀏覽器,顯示以".svg"結尾的文件以介紹SVG格式圖片顯示的方法,顯示效果如下圖所示。
在這里插入圖片描述
注意,在此我們使用了顯示SVG的控件,需要在Makefile添加svg模塊的庫,如下圖所示。
在這里插入圖片描述

打開svgwidget.cpp文件,在SvgWidget類構造函數獲得本窗體的QSvgRenderer對象,具體代碼如下:

SvgWidget::SvgWidget(QWidget *parent):QSvgWidget(parent)
{render =renderer();
}

以下是鼠標滾輪的響應事件,使SVG圖片能夠通過鼠標滾輪的滾動進行縮放。具體代碼如下:

void SvgWidget::wheelEvent(QWheelEvent *e)
{const double diff=0.1;QSize size =render->defaultSize();int width =size.width();int height =size.height();if(e->delta()>0){//對圖片的長、寬值進行處理,放大一定的比例width =int(this->width()+this->width()*diff);height =int(this->height()+this->height()*diff);}else{//對圖片的長、寬值進行處理,縮小一定的比例width =int(this->width()-this->width()*diff);height =int(this->height()-this->height()*diff);}resize(width,height);	//利用新的長、寬值對圖片進行resize()操作
}
  • const double diff=0.1:diff的值表示每次滾動一定的值,圖片大小改變的比例。
  • QSize size =render->defaultSize():該行代碼及下面兩行代碼用于獲取圖片顯示區的尺寸,以便進行下一步的縮放操作。
  • if(e->delta()>0):利用QWheelEvent的delta函數獲得滾動的距離值,通過此值來判斷滾輪滾動的方向。若delta值大于0,則表示滾輪向前(遠離用戶的方向)滾動;若小于0則表示向后(靠近用戶的方向)滾動。
    鼠標滾動事件,滾輪每滾動1°相當于移動了8°,而常見的滾輪鼠標撥動以下滾動的角度為15°,因此滾輪波動一下相當于移動了120(=15*8)。

SvgWindow類繼承自QScrollArea類,是一個帶滾動條的顯示區域。在SvgWindow類實現中包含SvgWidget類的頭文件。SvgWindow類使圖片在放大到超過主窗口大小時,能夠通過拖拽滾動條的方式進行查看。
SvgWindow類的構造函數,構造SvgWidget對象,并調用QScrollArea類的setWidget函數設置滾動區的窗體,使svgWidget成為SvgWindow的子窗口。具體代碼如下。

SvgWindow::SvgWindow(QWidget *parent):QScrollArea(parent)
{svgWidget =new SvgWidget;setWidget(svgWidget);
}

當主窗口中對文件進行了選擇或修改時,將調用setFile函數設置新的文件,具體代碼如下:

void SvgWindow::setFile(QString fileName)
{svgWidget->load(fileName);QSvgRenderer *render =svgWidget->renderer();svgWidget->resize(render->defaultSize());
}
  • svgWidget->load(fileName):將新的SVG文件加載到svgWidget中進行顯示。
  • svgWidget->resize(render->defaultSize()):使svgWidget窗體按SVG圖片的默認尺寸進行顯示。

當鼠標被按下時,對mousePressPos和scrollBarValuesOnMousePress進行初始化,QScrollArea類的horizontalScrollBar和verticalScrollBar函數可以分別獲得svgWidget的水平滾動條和垂直滾動條。具體代碼如下:

void SvgWindow::mousePressEvent(QMouseEvent *event)
{mousePressPos =event->pos();scrollBarValuesOnMousePress.rx()=horizontalScrollBar()->value();scrollBarValuesOnMousePress.ry()=verticalScrollBar()->value();event->accept();
}

當鼠標被按下并拖拽鼠標時觸發mouseMoveEvent函數,通過滾動條的位置設置實現圖片的拖拽效果,具體代碼如下:

void SvgWindow::mouseMoveEvent(QMouseEvent *event)
{//對水平滑動條的新位置進行設置horizontalScrollBar()->setValue(scrollBarValuesOnMousePress.x()-event->pos().x()+mousePressPos.x());//對垂直滑動條的新位置進行設置verticalScrollBar()->setValue(scrollBarValuesOnMousePress.y()-event->pos().y()+mousePressPos.y());horizontalScrollBar()->update();verticalScrollBar()->update();event->accept();
}

主窗口MainWindow繼承QMainWindow類,包含一個菜單欄,其中有一個“文件”菜單條,包含一個“打開”菜單項。
MainWindow構造函數中,創建一個SvgWindow對象作為主窗口的中央窗體。具體代碼如下:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{setWindowTitle(QStringLiteral("SVG Viewer"));createMenu();svgWindow =new SvgWindow;setCentralWidget(svgWindow);setMinimumSize(400, 300);
}

創建菜單欄具體代碼如下:

void MainWindow::createMenu()
{QMenu *fileMenu = menuBar()->addMenu(QStringLiteral("文件"));QAction *openAct = new QAction(QStringLiteral("打開"),this);connect(openAct,SIGNAL(triggered()),this,SLOT(slotOpenFile()));fileMenu->addAction(openAct);
}

通過標準文件對話框選擇SVG文件,并調用SvgWindow窗口的setFile函數將選擇的文件名傳遞給svgWindow進行顯示,具體代碼如下:

void MainWindow::slotOpenFile()
{QString name =QFileDialog::getOpenFileName(this, QStringLiteral("打開"),"./","svg files(*.svg)");svgWindow->setFile(name);
}

工程源碼

文章設計所有代碼可點擊工程源碼下載查看。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/44060.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/44060.shtml
英文地址,請注明出處:http://en.pswp.cn/web/44060.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

暑假自律日記十

7.11 &#xff08;半小時日記打卡之——暑假第十天&#xff09; 日程 8.30起床 9.20到達逸夫樓開始總結區間DP&#xff0c;上午完成了區間DP和四邊形優化部分的學習 下午組隊打了一場去年的牛客多校&#xff0c;壓力有點大&#xff0c;問題也有點多&#xff0c;總而言之&…

GD32F303RET6讀取SGM58031電壓值

1、SGM58031芯片詳解 &#xff08;1&#xff09;SGM58031是一款低功耗&#xff0c;16位精度&#xff0c;delta-sigma (ΔΣ)模數轉換器(ADC)。它從3V到5.5V供電。 &#xff08;2&#xff09;SGM58031包含一個片上參考和振蕩器。它有一個I2C兼容接口&#xff0c;可以選擇四個I2…

深入Memcached鍵值對限制:優化存儲策略

標題&#xff1a;深入Memcached鍵值對限制&#xff1a;優化存儲策略 Memcached作為一種廣泛使用的高性能分布式內存緩存系統&#xff0c;對鍵值對的大小有特定的限制。這些限制不僅關系到緩存效率&#xff0c;還直接影響到緩存數據的組織和內存的使用。本文將深入探討Memcache…

【RHCE】系統服務綜合實驗

一、實驗內容 現有主機 node01 和 node02&#xff0c;完成如下需求&#xff1a; 1、在 node01 主機上提供 DNS 和 WEB 服務 2、dns 服務提供本實驗所有主機名解析 3、web服務提供 www.rhce.com 虛擬主機 4、該虛擬主機的documentroot目錄在 /nfs/rhce 目錄 5、該目錄由 node02…

Python | Leetcode Python題解之第229題多數元素II

題目&#xff1a; 題解&#xff1a; class Solution:def majorityElement(self, nums: List[int]) -> List[int]:cnt {}ans []for v in nums:if v in cnt:cnt[v] 1else:cnt[v] 1for item in cnt.keys():if cnt[item] > len(nums)//3:ans.append(item)return ans

【conda】解決 An HTTP error occurred when trying to retrieve this URL.問題

1. 修改SSL驗證 如果其他方法無效&#xff0c;還可以嘗試關閉SSL驗證來解決問題。具體操作如下&#xff1a; 在終端中輸入以下命令&#xff0c;關閉SSL驗證&#xff1a; conda config --set ssl_verify false或者&#xff0c;在conda的配置文件&#xff08;.condarc&#xff0…

為什么渲染農場渲染的是幀,而不是視頻?

在3D動畫產業的壯闊畫卷中&#xff0c;渲染農場作為幕后英雄&#xff0c;以其龐大的計算能力支撐起無數視覺奇觀的誕生。這些由高性能計算機集群構成的系統&#xff0c;通過獨特的逐幀渲染策略&#xff0c;解鎖了單機難以企及的創作自由與效率。本文將深入剖析這一策略背后的邏…

maven7——(重要,構建項目)maven項目構建(命令)

Maven的常用命令管理項目的生命周期 clean命令 清除編譯產生的target文件夾內容&#xff0c;可以配合相應命令在cmd中使用&#xff0c;如mvn clean package&#xff0c; mvn clean test D:\工作\公司培訓-4班\day20\day20\untitled1>mvn clean compile命令 該命令可以…

element如何實現自定義表頭?

有時候我們需要實現自定義表頭,例如表頭里加按鈕啥的,這時候就需要用到自定義表頭,但是官方對自定義表頭的使用寫的還是比較簡單,今天就來詳細說說 在需要使用自定義表頭的表頭上使用:render-header來啟用自定義表頭: <el-table-column :render-header="button&…

機器學習開源分子生成系列(2)-基于三維形狀和靜電相似性的DeepFMPO v3D安裝及使用

前言 本文是基于 3D 的分子生成方法DeepFMPO v3D的介紹及安裝使用。 一、DeepFMPO v3D是什么&#xff1f; github代碼介紹文章 在藥物發現中&#xff0c;如何尋找具新穎性和結構多樣性的候選分子是頗受藥物設計科學家關注的問題。通過虛擬篩選的化學空間搜索往往會受限于篩選…

Linux賬戶和組管理——用戶密碼文件,工作組賬號文件,用戶管理

#### 用戶密碼文件 - /etc/shadow存儲密碼加密后的密文&#xff0c;又稱為“影子文件”&#xff0c;該文件為了保證了賬戶密碼的安全性只有 root 賬戶擁有讀權限&#xff0c;注意&#xff1a;若該文件權限發生變化&#xff0c;需要留心惡意攻擊 bash [rootserver ~]# ll /etc/…

linux之棧溢出分析

我們來創建一個例子&#xff0c;其中包含一個段錯誤&#xff0c;這次是由于棧溢出導致的。這是一個常見的錯誤&#xff0c;通常發生在程序遞歸調用深度過大&#xff0c;超出了為棧分配的內存空間。 下面是一個簡單的C程序&#xff0c;stack_overflow_example.c&#xff0c;它通…

優化與改進之輕量級Transformer - Transformer教程

在自然語言處理&#xff08;NLP&#xff09;的世界里&#xff0c;Transformer模型無疑是一顆璀璨的明珠。自從它在2017年被提出以來&#xff0c;就憑借其強大的性能和優雅的設計贏得了廣泛的關注和應用。然而&#xff0c;隨著應用的深入&#xff0c;Transformer的體量和計算資源…

牛頓力學和拉格朗日力學求解atwood machine問題對比

一個半徑為 R R R、轉動慣量為 I I I 的圓盤。繩子與圓盤無滑動&#xff0c;質量 m 2 m_2 m2? 的物體在重力 g g g 作用下下墜&#xff0c;帶動質量 m 1 m_1 m1? 的物體上升。求 m 1 m_1 m1?和 m 2 m_2 m2? 的加速度 a a a。 牛頓力學方法 對質量 m 1 m_1 m1? 和 …

Web 性能入門指南-1.2 分析在線零售 Web 性能及優化方向

讓顧客滿意是零售業成功的秘訣。事實證明&#xff0c;提供快速、一致的在線體驗可以顯著提高零售商關心的每項指標——從轉化率和收入到留存率和品牌認知度。 本文大綱&#xff1a; 頁面速度影響在線零售業務數據 如何將您的網站速度與競爭對手進行比較 性能優化入門&#xf…

Scanner工具類

掃描控制臺輸入 1.nextLine nextLine() 方法會掃描輸入流中的字符&#xff0c;直到遇到行末尾的換行符 \n&#xff0c;然后將該行的內容作為字符串返回&#xff0c;同時&#xff0c;nextLine() 會將 Scanner 對象的位置移動到下一行的開頭&#xff0c;以便下一次讀取數據時從下…

代碼隨想錄day09 151.翻轉字符串里的單詞 、卡碼網:55.右旋轉字符串

代碼隨想錄day09 151.翻轉字符串里的單詞 、卡碼網&#xff1a;55.右旋轉字符串 151. 反轉字符串中的單詞 這題我直接想到的是istringstream 和 stack 但不知道這樣使用是不是違反了規定 class Solution { public:string reverseWords(string s) {istringstream iss(s);stri…

MySQL的約束鍵多表查詢

約束 概念 概念&#xff1a;約束是作用于表中字段上的規則&#xff0c;用于限制存儲在表中的數據。目的&#xff1a;保證數據中數據的正確、有效性和完整性。 外鍵約束 概念 ? 外鍵用來讓兩張表的數據之間建立連接&#xff0c;從而保證數據的一致性和完整性。 注意&#x…

Qt常用基礎控件總結—輸入部件(QComboBox類和QLineEdit)

輸入部件 下拉列表控件QComboBox 類 QComboBox 類是 QWidget 類的直接子類,該類實現了一個下拉列表(組合框)。 QComboBox 類中的屬性函數 1)count:const int 訪問函數:int count() const; 獲取組合框中的項目數量,默認情況下,對于空組合框或未設置當前項目的組合框,…

網絡安全法視角下的等保測評法律責任與風險控制

《網絡安全法》是中國為了保障網絡安全、維護網絡空間主權和國家安全、社會公共利益&#xff0c;保護公民、法人和其他組織的合法權益而制定的一部重要法律。該法于2017年6月1日正式實施&#xff0c;其中對網絡安全等級保護制度&#xff08;簡稱“等保”&#xff09;做出了明確…