Lightweight CAD drawing software based on Qt

1. Interface display

2. Function display

Create a new canvas: (The dotted plaid flowers in the background are the reason why the screen recording is converted to gif. There are no flowers in the original video)

Update: Previously, a drawing button could only draw one shape at a time. Later, it was implemented to draw continuously when the button is pressed:

3. About Graphics View drawing architecture

Since QPainter draws graphics, it cannot implement operations such as selecting, editing, and moving graphics, so my entire project is based on the Graphics View drawing architecture.

3.1 Graphics View

(1) Introduction to Graphics View drawing architecture

The Graphics View architecture is mainly divided into three parts: views, scenes, and graphics items (primitives)

  • QGraphicsScene (scene): can manage multiple graphics items
  • QGraphicsItem (graphic item): It is also a graphic element and supports mouse event response.
  • QGraphicsView (view): Associated scenes can visualize all graphic items in the scene

The relationship diagram between scenes, views, and primitives:

(2) Some common operation interfaces in QGrphicsView

//Add scene

//Set the associated display scene

void QGraphicsView::setScene(QGraphicsScene *scene)

// Set the rectangular area of the visible part of the scene in the view

void QGraphicsView::setSceneRect(const QRectF & amp;rect)

//Scene appearance setting operation

//Set the alignment of the scene in the view. The default is to center both top and bottom.

 void QGraphicsView::setAlignment(Qt::Alignment alignment)

//Set the background brush of the scene scene

void QGraphicsView::setBackgroundBrush(const QBrush & amp;brush)

//Set the foreground brush of the scene

void QGraphicsView::setForegroundBrush(const QBrush & amp;brush)

//Set the drawing options of the view

 void QGraphicsView::setRenderHints(QPainter::RenderHints hints)

//Interaction

//Whether the scene is allowed to be interactive, if interaction is prohibited, any keyboard or mouse operations are ignored

void QGraphicsView::setInteractive(bool allowed)

//Return to the selection rectangle

 QRect QGraphicsView::rubberBandRect() const

//Selection mode, the parameter is the enumeration type Qt::ltemSelectionMode

 Qt::ItemSelectionMode rubberBandSelectionMode() const

//Get the graphic item at a certain position in the view coordinate system

QGraphicsItem *QGraphicsView::itemAt(const QPoint & amp;pos) const
QGraphicsItem *QGraphicsView::itemAt(int x, int y) const

//Get a list of all graphic items in the scene or a certain selection area

QList<QGraphicsItem *> QGraphicsView::items() const
QList<QGraphicsItem *> QGraphicsView::items(const QPoint & amp;pos) const
QList<QGraphicsItem *> QGraphicsView::items(int x, int y) const
....

//coordinate

//Convert a coordinate in the scene to the coordinates of the view

QPolygon QGraphicsView::mapFromScene(const QRectF & amp;rect) const

//Convert a coordinate in the view to the coordinates of the scene

 QPointF QGraphicsView::mapToScene(const QPoint & amp;point) const

(3) Some common operation interfaces in QGraphicsScene

//Scenes

//Set the rectangular area of the scene

?void QGraphicsScene::setSceneRect(const QRectF & amp;rect)

//Group

//Create graphic item group

QGraphicsItemGroup *QGraphicsScene::createItemGroup(const QList<QGraphicsItem *> & amp;items)

//Remove a graphics item group

void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)

//Input focus

//Return the currently focused graphic item

QGraphicsItem *QGraphicsScene::focusItem() const

//Remove selection focus

void QGraphicsScene::clearFocus()

//Whether the view has focus

 bool QGraphicsScene::hasFocus() const

//Operation of graphic items

//Add an already created graphic item

void QGraphicsScene::addItem(QGraphicsItem *item) 

//Delete graphic item

 void QGraphicsScene::removeItem(QGraphicsItem *item)

//Clear all graphic items

[slot] void QGraphicsScene::clear()

//Return the graphic item captured by the mouse

