C++Qt代码实现类似multisim的器件放置连线功能

时间: 2023-08-27 12:03:51 浏览: 99
实现类似 Multisim 的器件放置和连线功能需要进行如下步骤: 1. 创建器件类(Component),其中包含器件的位置、类型、属性等信息。 2. 创建连线类(Connection),其中包含连接的起点、终点、类型等信息。 3. 在主窗口中创建画布,用于展示器件和连线。 4. 实现鼠标事件处理函数,监听鼠标的按下、移动和释放事件,以便实现器件的放置和连线的绘制。 5. 实现键盘事件处理函数,监听键盘的按下和释放事件,以便实现器件的选择和删除。 6. 实现拖拽事件处理函数,监听拖拽事件,以便实现器件的移动和连线的调整。 下面是一个简单的示例代码: ``` // Component.h #ifndef COMPONENT_H #define COMPONENT_H #include <QObject> #include <QGraphicsItem> class Component : public QObject, public QGraphicsItem { Q_OBJECT public: Component(QGraphicsItem *parent = nullptr); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; void setType(int type); int type() const; void setProperties(const QMap<QString, QVariant> &properties); QMap<QString, QVariant> properties() const; signals: void clicked(Component *component); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; private: int m_type; QMap<QString, QVariant> m_properties; }; #endif // COMPONENT_H // Component.cpp #include "Component.h" #include <QPainter> #include <QStyleOptionGraphicsItem> #include <QGraphicsSceneMouseEvent> Component::Component(QGraphicsItem *parent) : QObject(nullptr), QGraphicsItem(parent) { setFlag(QGraphicsItem::ItemIsSelectable); setFlag(QGraphicsItem::ItemIsMovable); } QRectF Component::boundingRect() const { return QRectF(-25, -25, 50, 50); } void Component::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->drawRect(boundingRect()); } void Component::setType(int type) { m_type = type; } int Component::type() const { return m_type; } void Component::setProperties(const QMap<QString, QVariant> &properties) { m_properties = properties; } QMap<QString, QVariant> Component::properties() const { return m_properties; } void Component::mousePressEvent(QGraphicsSceneMouseEvent *event) { QGraphicsItem::mousePressEvent(event); if (event->button() == Qt::LeftButton) emit clicked(this); } void Component::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { QGraphicsItem::mouseReleaseEvent(event); } // Connection.h #ifndef CONNECTION_H #define CONNECTION_H #include <QObject> #include <QGraphicsItem> class Connection : public QObject, public QGraphicsItem { Q_OBJECT public: enum Type { Input, Output }; Connection(QGraphicsItem *parent = nullptr); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; void setType(Type type); Type type() const; void setConnected(Connection *connection); Connection *connected() const; signals: void clicked(Connection *connection); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; private: Type m_type; Connection *m_connected; }; #endif // CONNECTION_H // Connection.cpp #include "Connection.h" #include <QPainter> #include <QStyleOptionGraphicsItem> #include <QGraphicsSceneMouseEvent> Connection::Connection(QGraphicsItem *parent) : QObject(nullptr), QGraphicsItem(parent) { } QRectF Connection::boundingRect() const { return QRectF(-5, -5, 10, 10); } void Connection::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->drawEllipse(boundingRect()); } void Connection::setType(Type type) { m_type = type; } Connection::Type Connection::type() const { return m_type; } void Connection::setConnected(Connection *connection) { m_connected = connection; } Connection *Connection::connected() const { return m_connected; } void Connection::mousePressEvent(QGraphicsSceneMouseEvent *event) { QGraphicsItem::mousePressEvent(event); if (event->button() == Qt::LeftButton) emit clicked(this); } void Connection::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { QGraphicsItem::mouseReleaseEvent(event); } void Connection::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { QGraphicsItem::mouseMoveEvent(event); QPointF position = mapToScene(event->pos()); if (m_type == Input && m_connected) m_connected->setPos(position); else if (m_type == Output) setPos(position); } // MainWindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class QGraphicsScene; class QGraphicsView; class Component; class Connection; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: void createActions(); void createMenus(); void createToolbar(); void createScene(); void createView(); void createStatusBar(); Component *createComponent(int type, const QPointF &position); Connection *createConnection(const QPointF &start, const QPointF &end); private slots: void onComponentClicked(Component *component); void onConnectionClicked(Connection *connection); void onDeleteActionTriggered(); private: QGraphicsScene *m_scene; QGraphicsView *m_view; QAction *m_deleteAction; }; #endif // MAINWINDOW_H // MainWindow.cpp #include "MainWindow.h" #include "Component.h" #include "Connection.h" #include <QGraphicsScene> #include <QGraphicsView> #include <QToolBar> #include <QStatusBar> #include <QMenuBar> #include <QMenu> #include <QAction> #include <QKeyEvent> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { createActions(); createMenus(); createToolbar(); createScene(); createView(); createStatusBar(); } MainWindow::~MainWindow() { } void MainWindow::createActions() { m_deleteAction = new QAction(tr("Delete"), this); m_deleteAction->setShortcut(Qt::Key_Delete); m_deleteAction->setEnabled(false); connect(m_deleteAction, &QAction::triggered, this, &MainWindow::onDeleteActionTriggered); } void MainWindow::createMenus() { QMenu *editMenu = menuBar()->addMenu(tr("Edit")); editMenu->addAction(m_deleteAction); } void MainWindow::createToolbar() { QToolBar *editToolBar = addToolBar(tr("Edit")); editToolBar->addAction(m_deleteAction); } void MainWindow::createScene() { m_scene = new QGraphicsScene(this); m_scene->setSceneRect(-5000, -5000, 10000, 10000); } void MainWindow::createView() { m_view = new QGraphicsView(m_scene, this); setCentralWidget(m_view); m_view->setRenderHint(QPainter::Antialiasing); m_view->setDragMode(QGraphicsView::ScrollHandDrag); m_view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); } void MainWindow::createStatusBar() { QStatusBar *statusBar = this->statusBar(); statusBar->showMessage(tr("Ready")); } Component *MainWindow::createComponent(int type, const QPointF &position) { Component *component = new Component(); component->setType(type); component->setPos(position); component->setZValue(1); connect(component, &Component::clicked, this, &MainWindow::onComponentClicked); m_scene->addItem(component); return component; } Connection *MainWindow::createConnection(const QPointF &start, const QPointF &end) { Connection *connection = new Connection(); connection->setPos(start); connection->setZValue(0); connect(connection, &Connection::clicked, this, &MainWindow::onConnectionClicked); m_scene->addItem(connection); connection->setConnected(createConnection(end, start)); return connection; } void MainWindow::onComponentClicked(Component *component) { m_deleteAction->setEnabled(true); } void MainWindow::onConnectionClicked(Connection *connection) { m_deleteAction->setEnabled(true); } void MainWindow::onDeleteActionTriggered() { QList<QGraphicsItem*> items = m_scene->selectedItems(); for (QGraphicsItem *item : items) { if (Component *component = qgraphicsitem_cast<Component*>(item)) { for (QGraphicsItem *connection : component->childItems()) { m_scene->removeItem(connection); delete connection; } } m_scene->removeItem(item); delete item; } m_deleteAction->setEnabled(false); } void MainWindow::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Delete) onDeleteActionTriggered(); else QMainWindow::keyPressEvent(event); } void MainWindow::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { QPointF position = m_view->mapToScene(event->pos()); createComponent(0, position); } else if (event->button() == Qt::RightButton) { QPointF position = m_view->mapToScene(event->pos()); createConnection(position, position); } else { QMainWindow::mousePressEvent(event); } } void MainWindow::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { QPointF position = m_view->mapToScene(event->pos()); m_scene->addLine(m_scene->sceneRect().bottomRight(), position, QPen(Qt::blue, 5)); } else { QMainWindow::mouseMoveEvent(event); } } void MainWindow::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { QPointF position = m_view->mapToScene(event->pos()); createConnection(m_scene->items(Qt::DescendingOrder)[0]->pos(), position); } else { QMainWindow::mouseReleaseEvent(event); } } ``` 这段代码实现了一个简单的器件放置和连线功能的窗口,其中包含了器件类 Component 和连线类 Connection,以及主窗口类 MainWindow。在主窗口类的构造函数中,创建了画布和视图,并初始化了工具栏和菜单。在创建器件和连线时,可以分别通过 createComponent() 和 createConnection() 函数来创建。在鼠标事件处理函数中,监听了鼠标的按下、移动和释放事件,以便实现器件的放置和连线的绘制。在键盘事件处理函数中,监听了键盘的按下和释放事件,以便实现器件的选择和删除。在拖拽事件处理函数中,监听了拖拽事件,以便实现器件的移动和连线的调整。

