QML控件访问EPICS过程变量的思路

前言 写这篇文章的想法是使用自定义QML控件的方式访问EPICS过程变量,现有的Qt EPICS框架之前也介绍过了,还有配套的QEGui工具,框架的基本功能已经比较完善,但实际使用过程中还是遇到了一些问题。我总结有以下2点: QEGui工具只能加载基于Widget的.ui界面文件,文件只能包含布局、控件和控件属性,不能嵌入代码(C++代码必须编译)。用户的操作(如:输入、点击按钮等)的相应槽函数封装在框架自定义的控件里实现,这样极大方便了用户的开发,用户只需要设计界面,填写变量名就可以实现变量访问,但相应的也失去了很大的灵活性,程序的功能变得很单一。 QEGui工具不一定符合实际开发过程中的需求,仅使用QEGui加载.ui界面,脱离了C++代码,程序很难实现用户想要的效果。而更好的选择是调用Qt EPICS框架动态库提供的控件,结合C++代码开发应用程序,但却不得不进行编译操作。 那么,有没有更好的基于Qt的EPICS框架方案呢? 刚好最近我也学习实践了QML相关的内容,这种前后端分离开发的方式给了我一些灵感。我们完全可以在Qt EPICS框架的基础上,实现自定义QML控件访问EPICS过程变量,用户使用QML编写界面,调用自定义QML控件即可,可以实现和Qt EPICS框架加载.ui界面文件类似的功能。但QML在动画、3D显示等方面明显具有优势,还有一点是基于Widget的.ui界面文件不具备的:QML本身可以嵌入javascript函数,动态控制界面的显示、切换等,甚至可以实现和底层C++接口的交互。而QML本身也不需要进行编译,完全可以只使用QML语言实现程序开发,且具有很高灵活性。 实现思路 Qt EPICS 框架提供了QCaObject类访问EPICS过程变量,但该类几乎是完全为QEWidget服务的,并没有声明属性(property),无法直接在QML中使用。 所以第1步需要对QCaObject做一层封装,将EPICS过程变量的字段声明为QmlPvObject类的属性,然后就可以在QML中访问EPICS过程变量了。 第2步是将QmlPvObject封装进自定义的QML控件QmlPvControl,实现数据的显示、输入等操作。 第3步将QmlPvControl导入(import)到QML文件,在外部QML文件中使用自定义控件。 代码示例 由于完整的代码较多,这里只放部分代码。 QmlPvObject类的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 /* qmlpvobject.h */ class QmlPvObject : public QObject { Q_OBJECT public: enum epicsAlarmSeverity { NO_ALARM, /**< No alarm */ MINOR_ALARM, /**< Minor alarm severity */ MAJOR_ALARM, /**< Major alarm severity */ INVALID_ALARM,/**< Invalid alarm severity */ ALARM_NSEV /**< Number of alarm severities */ }; Q_ENUM(epicsAlarmSeverity) private: Q_PROPERTY(QString pvName READ pvName WRITE setPvName NOTIFY pvNameChanged FINAL) Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged FINAL) Q_PROPERTY(QString hostName READ hostName NOTIFY hostNameChanged FINAL) Q_PROPERTY(QString fieldType READ fieldType NOTIFY fieldTypeChanged FINAL) Q_PROPERTY(QString descriptor READ descriptor NOTIFY descriptorChanged FINAL) Q_PROPERTY(QString egu READ egu NOTIFY eguChanged FINAL) Q_PROPERTY(QCaDateTime dateTime READ dateTime NOTIFY dateTimeChanged FINAL) Q_PROPERTY(quint16 status READ status NOTIFY statusChanged FINAL) Q_PROPERTY(QmlPvObject::epicsAlarmSeverity severity READ severity NOTIFY severityChanged FINAL) Q_PROPERTY(QString statusName READ statusName NOTIFY statusNameChanged FINAL) Q_PROPERTY(QString severityName READ severityName NOTIFY severityNameChanged FINAL) Q_PROPERTY(bool readAccess READ readAccess NOTIFY readAccessChanged FINAL) Q_PROPERTY(bool writeAccess READ writeAccess NOTIFY writeAccessChanged FINAL) public: explicit QmlPvObject(QObject *parent = Q_NULLPTR); QString pvName() const; QVariant value() const; QString hostName() const; QString fieldType() const; QString descriptor() const; QString egu() const; QCaDateTime dateTime() const; quint16 status() const; QmlPvObject::epicsAlarmSeverity severity() const; QString statusName() const; QString severityName() const; bool readAccess() const; bool writeAccess() const; public Q_SLOTS: virtual void setPvName(const QString &pvname) = 0; virtual void setValue(const QVariant &value) = 0; virtual void onConnectionChanged(QCaConnectionInfo& connectionInfo, const uint& variableIndex); virtual void onDataChanged(const QVariant& value, QCaAlarmInfo& alarmInfo, QCaDateTime& timeStamp, const uint& variableIndex); Q_SIGNALS: void pvNameChanged(const QString&); void valueChanged(const QVariant&); void dateTimeChanged(const QCaDateTime&); void fieldTypeChanged(const QString&); void descriptorChanged(const QString&); void eguChanged(const QString&); void hostNameChanged(const QString&); void statusChanged(const quint16); void severityChanged(const epicsAlarmSeverity); void statusNameChanged(const QString); void severityNameChanged(const QString); void readAccessChanged(const bool); void writeAccessChanged(const bool); protected: QPointer<qcaobject::QCaObject> m_caobject; // ... }; 注意到QmlPvObject类有两个虚函数setPvName和setValue,这两个函数需要子类实现。 ...

