管理员 发布的文章

Qt: 表格控件(多级行列表头、表头单元格合并、右键菜单、内容联动)


概述

所里项目需要写关于Qt表的的东西,主要的东西有合并表头(包括列表头),百度里全都是一些关于QTableWidget的介绍及表格内容的操作啥的(Google里能还能找到几个有用的),关于表头的修改却少之又少,但是还是有两种方法来处理,虽然说是处理不如果说是相关介绍,代码都不知道在哪copy过来的,请问同学们,你们的代码能跑一下么?就算能跑不能分享一下么、、截个代码片段是什么意思。。。不够意思!!!

一、效果展示

  1. 普通合并表头
    屏幕截图 2021-12-25 151245.png
  2. 多级合并表头
    屏幕截图 2021-12-27 095141.png
  3. 右键菜单添加与删除及表格下拉联动
    test.gif

二、demo 下载链接

qt_demo.zip

三、定制表头

重中之重就是HeaderView,麻烦也在它,重写封装好的RTableHeaderView类已放到demo内。

1. 重写HeaderView (概述)

RTableHeaderView继承的QHeaderView, 添加setRowHeight、setColumnWidth、setSpan、setCellBackgroundColor、setCellForegroundColor这几个函数

  • class MultistageTableHeaderAPI RTableHeaderView : public QHeaderView
  • {
  • Q_OBJECT
  • public:
  • RTableHeaderView(Qt::Orientation orientation,int rows,int columns,QWidget* parent = 0);
  • virtual ~RTableHeaderView();
  • void setRowHeight(int row, int rowHeight);
  • void setColumnWidth(int col, int colWidth);
  • void setSpan(int row, int column, int rowSpanCount, int columnSpanCount);
  • void setCellBackgroundColor(const QModelIndex& index, const QColor&);
  • void setCellForegroundColor(const QModelIndex& index, const QColor&);
  • protected:
  • // override
  • virtual void mousePressEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
  • virtual QModelIndex indexAt(const QPoint&);
  • virtual void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const Q_DECL_OVERRIDE;
  • virtual QSize sectionSizeFromContents(int logicalIndex) const Q_DECL_OVERRIDE;
  • // inherent features
  • QModelIndex columnSpanIndex(const QModelIndex& currentIndex) const;
  • QModelIndex rowSpanIndex(const QModelIndex& currentIndex) const;
  • int columnSpanSize(int row, int from, int spanCount) const;
  • int rowSpanSize(int column, int from, int spanCount) const;
  • int getSectionRange(QModelIndex& index, int* beginSection, int* endSection) const;
  • protected slots:
  • void onSectionResized(int logicalIdx, int oldSize, int newSize);
  • signals:
  • void sectionPressed(int from, int to);
  • };

2. 定制列表头(概述)

  • // 横向表头
  • RTableHeaderView* p_header = new RTableHeaderView(Qt::Horizontal, 2, 15, ui->tableWidget);
  • QAbstractItemModel* pHeaderModel = p_header->model();
  • // 合并表头
  • p_header->setSpan(0, 0, 2, 1);
  • p_header->setSpan(0, 1, 2, 1);
  • p_header->setSpan(0, 2, 1, 13);
  • // 设置表头标题内容
  • pHeaderModel->setData(pHeaderModel->index(0, 0), QString("Reference"), Qt::DisplayRole);
  • pHeaderModel->setData(pHeaderModel->index(0, 1), QString("Action"), Qt::DisplayRole);
  • pHeaderModel->setData(pHeaderModel->index(0, 2), QString("Params"), Qt::DisplayRole);
  • for (int i = 0; i < 13; i++)
  • {
  • pHeaderModel->setData(pHeaderModel->index(1, i+2), QString("param_%1").arg(i), Qt::DisplayRole);
  • }
  • // 设置禁止点击
  • p_header->setSectionsClickable(false);
  • // 设置表头颜色
  • p_header->setCellBackgroundColor(pHeaderModel->index(0, 0), 0xcfcfcf);
  • p_header->setCellBackgroundColor(pHeaderModel->index(0, 1), 0xcfcfcf);
  • p_header->setCellBackgroundColor(pHeaderModel->index(0, 2), 0xcfcfcf);