相关推荐

最新推荐

recommend-type

元器件应用中的门电路延迟时间的Multisim仿真测试方案

摘 要:介绍了用Multisim 仿真软件测试门电路延迟时间的方法,提出了三种测试方案,即将奇数个门首尾相接构成环形振荡电路,用虚拟示波器测试所产生振荡信号的周期,计算门的传输延迟时间;奇数个门首尾相接构成...
recommend-type

multisim中导入元件的方法.doc

Multisim 是一个功能强大的电子设计自动化(EDA)软件,能够帮助用户快速设计和验证电子电路。然而,在使用 Multisim 进行设计时,用户需要导入所需的元件模型。本文将介绍如何在 Multisim 中导入元件的方法,以下是...
recommend-type

Multisim12基本应用 基础教程 全面初学者必看

Multisim 12 基础应用教程 Multisim 简介 Multisim 是一款著名的电子设计自动化软件,由美国国家仪器公司开发,是 NI Ultiboard 的同属软件套件之一。Multisim 广泛应用于电路教学、电路图设计以及 SPICE 模拟。...
recommend-type

仿真软件Multisim与PSpice在电路设计中的功能比较

随着计算机技术的迅速发展,计算机辅助设计技术(CAD)已渗透到电子...目前国际上比较流行两个仿真软件:Multisim (EWB的版本)和PSpice。通过对两个软件的认真学习和反复比较,发现二者存在很多差异,下面进行一一说明。
recommend-type