二月 20, 2025 · 4 分钟 · 822 字

EPICS Qt安装

前言 本文主要记录了EPICS Qt在Linux上的安装步骤。这里以loongnix操作系统为例,Ubuntu系统上编译安装步骤类似。 EPICS Qt是一个基于Qt的分层框架,使用Channel Access (CA) and PV Access(PVA)访问EPICS数据。它是为快速开发控制系统图形界面而设计的,最初是在澳大利亚同步加速器开发的。 安装EPICS 这里不再写具体步骤了,总之就是非常简单,下载、解压、编译即可。具体步骤可以参考以前的文章。 安装Qt 直接使用终端安装Qt 1 2 3 4 5 sudo apt update sudo apt install qtbase5-dev qt5-qmake qtcreator sudo apt install qtdeclarative5-dev qttools5-dev # 安装Qt Svg库,编译QWT时需要用到 sudo apt install libqt5svg5-dev 安装QWT Qt EPICS推荐使用Qwt 6.1.4,如果在Ubuntu 20.04上直接通过终端安装也是这个版本。我使用Qwt 6.2.0编译,也是没有问题的,这里以Qwt 6.2.0为例。 最新测试:Qwt 6.3.0也可以用 ~ 先下载Qwt的源码 下载Qwt-6.2.0。 下载完成后解压 1 2 3 4 # 解压tar.bz2 tar -jxvf qwt-6.2.0.tar.bz2 # 解压zip unzip qwt-6.2.0.zip 解压完成后编译Qwt,使用QtCreator或者在终端使用qmake都可以。 然后手动将编译生成的文件复制到以下位置,例: 1 2 3 4 5 6 7 # 复制编译生成的qwt sudo cp -r build-qwt-unknown-Release/lib/* /usr/lib/loongarch64-linux-gnu/ # 复制编译生成的designer插件 sudo cp build-qwt-unknown-Release/designer/plugins/designer/libqwt_designer_plugin.so /usr/lib/loongarch64-linux-gnu/qt5/plugins/designer/ # 复制qwt头文件 sudo mkdir /usr/include/qwt sudo cp qwt-6.2.0/src/*.h /usr/include/qwt 安装ACAI ACAI Channel Access Interface ...

五月 4, 2023 · 2 分钟 · 350 字