QT+ CLion + Revit 问题汇总

15 篇文章 1 订阅
5 篇文章 0 订阅

ui因为一直想实现QT+CLion+Revit的开发路径,所以从头开始学习QT与C++,在这里记录一下QT遇到的问题及后续的问题。如果开发周期不足估计会用一两周爆肝出来,随时会断更。

目前的思路是C++创建dll,在dll里面编写QT界面,之后用C++ Revit 的API接口实现整个步骤。
中间需要用到sqlite3的数据库组件,目前就想到这么多。现在已经实现c++读取sqlite3并完成数据接口。


由于项目进度,之前为了实现cpp+QT耽误了太多时间,所以国庆肝了三天完成整个程序,能够将整个数据库的结构模型创建在revit中,在思路已经清晰的情况下,写起来速度确实快了很多,用完cpp再用c#发现c#的继承还挺好用的,测试一下整个项目之后再继续修复这个项目。下面是所有楼板的成果,21层的框架结构预估时间在十分钟以内可以完成,我是分块测试没有集中测试,明天去公司测试一下。
在这里插入图片描述

2021/09/14

SQLite3

带有中文路径的字符串转码
inline string UTF8ToGB(const char* str)
{
    string result;
    WCHAR *strSrc;
    LPSTR szRes;

    //获得临时变量的大小
    int i = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
    strSrc = new WCHAR[i + 1];
    MultiByteToWideChar(CP_UTF8, 0, str, -1, strSrc, i);

    //获得临时变量的大小
    i = WideCharToMultiByte(CP_ACP, 0, strSrc, -1, NULL, 0, NULL, NULL);
    szRes = new CHAR[i + 1];
    WideCharToMultiByte(CP_ACP, 0, strSrc, -1, szRes, i, NULL, NULL);

    result = szRes;
    delete[]strSrc;
    delete[]szRes;

    return result;
}

const char* path = strdup(UTF8ToGB(R"(C:\Users\xu.lanhui\Desktop\二次开发\test_db_files\morelevel.db)").c_str());

bool getValueFromDatabase::OpenSQLite(const char* path) {
    if(path == NULL)
        return false;
    int nlen = 0,codepage;
    char cpath[130];
    wchar_t wpath[130];
    codepage = AreFileApisANSI()?CP_ACP:CP_OEMCP;
    nlen = MultiByteToWideChar(codepage,0,path,-1,NULL,0);
    MultiByteToWideChar(CP_ACP,0,path,-1,wpath,nlen);
    nlen = WideCharToMultiByte(CP_UTF8,0,wpath,-1,0,0,0,0);
    WideCharToMultiByte(CP_UTF8,0,wpath,-1, cpath,nlen,0,0);
    int result = sqlite3_open_v2(cpath,&db,SQLITE_OPEN_READONLY,NULL);
    if(result == SQLITE_OK)
        return true;
    else
        return false;
}

QT

1. CMAKE文件
cmake_minimum_required(VERSION 3.20)
project(ReadDatabase)

set(CMAKE_CXX_STANDARD 14)
#自动调用moc,uic,rcc处理qt的部分
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

SET(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_PREFIX_PATH "E:\\Qt\\Qt5.14.2\\5.14.2\\mingw73_64")

find_package(Qt5 COMPONENTS
        Core
        Gui
        Widgets
        REQUIRED)


set(SOURCE_FILES  library.cpp sql_src/sqlite3.c unit.h ui/pathwindow.cpp ui/pathwindow.h)

add_executable(ReadDatabase ${SOURCE_FILES})

target_link_libraries(ReadDatabase
        Qt5::Core
        Qt5::Gui
        Qt5::Widgets
        )

if (WIN32)
    set(DEBUG_SUFFIX)
    #if (CMAKE_BUILD_TYPE MATCHES "Debug")
    #set(DEBUG_SUFFIX "d")
    #endif ()
    set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")
    if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
        set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
        if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
            set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
        endif ()
    endif ()
    if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E make_directory
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy
                "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
    endif ()
    foreach (QT_LIB Core Gui Widgets)
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy
                "${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll"
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
    endforeach (QT_LIB)
endif ()

2. mingw 编译报错 Must construct a QApplication before a QWidget

网上参考了很多链接,有说是debug与realse版本同时生成造成静态库冲突的问题,还有说是定义全局变量导致的问题,后来我发现我的问题是由于

int main() //修改前
int main(int argc , char* argv[]) // 修改后

在类中没有初始化QApplication造成的,归根结底还是自己菜。
3. 创建的ui.cpp,ui.h,ui.ui三件套在cpp中一直报错,但是运行时不报错,先build后运行也是没有问题但是依旧是错误提示不知道是IDE的问题还是确实存在这个事情。
在这里插入图片描述