QGraphicsItem *QGraphicsScene::mouseGrabberItem() const

//Return the selected graphic item list

QList<QGraphicsItem *> QGraphicsScene::selectedItems() const

//Clear all selections

[slot] void QGraphicsScene::clearSelection()

//Get the top-level graphic item at a certain position

QGraphicsItem *QGraphicsScene::itemAt(const QPointF & amp;position, const QTransform & amp;deviceTransform) const

QGraphicsItem *QGraphicsScene::itemAt(qreal x, qreal y, const QTransform & amp;deviceTransform) const

//Return a list of graphic items within a certain rectangular area, polygon, etc. selection area

QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order = Qt::DescendingOrder) const

//Add graphic item

//Add an ellipse
QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF & amp;rect, const QPen & amp;pen = QPen(), const QBrush & amp;brush = QBrush());

//Add a straight line
QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen & amp;pen = QPen());

//Add a drawing path
QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath & amp;path, const QPen & amp;pen = QPen(), const QBrush & amp;brush = QBrush());

//Add a picture
QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap & amp;pixmap);

//Add a polygon
QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF & amp;polygon, const QPen & amp;pen = QPen(), const QBrush & amp;brush = QBrush());

//Add a rectangle
QGraphicsRectItem *QGraphicsScene::addRect(const QRectF & amp;rect, const QPen & amp;pen = QPen(), const QBrush & amp;brush = QBrush());

//Add simple text
QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString & amp;text, const QFont & amp;font = QFont());

//Add string
QGraphicsTextItem *QGraphicsScene::addText(const QString & amp;text, const QFont & amp;font = QFont());

//Add interface components
QGraphicsProxyWidget *QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags = Qt::WindowFlags());

(4) Some common operation interfaces in QGraphicsItem

//Property settings

//Set the operation attributes of the graphic item, for example, selectable, movable, etc.

void QGraphicsItem::setFlags(QGraphicsItem::GraphicsItemFlags flags)

//Set transparency

void QGraphicsItem::setOpacity(qreal opacity)

//Set graphic effects

void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect)

//Whether the graphic item is selected

void QGraphicsItem::setSelected(bool selected)

//User-defined data

void QGraphicsItem::setData(int key, const QVariant & amp;value)

//coordinate

//X coordinate of graphic item

void QGraphicsItem::setX(qreal x)

//Y coordinate of graphic item

void QGraphicsItem::setY(qreal y)

//Z value of graphic items, Z value controls the stacking order of graphic items

void QGraphicsItem::setZValue(qreal z)

//The position of the graphic item in the parent item

void QGraphicsItem::setPos(const QPointF & amp;pos)

//Return the coordinates of the graphic item in the scene, equivalent to calling mapToScene(0,0)

QPointF QGraphicsItem::scenePos() const

//Coordinate transformation

//Reset the coordinate system and cancel all coordinate transformations

void QGraphicsItem::resetTransform()

//Rotate a certain angle. When the parameter is a positive number, it means clockwise rotation.

void QGraphicsItem::setRotation(qreal angle)

//Scale proportionally, the default value is 1

void QGraphicsItem::setScale(qreal factor)

//Coordinate mapping

//Map a point of another graphic item to this graphic item to the coordinate system

QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPointF & amp;point) const

//Map a point of the parent item to the coordinate system of this graphic item

QPointF QGraphicsItem::mapFromParent(const QPointF & amp;point) const

//Map a point in the scene to this graph item to the coordinate system

QPointF QGraphicsItem::mapFromScene(const QPointF & amp;point) const

//Map a point within this graphic item to the coordinate system of another graphic item

QPainterPath QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPainterPath & amp;path) const
QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal x, qreal y) const
QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPointF & amp;point) const
QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QRectF & amp;rect) const
QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPolygonF & amp;polygon) const
...

//Map a point within this graphic item to the parent coordinate system

