Qt中的基础图形绘制
生活随笔
收集整理的這篇文章主要介紹了
Qt中的基础图形绘制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1 Qt中的基礎圖形繪制
- 2 Qt基礎圖形繪制中的視口和窗口
- 3 綜合實例開發:簡易繪圖程序
- 3.1 需求分析
- 3.2 設計分析
1 Qt中的基礎圖形繪制
Qt圖形系統中的關鍵角色:
- QPainter:
- Qt中的畫家,能夠繪制各種基礎圖形。
- 擁有繪圖所需的畫筆(QPen)、畫刷(QBrush)、字體(QFont)。
- QPaintDevice:
- Qt中的畫布,畫家(QPainter)的繪圖板。
- 所有的QWidget類都繼承自QPaintDevice。
畫家QPainter所使用的工具角色:
- QPen:
- 用于繪制幾何圖形的邊緣,由顏色、寬度、線風格參數組成。
- QBrush:
- 用于填充幾何圖形的調色板,由顏色和填充風格組成。
- QFont:
- 用于文本繪制,由字體屬性組成。
QPainter的基本繪圖能力:
重要規則:
- 只能QWidget::paintEvent中繪制圖形。
問題:如何動態繪制需要的圖形?
工程中的解決方案:
Widget.h:
#ifndef WIDGET_H #define WIDGET_H#include <QtGui/QWidget> #include <QPushButton> #include <QPoint> #include <QList>class Widget : public QWidget {Q_OBJECTenum{LINE,RECT,ELLIPSE};struct DrawParam{int type;Qt::PenStyle pen;QPoint begin;QPoint end;};QPushButton m_testBtn;QList<DrawParam> m_list;protected slots:void onTestBtnClicked(); protected:void paintEvent(QPaintEvent *); public:Widget(QWidget *parent = 0);~Widget(); };#endif // WIDGET_HWidget.cpp:
#include "Widget.h" #include <QPainter> #include <QPoint>Widget::Widget(QWidget *parent): QWidget(parent) {m_testBtn.setParent(this);m_testBtn.move(400, 300);m_testBtn.resize(70, 30);m_testBtn.setText("Test");resize(500, 350);connect(&m_testBtn, SIGNAL(clicked()), this, SLOT(onTestBtnClicked())); }void Widget::onTestBtnClicked() {DrawParam dp ={qrand() % 3,static_cast<Qt::PenStyle>(qrand() % 5 + 1),QPoint(qrand() % 400, qrand() % 300),QPoint(qrand() % 400, qrand() % 300)};if( m_list.count() == 5 ){m_list.clear();}m_list.append(dp);update(); }void Widget::paintEvent(QPaintEvent *) {QPainter painter;painter.begin(this);for(int i=0; i<m_list.count(); i++){int x = (m_list[i].begin.x() < m_list[i].end.x()) ? m_list[i].begin.x() : m_list[i].end.x();int y = (m_list[i].begin.y() < m_list[i].end.y()) ? m_list[i].begin.y() : m_list[i].end.y();int w = qAbs(m_list[i].begin.x() - m_list[i].end.x()) + 1;int h = qAbs(m_list[i].begin.y() - m_list[i].end.y()) + 1;painter.setPen(m_list[i].pen);switch(m_list[i].type){case LINE:painter.drawLine(m_list[i].begin, m_list[i].end);break;case RECT:painter.drawRect(x, y, w, h);break;case ELLIPSE:painter.drawEllipse(x, y, w, h);break;default:break;}}painter.end(); }Widget::~Widget() {}main.cpp:
#include <QtGui/QApplication> #include "Widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }2 Qt基礎圖形繪制中的視口和窗口
首先來看下Qt圖形系統中的坐標系:
- 物理坐標系(設備坐標系):
- 原點(0, 0)在左上角的位置,單位:像素(點)。
- x坐標向右增長,y坐標向下增長。
- 邏輯坐標系:
- 數學模型中的抽象坐標系,單位由具體問題決定。
- 坐標軸的增長方向由具體問題決定。
我們必須知道的事實:
- QPainter使用邏輯坐標系繪制圖形。
- 邏輯坐標系中圖形的大小和位置經由轉換后繪制于具體設備。
- 默認情況下的邏輯坐標系與物理坐標系完全一致。
小例子:
- A4紙的大小是固定的,但可以用于繪制任意類型的曲線圖。
視口與窗口的概念:
- 視口(view port):
- 物理坐標系中一個任意指定的矩形。
- 窗口(window):
- 邏輯坐標系下對應到物理坐標系中的相同矩形。
站在不同的角度看同一個矩形,就有了視口和窗口。
深入理解視口和窗口:
- 視口與窗口是不同坐標系中的同一個矩形。
- 視口與窗口中的坐標點存在一一映射的關系。
- 視口與窗口能夠通過坐標變換而相互轉換。
視口與窗口的變換方法:
- 定義視口(setViewPort):
- 左上角坐標,右下角坐標,計算寬度和高度。
- 定義窗口(setWindow):
- 左上角坐標,右下角坐標,計算寬度和高度。
下面看一下正弦波形繪圖實例:
Widget.h:
#ifndef WIDGET_H #define WIDGET_H#include <QtGui/QWidget>class Widget : public QWidget {Q_OBJECTprotected:void paintEvent(QPaintEvent *); public:Widget(QWidget *parent = 0);~Widget(); };#endif // WIDGET_HWidget.cpp:
#include "Widget.h" #include <QPainter> #include <QPointF> #include <QPen> #include <qmath.h>Widget::Widget(QWidget *parent): QWidget(parent) { }void Widget::paintEvent(QPaintEvent *) {QPainter painter(this);QPen pen;pen.setColor(Qt::green);pen.setStyle(Qt::SolidLine);pen.setWidthF(0.01);painter.setPen(pen);painter.setViewport(50, 50, width()-100, height()-100);painter.setWindow(-10, 2, 20, -4); // (-10, 2) (10, -2)painter.fillRect(-10, 2, 20, -4, Qt::black);painter.drawLine(QPointF(-10, 0), QPointF(10, 0)); // xpainter.drawLine(QPointF(0, 2), QPointF(0, -2)); // yfor(float x=-10; x<10; x+=0.01){float y = qSin(x);painter.drawPoint(QPointF(x, y));}}Widget::~Widget() {}main.cpp:
#include <QtGui/QApplication> #include "Widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }3 綜合實例開發:簡易繪圖程序
3.1 需求分析
功能需求:
- 自由圖形繪制。
- 基本圖形繪制(直線、矩形、橢圓)。
- 能夠選擇圖形繪制顏色。
3.2 設計分析
界面解決方案:
自由繪圖分析:
- 自由繪圖的本質是跟蹤鼠標的移動軌跡;因此,必須考慮什么時候開始?什么時候結束?如何記錄鼠標移動?
要點:
- 從繪圖參數的角度,可以將已經繪制結束的圖形與正在繪制的圖形分開處理。
- 自由繪圖必須記錄鼠標移動時經過的所有點坐標。因此,繪圖參數必須有能力保存多個坐標值。
自由繪圖解決方案:
基礎圖形動態繪制分析:
- 基礎圖形的目標是固定的,但是開始點與結束點的不同會導致最終形狀的差異;因此,鼠標移動時根據當前坐標實時繪圖,鼠標松開時確定最終圖形。
- 基本圖形繪制需要在鼠標按下并移動時進行動態繪圖;但是,無論何時都只需要記錄兩個坐標值。
基礎圖形繪制解決方案:
總結一下:
- 繪圖程序需要重寫鼠標事件處理函數。
- 模型視圖的思想適用于繪圖程序。
- 所有圖形的繪制由paintEvent函數完成。
- 工程中需要避免在繪制時進行浮點運算。
Widget.h:
#ifndef WIDGET_H #define WIDGET_H#include <QtGui/QWidget> #include <QRadioButton> #include <QComboBox> #include <QGroupBox> #include <QList> #include <QPoint>class Widget : public QWidget {Q_OBJECTenum DrawType{NONE,FREE,LINE,RECT,ELLIPSE};struct DrawParam{DrawType type;Qt::GlobalColor color;QList<QPoint> points;};QGroupBox m_group;QRadioButton m_freeBtn;QRadioButton m_lineBtn;QRadioButton m_rectBtn;QRadioButton m_ellipseBtn;QComboBox m_colorBox;QList<DrawParam> m_drawList;DrawParam m_current;DrawType drawType();Qt::GlobalColor drawColor();void draw(QPainter& painter, DrawParam& param);void append(QPoint p); protected:void mousePressEvent(QMouseEvent *evt);void mouseMoveEvent(QMouseEvent *evt);void mouseReleaseEvent(QMouseEvent *evt);void paintEvent(QPaintEvent *); public:Widget(QWidget *parent = 0);~Widget(); };#endif // WIDGET_HWidget.cpp:
#include "Widget.h" #include <QMouseEvent> #include <QPainter> #include <QPen> #include <QBrush>Widget::Widget(QWidget *parent): QWidget(parent) {m_group.setParent(this);m_group.setTitle("Setting");m_group.resize(600, 65);m_group.move(20, 20);m_freeBtn.setParent(&m_group);m_freeBtn.setText("Free");m_freeBtn.resize(70, 30);m_freeBtn.move(35, 20);m_freeBtn.setChecked(true);m_lineBtn.setParent(&m_group);m_lineBtn.setText("Line");m_lineBtn.resize(70, 30);m_lineBtn.move(140, 20);m_rectBtn.setParent(&m_group);m_rectBtn.setText("Rect");m_rectBtn.resize(70, 30);m_rectBtn.move(245, 20);m_ellipseBtn.setParent(&m_group);m_ellipseBtn.setText("Ellipse");m_ellipseBtn.resize(70, 30);m_ellipseBtn.move(350, 20);m_colorBox.setParent(&m_group);m_colorBox.resize(80, 25);m_colorBox.move(480, 23);m_colorBox.addItem("Black");m_colorBox.addItem("Blue");m_colorBox.addItem("Green");m_colorBox.addItem("Red");m_colorBox.addItem("Yellow");setFixedSize(width(), 600);m_current.type = NONE;m_current.color = Qt::white;m_current.points.clear(); }Widget::DrawType Widget::drawType() {DrawType ret = NONE;if( m_freeBtn.isChecked() ) ret = FREE;if( m_lineBtn.isChecked() ) ret = LINE;if( m_rectBtn.isChecked() ) ret = RECT;if( m_ellipseBtn.isChecked() ) ret = ELLIPSE;return ret; }Qt::GlobalColor Widget::drawColor() {Qt::GlobalColor ret = Qt::black;if( m_colorBox.currentText() == "Black") ret = Qt::black;if( m_colorBox.currentText() == "Blue") ret = Qt::blue;if( m_colorBox.currentText() == "Green") ret = Qt::green;if( m_colorBox.currentText() == "Red") ret = Qt::red;if( m_colorBox.currentText() == "Yellow") ret = Qt::yellow;return ret; }void Widget::mousePressEvent(QMouseEvent *evt) {m_current.type = drawType();m_current.color = drawColor();m_current.points.append(evt->pos()); }void Widget::mouseMoveEvent(QMouseEvent *evt) {append(evt->pos());update(); }void Widget::mouseReleaseEvent(QMouseEvent *evt) {append(evt->pos());m_drawList.append(m_current);m_current.type = NONE;m_current.color = Qt::white;m_current.points.clear();update(); }void Widget::append(QPoint p) {if( m_current.type != NONE ){if( m_current.type == FREE ){m_current.points.append(p);}else{if( m_current.points.count() == 2 ){m_current.points.removeLast();}m_current.points.append(p);}} }void Widget::paintEvent(QPaintEvent *) {QPainter painter(this);for(int i=0; i<m_drawList.count(); i++){draw(painter, m_drawList[i]);}draw(painter, m_current); }void Widget::draw(QPainter& painter, DrawParam& param) {if( (param.type != NONE) && (param.points.count() >= 2) ){int x = (param.points[0].x() < param.points[1].x()) ? param.points[0].x() : param.points[1].x();int y = (param.points[0].y() < param.points[1].y()) ? param.points[0].y() : param.points[1].y();int w = qAbs(param.points[0].x() - param.points[1].x()) + 1;int h = qAbs(param.points[0].y() - param.points[1].y()) + 1;painter.setPen(QPen(param.color));painter.setBrush(QBrush(param.color));switch(param.type){case FREE:for(int i=0; i<param.points.count()-1; i++){painter.drawLine(param.points[i], param.points[i+1]);}break;case LINE:painter.drawLine(param.points[0], param.points[1]);break;case RECT:painter.drawRect(x, y, w, h);break;case ELLIPSE:painter.drawEllipse(x, y, w, h);break;default:break;}} }Widget::~Widget() {}main.cpp:
#include <QtGui/QApplication> #include "Widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }參考資料:
總結
以上是生活随笔為你收集整理的Qt中的基础图形绘制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用从盘装系统怎么装 从外置光驱安装系统步
- 下一篇: 调度锁解决任务间资源共享问题