2021/09/15

1. ui::pathwindow提示无法找到,但是可以正常生成

接上面的问题,由于能够显示界面所以昨天降错误忽视,结果今天赋值的时候发现无法赋值,因为ui指针是无效指针,并且无法找到ui_pathwindow.h的文件。注意到QT文件生成时会有一句注释,昨天研究过但是因为懒没有继续深入,造成今天的错误。。。。
// You may need to build the project (run Qt uic code generator) to get "ui_pathWindow.h" resolved
注释告诉我们build项目之前应该先使用uic生成一下ui_pathwindow.h,下面是uic的使用步骤,参照博客:QT中 uic 工具的使用

  • 直接在Window搜索界面搜索QT的控制台程序,因为我的程序使用的是MinGW64所以选择相应版本即可
    在这里插入图片描述
  • 点开后进入项目文件,我这里cd无法进入,可以直接输入盘符,然后执行cd命令
  • 因为我的ui文件在单独的ui文件夹中所以先qmake创建项目,使用命令:
    qmake -project,qmake ReadDatabase.pro在qmake项目之后会有.pro文件,可以直接去文件夹看名称
  • 之后cd进入ui文件执行uic命令pathwindow.ui -o ui_pathwindow.h,头文件名称按照自己的UI文件命名即可
    在这里插入图片描述

connector函数无效

如果在QT 5中使用连接器的老式写法,及connector( , SINGNAL() , ,SLOT())
会发现函数无效,比如listview无法调出clicked函数,这时我们需要采用新式写法,直接调取相应构件下的函数,如:QListview::clicked , 如果是自己写的函数,直接 pathWindow::show即可调用。具体的操作可以参照豆子的博客


2021/09/16

1.再CLion中使用external tools 修改ui文件后无法更新格式

解决办法,参照上面难问题,进入ui文件位置输入命令uic pathwindow.ui -o ui_pathwindow.h重新生成ui-pathwindow.h文件,有时间的可以直接修改.h文件小的构件可以这样修改,如果改动较大还是重新跑一边比较好。

使用MinGW-64编译是报错:multiple definition of xxx

解决办法:使用内联函数,通过内联函数减少重复定义,解决此问题。

生成QTlistview 最下面一行数据始终无法显示完整

重新生成一遍.h文件以后可以正常显示,不清楚具体的原因,todo:

qlistview添加checkbox

如果希望给listwidget添加checkbox可参照下面链接:http://www.qtcentre.org/threads/47119-checkbox-on-QListView
code:

    for (int i = 0; i < count; ++i) {
        QString string = static_cast<QString>(stringList.at(i));
        QStandardItem *item = new QStandardItem(string);

        item->setCheckable(true);
        item->setCheckState(Qt::Checked);

        itemModel->setItem(i,item);
    }

关于listview与listwidget的区别

listview继承自model类,listwidget继承自item,listview相对灵活,listwidget操作方便。具体解释参照链接:QListView和QListWidget的区别


2021/09/17

QListview中添加Checkbox之后,如何点击行,改变Checkbox状态。

  • 因为ListView继承自Model 所以数据存放在Model中,如果想要获取某一行的数据或是CheckBox的数据,需要进入QAbstractiteModel,获取改行某一列的具体值类型为QVaiant类型,QT中数据赋值依据相应的Role,像Checkbox就是CheckStatusRole,如果单纯的数据直接导出即可,自定义的话需要在加上强制转换即可。
int r_count = ui->listView->model()->rowCount();
    for (int i = 0; i < r_count; ++i) {
        //selected
        QModelIndex b_index = ui->listView->model()->index(i,0);
        QString level = b_index.data().toString();
        bool checked = b_index.data(Qt::CheckStateRole).toBool();
        if(checked)
        {
            float f_level = level.toFloat();
            tFloors.push_back(f_level);
        }
    }

实现点击按钮打开FileDialog对话框

这里面Filter的分割使用空格,如下面示例

QString fileName = QFileDialog::getOpenFileName(this, tr("open the data file"), "D:/", tr("files(*.db *.ydb)"));
    qDebug()<<fileName;

QTableview 简单初始化,及赋值