3. 定制行表头(概述)

  • // 纵向表头
  • RTableHeaderView* p_vertical = new RTableHeaderView(Qt::Vertical, 6, 2, ui->tableWidget);
  • QAbstractItemModel* pVerticalModel = p_vertical->model();
  • // 合并表头
  • p_vertical->setSpan(0, 0, 2, 2);
  • p_vertical->setSpan(2, 0, 2, 1);
  • p_vertical->setSpan(4, 0, 2, 1);
  • // 设置表头标题内容
  • pVerticalModel->setData(pVerticalModel->index(0,0), QString("0"), Qt::DisplayRole);
  • pVerticalModel->setData(pVerticalModel->index(2,0), QString("1"), Qt::DisplayRole);
  • pVerticalModel->setData(pVerticalModel->index(4,0), QString("2"), Qt::DisplayRole);
  • pVerticalModel->setData(pVerticalModel->index(0,1), QString("name"), Qt::DisplayRole);
  • pVerticalModel->setData(pVerticalModel->index(1,1), QString("value"), Qt::DisplayRole);
  • pVerticalModel->setData(pVerticalModel->index(2,1), QString("name"), Qt::DisplayRole);
  • pVerticalModel->setData(pVerticalModel->index(3,1), QString("value"), Qt::DisplayRole);
  • pVerticalModel->setData(pVerticalModel->index(4,1), QString("name"), Qt::DisplayRole);
  • pVerticalModel->setData(pVerticalModel->index(5,1), QString("value"), Qt::DisplayRole);
  • // 设置禁止点击
  • p_vertical->setSectionsClickable(false);
  • // 设置表头颜色
  • p_vertical->setCellBackgroundColor(pHeaderModel->index(0,0), 0xcfcfcf);

四、右键菜单

在table中连接菜单槽函数

connect(ui->tableWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenu(QPoint)));

  • QMenu *menu = new QMenu(ui->tableWidget);
  • QAction *menu1 = new QAction(QString("添加"));
  • QAction *separator = new QAction();
  • separator->setSeparator(true);
  • QAction *menu2 = new QAction(QString("删除"));
  • connect(menu1, SIGNAL(triggered()), this, SLOT(menu_add()));
  • connect(menu2, SIGNAL(triggered()), this, SLOT(menu_delete()));
  • menu->addAction(menu1);
  • menu->addAction(separator);
  • menu->addAction(menu2);
  • menu->move(QCursor::pos());
  • menu->show();

CMake: 包含子项目


要求

在当前项目中包含一个library库项目,并使用子项目的相关东西。

目录结构树

  • cmake_demo
  • ├─ CMakeLists.txt
  • ├─ domo.tree
  • ├─ main.cpp
  • └─ sublibrary
  • ├─ CMakeLists.txt
  • ├─ sublibrary.cpp
  • └─ sublibrary.h

过程

在main.cpp 中调用子目录内的sublibrary类内的东西,这样方便拓展,也方便迁移。比如sublibrary可直接拿到其他项目内调用。

代码

main 内的 CMakeLists.txt

  • cmake_minimum_required(VERSION 3.0.0)
  • project(cmake_demo VERSION 0.0.1 LANGUAGES CXX)
  • # 自动添加CMAKE_CURRENT_BINARY_DIR和CMAKE_CURRENT_SOURCE_DIR到当前处理的CMakeLists.txt
  • SET(CMAKE_INCLUDE_CURRENT_DIR ON)
  • # 添加子项目目录
  • add_subdirectory(sublibrary)
  • # 分别将h和cpp归至变量
  • FILE(GLOB SRC_HEADER "*.h")
  • FILE(GLOB SRC_SOURCE "*.cpp")
  • # 添加执行文件
  • add_executable(${PROJECT_NAME} ${SRC_HEADER} ${SRC_SOURCE})
  • # 自动包含目录
  • set_property(TARGET ${PROJECT_NAME} PROPERTY
  • INTERFACE_INCLUDE_DIRECTORIES
  • ${CMAKE_CURRENT_SOURCE_DIR}
  • )
  • # 链接子项目
  • target_link_libraries(${PROJECT_NAME} sublibrary)
  • target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
  • set(CPACK_PROJECT_NAME ${PROJECT_NAME})
  • set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
  • include(CPack)

