基于Qt实现的电路图编辑程序

参考Qt Diagram Scene Example

图场景示例是一个应用程序,您可以在其中创建流程图。可以添加流程图形状和文本,并通过箭头连接形状,如上图所示。形状、箭头和文本可以被赋予不同的颜色,并且可以更改文本的字体、样式和下划线。

电路图编辑程序具有以下功能:

1. 自定义元件
2. 实现电路图的导入,导出功能
3. 实现绘制动作的撤销,恢复功能
4. 实现元件的搜索功能
5. 实现元件的连接及动态连接
6. 实现元件的右键功能

在这里插入图片描述

实现自定义电路元件绘制

通过实现继承类来创建这样的自定义电路元件, 电源,开关,电阻,电容,电感等.并自动生成对应元件的图标. 具体代码如下:

DiagramItem::DiagramItem(DiagramType diagramType, QMenu *contextMenu,
                         QGraphicsItem *parent)
    : QGraphicsRectItem(parent)
{
    myDiagramType = diagramType;
    myContextMenu = contextMenu;

    point_left = QPoint( -120, 0 );
    point_right = QPoint( 120, 0 );

    switch (myDiagramType) {
    case Power:
        myPath.moveTo(-120, 0);
        myPath.lineTo(-10, 0);
        myPath.moveTo(-10, 10);
        myPath.lineTo(-10, -10);
        myPath.moveTo(10, 20);
        myPath.lineTo(10, -20);
        myPath.moveTo(10, 0);
        myPath.lineTo(120, 0);
        break;
    case Capacitor:
        myPath.moveTo(-120, 0);
        myPath.lineTo(-10, 0);
        myPath.moveTo(-10, 20);
        myPath.lineTo(-10, -20);
        myPath.moveTo(10, 20);
        myPath.lineTo(10, -20);
        myPath.moveTo(10, 0);
        myPath.lineTo(120, 0);
        break;
    case Resistor:
        myPath.moveTo(-120, 0);
        myPath.lineTo(-40, 0);
        myPath.lineTo(-40, -20);
        myPath.lineTo(40, -20);
        myPath.lineTo(40, 20);
        myPath.lineTo(-40, 20);
        myPath.lineTo(-40, 0);
        myPath.moveTo(40, 0);
        myPath.lineTo(120, 0);
        break;
    case GND:
        myPath.moveTo(0, -80);
        myPath.lineTo(0, 40);
        myPath.moveTo(-20,40);
        myPath.lineTo(20,40);
        myPath.moveTo(-15, 60);
        myPath.lineTo(15, 60);
        myPath.moveTo(-10, 78);
        myPath.lineTo(10, 78);

        point_left = QPoint( 0, -80 );

        break;
    case Inductor:
        myPath.moveTo(-120, 0);
        myPath.lineTo(-40, 0);

        myPath.cubicTo( -40,0, -30,-20, -20,0 );
        myPath.cubicTo( -20,0, -10,-20, 0,0 );
        myPath.cubicTo( 0,0, 10,-20, 20,0 );
        myPath.cubicTo( 20,0, 30,-20, 40,0 );

        myPath.moveTo(40,0);
        myPath.lineTo(120,0);
        break;
    }
    setRect( QRect( -125, -125, 250, 250 ) );

通过继承QGraphicsRectItem图形项, 使用QPainterPath来绘图各种元件.
实现对应元件的图标,代码如下:

QPixmap DiagramItem::image() const
{
    QPixmap pixmap(250, 250);
    pixmap.fill(Qt::transparent);
    QPainter painter(&pixmap);
    painter.setPen(QPen(Qt::black, 8));
    painter.translate(125, 125);
    painter.drawPath( myPath );
    return pixmap;
}

实现电路图的导入导出功能

使用QSettings来对图元进行保存, 需要保存各个图形项的位置,类型,角度,连接线等信息, 实现电路图的导出功能. 代码如下:

QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "./1.ini", tr("(*.ini)"));
    QSettings settings( fileName, QSettings::IniFormat);
    settings.setIniCodec("utf-8");
    settings.clear();
    int cnt = 0;

    QMap< QGraphicsItem*, QString > map_item;
    foreach ( auto item, scene->items() ){
        QString str = "item" + QString::number(++cnt);
        settings.beginGroup(str);
        settings.setValue( "pos", item->pos() );
        settings.setValue( "type", item->type() );
        settings.setValue( "degree", item->rotation() );
        map_item.insert( item, str );
        if( item->type() == Arrow::Type ){
            auto ln = (Arrow*)item;
            settings.setValue( "Arrow", ln->line() );
            settings.setValue( "startItem", map_item.value( ln->startItem() ) );
            settings.setValue( "endItem", map_item.value( ln->endItem() ) );
            settings.setValue( "startPoint", ln->startPoint()  );
            settings.setValue( "endPoint", ln->endPoint() );
        }
        else if( item->type() == DiagramItem::Type ){
            auto ln = (DiagramItem*)item;
            settings.setValue( "DiagramType", ln->diagramType() );
        }
        else if( item->type() == DiagramTextItem::Type ){
            auto text = (DiagramTextItem*)item;
            settings.setValue( "text", text->toPlainText().toLocal8Bit() );
        }
        settings.endGroup();
    }