//ui style

    //hide row number
    ui->tableView->verticalHeader()->hide();
    //create model
    QStandardItemModel *tableModel = new QStandardItemModel(this);


    //set column titles

    QStringList columnTitles;
    columnTitles<<"Location"<<"Floor"<<"Name";
    tableModel->setHorizontalHeaderLabels(columnTitles);

    for (int i = 0; i < columns.size(); ++i) {
        stcolumn value = columns.at(i);
        QString column_locate = QString(value.location.display().c_str());
        QString column_name = QString(value.name.c_str());
        tableModel->setItem(i,0,new QStandardItem(column_locate));
        tableModel->setItem(i,1,new QStandardItem(QString::number(value.floor.evaluate)));
        tableModel->setItem(i,2,new QStandardItem(column_name));
        qDebug()<<column_locate;
        qDebug()<<value.floor.evaluate;
        qDebug()<<value.name.c_str();
    }

    ui->tableView->setModel(tableModel);

vector<> 自定义类中使用const char*传递字符串为空值

我定义了一个类,类中字符串使用const char*记录值,但是当值存放在vector容器中时,相应的字符串值变为空值,应该是vector作为一个指针存放数据,const char 此时指向失败,更换为string类型即可正常显示*
在这里插入图片描述

变换文件分隔符 ’ \ ’ ‘/’

QT中文件路径分隔符为/在Linux中使用这种格式,在Windows中需要将分隔符变为\,此时需要函数进行转换。来源:https://blog.csdn.net/Littlehero_121/article/details/115078556

QDir::toNativeSeparators(fileName).toStdString().c_str()

2021/09/22

经过假期与肠胃炎的争斗,现在继续编写程序-.-。

数组出界,自己检查代码不规范引发的 SIGTRAP (Trace/breakpoint trap)

节前取一个模块的数据,发现一直报错SIGTRAP (Trace/breakpoint trap),或是Process finished with exit code -1073740940 (0xC0000374),打开搜索引擎开始复制粘贴发现数组错误,或是数组读取出界又或是析构函数发现错误,为此我改动了我的类结构,发现还是此错误,最终发现是因为工厂模式中指向出现错误,将楼板类指向了楼层类,因此直接读取vector容器报错,不过以后碰到数组出界的问题可以参照下面的博客解决。c++调试在容器释放内存时报Unknown Signal 或 Trace/breakpoint trap异常

2021/09/24

程序的功能基本完成,简单点来说就是数据库的数据读取与整理,完成后因为要与Revit关联所以中建需要用到VC++,为了方便便将窗口程序打包成了dll,方便后期的使用,中间遇到了一些问题记录一下

CLion生成的带有dll窗口的类如何被其他c++调用

-  为了测试方便,所以我将原来的动态链接文件修改为执行文件,只一个修改一下CMAKElist即可
```cmake
# add_executable(ReadDatabase ${SOURCE_FILES})

add_library(ReadDatabase SHARED ${SOURCE_FILES})
```

修改CMAKE生成文件格式后无法生成dll文件

修改cmake文件后发现一直无法生成dll文件,发现将原有的.exe可执行文件删除后即可成功生成。
在这里插入图片描述

静态载入dll的方法

CMAKE文件,我们采用静态载入的办法,关于静态载入或是动态载入可以参照Windows:CLion下编写及动/ 静态调用DLL,重新创建项目编写cmake文件,将lib载入即可使用,此处注意一个事情,如果事情像我一样需要载入带有QT窗口的dll,需要将工程文件debug下的三个QT开头的dll一起copy过来,不然会一直报错无法找到文件,这种错误debug也不会有提示,错误名称为:Process finished with exit code -1073741515 (0xC0000135),此时我们需要将文件copy到debug文件下面,如下图。之后修改CMAKE文件与窗口文件相同,将QT环境配置好,就可以引用相应的内容,见下图
在这里插入图片描述

在这里插入图片描述

制作调用dll的函数接口

调用的话需要将dll文件中的部分函数公开,通过在头文件中定义使用extern "C" __declspec(dllexport) int hello2(int argc , char* argv[]); 并在cpp文件中实现,然后在引用文件中声明函数,即可使用函数接口实现功能


extern "C"{
    void get_lib();
    int hello2(int args,char* argv[]);
}

2021/09/25

C++ exe文件执行时报错缺少必要dll文件

  1. add command to cmake file
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
  1. 如添加1依旧报错,从MinGW的bin文件夹中copy出相应dll放在同一目录下即可

2021/09/28

multiple definition of 问题

昨天定义了一个单例类,向作为导出类导出交互数据,创建完单例模式之后运行报错重复定义,位置是在我的ui_pathwindow.hunit.h,根据网上的办法

  1. .pro文件内文件重复引用 排查后不是此问题
  2. 使用extern关键词,因为太麻烦没有使用
  3. 排查是否类名重复命名,导致生成时错误。重新修改名称为唯一名称后还是报错
    最后博客github案例,博客中警告具体的内容写在cpp文件中,不要再头文件定义内容,单例的初始化也在cpp中完成,案例也是分开编写,将原有的单例模式分成.h和.cpp后编译通过正常运行.