QPointF QGraphicsItem::mapToParent(const QPointF & amp;point) const
QPolygonF QGraphicsItem::mapToParent(const QRectF & amp;rect) const
QPolygonF QGraphicsItem::mapToParent(const QPolygonF & amp;polygon) const
QPolygonF QGraphicsItem::mapToParent(const QPolygonF & amp;polygon) const
QPolygonF QGraphicsItem::mapToParent(const QPolygonF & amp;polygon) const
QPainterPath QGraphicsItem::mapToParent(const QPainterPath & amp;path) const
QPointF QGraphicsItem::mapToParent(qreal x, qreal y) const

//Map a point within this graphic item to the scene coordinate system

QPointF QGraphicsItem::mapToScene(const QPointF & amp;point) const
QPolygonF QGraphicsItem::mapToScene(const QRectF & amp;rect) const
QPolygonF QGraphicsItem::mapToScene(const QPolygonF & amp;polygon) const
QPainterPath QGraphicsItem::mapToScene(const QPainterPath & amp;path) const
QPointF QGraphicsItem::mapToScene(qreal x, qreal y) const
QPolygonF QGraphicsItem::mapToScene(qreal x, qreal y, qreal w, qreal h) const

4. Overall project structure

4.1 Classes used in the project

Project summary:

Some problems encountered on the project:

1. When I start adding a canvas to the tabWidget, I cannot draw. After selecting the graphics to draw, the program crashes and exits as soon as I click the brush. Then I added some judgment conditions. If tabWidget->currentIndex() < 0, the pointer is assigned a value. It failed. Later, after adding a judgment condition, it worked. Then I directly improved it. When the application window is opened, the canvas will be created on the tabWidget.

2. In mainwindow.cpp, I rewrote the mouseDoubleClickEvent method. When double-clicking the graphic, the property list on the right is updated. However, the program will crash when double-clicking the blank view. The solution used later is to add a judgment condition. If If the graphic has been selected, double-clicking the graphic will update the attribute list. If the graphic is not selected, simply double-clicking the canvas will ignore the event. The specific code implementation is as follows:

//Double-click the graphic to update the graphic’s attribute list
void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{ QGraphicsScene * scene = m_scene;
    if (scene & amp; & amp; !scene->selectedItems().isEmpty()) {
        if (scene->selectedItems().first()->isSelected()) {
            updateItemProperty(); //Update property list
        }
    }else{
        event->ignore();
    }
}

3. When pressing the following button, if the graphic is not selected, the program will crash and crash. Later, I added some judgment conditions. For example, operations such as combination, alignment, and stretching can only be performed when the selected graphic is greater than 1. This problem Also a perfect solution

void MainWindow::aglin() {
    graphicsScene * scene = dynamic_cast<graphicsScene*>(m_scene);
    int selectedItemCount = scene->selectedItems().count();
    if(ui->tabWidget->currentIndex() >= 0 & amp; & amp; scene & amp; & amp; selectedItemCount > 1){
        if (sender() == ui->top_align_button){
            scene->align(TOP_ALIGN);
        }else if(sender() == ui->bottom_align_button){
            scene->align(BOTTOM_ALIGN);
        }else if(sender() == ui->left_align_button){
            scene->align(LEFT_ALIGN);
        }else if(sender() == ui->right_align_button){
            scene->align(RIGHT_ALIGN);
        }else if(sender() == ui->horizontal_align){
            scene->align(HORZEVEN_ALIGN);
        }else if(sender() == ui->vertical_align){
            scene->align(VERTEVEN_ALIGN);
        }else if(sender() == ui->vertical_space_Button){
            scene->align(HORZEVEN_SPACE);
        }else if(sender() == ui->horizontal_space_Button){
            scene->align(VERTEVEN_SPACE);
        }else if(sender() == ui->widthButton){
            scene->align(WIDTH_ALIGN);
        }else if(sender() == ui->heightButton){
            scene->align(HEIGHT_ALIGN);
        }
    }
}

The above are some of the problems I encountered during development. Of course, there are also some minor problems, so I won’t elaborate on them one by one.