君方智能设计平台-平台扩展机制

1.背景介绍

        建模平台扩展机制的背景是随着建筑行业数字化的发展,基于BIM技术的建模平台将成为建筑设计、施工和运营的标准工具。为了满足不同用户的需求,BIM建模平台需要具备扩展机制,可以通过插件、API接口等方式,允许用户自定义功能或集成第三方工具。这种扩展机制能够提升建模平台的灵活性和可扩展性,使其适应不同用户的特定需求。

2.设计目标

建模平台扩展机制的设计目标包括:

  1. 可扩展性:提供灵活的扩展接口和机制,允许用户根据需求定制和扩展功能,同时保持平台的稳定和高性能。

  2. 开放性:提供开放的API和文档,以便第三方开发者可以轻松地集成和拓展平台的功能。

  3. 管理性:提供可视化的扩展管理界面,方便用户管理和配置扩展,包括安装、升级、禁用和卸载等操作。

  4. 兼容性:保持向后兼容性,确保扩展的稳定性和可迁移性,防止扩展对原有功能的冲突和破坏

3.技术方案
3.1 技术框架

3.2 技术方案

平台扩展机制可以分为三个方面来实现:

(1)C++ API二次开发工具包以及Python API 接口

外部用户根据提供C++ API二次开发工具包以及Python API 接口,充分利用平台的基础能力,开发出符合用户业务需求的功能插件。

(2)平台+组件机制

内部用户可以利用该机制拆分为平台和插件,平台赋予基础能力,插件负责业务功能分,有效隔离平台开发和应用开发间的相互影响。平台和应用可以独立进行互不影响,提高开发的效率。

(3)事件订阅处理机制

使用事件订阅处理机制,减少系统耦合,增强可扩展性。平台提供事件定义扩展及事件管理机制,提高用户与定义事件的效率和便捷性。

4.技术实现
4.1 平台+组件机制实现

(1)业务插件组成

插件包含了三个模块,分别是数据模块,业务处理Builder模块和UI交互模块以及一个插件配置文件,描述插件的定义。

(2)业务插件的管理

插件配置文件放在Addins目录下,程序启动时AppImpl模块,平台的插件管理识别插件模块目录下的配置,获取要加载的插件信息,按照依赖关系依次加载插件。

(3)插件两个接口

分别是OnAddInInitialize、OnAddInUnInitialize。插件加载调用OnAddInInitialize,可以在这个函数做一些插件相关的环境准备工作,例如资源、UI菜单设置、插件配置等。插件卸载时调用OnAddInUnInitialize,在做些资源清理工作,例如数据库关闭等。

(4)插件配置文件定义

 采用JSON或XML文件定义插件信息,例如插件名称,DLL的名称及依赖库的名称列表等。

(4)其他资源定义

  1. 每个插件有自己的资源文件。目前涉及到的主要是Qt的资源文件
  2. 命令定义文件各个插件创建自己的命令定义文件
4.2 事件订阅处理机制实现
4.2.1 事件处理机制介绍

        事件处理器是一种编程机制,用于监视和响应特定事件。在图形平台中,这些事件可以是用户交互、对象修改、文档操作等。事件处理器您注册事件处理程序,以在事件发生时执行自定义操作。

        事件处理器的核心思想是“触发-响应”。当特定事件触发时,系统会调用相关的事件处理程序,以执行定义的操作。这种机制使您能够实现自动化、自定义和实时反馈,从而提高图形平台的功能和效率。

4.2.2 事件处理机制原理

反应器的工作原理通常包括以下步骤:

(1)注册事件

首先,您需要确定要监视的事件类型。这可以是用户的交互事件(例如鼠标点击或键盘输入)、对象的修改事件(例如图元的移动或属性的更改)或文档级别的事件(例如文档的保存或关闭)。

(2)事件捕获

一旦事件发生,系统会捕获它并识别触发该事件的原因。

(3)事件处理

事件捕获后,系统会查找与事件相关联的事件处理程序。事件处理程序是您编写的代码块,它定义了在事件发生时应执行的操作。

(4)执行操作