pathwindow.h

/*
 * singleton from
 * https://zhuanlan.zhihu.com/p/37469260
 */

class getSingletonValue{
private:
    static getSingletonValue* instance;
private:
    getSingletonValue() = default;
    ~getSingletonValue() = default;
    //prevent copying
    getSingletonValue(const getSingletonValue&) =delete;
    getSingletonValue& operator=(const getSingletonValue&) = delete;

private:
    class _Deletor{
    public:
        ~_Deletor();
        static _Deletor deletor;
    };

public:
    static getSingletonValue* getInstance();

    vector<st_slab> _Slabs;
    vector<st_wall> _Walls;
    vector<st_beam> _Beams;
    vector<float> _Levels;
    vector<st_column> _Columns;


};

pathwindow.cpp

//must initialization static variables out of class
getSingletonValue* getSingletonValue::instance = NULL;

getSingletonValue *getSingletonValue::getInstance() {
    if(instance == NULL)
        return new getSingletonValue();
    return instance;
}

getSingletonValue::_Deletor::~_Deletor() {
    if(getSingletonValue::instance != NULL)
        delete getSingletonValue::instance;
}

function ‘IDLL* GetObj()’ definition is marked dllimport

使用宏定义dll导出接口报错,无法标记dllexport,需要将宏定义放在#include的上方,让编译器首先编译宏命令即可解决。

extern_dll.h

#ifndef READDATABASE_EXTERN_DLL_H
#define READDATABASE_EXTERN_DLL_H

//1. macro definition
#ifdef DLL_EXPORTS
#define DLL_API_ __declspec(dllexport)
#else
#define DLL_API_ __declspec(dllimport)
#endif

#include "unit.h"
#include "library.h"

using namespace std;



class IDLL{
public:
    virtual vector<st_column> GetColumn() = 0;
    virtual vector<float> GetLevel() = 0;
    virtual vector<st_beam> GetBeam() = 0;
    virtual vector<st_slab> GetSlab() = 0;
    virtual vector<st_wall> GetWall() = 0;
    virtual void Release() = 0;

protected:
    getSingletonValue* _instance = getSingletonValue::getInstance();
};
extern "C" DLL_API_ IDLL* __stdcall GetObj();



#endif //READDATABASE_EXTERN_DLL_H


extern_dll.cpp

#define DLL_EXPORTS

#include "extern_dll.h"
#include "library.h"


class ImiDLL: public IDLL{
    vector<st_column> GetColumn() override;
    vector<float> GetLevel() override;
    vector<st_beam> GetBeam() override;
    vector<st_slab> GetSlab() override;
    vector<st_wall> GetWall() override;
    void Release() override;
};

vector<st_column> ImiDLL::GetColumn() {
    return _instance->_Columns;
}

vector<float> ImiDLL::GetLevel() {
    return _instance->_Levels;
}

vector<st_beam> ImiDLL::GetBeam() {
    return _instance->_Beams;
}

vector<st_slab> ImiDLL::GetSlab() {
    return _instance->_Slabs;
}

vector<st_wall> ImiDLL::GetWall() {
    return _instance->_Walls;
}

void ImiDLL::Release() {
    delete this;
}

extern "C" DLL_API_ IDLL* __stdcall GetObj(){
    return new ImiDLL;
}

2021/10/15

参照链接

  1. Qt5.8生成dll和调用详细图文教程
  2. QT窗口调用子窗口一闪而过问题
  3. 讲qt中的界面做成dll以便调用

QT创建dll并引用

今天继续修复之前的问题,考虑到之前实在CLion中创建的QT窗口,并且使用的时QMainWIndow类,所以这次将项目移植到QT Creater中并使用QWidgets类创建,整体都和之前一样就是修改导出函数和之前不一样。

QT Creater中导出类文件编写

还是和c++写的时候宏定义不同,如果QT直接创建Library会得到一个*_global文件,直接将文件宏定义复制把这个文件删除就可以了


#if defined(RDSTRUCALSOURCE_LIBRARY)
#  define RDSTRUCALSOURCE_EXPORT Q_DECL_EXPORT
#else
#  define RDSTRUCALSOURCE_EXPORT Q_DECL_IMPORT
#endif


#ifndef EXTERNAL_DLL_H
#define EXTERNAL_DLL_H


#include "unit.h"
#include "library.h"
#include <QtCore/qglobal.h>

