创建带下拉菜单的工具条按钮
创建带下拉菜单的工具条按钮如何构造一个带图标和下拉菜单的工具条按钮, Qt的例子DiagramScene给出了很好的例子.
提供了三个函数, 并在MainWindow的构造函数中依次调用:
createActions()
createToolBox()
createMenus()
重要的代码在createToolBox()中, 创建的:
下面是创建了按钮fontColorButton, 就是上图中被展开下拉菜单的按钮.
首先要创建QToolButton,
然后要调用它的setPopupMode()函数, 将其设置为QToolButton::MenuButtonPopup. 这样, 就会有下拉的标志和菜单动作.
然后要调用它的setMenu()函数为它设置菜单. 在这里, 我们通过函数createColorMenu()来创建并返回创建的菜单的指针.
这个按钮对应的QAction是textAction, 注意, 当为下来菜单的时候, 我们指定QAction的方式.
另外, 一个要注意的是对setAutoFillBackground()的调用.
1234567fontCo ...
std::expected和boost::leaf
std::expected和Boost::Leaf 使用笔记一直没有时间认真看一下Boost::Leaf。抽着有时间,把它和expect一起对比以下,看看它们有什么关系。
背景Boost::Leaf和std::expected, std::optional, std::variant等的区别:
optional是C++17提供的, expected是C++23提供的
std::optional<T>持有对象T或没有. 当它持有对象T时, 存储的是T对象本身而不是指针.
std::variant<T1,T2,T3>, 表示的是某一时刻该对象可能是T1, T2, T3种的任意一个( 有没有可能不持有任何对象? 要再去看看)
std::any表示可以表示任意类型的对象
std::expected<T,E>正常情况下表示T, 非正常情况下表示E, 同一时刻只能表示一个值
Boost::Leaf的Result<T>, 好像它的意思是在result<T>中只提供期望值,非期望值不提供了。而是通过它使用的特殊的语法来获得。
std: ...
decltype的关注点
读书笔记
decltype的关注点两种场景decltype有两种推导场景: 标识符的类型和表达式的类型. 区别是带不带括号. 如果不带括号, 表示要推导标识符的类型. 如果带了括号, 表示要推导表达式的类型. 我们通常看得不仔细, 往往会忽略后面一点.
当要推导表达式时, 遵循下面的规则:
若表达式的值为左值, 则推导出T&
若表达式的值为纯右值, 则推导出T
若表达式的值类别为将亡值, 则推导出T&&
例如, 考虑下面的声明:
12345QPoint pt;QPoint* pPt = &pt;const QPoint* cpPt = & pt;QPoint& lrPt = pt;QPoint&& rrPt = {};
则表达式推导结果:
12345678910111213// 左值using T1 = decltype((pt)); // T1为QPoint&using T2 = decltype((pPt)); // T2为QPoint*using T3 = dec ...
CPP中的智能指针
重新读一下Modern Effective C++这本书。
CPP中的智能指针unique_ptr和shared_ptr
尺寸:
unique指针和普通指针相同大小, 除非定义了自定义析构函数.
shared指针为两倍大小: 它还包括一个指向引用计数的指针. 它的析构函数指针不在类中.
析构函数 - unique_ptr的析构函数是类型的一部分, shared_ptr的析构函数是外部的东西
使用shared指针的注意点:
尽量使用make_shared()而不是使用构造函数. 避免多次使用裸指针构造shared_ptr时出现的问题: 尽量避免裸指针可见.
千万不能将一个shared_ptr的指针传给一个shared_ptr的容器.
12345678910std::vector<std::shared_ptr<Widget>> widgets;class Widget{public: ... void process() { widgets.emplace_back(this); ...
Qt的cmake项目中使用预编译头文件
在Qt的cmake项目中使用预编译头文件对Qt来说, 如果使用qmake, 要支持预编译头文件是很简单的一件事情. 但是在cmake下怎么做就有点难了. 这也是我长期以来不喜欢用cmake的原因之一.
但是, 因为要联编VTK, 终于不得不切换到cmake里面了. 研究了一下, 还是给整出来了.
考虑hierarchy项目层次的情况, 如果是单一的小项目, 也没有必要这么整.
可以在顶层CMakeLists.txt里面定义出所有要放到预编译头文件的头文件, 为了简单, 将其定义到一个变量PCH_FILES里面:
123456789101112131415set(PCH_FILES <QDebug> <QList> ... <vtkActor.h> <vtkActor2D.h> <vtkAngleWidget.h> <vtkAngleRepresentation2D.h> <vtkAngleRepresentation3D.h> <vtk ...
Qt5 Boxes示例编译失败
Qt5 Boxes示例编译失败在研究Qt的GraphicsView下使用OpenGL的事情, 一个很经典的例子就是Qt5的Boxes示例(在Qt6里面没有了). 但是Qt5的Boxes在Windows下会编译失败. 经过网上查找, 需要这么修改:
注释掉qtConfig(...)
增加LIBS += -lopengl32或LIBS += -lopengl
1234567891011121314151617181920212223242526272829QT += opengl widgetsrequires(qtConfig(combobox))#qtConfig(opengles.|angle|dynamicgl): error("This example requires Qt to be configured with -opengl desktop")HEADERS += 3rdparty/fbm.h \ glbuffers.h \ glextensions.h \ gltrianglemes ...
模板元编程技巧练习
模板元编程技巧练习使用conditional控制分支使用conditional和conditional_t来控制
12std::conditional<true, int, float>::type x=3;std::conditional<false, int, float>::type y=1.0f;
自己实现一个conditional的实现:
1234567891011template <bool B, typename T, typename F>struct conditional{ using type = T;};template <typename T, typename F>struct conditional<false, T, F>{ using type = F;};template <bool B, typename T, typename F>using conditiona_t = typename conditional<B ...
Qt中的ItemDelegate总结
Qt中的ItemDelegate总结本文是对这几年Model/View框架中使用Delegate的一个总结.
在Qt的Model/View框架中, 当我们需要在ItemView中对数据做编辑, 或者我们需要定制特殊的显示模式的时候, 标准的做法是使用ItemDelegate, 当然, 还可以使用QTableWidgetItem::setItemWidget()和QTreeWidgetItem::setitemWidget(), 但是这两个函数的限制也很大, 基本上也只能用来显示静态内容.
Qt中的ItemView中可以通过定制Delegate来定制特定Item的编辑和显示功能. 做这件事情呢, 有几种方法:
使用工厂类QItemEditorFactor
利用QItemEditorFactory, 注册指定数据类型使用的editor. 这种做法可能是最简单的, 但是同时也是使用限制最多的一种. 因为从接口上看, 我们完全看不到任何精细的控制途径. 但是对于简单场景, 这个已经足够了.
QItemEditorFactory是一个工厂类, 它负责管理QStyle ...
在Qt中集成VTK
1. 下载和安装VTK
下载源码包, 保存到工作目录中. 比如, 我自己的目录为c:/libs/vtk.
解压缩vtk的源码包. 默认解压缩当当前目录后是VTK-9.3.0, 我打算将这个目录用于构建后的版本目录, 因此将它改一下名字, VTK-9.3.0-src
建立两个同级的目录, VTK-9.3.0-build和VTK-9.3.0, 第一个是构建时的工作目录, 这样cmake的所有生成文件都放在这里, 不会破坏源代码目录VTK-9.3.0-src. 而VTK-9.3.0用于安装VTK的目录. 将这些目录都和安装目录隔离开, 避免万一构建出了什么问题后清理起来麻烦.
1.1 修改bugVTK9.3有一个bug, 会导致Debug模式下编译失败. 我们先修改一下.
打开Common\Core\vtkConstantImplicitBackend.h,
1234567891011121314VTK_ABI_NAMESPACE_BEGINtemplate <typename ValueType>struct VTKCOMMONCORE_EXPORT vtkConstan ...
线程安全接口的设计注意点
线程安全接口的设计注意点在多线程下, 最基本的保护数据的做法是使用互斥量来做保护. 比如, 标准C++库中的std::lock_guard, Qt中的QMutexLocker等.
注意点:
要注意检查是否向调用者提供了指向受保护的数据的指针或引用, 这些是危险的
要注意若内部函数调用了别的不受我们掌控的函数, 而且向这些函数传递了指针或引用, 也是危险的.
即使单个接口安全, 也要考虑接口之间的固有竞争问题. 因此要注意接口设计. 注意两个安全的接口调用之间的状态发生变化导致第一个接口的结果不可信的问题.
比如, 一个stack提供了size()和top()两个接口, 每个接口都是线程安全的, 但是客户先调用size()判断栈非空, 再调用top()获取栈顶元素, 这个逻辑就不是线程安全的了.
因此, 尽量使用单一接口实现判断-操作等工作, 不要让线程被打断.
在低负载的情况下, 也可以考虑在外部对整个数据接口再加上加互斥. 这是以效率为代价求得安全, 不是讨论的范畴. 并且, 甚至可能导致死锁, 更不值得考虑.
另一个要考虑的地方是异常的安全性. 应当 ...