基于三态门总线传输电路的Multisim仿真方案

基于三态门总线传输电路的Multisim仿真方案 本文介绍了基于三态门总线传输电路的Multisim仿真方案,以解决总线分时传输的工作特性难以直观形象描述的问题。该方案使用Multisim仿真软件进行三态总线电路工作过程波形...
recommend-type

GO婚礼设计创业计划:技术驱动的婚庆服务

"婚礼GO网站创业计划书" 在创建婚礼GO网站的创业计划书中,创业者首先阐述了企业的核心业务——GO婚礼设计,专注于提供计算机软件销售和技术开发、技术服务,以及与婚礼相关的各种服务,如APP制作、网页设计、弱电工程安装等。企业类型被定义为服务类,涵盖了一系列与信息技术和婚礼策划相关的业务。 创业者的个人经历显示了他对行业的理解和投入。他曾在北京某科技公司工作,积累了吃苦耐劳的精神和实践经验。此外,他在大学期间担任班长,锻炼了团队管理和领导能力。他还参加了SYB创业培训班,系统地学习了创业意识、计划制定等关键技能。 市场评估部分,目标顾客定位为本地的结婚人群,特别是中等和中上收入者。根据数据显示,广州市内有14家婚庆公司,该企业预计能占据7%的市场份额。广州每年约有1万对新人结婚,公司目标接待200对新人,显示出明确的市场切入点和增长潜力。 市场营销计划是创业成功的关键。尽管文档中没有详细列出具体的营销策略,但可以推断,企业可能通过线上线下结合的方式,利用社交媒体、网络广告和本地推广活动来吸引目标客户。此外,提供高质量的技术解决方案和服务,以区别于竞争对手,可能是其市场差异化策略的一部分。 在组织结构方面,未详细说明,但可以预期包括了技术开发团队、销售与市场部门、客户服务和支持团队,以及可能的行政和财务部门。 在财务规划上,文档提到了固定资产和折旧、流动资金需求、销售收入预测、销售和成本计划以及现金流量计划。这表明创业者已经考虑了启动和运营的初期成本,以及未来12个月的收入预测,旨在确保企业的现金流稳定,并有可能享受政府对大学生初创企业的税收优惠政策。 总结来说,婚礼GO网站的创业计划书详尽地涵盖了企业概述、创业者背景、市场分析、营销策略、组织结构和财务规划等方面,为初创企业的成功奠定了坚实的基础。这份计划书显示了创业者对市场的深刻理解,以及对技术和婚礼行业的专业认识,有望在竞争激烈的婚庆市场中找到一席之地。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

