全国产信创环境开发(二)--- 路线选型及AI开发安装使用
以下笔记是本人开发时的工作笔记,鸣谢仓颉编程语言交流群6中的xffish 、仓颉程序员和王总,谢谢您们的无私帮助。
一、开发基础部分:
操作系统openEuler,桌面环境Kiran Desktop,数据库openGauss,后端开发语言仓颉,前端GUI是CJ-tauri。(因为仓颉并没有自己官方的前端GUI,选择了CJQT,退而求其次的话可以选Qt。)
二、开发工具部分:
AI开发工具:TRAE CN 下载地址:https://www.trae.cn/ide/download (仓颉推荐使用码道,但码道未能提供openEuler下的RPM版本,所以选择TRAE。)
仓颉SDK:STS Version 1.2.0 下载地址:https://cangjie-lang.cn/download/1.2.0 (LTS Version 1.0.5 存在问题, STS 1.2.0此问题已修复。)
1、解压文件包,并将cangjie文件夹剪切到 /home/work/tools目录下。
2、在work目录下显示隐藏文件,找到.bashrc文件,在文件最后一行添加 source /home/work/tools/cangjie/envsetup.sh
开发基础组件安装:
1、仓颉stdx组件
终端执行 bash -c "$(curl -fsSL https://raw.gitcode.com/Cangjie/cangjie_stdx/raw/main/downloader.sh)" -- 1.2.0.1 -p linux-aarch64 -d ./tools X86_64: bash -c "$(curl -fsSL https://raw.gitcode.com/Cangjie/cangjie_stdx/raw/main/downloader.sh)" -- 1.2.0.1 -p linux-x64 -d ./tools
重命名下载下来的文件夹为 stdx
在work目录下显示隐藏文件,找到.bashrc文件,在文件最后一行添加 export CANGJIE_STDX=/home/work/tools/stdx
2、安装GUI开发缺失的工具包
sudo dnf install -y gcc-c++ cmake make qt5-qtbase-devel libxkbcommon-x11
3、克隆CJQT (终端执行 cd ~/tools && git clone https://gitcode.com/Cangjie-TPC/CJQT.git && cd CJQT )
修正CJQT项目文件
1、修改/home/work/tools/CJQT/native/includes/gui/gui_application.h 将其替换为如下内容
#ifndef CJ_GUI_APPLICATION_H
#define CJ_GUI_APPLICATION_H
#include <QGuiApplication>
class CjGuiApplication : public QGuiApplication
{
public:
CjGuiApplication(int &argc, char **argv)
: QGuiApplication(argc, argv)
{
}
};
#endif
2、修改/home/work/tools/CJQT/native/includes/gui/paint_device.h 将其替换为如下内容
#ifndef CJ_PAINT_DEVICE_H
#define CJ_PAINT_DEVICE_H
#include <QPaintDevice>
#include <QPaintEngine>
class CjPaintDevice : public QPaintDevice
{
public:
CjPaintDevice() {}
protected:
QPaintEngine *paintEngine() const override
{
return nullptr;
}
};
#endif // CJ_PAINT_DEVICE_H
3、修改/home/work/tools/CJQT/native/includes/widgets/abstract_graphics_shape_item.h 将其替换为如下内容
#ifndef CJ_ABSTRACT_GRAPHICS_SHAPE_ITEM_H #define CJ_ABSTRACT_GRAPHICS_SHAPE_ITEM_H #include <QAbstractGraphicsShapeItem> #include <QPainter> #include <QStyleOptionGraphicsItem> class CjAbstractGraphicsShapeItem : public QAbstractGraphicsShapeItem { public: explicit CjAbstractGraphicsShapeItem(QGraphicsItem *parent = nullptr) : QAbstractGraphicsShapeItem(parent) {} QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; }; #endif // CJ_ABSTRACT_GRAPHICS_SHAPE_ITEM_H
4、修改/home/work/tools/CJQT/native/includes/widgets/application.h 将其替换为如下内容
#ifndef CJ_APPLICATION_H #define CJ_APPLICATION_H class Config; // 前置声明:指针足够,不需要完整定义 #ifdef __cplusplus extern "C" { #endif // 仅声明;定义在 application.cpp 中(否则多重定义) extern Config *appConfig; void nativeApplicationInit(); #ifdef __cplusplus } #endif #endif // CJ_APPLICATION_H
5、修改/home/work/tools/CJQT/native/includes/widgets/graphics_item.h 将其替换为如下内容
#ifndef CJ_GRAPHICS_ITEM_H #define CJ_GRAPHICS_ITEM_H #include <QGraphicsItem> #include <QPainter> #include <QStyleOptionGraphicsItem> #include <QGraphicsSceneContextMenuEvent> #include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneWheelEvent> class CjGraphicsItem : public QGraphicsItem { public: explicit CjGraphicsItem(QGraphicsItem *parent = nullptr); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; // 绑定层入口:设置外接矩形(内部自动触发重绘) void setBoundingRect(const QRectF &rect); // 事件转发入口:基类对应函数是 protected,extern "C" 绑定层无法直接调用。 // 注意:这里不带 QGraphicsItem:: 限定,走虚派发—— // 子类重写了事件函数时走子类版本,未重写时落到基类默认实现 void doContextMenuEvent(QGraphicsSceneContextMenuEvent *event) { contextMenuEvent(event); } void doMouseMoveEvent(QGraphicsSceneMouseEvent *event) { mouseMoveEvent(event); } void doMousePressEvent(QGraphicsSceneMouseEvent *event) { mousePressEvent(event); } void doMouseReleaseEvent(QGraphicsSceneMouseEvent *event) { mouseReleaseEvent(event); } void doWheelEvent(QGraphicsSceneWheelEvent *event) { wheelEvent(event); } private: QRectF m_boundingRect; }; #endif // CJ_GRAPHICS_ITEM_H
6、 修改 /home/work/tools/CJQT/native/src/widgets/graphics_view.cpp 文件,在#include "graphics_view.h"下面补充上如下引用
#include <QGraphicsView> #include <QGraphicsScene> #include <QGraphicsItem> #include <QPainterPath> #include <QBrush> #include <QPoint> #include <QPointF> #include <QRect> #include <QRectF> #include <QPolygon> #include <QPolygonF> #include <QTransform> #include <QPainter>
7、修改/home/work/tools/CJQT/native/src/widgets/header_view.cpp 文件,找到 delete instance; 大约在16行,在下面添加 “ return 0; ”
8、修改/home/work/tools/CJQT/native/src/widgets/abstract_graphics_shape_item.cpp 文件,将uintptr_t nativeAbstractGraphicsShapeItemCreate(uintptr_t parentPtr) 函数内容改为如下
1 uintptr_t nativeAbstractGraphicsShapeItemCreate(uintptr_t parentPtr) 2 { 3 QGraphicsItem *parent = reinterpret_cast<QGraphicsItem *>(parentPtr); 4 CjAbstractGraphicsShapeItem *item = new CjAbstractGraphicsShapeItem(parent); 5 return reinterpret_cast<uintptr_t>(item); 6 }
9、修改/home/work/tools/CJQT/native/src/widgets/tree_view.cpp 文件,32行 qDebug()<<"hide ok!!!"<<endl; 的<<endl 删掉 改为 qDebug()<<"hide ok!!!";
10、修改/home/work/tools/CJQT/native/src/core/abstract_item_model.cpp 文件,17行 和 27行的<<endl 删掉
11、修改/home/work/tools/CJQT/native/src/core/item_selection_model.cpp 文件,13行 的<<endl 删掉
12、修改/home/work/tools/CJQT/native/src/gui/standard_item_model.cpp 文件,(nativeStandardItemModelRemoveColumn) 约67行 75行 82行 89行 下面添加 return 0;
13、修改/home/work/tools/CJQT/native/src/gui/standard_item.cpp 文件, 在 uintptr_t nativeStandardItemCreateRC(int rows,int columns) 函数内添加两句 QStandardItem *item = new QStandardItem(); return reinterpret_cast<uintptr_t>(item);
14、修改/home/work/tools/CJQT/native/src/gui/gui_application.cpp 文件修改为如下内容
#include "gui_application.h" #include <QGuiApplication> #include <QScreen> #include <QDebug> // QGuiApplication 构造要求 argc 是左值引用,且 argv 在应用整个生命周期内有效, // 因此使用静态伪造参数,绑定层调用时无需传递 argc/argv。 static int fakeArgc = 1; static char fakeArgv0[] = "cjqt"; static char *fakeArgv[] = { fakeArgv0, nullptr }; extern "C" { uintptr_t nativeGuiApplicationCreate() { CjGuiApplication *app = new CjGuiApplication(fakeArgc, fakeArgv); return reinterpret_cast<uintptr_t>(app); } void nativeGuiApplicationDelete(uintptr_t ptr) { CjGuiApplication *instance = reinterpret_cast<CjGuiApplication *>(ptr); delete instance; } int nativeGuiApplicationExec(uintptr_t ptr) { CjGuiApplication *instance = reinterpret_cast<CjGuiApplication *>(ptr); return instance->exec(); } void nativeGuiApplicationQuit() { // quit 是静态槽,不需要实例指针 QGuiApplication::quit(); } uintptr_t nativeGuiApplicationPrimaryScreen() { qDebug() << "nativeGuiApplicationPrimaryScreen"; QScreen *screen = QGuiApplication::primaryScreen(); if (screen == nullptr) { qWarning() << "nativeGuiApplicationPrimaryScreen: no screen, " "请确认已先调用 nativeGuiApplicationCreate()"; return 0; } qDebug() << "primaryScreen:" << screen->name(); return reinterpret_cast<uintptr_t>(screen); } }
15、修改/home/work/tools/CJQT/native/src/widgets/application.cpp 文件修改为如下内容
#include "application.h" #include "config.h" // Config 完整定义,按你项目实际路径写 #include <QApplication> // 全局变量唯一一处定义(配合头文件中的 extern 声明) Config *appConfig = nullptr; namespace { void register_meta_types() { qRegisterMetaType<QVector<int>>(); } } extern "C" { void nativeApplicationInit() { register_meta_types(); appConfig = new Config(); appConfig->appInit = true; } void nativeApplicationInitWithArg(int argc, char *argv[]) { register_meta_types(); appConfig = new Config(); appConfig->appInit = true; appConfig->argc = argc; appConfig->argv = argv; // 注意:QApplication 后续会读取 argv,argv 指向的内存 // 必须在整个应用生命周期内保持有效 } bool nativeApplicationIsCreate() { return appConfig != nullptr && appConfig->app != nullptr; } bool nativeApplicationExec() { if (appConfig != nullptr && appConfig->app != nullptr) { return appConfig->app->exec(); } return false; } void nativeApplicationBeep() { if (appConfig != nullptr && appConfig->app != nullptr) { appConfig->app->beep(); } } uintptr_t nativeApplicationPrimaryScreen() { if (appConfig != nullptr && appConfig->app != nullptr) { return reinterpret_cast<uintptr_t>(appConfig->app->primaryScreen()); } return 0; } void nativeApplicationQuit() { if (appConfig != nullptr && appConfig->app != nullptr) { appConfig->app->quit(); } } void nativeApplicationDelete() { if (appConfig != nullptr) { if (appConfig->app != nullptr) { delete appConfig->app; // 先删 Qt 应用对象 appConfig->app = nullptr; } delete appConfig; // 再删配置对象 appConfig = nullptr; // 置空,防悬挂指针被复用 } } }
16、修改/home/work/tools/CJQT/native/src/widgets/graphics_item.cpp 文件修改为如下内容
#include "graphics_item.h" CjGraphicsItem::CjGraphicsItem(QGraphicsItem *parent) : QGraphicsItem(parent) , m_boundingRect(0.0, 0.0, 0.0, 0.0) { } QRectF CjGraphicsItem::boundingRect() const { return m_boundingRect; } void CjGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(painter); Q_UNUSED(option); Q_UNUSED(widget); // 占位:通用图元默认不绘制内容。 // 具体形状子类(矩形/椭圆等)必须重写本函数绘制真实图形 } void CjGraphicsItem::setBoundingRect(const QRectF &rect) { if (rect == m_boundingRect) return; prepareGeometryChange(); // 几何变化前必须调用,否则重绘区域错乱、留下残影 m_boundingRect = rect; } extern "C" { uintptr_t nativeGraphicsItemCreate(uintptr_t parentPtr) { if (parentPtr == 0L) { CjGraphicsItem *item = new CjGraphicsItem(); return reinterpret_cast<uintptr_t>(item); } QGraphicsItem *parent = reinterpret_cast<QGraphicsItem *>(static_cast<uintptr_t>(parentPtr)); CjGraphicsItem *item = new CjGraphicsItem(parent); return reinterpret_cast<uintptr_t>(item); } void nativeGraphicsItemDelete(uintptr_t ptr) { CjGraphicsItem *instance = reinterpret_cast<CjGraphicsItem *>(static_cast<uintptr_t>(ptr)); if (instance == nullptr) return; // 所有权规则:加入场景后归场景管。先移出场景再 delete, // 否则场景析构时会再删一遍,双重释放崩溃 if (instance->scene() != nullptr) instance->scene()->removeItem(instance); delete instance; } void nativeGraphicsItemSetBoundingRect(uintptr_t ptr, double x, double y, double width, double height) { CjGraphicsItem *instance = reinterpret_cast<CjGraphicsItem *>(static_cast<uintptr_t>(ptr)); if (instance != nullptr) instance->setBoundingRect(QRectF(x, y, width, height)); } void nativeGraphicsItemDoContextMenuEvent(uintptr_t ptr, uintptr_t eventPtr) { CjGraphicsItem *instance = reinterpret_cast<CjGraphicsItem *>(static_cast<uintptr_t>(ptr)); QGraphicsSceneContextMenuEvent *event = reinterpret_cast<QGraphicsSceneContextMenuEvent *>(static_cast<uintptr_t>(eventPtr)); if (instance != nullptr && event != nullptr) instance->doContextMenuEvent(event); } void nativeGraphicsItemDoMouseMoveEvent(uintptr_t ptr, uintptr_t eventPtr) { CjGraphicsItem *instance = reinterpret_cast<CjGraphicsItem *>(static_cast<uintptr_t>(ptr)); QGraphicsSceneMouseEvent *event = reinterpret_cast<QGraphicsSceneMouseEvent *>(static_cast<uintptr_t>(eventPtr)); if (instance != nullptr && event != nullptr) instance->doMouseMoveEvent(event); } void nativeGraphicsItemDoMousePressEvent(uintptr_t ptr, uintptr_t eventPtr) { CjGraphicsItem *instance = reinterpret_cast<CjGraphicsItem *>(static_cast<uintptr_t>(ptr)); QGraphicsSceneMouseEvent *event = reinterpret_cast<QGraphicsSceneMouseEvent *>(static_cast<uintptr_t>(eventPtr)); if (instance != nullptr && event != nullptr) instance->doMousePressEvent(event); } void nativeGraphicsItemDoMouseReleaseEvent(uintptr_t ptr, uintptr_t eventPtr) { CjGraphicsItem *instance = reinterpret_cast<CjGraphicsItem *>(static_cast<uintptr_t>(ptr)); QGraphicsSceneMouseEvent *event = reinterpret_cast<QGraphicsSceneMouseEvent *>(static_cast<uintptr_t>(eventPtr)); if (instance != nullptr && event != nullptr) instance->doMouseReleaseEvent(event); } void nativeGraphicsItemDoWheelEvent(uintptr_t ptr, uintptr_t eventPtr) { CjGraphicsItem *instance = reinterpret_cast<CjGraphicsItem *>(static_cast<uintptr_t>(ptr)); QGraphicsSceneWheelEvent *event = reinterpret_cast<QGraphicsSceneWheelEvent *>(static_cast<uintptr_t>(eventPtr)); if (instance != nullptr && event != nullptr) instance->doWheelEvent(event); } }
13、用系统 Qt 编译 native 桥
cd native && mkdir -p build && cd build #完成修改后应该全程无错。
unset QT_HOME # 防止残留值干扰
QT_HOME=/usr cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
ls -l libnativeQt.so # 产物必须落在这里(cjpm.toml 的 ffi 路径指向此目录)
浙公网安备 33010602011771号