sublibrary 内的CMakeLists.txt

  • cmake_minimum_required(VERSION 3.0.0)
  • project(sublibrary VERSION 0.0.1 LANGUAGES CXX)
  • # 自动添加CMAKE_CURRENT_BINARY_DIR和CMAKE_CURRENT_SOURCE_DIR到当前处理的CMakeLists.txt
  • SET(CMAKE_INCLUDE_CURRENT_DIR ON)
  • SET(BUILD_SHARED_LIBS ON)
  • # 分别将h和cpp归至变量
  • FILE(GLOB SRC_HEADER "*.h")
  • FILE(GLOB SRC_SOURCE "*.cpp")
  • # 添加库文件
  • add_library(${PROJECT_NAME} SHARED ${SRC_HEADER} ${SRC_SOURCE})
  • # 自动包含目录
  • set_property(TARGET ${PROJECT_NAME} PROPERTY
  • INTERFACE_INCLUDE_DIRECTORIES
  • ${CMAKE_CURRENT_SOURCE_DIR}
  • )
  • target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
  • set(CPACK_PROJECT_NAME ${PROJECT_NAME})
  • set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
  • include(CPack)

算法(C++): 数值积分(龙贝格积分法)


算法原理

龙贝格(Romberg)求积法是甲酸定积分$T=\int_{a}^{b}f(x)dx$的最常用算法之一。
设$T_{m}(h)$ 步长为h时利用2m-2 阶牛顿-科茨(Newton-Cotes)公式计算得到的结果:$T_{m}(\frac{h}{2})$ 为将步长h减半后用2m-2 阶牛顿-科茨公式计算得到的结果。将他们机型线性组合,便得到步长为h的2m阶牛顿-科茨公式,即:

$$ T_{m+1}(h)=\frac{4^{m}T_{m}(h/2)-T_{m}(h)}{4^{m}-1} $$

其中$T_{1}(h)$为步长为h时的梯形公式计算得到的结果。$T_{1}(h/2)$为步长为h/2时的梯形公式计算得到的结果。
在实际计算时,龙贝格求积法按下表所示的计算格式进行,直到$|T_{m+1}(h)-T_{m}(h)| < \xi$为止。

梯形法则二阶公式四阶公式六阶公式八阶公式···
$T_{1}(h)$
$T_{1}(\frac{h}{2})$$T_{2}(h)$
$T_{1}(\frac{h}{2^{2}})$$T_{2}(\frac{h}{2})$$T_{3}(h)$
$T_{1}(\frac{h}{2^{3}})$$T_{2}(\frac{h}{2^{2}})$$T_{3}(\frac{h}{2})$$T_{4}(h)$
$T_{1}(\frac{h}{2^{4}})$$T_{2}(\frac{h}{2^{3}})$$T_{3}(\frac{h}{2^{2}})$$T_{4}(\frac{h}{2})$$T_{5}(g)$···
::::::

算法实现

  • double CommonAlgorithm::integral(double (* vFunction)(double x), double a, double b, double eps = 1e-6){
  • int m,n,i,k;
  • double y[10],h,ep,p,x,s,q;
  • // 迭代初值
  • h=b-a;
  • y[0]=h*(vFunction(a)+vFunction(b))/2.0;
  • m=1;
  • n=1;
  • ep=eps+1.0;
  • // 迭代计算
  • while ((ep>=eps)&&(m<=9))
  • {
  • p=0.0;
  • for (i=0;i<=n-1;i++)
  • {
  • x=a+(i+0.5)*h;
  • p=p+vFunction(x);
  • }
  • p=(y[0]+h*p)/2.0;
  • s=1.0;
  • for (k=1;k<=m;k++)
  • {
  • s=4.0*s;
  • q=(s*p-y[k-1])/(s-1.0);
  • y[k-1]=p; p=q;
  • }
  • ep=fabs(q-y[m-1]);
  • m=m+1;
  • y[m-1]=q;
  • n=n+n;
  • h=h/2.0;
  • }
  • return(q);
  • }

Window: wsappx搞事情,把磁盘占用到100%,禁用此服务!