【基础】PostgreSQL的安装和配置步骤

![【基础】PostgreSQL的安装和配置步骤](https://img-blog.csdnimg.cn/direct/8e80154f78dd45e4b061508286f9d090.png) # 2.1 安装前的准备工作 ### 2.1.1 系统要求 PostgreSQL 对系统硬件和软件环境有一定要求,具体如下: - 操作系统:支持 Linux、Windows、macOS 等主流操作系统。 - CPU:推荐使用多核 CPU,以提高数据库处理性能。 - 内存:根据数据库规模和并发量确定,一般建议 8GB 以上。 - 硬盘:数据库文件和临时文件需要占用一定空间,建议预留足够的空间。
recommend-type

字节跳动面试题java

字节跳动作为一家知名的互联网公司,在面试Java开发者时可能会关注以下几个方面的问题: 1. **基础技能**:Java语言的核心语法、异常处理、内存管理、集合框架、IO操作等是否熟练掌握。 2. **面向对象编程**:多态、封装、继承的理解和应用,可能会涉及设计模式的提问。 3. **并发编程**:Java并发API(synchronized、volatile、Future、ExecutorService等)的使用,以及对并发模型(线程池、并发容器等)的理解。 4. **框架知识**:Spring Boot、MyBatis、Redis等常用框架的原理和使用经验。 5. **数据库相
recommend-type

微信行业发展现状及未来发展趋势分析

微信行业发展现状及未来行业发展趋势分析 微信作为移动互联网的基础设施,已经成为流量枢纽,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信月活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。 微信作为流量枢纽,已经成为移动互联网的基础设施,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信的用户数量增长已经开始呈现乏力趋势,这是因为微信自身也在重新寻求新的增长点。微信日活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。 微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。因此,在整体用户数量开始触达天花板的时候,微信自身也在重新寻求新的增长点。 中国的整体移动互联网人均单日使用时长已经较高水平。18Q1中国移动互联网的月度总时长达到了77千亿分钟,环比17Q4增长了14%,单人日均使用时长达到了273分钟,环比17Q4增长了15%。而根据抽样统计,社交始终占据用户时长的最大一部分。2018年3月份,社交软件占据移动互联网35%左右的时长,相比2015年减少了约10pct,但仍然是移动互联网当中最大的时长占据者。 争夺社交软件份额的主要系娱乐类App,目前占比达到约32%左右。移动端的流量时长分布远比PC端更加集中,通常认为“搜索下載”和“网站导航”为PC时代的流量枢纽,但根据统计,搜索的用户量约为4.5亿,为各类应用最高,但其时长占比约为5%左右,落后于网络视频的13%左右位于第二名。PC时代的网络社交时长占比约为4%-5%,基本与搜索相当,但其流量分发能力远弱于搜索。 微信作为移动互联网的基础设施,已经成为流量枢纽,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信的用户数量增长已经开始呈现乏力趋势,这是因为微信自身也在重新寻求新的增长点。微信日活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。 微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。因此,在整体用户数量开始触达天花板的时候,微信自身也在重新寻求新的增长点。 微信作为移动互联网的基础设施,已经成为流量枢纽,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信的用户数量增长已经开始呈现乏力趋势,这是因为微信自身也在重新寻求新的增长点。微信日活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。 微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。因此,在整体用户数量开始触达天花板的时候,微信自身也在重新寻求新的增长点。 微信作为移动互联网的基础设施,已经成为流量枢纽,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信的用户数量增长已经开始呈现乏力趋势,这是因为微信自身也在重新寻求新的增长点。微信日活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。 微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。因此,在整体用户数量开始触达天花板的时候,微信自身也在重新寻求新的增长点。