事件处理程序包含要执行的操作,这些操作可以涵盖各种任务。例如,您可以创建一个文档保存的反应器,以在文档保存时执行数据验证,或者创建一个对象修改的反应器,以在图元属性更改时更新相关信息。

4.2.3 事件处理机制的应用场景

应器在自主图形平台中有广泛的应用场景,以下是一些示例:

(1)用户交互事件处理

捕获鼠标点击、键盘输入等用户交互事件,以实现自定义命令或实时反馈。

(2)对象修改事件处理

监视图元的修改事件,以验证数据的有效性、更新关联信息或自动执行特定任务。

(3)文档级别事件处理

用于监听文档级别的事件,例如文档的保存、关闭或打开,以执行自动备份、数据导出等操作。

(4)用户界面交互事件处理

通过在事件中更新用户界面,改进图形平台的用户体验,例如动态显示属性编辑器或工具栏按钮状态。

4.2.4 技术实现

另外,实现UIEventManager来管理事件。

4.3 二次开发工具实现
4.3.1 C++二次接口API实现方案

(1)暴露C++ API(后续还支持Python API)及SDK二次开发工具包,用来支持二次开发人员在平台及各专业插件的基础上,自定义开发新增命令及新增UI菜单项,扩展平台的业务及应用场景,打造软件平台+二次开发插件的生态环境。

(2)为使使用平台的API二次开发的插件DLL在软件启动时被通知Load,并且作为执行入口的新定义Command可以被识别注册,在UI菜单“附加模块”或特定位置自动添加新菜单项,便于用户点击执行自定义开发的新Command。

        具体实现可以参照Revit API Addin注册加载机制,需要建立仅通过用户添加符合API Addin配置文件格式要求的新配置文件(如.addin文件),放置于软件约定目录下,软件在启动时按顺序查找并解析这些API Addin配置文件,根据其内容信息,找到并Load相应的Addin DLL。根据其请求注册的Command name,Create对应的Command Class(继承自API IExternalCommand接口),并在平台内部CommandManager中注册新的Command。在平台的菜单“附加模块”或特定位置添加一新菜单项,关联新注册的Command。做到用户点击该菜单项即执行新Command。

4.3.2 Python二次开发API实现

(1)参照FreeCAD,平台的 Python API采用通过Python C API暴露Python API接口,及在C++程序中嵌入Python解释器的方式解释运行Python代码,Python API随C++ API Dll一起编译发布,即可调用C++ API情况下,也可以调用到Python API。

(2)但目前C++ API对应的Python API Class(如APIDocument对应的APIDocumentPy)内部代码既可以使用手写方式暴露,也可以使用Pybind11自动将C++ API Class及接口转化为Python API Class及接口代码.