读取ini文件,获取每个图形项的位置,类型,角度,连接线等信息, 并创建对应的图形项, 即可实现电路图的导入功能. 代码如下:

QString fileName = QFileDialog::getOpenFileName(this, tr("Opem File"), "./", tr("(*.ini)"));
    if(fileName.isEmpty()) return;
    QSettings settings( fileName, QSettings::IniFormat);

    scene->clear();
    int cnt = 0;
    QMap< QString, DiagramItem* > map_item;
    while(1){
        QString item = "item" + QString::number(++cnt);
        if( !settings.contains(item+"/type") )
            break;
        int type = settings.value( item+"/type" ).toInt();
        if( type == DiagramItem::Type ){
            int DiagramType = settings.value( item+"/DiagramType" ).toInt();
            auto item0 = new DiagramItem( DiagramItem::DiagramType( DiagramType ), ui->menuItem );
//            item0->setPen( QPen( Qt::black, 3 ) );
            item0->setPos( settings.value( item+"/pos" ).toPointF() );
            item0->setRotation( settings.value( item+"/degree" ).toDouble() );
            scene->addItem( item0 );
            map_item.insert( item, item0 );
        }
        else if( type == Arrow::Type ){
            auto startItem = map_item.value( settings.value( item+"/startItem").toString() );
            auto endItem = map_item.value( settings.value( item+"/endItem").toString() );
            if( startItem==nullptr || endItem==nullptr ) continue;
            auto arrow = new Arrow( startItem, endItem );
            arrow->setStartPoint( settings.value(item+"/startPoint").toPointF() );
            arrow->setEndPoint( settings.value(item+"/endPoint").toPointF() );
            startItem->addArrow(arrow);
            endItem->addArrow(arrow);
            arrow->setZValue(-1000.0);
            scene->addItem(arrow);
            arrow->updatePosition();
        }
        else if( type == DiagramTextItem::Type ){
            auto item0 = new DiagramTextItem();
            item0->setPos( settings.value( item+"/pos" ).toPointF() );
            item0->setRotation( settings.value( item+"/degree" ).toDouble() );
            item0->setPlainText( QString::fromLocal8Bit( settings.value( item+"/text" ).toByteArray() ) );
            scene->addItem( item0 );
        }
    }

实现绘制动作的撤销,恢复功能

使用QUndoCommand来实现绘制动作的撤销恢复功能.
定义每一个动作, 并加入QUndoStack, 通过
QAction *createUndoAction(QObject *parent, const QString &prefix = QString()) const;
QAction *createRedoAction(QObject *parent, const QString &prefix = QString()) const;
实现撤销和恢复功能. 具体的工作的代码如下:

class MoveCommand : public QUndoCommand
{
public:
    enum { Id = 1234 };

    MoveCommand(DiagramItem *diagramItem, const QPointF &oldPos,
                QUndoCommand *parent = 0);

    void undo() override;
    void redo() override;
    bool mergeWith(const QUndoCommand *command) override;
    int id() const override { return Id; }

private:
    DiagramItem *myDiagramItem;
    QPointF myOldPos;
    QPointF newPos;
};

class DeleteCommand : public QUndoCommand
{
public:
    explicit DeleteCommand(QGraphicsScene *graphicsScene, QUndoCommand *parent = 0);

    void undo() override;
    void redo() override;

private:
    QList<QGraphicsItem *> list_item;
    QMap<QGraphicsItem *, QList<Arrow *> > map_item_arrow;
    QGraphicsScene *myGraphicsScene;
};

class AddCommand : public QUndoCommand
{
public:
    AddCommand(DiagramItem *item, QGraphicsScene *graphicsScene,
               QUndoCommand *parent = 0);
    ~AddCommand();

    void undo() override;
    void redo() override;

private:
    DiagramItem *myDiagramItem;
    QGraphicsScene *myGraphicsScene;
    QPointF initialPosition;
};

实现元件的搜索功能

这个功能比较简单, 只是简单的图元名称的匹配, 包含搜索关键词的显示, 否则隐藏,并对元件图标进行重新显示. 代码如下:

auto keys = map_name_widget.keys();
    foreach( auto key, keys ){
        if( key.contains( arg1, Qt::CaseInsensitive ) ){
            map_name_widget.value(key)->show();
        }
        else
            map_name_widget.value(key)->hide();
        if( arg1.isEmpty() )
            map_name_widget.value(key)->show();
    }
    QGridLayout *layout = ui->gridLayout_2;
    int r = 1;
    int c = 0;
    foreach( auto w, map_name_widget.values() ){
        if( w->isHidden() )
            layout->removeWidget( w );
        else{
            layout->addWidget( w, r, c );
            if( ++c>=2 ){
                c=0;
                ++r;
            }
        }
    }

实现元件的连接功能

在每个元件中记录各自的连接点, 在元件移动的时候更新连接线, 保证元件始终连接在一起. 重载图形项方法,通知连接线更新.

    QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
QVariant DiagramItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == QGraphicsItem::ItemPositionChange) {
        foreach (Arrow *arrow, arrows) {
            arrow->updatePosition();
        }
    }
    return value;
}

项目源码

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
QT是一个跨平台的图形用户界面开发框架,可以用于实现各种应用程序,包括图形图像编辑器。 首先,我们可以使用QT的图形视图框架来构建图形图像编辑器的界面。可以使用QT自带的控件来实现工具栏、菜单栏、绘图区域等界面元素。通过QT的信号槽机制,可以实现用户对界面的操作响应,例如点击菜单项或者按钮时触发相应的功能。 其次,为了实现图形图像编辑的功能,需要基于QT提供的绘图API进行开发。通过使用QT的绘图函数,可以实现在绘图区域上绘制各种图形,如直线、矩形、圆形等。可以通过监听鼠标事件、键盘事件等来捕捉用户的操作,例如拖动鼠标绘制直线或者移动图形。 此外,图形图像编辑器还可以提供一些额外的功能,如选择、变换、编辑等。可以通过使用QT的图形视图框架来实现图形的选择、移动、缩放等操作。可以使用QT的图像处理函数,如旋转、裁剪、滤镜等来实现图像的编辑功能。 最后,为了提升用户体验,可以结合QT的其他功能,如撤销/重做功能、多文档支持、拖放操作等。这些功能可以通过使用QT的相关类库或者自定义类来进行开发。 总而言之,QT提供了丰富的工具和功能,可以方便地实现图形图像编辑器。通过使用QT的图形视图框架、绘图API和其他相关功能,可以创建一个功能完善的图形图像编辑器,满足用户的需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北方有佳人,绝世而独立

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值