事情的缘由

所里的电脑突然间卡的要死,看了眼任务管理器,磁盘占用100%,再一找,是个wxappx个东西一直在往盘里写东西,不知道干啥呢,直接停掉吧,要不一时半会占用下不来。

解决办法

win+R -> regedit 进注册表
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\AppXSvc
点击start
把3改成4

最后重启一下就可以了


HDF5: C++ 类封装(创建、写入操作)


简介

直接用c的代码写呢太麻烦,用官网的c++用例写呢还乱码,逼得我只能自己写个类来处理了,要不写的东西太多,c的太繁琐,所以自己封装个类方便调用。

hdf5 封装c++ 类

  • #ifndef _OPEN_HDF5_
  • #define _OPEN_HDF5_
  • #include <iostream>
  • #include <string>
  • #include <vector>
  • #include <typeinfo>
  • #include "h5Cpp.h"
  • using namespace std;
  • struct H5TITLE{
  • string name;
  • string type;
  • };
  • /******** ATTR ********/
  • class CRattr
  • {
  • private:
  • hid_t hand_id;
  • public:
  • CRattr(hid_t id){
  • hand_id = id;
  • };
  • ~CRattr(){};
  • template <class T>
  • shared_ptr<CRattr> attr(string key, T value, int len=1){
  • hid_t attr_type, attr_space;
  • hsize_t attr_dims[1] = { len };
  • char* value2 = new char(len);
  • if(typeid(T) == typeid(string) || typeid(T) == typeid(char*)){
  • attr_type = H5Tcopy(H5T_C_S1);
  • H5Tset_size(attr_type, H5T_VARIABLE);
  • }else if(typeid(T) == typeid(int)){
  • attr_type = H5T_NATIVE_INT;
  • }else if(typeid(T) == typeid(double)){
  • attr_type = H5T_NATIVE_DOUBLE;
  • }else{
  • return NULL;
  • }
  • attr_space = H5Screate_simple(1, attr_dims, NULL);
  • hid_t attr = H5Acreate(hand_id, key.c_str(), attr_type, attr_space, H5P_DEFAULT, H5P_DEFAULT);
  • if(typeid(T) == typeid(string) || typeid(T) == typeid(char*)){
  • H5Awrite(attr, attr_type, value2);
  • }else{
  • H5Awrite(attr, attr_type, value);
  • }
  • shared_ptr<CRattr> tmp = make_shared<CRattr>(hand_id);
  • return tmp;
  • }
  • };
  • /******** DATA ********/
  • class CRdata
  • {
  • private:
  • hid_t hand_id;
  • string dataset_name;
  • public:
  • CRdata(hid_t id, string name){
  • hand_id = id;
  • dataset_name = name;
  • };
  • ~CRdata(){};
  • template <class T>
  • shared_ptr<CRattr> insert(int len, T* wdata, vector<H5TITLE> &title){
  • herr_t status;
  • hsize_t dims[1] = { len };
  • hid_t memtype, space, dset, strtype = H5Tcopy(H5T_C_S1);
  • status = H5Tset_size(strtype, H5T_VARIABLE);
  • status = H5Tset_cset(strtype, H5T_CSET_UTF8);
  • memtype = H5Tcreate(H5T_COMPOUND, sizeof(T));
  • int sizet = 0;
  • for (int i = 0; i < title.size(); i++)
  • {
  • if (title.at(i).type == "string" || title.at(i).type == "char") {
  • H5Tinsert(memtype, title.at(i).name.c_str(), sizet, strtype);
  • } else if (title.at(i).type == "double") {
  • H5Tinsert(memtype, title.at(i).name.c_str(), sizet, H5T_NATIVE_DOUBLE);
  • } else if (title.at(i).type == "int") {
  • H5Tinsert(memtype, title.at(i).name.c_str(), sizet, H5T_NATIVE_INT);
  • }
  • sizet += sizeof(char*);
  • }
  • space = H5Screate_simple(1, dims, NULL);
  • // 创建数据集
  • dset = H5Dcreate(hand_id, dataset_name.c_str(), memtype, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
  • // 插入数据
  • status = H5Dwrite(dset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata);
  • shared_ptr<CRattr> tmp = make_shared<CRattr>(dset);
  • return tmp;
  • };
  • template <class T>
  • shared_ptr<CRattr> insertList(int rows, int cols, T* wdata){
  • hid_t space, dset;
  • hid_t memtype;
  • if (typeid(T) == typeid(double)) {
  • memtype = H5T_NATIVE_DOUBLE;
  • } else if (typeid(T) == typeid(long double)){
  • memtype = H5T_NATIVE_LDOUBLE;
  • } else {
  • memtype = H5T_NATIVE_INT;
  • }
  • hsize_t dims[] = { rows, cols };
  • space = H5Screate_simple(2, dims, NULL);
  • // 创建数据集
  • dset = H5Dcreate(hand_id, dataset_name.c_str(), memtype, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
  • // 插入数据
  • herr_t status = H5Dwrite(dset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata);
  • shared_ptr<CRattr> tmp = make_shared<CRattr>(dset);
  • return tmp;
  • };
  • };
  • /******** GROUP ********/
  • class CRgroup
  • {
  • private:
  • hid_t hand_id;
  • public:
  • CRgroup(hid_t id){
  • hand_id = id;
  • };
  • ~CRgroup(){};
  • shared_ptr<CRgroup> gopen(string group_name){
  • hid_t group_id = H5Gcreate(hand_id, group_name.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
  • shared_ptr<CRgroup> tmp = make_shared<CRgroup>(group_id);
  • return tmp;
  • };
  • shared_ptr<CRdata> dataset(string dataset_name){
  • shared_ptr<CRdata> tmp = make_shared<CRdata>(hand_id, dataset_name);
  • return tmp;
  • };
  • template <class T>
  • shared_ptr<CRattr> attr(string key, T* value, int len = 1){
  • shared_ptr<CRattr> tmp = make_shared<CRattr>(hand_id);
  • tmp->attr<T>(key, value, len);
  • return tmp;
  • }
  • };
  • /******** FILE ********/
  • class CRfile
  • {
  • private:
  • hid_t hand_id;
  • public:
  • CRfile(string file_name){
  • hand_id = H5Fcreate(file_name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
  • };
  • ~CRfile(){};
  • shared_ptr<CRgroup> gopen(string group_name){
  • shared_ptr<CRgroup> tmp = make_shared<CRgroup>(hand_id);
  • return tmp.gopen(group_name);
  • };
  • shared_ptr<CRdata> dataset(string dataset_name){
  • shared_ptr<CRdata> tmp = make_shared<CRdata>(hand_id, dataset_name);
  • return tmp;
  • };
  • hid_t getHand() {
  • return hand_id;
  • }
  • };
  • #endif

封装的使用示例

  • struct mtx{
  • double x;
  • double y;
  • string z;
  • };
  • struct mt{
  • double x;
  • double y;
  • char* z;
  • };
  • struct mtx mtt1[5];
  • for (int i = 0; i < 5; i++)
  • {
  • mtt1[i].x = i;
  • mtt1[i].y = i;
  • mtt1[i].z = "test";
  • }
  • struct mt mtt2[5];
  • for (int i = 0; i < 5; i++)
  • {
  • mtt2[i].x = mtt1[i].x;
  • mtt2[i].y = mtt1[i].y;
  • mtt2[i].z = (char*)mtt1[i].z.c_str();
  • }
  • double wdata[4] = {1,2,3,4};
  • Rfile test("test.h5");
  • struct mt *wdata2 = new struct mt[5];
  • vector<H5TITLE> title = {{"X","double"},{"Y","double"},{"Z","char"}};
  • for (int i = 0; i < 5; i++)
  • {
  • wdata2[i].x = mtt1[i].x;
  • wdata2[i].y = mtt1[i].y;
  • wdata2[i].z = (char*)mtt1[i].z.c_str();
  • }
  • test.gopen("gtest").gopen("gtest2").dataset("dset").insertList<double>(2,2,wdata);
  • int value[1] = {1};
  • test.dataset("dtest").insert<mt>(5, wdata2, title).attr<int>("Name", value, 1);
  • test.gopen("att").attr<int>("test", value, 1).attr<int>("test2", value, 1);

图示

微信图片编辑_20211129145125.jpg