### 日历前端实现教程 #### React 实现日历组件 通过学习基于 React 的日历组件开发,可以快速掌握如何构建一个基础的日历界面并扩展其功能。React 提供了强大的状态管理和组件化能力,使得开发者能够轻松创建复杂的 UI 组件[^1]。 以下是使用 React 构建简单日历的核心逻辑: ```javascript import React, { useState } from 'react'; function Calendar() { const [currentMonth, setCurrentMonth] = useState(new Date()); function getDaysInMonth(year, month) { return new Date(year, month + 1, 0).getDate(); } function renderCalendarDays(daysCount, startDayIndex) { let daysArray = []; for (let i = 0; i < startDayIndex; i++) { daysArray.push(<div key={`empty-${i}`} className="calendar-day empty"></div>); } for (let day = 1; day <= daysCount; day++) { daysArray.push( <div key={day} className="calendar-day"> {day} </div> ); } return daysArray; } const year = currentMonth.getFullYear(); const month = currentMonth.getMonth(); const daysCount = getDaysInMonth(year, month); const firstDayOfMonth = new Date(year, month, 1).getDay(); return ( <div className="calendar-container"> <h2>{`${year} 年 ${month + 1} 月`}</h2> <div className="calendar-days-header"> {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(weekday => ( <div key={weekday}>{weekday}</div> ))} </div> <div className="calendar-days-body">{renderCalendarDays(daysCount, firstDayOfMonth)}</div> </div> ); } export default Calendar; ``` 此代码片段展示了如何利用 JavaScript 中 `Date` 对象计算每个月的天数以及每周的第一天位置,并将其渲染到页面上。 --- #### 使用原生 HTML 和 CSS 制作简易日历 对于初学者来说,可以通过纯 HTML、CSS 和少量 JavaScript 来制作一个静态日历。这种法有助于理解日期对象的基础操作和布局设计原理[^2]。 下面是一个简单的例子: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Simple Calendar</title> <style> .calendar-table { border-collapse: collapse; width: 100%; } .calendar-table td, .calendar-table th { border: 1px solid black; padding: 10px; text-align: center; } </style> </head> <body> <table class="calendar-table"> <tr> <th>Sun</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th> </tr> <tbody id="calendarBody"></tbody> </table> <script> const today = new Date(); const year = today.getFullYear(); const month = today.getMonth(); // Months are zero-based. // Get the number of days in this month. function getDaysInMonth(y, m) { return new Date(y, m + 1, 0).getDate(); } // Find out which weekday is the first one of the given month/year combination. function getFirstWeekdayOfTheMonth(y, m) { return new Date(y, m, 1).getDay(); } const totalDays = getDaysInMonth(year, month); const startingPosition = getFirstWeekdayOfTheMonth(year, month); document.getElementById('calendarBody').innerHTML = Array.from({ length: Math.ceil((startingPosition + totalDays) / 7) }, (_, rowIndex) => `<tr>${Array.from({ length: 7 }, (_, colIndex) => { const dateNumber = rowIndex * 7 + colIndex - startingPosition + 1; if (dateNumber > 0 && dateNumber <= totalDays) { return `<td>${dateNumber}</td>`; } else { return '<td></td>'; } }).join('')}</tr>` ).join(''); </script> </body> </html> ``` 这段脚本定义了一张表格形式的日历,其中填充了当前月份的所有日子及其对应的星期几。 --- #### Vue.js 开发动态交互式日历 如果倾向于采用 Vue 框架,则可以从头开始搭建具备高度自定义特性的日历插件。Vue 的双向绑定机制让数据更新变得极为简便,从而简化了许多繁琐的手动 DOM 调整工作[^3]。 示例代码如下所示: ```vue <template> <div class="calendar"> <h3>{{ selectedYear }}年{{ selectedMonth + 1 }}月</h3> <table> <thead> <tr> <th v-for="(weekName, index) in weekNames" :key="'w' + index">{{ weekName }}</th> </tr> </thead> <tbody> <tr v-for="(row, rindex) in calendarRows" :key="'r' + rindex"> <td v-for="(cell, cindex) in row" :key="'c' + cindex" :class="{ inactive: !cell.active, active: cell.active }"> {{ cell.day }} </td> </tr> </tbody> </table> </div> </template> <script> export default { data() { return { selectedDate: new Date(), }; }, computed: { selectedYear() { return this.selectedDate.getFullYear(); }, selectedMonth() { return this.selectedDate.getMonth(); }, daysInSelectedMonth() { return new Date(this.selectedYear, this.selectedMonth + 1, 0).getDate(); }, firstDayOfWeek() { return new Date(this.selectedYear, this.selectedMonth, 1).getDay(); }, lastDayOfWeek() { return new Date(this.selectedYear, this.selectedMonth + 1, 0).getDay(); }, calendarRows() { const rows = []; let count = 1; for (let i = 0; i < 6; i++) { rows[i] = []; for (let j = 0; j < 7; j++) { if ((i === 0 && j >= this.firstDayOfWeek || count <= this.daysInSelectedMonth)) { rows[i][j] = { day: count++, active: true }; } else { rows[i][j] = { day: null, active: false }; } } if (count > this.daysInSelectedMonth) break; } return rows; }, weekNames() { return ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; }, }, methods: {}, }; </script> <style scoped> .inactive { color: lightgray; cursor: not-allowed; } .active:hover { background-color: yellowgreen; cursor: pointer; } </style> ``` 上述模板描述了一个完整的响应式日历视图结构,支持跨平台部署至 Web 应用程序中运行良好。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值