using namespace std;

class getSingletonValue{
private:
    static getSingletonValue* instance;
private:
    getSingletonValue() = default;
    ~getSingletonValue() = default;
    //prevent copying
    getSingletonValue(const getSingletonValue&) =delete;
    getSingletonValue& operator=(const getSingletonValue&) = delete;

private:
    class _Deletor{
    public:
        ~_Deletor();
        static _Deletor deletor;
    };

public:
    static getSingletonValue* getInstance();

    vector<st_slab> _Slabs;
    vector<st_wall> _Walls;
    vector<st_beam> _Beams;
    vector<float> _Levels;
    vector<st_column> _Columns;

};


struct IDLL{
    virtual vector<st_column> GetColumn() = 0;
    virtual vector<float> GetLevel() = 0;
    virtual vector<st_beam> GetBeam() = 0;
    virtual vector<st_slab> GetSlab() = 0;
    virtual vector<st_wall> GetWall() = 0;
    virtual void Release() = 0;
};

class RDSTRUCALSOURCE_EXPORT GetObj{

public:
    GetObj();
    void MakeShow();
    IDLL* GetValue();
private:
    IDLL* _value;
};



#endif // EXTERNAL_DLL_H

链接sqlite3出现的undefine问题

由于是项目移植所以没有使用QT += sql这种配置模式,通过点击项目右键添加库选择外部库,选择自己的lib文件夹即可配置,我在这里头文件直接写的绝对路径,这里还没有修改试错过

win32: LIBS += -L$$PWD/../lib/ -lRDstrucalSource

INCLUDEPATH += $$PWD/../
DEPENDPATH += $$PWD/../

链接dll

和上面的链接库一样的操作步骤,将界面dll,.a,.h文件拷贝到一个文件夹中并添加外部连接,直接在项目中引用头文件即可使用。

#include "widget.h"

#include <QApplication>
#include "E:\QTprogram\lib\external_dll.h"
#include <qdebug.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

   GetObj* getObj = new GetObj();
   getObj->MakeShow();

    qDebug()<<"success";
    return a.exec();
}

QT 链接dll文件中界面一闪而逝的情况

其实是堆栈的应用,我们可以将创建窗口指针,show(),程序就会等待界面运行完成后继续运行后续的程序。

void GetObj::MakeShow()
{
    //show window
    PATHWINDOW *pathwindow = new PATHWINDOW();
    pathwindow->show();
}

今天下午没有什么事情,试了一下自己的想法目前一切正常,在下班时完成mingwc++项目间的相互调用,明天继续vc++的调用。放一张成果图。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ESP32是一款32位的微控制器,而ESP-IDF是官方提供的用于开发ESP32的软件开发框架。Clion是一款集成开发环境(IDE),可以用于开发和调试ESP32项目。 在使用Clion进行ESP32开发之前,需要先搭建好ESP-IDF和Clion的开发环境。以下是搭建ESP32+Clion开发环境的步骤: 1. 安装ESP-IDF:根据官方文档的指引,下载并安装ESP-IDF。确保安装的是与你的ESP32兼容的版本。 2. 安装Clion:下载并安装Clion,确保安装的是最新版本。 3. 配置ESP-IDF路径:打开Clion,进入File -> Settings -> Build, Execution, Deployment -> CMake,将ESP-IDF的路径添加到"CMake Options"中。例如,如果ESP-IDF安装在`/path/to/esp-idf`,则添加以下内容: ``` -DCMAKE_TOOLCHAIN_FILE=/path/to/esp-idf/tools/cmake/toolchain-esp32.cmake ``` 4. 创建ESP32项目:在Clion中创建一个新的CMake项目,并将ESP-IDF的示例项目导入到Clion中。可以通过以下命令将示例项目复制到你的项目目录中: ``` cp -r /path/to/esp-idf/examples/get-started/hello_world /path/to/your/project ``` 5. 配置CMakeLists.txt:打开项目中的CMakeLists.txt文件,并根据你的项目需求进行配置。确保设置了正确的目标硬件和端口。 6. 构建和烧录:在Clion中点击Build按钮,Clion将自动构建项目并生成可执行文件。然后,使用ESP-IDF提供的烧录工具将可执行文件烧录到ESP32上。 7. 调试:在Clion中配置调试器,可以使用GDB进行调试。在调试过程中,可以设置断点、查看变量的值等。 请注意,以上步骤仅为搭建ESP32+Clion开发环境的基本步骤,具体的配置和操作可能会因个人需求和环境而有所不同。建议参考ESP-IDF和Clion的官方文档以获取更详细的指导。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值