QString与数转换
QByteArrary、QString、QSL使用注意事项
Qt在视频画面上绘制动态矩形
Qt开发经验
Qt5官方demo解析
Qt实现象棋
qt 如何设计好布局和漂亮的界面
官方下载: https://download.qt.io/official_releases/qt/
https://code.qt.io/cgit/
Qt Creator基本使用方法学习
QT的配置及目录结构
1、构建套件(Kit)中MSVC编译器报黄
因为msvc编译器的调试器为none,下载安装window software development kit即可。
2、用MSVC编译器时报下面的错(VC的问题):
3、vcaddin的配置
(1)属性配置要一致
工具->选项->Qt->Versions
项目属性->Qt Project Settings->Qt Istallation
(2)addin配置要一致
QT VS Tools->Qt Project Settings->version
4、注意安装路径和项目路径中,不能有中文、特殊符号。
5、MinGW是Minimalist GNU for Windows的缩写,是在Windows平台上使用的GNU工具集导入库的集合,这个集合包括了C编译器gcc,C++编译器g++,和调试器gdb等工具。
6、Qt creator theme更换
护眼较好的:Solarized (dark) by altercation:
https://github.com/ihonen/qt-creator-themes
- Download the .xml file containing the color scheme.
- On Linux/Mac OS: Copy the XML file to ~/.config/QtProject/qtcreator/styles.
On Windows: Copy the XML file to \Tools\QtCreator\share\qtcreator\styles.- Open Qt Creator and navigate to Tools > Options > Text Editor > Font & Colors and select your desired color scheme from the drop menu.
7、编译安装
mkdir build
cd build
../configure -prefix /usr/local/Qt-5.12.12 -release -opensource -nomake examples -nomake tests -confirm-license -shared -no-pkg-config -no-opengl -no-iconv -qt-xcb
make -j4
make
sudo make install
8、编译qt项目要三个步骤
1、qmake -project:生成pro文件
2、qmake xxx.pro:生成Debug,Release以及ui_xxx.h文件
3、make:生成exe可执行文档
Qt编译过程
编译Qt程序
一般的问题解决:清除、qmake、重新构建。
特殊的问题解决:须手动删除qmake生成的中间文件,诸如Makefile、.qmake.stash、ui_xxx.h、xxx.o、moc_xxx等。
jome编译生成的文件有:Makefile、.qmake.stash、Makefile.Debug、Makefile.Release等。
QString winName="新建文本文档.txt";//不报错
QString winName="新建文本文档.txt - 记事本";//报常量中有换行符错误
QString winName="新建文本文档.txt记事本";//报常量中有换行符错误
原因:VS的编译器不认中文,MinGW应该没问题
解决方法:
第一步:工具->选项中
第二步:所有使用中文的地方用fromLocal8Bit()
QString winName=QString::fromLocal8Bit("新建文本文档.txt - 记事本");
std::string转QString:
QString str = QString :: fromUtf8(content.c_str());
导致此error的原因有很多,遇到最多的是:头文件里定义了函数而源文件里没实现。
其次是有类同名,即重复定义了。
这种往往是复制的工程,影子生成目录还是复制前的目录,若是插件则run程序还是复制前的目录下程序名。取消影子目录,设run程序为插件生成目录的程序,注意清除、qmake、重新构建。
(1)“工具->选项->构建和运行->构建套件”中的套件名称不能有中文,且Sysroot要为空。
(2)调试lib时,工作目录要设到生成lib所在目录,而不能为%build。
路径中有中文或"02.myproject"之类的有特殊符号
两个解决方法:
(1)将代码文件夹同级目录下的Debug文件夹删除后重新build。
(2)qmake后生成了.qmake.stash文件,删除该文件后再qmake。实践证明不用关闭qtcreator,在工程所在目录执行: rm -f .qmake.stash 后重新构建即可。
原因: 是项目原来所在机子时间比较新,拷贝到目的机的时间旧造成的
解决: 关闭qt,在项目所在目录打开终端执行:
find . -type f -exec touch {} \;
find ./* -exec touch {} \;
- 1.变量真正重定义了
- 2.文件重复包含
- 3.自己手动删除了旧文件,使用新文件替换了,但是pro文件中并没有更改!!!也就是说在pro文件中对某个文件多次包含导致了变量或者函数重定义了!这是最坑的!
注意:删除项目文件时记得查看pro文件中是否同时删除了对应项!
undefined reference问题总结
- 1、项目所在文件夹有些cpp,但在pro中未添加
- 2、若是库,则找不到库
qt官方关于undefined symbol说明
(1)清理,重新构建。
(2)主程序、各插件所用的编译套件是否一致。
(3)函数在cpp中实现了,却没在头文件中定义。
(4)该类缺少了Q_OBJECT。
(5)pro中没有添加相应.h头文件。(虽然F2也能跳转过去)
file命令查看so架构与主程序是否一致:
$ file libaslam_cameras_april.so
ldd -r xxx.so 命令查看so库链接状态和错误信息:
ldd -r libaslam_cameras_april_python.so
linux-vdso.so.1 (0x00007ffdbddce000)
libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f3061675000)
libboost_python-py27.so.1.65.1 => /usr/lib/x86_64-linux-gnu/libboost_python-py27.so.1.65.1 (0x00007f3061435000)
libaslam_cameras_april.so => /home/os/catkin_ws/devel/lib/libaslam_cameras_april.so (0x00007f30610fa000)
libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007f304b692000)
undefined symbol: _ZN2cv6imshowERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_11_InputArrayE (/home/os/catkin_ws/devel/lib/libaslam_cameras_april.so)
undefined symbol: _ZN2cv7putTextERKNS_17_InputOutputArrayERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS_6Point_IiEEidNS_7Scalar_IdEEiib (/home/os/catkin_ws/devel/lib/libaslam_cameras_april.so)
undefined symbol: _ZN2cv11namedWindowERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi (/home/os/catkin_ws/devel/lib/libaslam_cameras_april.so)
因为类对象a被const修饰,表示该对象无法被修改, 但是A::getHeight()并没有const后缀修饰,导致编译器认为该函数可能会有修改对象的可能,因此编译器报此错误。如果确认只是getter函数且不修改数据,可将成员函数以const后缀修饰即可消除该错误。
在工程中使用LIBS+=-Lxx和LIBS+=-lxx可以指定动态库和静态库链接文件和路径,但是在运行程序时,对动态库的可能查找不到。
可以使用ldd test 进行测试验证,是否所有的动态库都已经定位成功,若没有定位成功,则需要考虑以下搜索过程:
(1).编译目标代码时指定的动态库搜索路径; QMAKE_RPATHDIR+=xxx 例如QMAKE_RPATHDIR+=/usr/local/lib,连接时将使用-rpath,/usr/local/lib/
(2).环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
(3).配置文档/etc/ld.so.conf中指定的动态库搜索路径;
(4).默认的动态库搜索路径/lib;
(5).默认的动态库搜索路径/usr/lib.
1、在不同线程启动QTimer。
2、在不同线程中直接操作QObject及子类。
3、在主线程new出QGraphicsScene对象,又传给子线程使用。
解决办法:在子线程中发信号,将数据传给创建对象的线程中处理。
问题:
pure virtual method called
terminate called without an active exception
segmentation fault
字面意思是调用了纯虚函数
1、子类中没有实现父类的纯虚函数。
2、子类在构造函数中调用了此函数(即使子类重写了纯虚函数)。
问题表现:在界面的btnClicked()函数中setText()操作可以在界面中显示,但在接收数据的处理函数中将结果setText()等对控件的所有操作都无效。 Qt5.12 creater警告:the code model could not parse an included file 编辑页面上部弹出: the code model could not parse an included file,which might lead to incorrect code completion and highlighting,for example 解决方法:删除.pro里面 重复的.cpp文件和重复的.h 文件 如果出现 “QPainter::begin: Paint device returned engine == 0, type: 2” 的问题,需要检查 QPainter 画布的大小。 QPainter::setRenderHint: Painter must be active to set rendering hints void QCPLayer::drawToPaintBuffer() paint buffer returned inactive painter 有两种方法: 方法2、禁用指定警告设置: 原因: 在代码中存在可能超出实际内存(越界)的操作,覆盖了xxx类的存储空间。 0、问题解决 (1)先建立或从别处拷来的类,为了发信号后加的Q_OBJECT,会报一堆"undefined reference to…",在.pro文件中随便改动一下再运行就好的(qmake一下)。 1、连接方式 (2)在 .ui设计界面中,在其中的Signals & Slots Editor选项框中,对signal和slot进行关联;在ui->setupUi(this);函数里进行connect,自动生成。 2、第5个参数 Qt::AutoConnection 表示默认的链接方式,sender和receiver在同一个线程,则表示槽函数会在当前线程中执行,等同于Qt::DirectConnection,也就是说,槽函数在sender线程中直接调用,如果sender和receiver不在同一个线程,则等同于Qt::QueuedConnection,也就是说,槽函数在recevier线程中执行. Qt::DirectConnection 当信号发送时,槽函数立即直接调用执行,无论槽函数所属对象在哪个线程。也就是上面说的槽函数在sender所在线程调用。 Qt::QueuedConnection 当信号发送时候,槽函数不会直接调用,直到接受者线程取得控制权时进行事件处理循环时候,槽函数才会调用执行。 Qt::BlockingQueuedConnection 和QueuedConnectionx相同,但是sender发送后线程会进入阻塞状态,只有receiver线程执行槽函数完成,才会结束阻塞状态,所以这种参数类型设定情况下,sender和receiver不能在同一个线程,否则会造成死锁发生。 Qt::UniqueConnection 这个作为一个flag需要和上面四种类型进行 按照位 或(|)放置重复连接,因为重复连接会造成connection 失败。 注意:如果槽函工作在receiver线程(不和sender在同一个线程),并且槽函数中有耗时操作,比如while循环等,这个时候sender在发送信号,槽函数是不会响应的,除非槽函数工作在sender线程中,也就是要把参数设置为DirectConnection 3、信号传递自定义结构体 需要注意以下几点: 4、两个类之间的通信方式 1、其中一个为另一个成员变量。 5、QMetaObject::invokeMethod() 参数介绍: QT pro文件解析 1、常用设置 程序运行时,动态库查找目录添加方法如下几种: 3、特殊用法 4、全局忽略编译警告(设置QMAKE_CXXFLAGS ) 5、包含不同版本的库 7、pro中的目录 切换头文件/源文件:在同一类的.h和.cpp文件之间切换 函数出现参数提示时按 特别注意:封装成库(带资源文件)的仍需额外提供资源文件。 1、右击项目名->添加新文件->Qt->Qt设计师界面类->Widget 1、鼠标进入 enterEvent QTimer和timeEvent两种方法 Qt的事件处理有5中级别: Qt绘图:画选中区域 QPixmap专门为图像在屏幕上显示做了优化 背景颜色和图片设置 Qt读写txt文件每一行的不同列的数据 Qt TCP/UDP通讯封装 udp简单使用 udp遇到的问题: 上面的方法为了清空缓冲区而关闭socket,有点大动干戈。可用select方法,利用其超时特性检测缓冲区是否为空来判断是否有数据,有数据时才调用recv进行清除。 B、socket一直发送得不到接收焦点,专门开个线程发送: C、服务端关闭后重启,客户端一直在发送,客户端收不到UDP 以上是如何收到ICMP端口不可达错误(内核收到如何让用户态感知),下面讨论的是如何让udpsocket不报告错误,从而不影响继续接收 还有就是采用A中的方法。 (2)丢包问题,发送间隔和缓冲区大小引起 udp发送中文: (1)服务器 (2)客户端 关于Qt多线程操作数据库 查看你的Qt有哪些驱动: margin与padding区别: border-radius可以将button变成圆形,也可以给div加有弧度边框 Qt实现只运行一个程序实例 1、pro文件中加入 2、加入头文件 3、寻找窗口,最大化显示 DOM解析xml实现读、写、增、删、改 XML操作: XML保存: 调整qtcreator界面字体大小 QMessageBox使用 若不知道某函数包含的头文件,在linnux终端下输入:man printf,man 3 printf,这个是第3节,进入后用b、z控制上下页,查看包含的头文件。 原因是一些窗体、QMessageBox、对象等没有析构,导致进程还在 Qt窗口关闭和应用程序停止是否调用析构函数的一些说明 在Qt中将QWindow或者QWidget嵌入到别的进程中的窗口中(windows) QT 自定义类访问UI控件的几种方法 (1)qt编写dll (2)qt调用dll 2、显示调用(太麻烦,不推荐) Qt调用dll(qt写的、vs写的) 工具–选项—构建和运行—概要:下方的“default build directory”是默认构建路径,把他修改为: 原来为: Qt交叉编译 界面类的重命名 ui与类关联的4种方法 (1)在/etc/xdg/QtProject/路径下找到qtlogging.ini文件,如果没有则创建 (2)将文件内容修改为如下内容 (3)重新运行Qt程序,就可以看到qDebug的输出了 c++多线程的三种方式: qt多线程同步 有4种Qt多线程方式: QThread::run()、moveToThread、QtConcurrent::run()、QRunnable。 2、moveToThread 3、QtConcurrent::run() 如果需要判断耗时操作执行完毕与否,可以使用QFuture和QFutureWatcher的结合。QFuture 表示异步计算的结果,QFutureWatcher 则允许使用信号和槽监视 QFuture。 QtConccurent管理的线程实际是从线程池分配线程资源的,而绑定QFutureWatcher的槽是在主线程中执行的。在需要单次执行且内部逻辑较简单的时候使用QtConccurrent + QFuture + QFutureWatcher是很方便的,可以减少很多编码工作量,而且在多cpu环境中,QtConccurent也会启用多核。 因为QRunnable没有继承于QObject,所以没法使用信号槽与外界通信,那么,如果要在QRunnable线程中和外界通信怎么办呢,通常有两种做法: 5、Qt多线程注意事项: ② Qt 还要求,在代表一个线程的QThread对象销毁之前,所有在这个线程中的对象都必须先delete。 1、QSemsphore 2、C语言中的 Semaphore 3、std::counting_semaphore( C++20 ) acquire 操作,信号量为零时,无法再减,堵塞线程,直到 release 操作让信号量加一(大于零) 4、c++11中实现信号量 QDirIterrator遍历目录 Qt的智能指针 传信号可直接用智能指针: 使用QProcess启动并嵌入带界面应用程序(好) 对于linux中如何将QProcess打开的程序最小化后再最大化显示的思路: 嵌入的思路: windows下cmd执行多条命令: QProcess调用cmd拷贝文件: 依次执行多个cmd下的命令:close()一下再执行 重启软件 linux下Qt切换输入法步骤 qt安装目录下/5.3/gcc_64/plugins 这个目录是用qt creator编译出的程序运行时调用插件的目录 若上面的拷贝不能解决问题,则自己编译fcitx-qt5再拷贝。 转到Qt6要注意的地方 三个渐变色类 1、阻塞延时 2、非阻塞延时 QTextStream是个非常好用的字符串处理类,它能够使得字符串或者是基于字符的设备、文件处理变得非常方便。如下操作,就可以像正常的C++那样,在QString的环境下使用cin、cout、cerr这些类了。 qt写串口助手 qt获取程序目录及名称 利用QSystemSemaphore和QSharedMemory实现进程间通讯 QSharedMemory传图片(通过QDataStream): 传文字(通过QDataStream): 传文字(通过QByteArray直接读写): 字符数组:memcpy固定数组 QGraphicsItem的使用 Scene相当于实际的景色,用view这个相机(画布)来展示scene。 setSceneRect()将QGraphicsScene坐标中的某点,放在视图的左上角(QGraphicsView坐标原点)。 在Qt的视图框架中,如果在scene中直接添加一个item,scene的大小就是这个item的boundingRect尺寸,也就是item的最大边界矩形。 对于使用removeItem()后是否还需要delete的问题,官方问题有给出明确解释: 62.1 局部事件循环 62.2 延迟中的事件循环 QtXlsxWriter操作excel Qurl和QurlQuery正确的搭配使用方法 生成json并转成QByteArray: Qt入门【内容基础、教程详细、AI项目实战】 索引0是char的低位 QSignalMapper类可以看成是信号的翻译和转发器。 菜单项的定制,QWidgetAction的使用 嵌入式QT移植 Qt在Linux下实现无边框可缩放的窗口 亲身实验以上两个链接ubuntu下都不行,下面的才有效: Qt官方示例-窗口标志 Qt::QWidget 窗口的默认属性 可以设置多个的窗口标志对照表 Qt::MSWindowsFixedSizeDialogHint Windows系统固定大小窄边框窗口 QT一种设置遮罩的方法 Qt笔记(六十三)之Qt实现窗口以及控件的全屏效果 调用QWidget的setWindowFlags()函数。 设置为Qt::Tool、Qt::SubWindow、Qt::Popup可以达到目的。 副作用: 设置Qt::Popup不能设置保持窗口在顶层和底层。 设置Qt::SubWindow的窗口没有标题栏,没有关闭按钮,也不能进行拉伸。这些功能需要自己实现。 设置Qt::Tool窗口可以拉伸也有关闭按钮,但是点击关闭按钮,程序并不退出。
原因:因为是调别人写的程序,这个窗体类有两个对象,显示的是一个,而接收数据却关联到另一个对象(不是当前显示的对象)。
总结:当时以为是多线程的原因,打印线程ID是相同的,如果是多线程造成的程序大概率要崩,但这个问题没有让程序崩,所以也就不是多线程的问题。应该往多实例上想,打印对象的地址进行比较(qDebug()<16、the code model could not parse an included file
故障现象: QApplication、QMainWidget不是有效的变量
解决方法: QtCreator–>帮助–>关于插件–>C+±->ClangCodeModel的勾去掉即可17、调试时std::string无法访问
sudo vim /qtcreator/debugger/stdtypes.py
#修改为:
def qdumpHelper_std__string(d, value, charType, format):
if d.isQnxTarget():
qdumpHelper__std__string__QNX(d, value, charType, format)
return
if d.isMsvcTarget():
qdumpHelper__std__string__MSVC(d, value, charType, format)
return
data = value.extractPointer()
# We can't lookup the std::string::_Rep type without crashing LLDB,
# so hard-code assumption on member position
# struct { size_type _M_length, size_type _M_capacity, int _M_refcount; }
(size, alloc, refcount) = d.split("ppp", value.address() + d.ptrSize())
refcount = refcount & 0xffffffff
d.check(refcount >= -1) # Can be -1 according to docs.
if size > 4002:
size = 4002
d.putCharArrayHelper(data, size, charType, format)
18、Qt编译报错:警告:覆盖关于目标“xxx”的配方
19、QPainter::begin: Paint device returned engine == 0, type: 2
pixmap 的Size =0, 或者 Size 过大 都会引起这个问题。
解决办法是初始化QPixmap的size不为0//QPixmap picture; //出警告,size为0
QPixmap picture(640, 480); //给个初始大小
QPainter painter;
if(painter.begin(&picture)) // begin返回false,因为picture是null,
{
painter.drawEllipse(10,20, 80,70); // draw an ellipse
painter.end();
picture.save("drawing.bmp");
}
原因是:没有beginQPainter painter(this);
painter.begin(this);
painter.end();
20、禁用指定的警告:如数值隐式转换
方法1、 禁用ClangCodeModel插件
打开QtCreator-帮助-关于插件
取消勾选C++下面的ClangCodeModel
打开QtCreator-工具-选项-C++ - Code Model - Diagnostic Configuration
拷贝Bulid-in下的Build-system warning,将警告名称前加-Wno-即可。
例如警告内容为-Wsign-conversion,则禁用语句为 -Wno-sign-conversion
21、can’t find linker symbol for virtual table for ‘xxx’ value
比如:int elmArray[10];
for(int i = 0; i < 20; ++i)
{
elmArray[i] = 0;
}
char* cpyString;
strcpy(cpyString , "TEST");
三、信号和槽
Qt信号槽连接不成功问题原因汇总
Qt多线程中的信号与槽
(2)若忘记实例化对象,而先进行了connect()连接,编译不报错,程序刚起就异常退出,这个比较隐蔽。
(3)新手常犯的错误是connect中的signal或slot的参数中带变量名(直接拷贝的)
(4)跨线程只有指定第5个参数才能连接的,是由于信号的参数不是基本数据类型,要么注册一下,要么指定连接方式Qt::QueuedConnection。
(5)路线程信号发送后会直接进入槽函数所依附的线程的事件队列(无论事件循环是否开启),然而,只有开启了事件循环,对应的槽函数才会在线程中得到调用。
(6)需要注意的是,当信号的发送与对象的槽函数的执行在不同线程中时,可能会产生临界资源的竞争问题。// Connection判断信号槽连接是否成功;
QMetaObject::Connection connectHandle = connect(m_pBtn, SIGNAL(clicked()), this, SLOT(onBtnCLicked()));
// bool isSuccess = connect(m_pBtn, SIGNAL(clicked()), this, SLOT(onBtnCLicked())); // 也可以这样写;
if (connectHandle)
{
qDebug() << "Connect Success";
}
(1)使用connect语句,比如://QT4中使用字符串作为信号槽,使用灵活,但对新手不友好,不能再编译期检查,容易在运行中出错。
connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
//QT5中使用强类型作为信号槽参数,能在编译期检查错误,提高容错性。
connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection)
//---------基本连接--------------------------------------------
connect(ui->btnTest, &QPushButton::clicked, this, &MainWindow::testmyfun);//这个可以正确连接
//头文件中testmyfun()的声明要放在private slots块中才能正确连接,
//否则编译不报错,运行时提示QObject::connect: No such slot MainWindow::testmyfun()
connect(ui->btnTest,SIGNAL(clicked()),this,SLOT(testmyfun()));
connect(ui->btnTest,SIGNAL(clicked()),this,SLOT(close()));//这个执行了
//---------信号槽重载---------------------------------------------------
//新版重载,用函数指针,指明函数类型,使编译器准确定位
void (Newspaper:: *pFunc)(const QString &, const QDate &) = &Newspaper::newPaper;
connect(&newspaper, pFunc, &reader, &Reader::receiveNewspaper);
//新版重载,也可以直接声明(强制类型转换):
connect(&newspaper, (void (Newspaper:: *)(const QString &, const QDate &))&Newspaper::newPaper, &reader, &Reader::receiveNewspaper);
//旧版重载,带参数-------------------------------------------------------
connect(mySpinBox, SIGNAL(valueChanged(int)), mySlider, SLOT(setValue(int));
connect(mySpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), mySlider, &QSlider::setValue);
//slot重载-------------------------
//连接重载过的函数,使用QOverload做类型转换
connect(socket, QOverload<QLocalSocket::LocalSocketError>::of(&QLocalSocket::error), this, &XXX::onError);
//连接重载过的函数,使用qOverload做类型转换,如果编译器支持C++14,
connect(socket, qOverload<QLocalSocket::LocalSocketError>(&QLocalSocket::error), this, &XXX::onError);
(3)同样是在 .ui界面,右键点击某个能发出信号的部件(比如PushButton),选择Go to Slot(转到槽),即可转到一个名为 on_btnClear_clicked()的槽进行具体响应程序的编写;连接实现是在setupUI()里用QMetaObject::connectSlotByName(QWDialog); 实现,简单直观最常用
(不需要自己写connect函数连接) 。
声明必须是:on_发射信号的部件对象名_信号名();private slots:
void on_pushButton_clicked();
connect()参数Qt:ConnectionType使用讲解
1)函数的第五个参数的不同表示槽函数在哪个线程中执行
2)具体的参数如下:
#include
高调低,直接调;低调高,发信号给高(或将高的指针传给低,用指针调用高)
2、两个平级,进行信号关联
3、单例取指针后,进行信号关联
QMetaObject的invokeMethod()方法用来调用一个对象的信号、槽、可调用的方法。这是一个静态方法,不管被调用方法是不是私有的,其函数原型如下:bool QMetaObject::invokeMethod(QObject *obj, //对象指针
const char *member, //对象方法
Qt::ConnectionType type, //连接类型
QGenericReturnArgument ret, //返回值
QGenericArgument val0 = QGenericArgument(nullptr), //参数
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument())
//例子
QMetaObject::invokeMethod( const_cast< QgsAbstractContentCacheBase * >( qobject_cast< const QgsAbstractContentCacheBase * >( this ) ),
"onRemoteContentFetched",
Qt::QueuedConnection,
Q_ARG( QString, path ),
Q_ARG( bool, true ) );
Qt :: DirectConnection,则会立即调用该成员。
Qt :: QueuedConnection,则会发送一个QEvent,并在应用程序进入主事件循环后立即调用该成员。
Qt :: BlockingQueuedConnection,则将以与Qt ::QueuedConnection相同的方式调用该方法,除了当前线程将阻塞直到事件被传递。使用此连接类型在同一线程中的对象之间进行通信将导致死锁。
Qt :: AutoConnection,则如果obj与调用者位于同一个线程中,则会同步调用该成员; 否则它将异步调用该成员。四、Pro文件使用
Qt 中pro文件详解TEMPLATE = app
#TEMPLATE:模板变量告诉qmake为这个应用程序生成哪种makefile,选项如下:
#app 创建一个用于构建应用程序的Makefile(默认)
#lib 创建一个用于构建库的Makefile
#subdirs 创建一个用于构建目标子目录的Makefile,子目录使用SUBDIRS变量指定
#aux 创建一个不建任何东西的Makefile。
#vcapp 仅适用于Windows。创建一个Visual Studio应用程序项目
#vclib 仅适用于Windows。创建一个Visual Studio库项目。
CONFIG += c++11
#CONFIG:指定编译器选项和项目配置,值由qmake内部识别并具有特殊意义。
#可以指定是生成debug模式还是release模式,还是都生成。
#也可以用来打开编译器警告或者关闭。还可以用来配置要Qt加载库
#release 项目以release模式构建。如果也指定了debug,那么最后一个生效。
#debug 项目以debug模式构建。
#debug_and_release 项目准备以debug和release两种模式构建。
#debug_and_release_target 此选项默认设置。如果也指定了debug_and_release,最终的debug和release构建在不同的目录。
#build_all 如果指定了debug_and_release,默认情况下,该项目会构建为debug和release模式。
#autogen_precompile_source 自动生成一个.cpp文件,包含在.pro中指定的预编译头文件。
#ordered 使用subdirs模板时,此选项指定应该按照目录列表的顺序处理它们。
#precompile_header 可以在项目中使用预编译头文件的支持。
#warn_on 编译器应该输出尽可能多的警告。如果也指定了warn_off,最后一个生效。
#warn_off 编译器应该输出尽可能少的警告。
#exceptions 启用异常支持。默认设置。
#exceptions_off 禁用异常支持。
#rtti 启用RTTI支持。默认情况下,使用编译器默认。
#rtti_off 禁用RTTI支持。默认情况下,使用编译器默认。
#stl 启用STL支持。默认情况下,使用编译器默认。
#stl_off 禁用STL支持。默认情况下,使用编译器默认。
#thread 启用线程支持。当CONFIG包括qt时启用,这是缺省设置。
#c++11 启用c++11支持。如果编译器不支持c++11这个选项,没有影响。默认情况下,支持是禁用的。
#c++14 启用c++14支持。如果编译器不支持c++14这个选项,没有影响。默认情况下,支持是禁用的。
#console 只用于app模板 应用程序是一个windows的控制台应用程序
#windows 只用于app模板 应用程序是一个windows的窗口应用程序
#testcase
#depend_includepath
#dll 只用于”lib”模板,库是一个共享库(dll)
#staticlib 只用于“lib”模板,库一个静态库
#plugin 只用于“lib”模板,库是一个插件,这会使dll选项生效
#当使用debug和release选项时(Windows下默认的),该项目将被处理三次:一次生成一个”meta”Makefile,另外两次生成Makefile.Debug和Makefile.Release。
#生成目标的目录
DESTDIR = $$PWD/../DH_Bin
#MOC_DIR:指定来自moc的所有中间文件放置的目录(含Q_OBJECT宏的头文件转换成标准.h文件的存放目录)
MOC_DIR = $$PWD/../DH_Compile/moc
#OBJECTS_DIR:指定所有中间文件.o(.obj)放置的目录。
OBJECTS_DIR = $$PWD/../DH_Compile/obj
#RCC_DIR:指定Qt资源编译器输出文件的目录(.qrc文件转换成qrc_*.h文件的存放目录)。
RCC_DIR = $$PWD/../DH_Compile/rcc
#UI_DIR:指定来自uic的所有中间文件放置的目录(.ui文件转化成ui_*.h文件的存放目录)。
#unix:UI_DIR = ../myproject/ui
#win32:UI_DIR = c:/myproject/ui
UI_DIR = $$PWD/../DH_Compile/ui
#RESOURCES:指定资源文件 (qrc) 的名称
#DEPENDPATH:程序编译时依赖的相关路径.即makefile生成.o时的依赖目录
DEPENDPATH += .
#INCLUDEPATH:头文件的包含路径,即指定编译项目时应该被搜索的#include目录。如果路径包含空格,需要使用引号包含。
INCLUDEPATH = c:/include
INCLUDEPATH += "C:/extra headers"
#LIBS:指定链接到项目中的库列表。如果使用Unix -l (library) 和 -L (library path) 标志,在Windows上qmake正确处理库(也就是说,将库的完整路径传递给链接器),库必须存在,qmake会寻找-l指定的库所在的目录。如果路径包含空格,需要使用引号包含路径。
win32:LIBS += c:/mylibs/math.lib
unix:LIBS += -L/usr/local/lib -lmath
#RC_FILE:指定应用程序资源文件的名称。这个变量的值通常是由qmake或qmake.conf处理,很少需要进行修改。
RC_FILE += $$PWD/UrgBenri.rc
#RC_ICONS:仅适用于Windows,指定的图标应该包含在一个生成的.rc文件里。如果RC_FILE 和RES_FILE变量都没有设置这才可利用。
RC_ICONS = myapp.ico
#CODECFORSRC:源文件编码方式
CODECFORSRC = GBK
# pro中LIBS、INCLUDEPATH 引入三方库时“空格”的处理有两种方式:(quote、"")
INCLUDEPATH +=$$quote(C:/Program Files (x86)/Windows Kits/8.1/Include/winrt)
LIBS += -L$$"C:/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x64"
LIBS+= -lquartz -lole32 -lstrmiids -lVfw32 -lstrmbase
//库查找目录为可执行程序目录下的lib目录
QMAKE_LFLAGS += -Wl,-rpath,\'\$\$ORIGIN\'/lib/
//.pro文件中的设置仅用于链接,并且不解决这些库的动态加载(应该通过该QMAKE_RPATHDIR指令解析).
QMAKE_RPATHDIR += $$PWD/../../Lib
(1).编译目标代码时指定的动态库搜索路径; QMAKE_RPATHDIR+=xxx 例如QMAKE_RPATHDIR+=/usr/local/lib,连接时将使用-rpath,/usr/local/lib/
(2).环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
(3).配置文档/etc/ld.so.conf中指定的动态库搜索路径;
(4).默认的动态库搜索路径/lib;
(5).默认的动态库搜索路径/usr/lib.TEMPLATE = subdirs
CONFIG += ordered #定义了ordered表示子项目按照添加的顺序来编译
SUBDIRS += lightbutton #高亮按钮控件
SUBDIRS += movewidget #通用控件移动类
SUBDIRS += flatui #模仿flatui类
SUBDIRS += countcode #代码统计组件
SUBDIRS += gifwidget #屏幕录制控件
SUBDIRS += comtool #串口调试助手
SUBDIRS += nettool #网络调试助手
SUBDIRS += ntpclient #NTP服务器时间同步
win32 {
SUBDIRS += ffmpegdemo #视频流播放ffmpeg内核
SUBDIRS += vlcdemo #视频流播放vlc内核
SUBDIRS += mpvdemo #视频流播放mpv内核
SUBDIRS += miniblink #miniblink示例
}
#如果你电脑对应的Qt版本有webkit或者webengine组件可以自行打开
#SUBDIRS += echartgauge #echart仪表盘含交互支持webkit及webengine
#designer项目只支持Qt4,如果是Qt4可以自行打开
#SUBDIRS += designer #QtDesigner4源码
关于QMAKE_POST_LINK、QMAKE_PRE_LINK
linux下多条语句用;分开
window下多语句用&&分开unix {
# 拷贝文件
QMAKE_POST_LINK += cp -rf $$PWD$${TARGET}.xml $$DESTDIR/$${TARGET}.pssf;
QMAKE_CXXFLAGS += -fvisibility=hiden
QMAKE_CXXFLAGS_RELEASE += -o0 #发布不优化
}
win32 {
RC_FILE = version.rc #版本信息
SRCCONFIGFILE = $$PWD/$${TARGET}.xml
SRCCONFIGFILE = replace(SRCCONFIGFILE,/,\\\\)
DESTCONFIGFILE = $$DESTDUR/$${TARGET}.pssf
DESTCONFIGFILE = $$replace(DESTCONFIGFILE,/,\\\\)
win32-msvc*:QMAKE_CXXFLAGS += /wd"4819" /utf-8
QMAKE_POST_LINK += copy /Y $${SRCCONFIGFILE} $${DESTCONFIGFILE} &&
}
# 编译后拷贝文件
DIR1 = $$PWD\config.ini
DIR2 = $$OUT_PWD\debug\config.ini
# 将/替换为\\才能正确识别路径
DIR11 = $$replace(DIR1, /, \\) # replace函数的第一个参数必须是大写,坑死了
DIR21 = $$replace(DIR2, /, \\)
QMAKE_POST_LINK += copy $$DIR11 $$DIR21
message($$DIR11)
message($$DIR21)
msvc编译器虽支持UTF-8源码文件,但在编译时仍会出现4819的警告,故设置忽略警告:win32-msvc*:QMAKE_CXXFLAGS += /wd"4819" /source-charset:utf-8 /execution-charset:utf-8
win32-msvc*:QMAKE_CXXFLAGS += /wd"4819" /utf-8
Qt音视频开发34-不同库版本不同位数的库和头文件的引用
6、遍历目录
Qt Pro文件 递归搜寻添加所有代码文件 并添加库路径message($$PROJECT_ROOT) //工程目录
message($$PWD) //当前目录
message($$DESTDIR) //生成文件目的目录
message($$TARGET) //生成文件的名字
message($${BuildPath}) //构建目录
./ ../ //相对目录(相对于当前pro文件)
五、右键菜单的涵义及常用快捷键
Follw Symbol Under Cursor:跟随光标下的符号,即转到符号定义处
Switch Between Function Declaration/Definition:在函数的声明和定义之间切换
Find Reference to Symbol Under Cursor:查找对符号的引用,相当于搜索这个符号
Open Type Hierarchy:获取类的继承关系,即类的层次结构
Open Include Hierarchy:打开包含层次结构
Refactor:
auto indent selection :自动缩进所选择的内容
Toggle Comment Selection:反转注释所选择的内容
上下文相关帮助:提示当前光标下内容的相关帮助
功能
快捷键
解释
Switch Header/Source
F4
在同名的头文件和源程序文件之间切换
Follow Symbol Under Cursor
F2
跟踪光标下的符号,若是变量,可跟踪到变量声明的地方;若是函数体或函数声明,可在两者之间切换
Switch Between Function Declaration and Definition
Shift+F2
在函数的声明(函数原型)和定义(函数实现)之间切换
Refactor\Rename Symbol Under Cursor
Ctrl+Shift+R
对光标处的符号更改名称,这将替换到所有用到这个符号的地方
Refactor\Add Definition in .cpp
为函数原型在 cpp 文件里生成函数体
Auto-indent Selection
Ctrl+I
为选择的文字自动进行缩进
Toggle Comment Selection
Ctrl+/
为选择的文字进行注释符号的切换,即可以注释所选代码,或取消注释
Context Help
F1
为光标所在的符号显示帮助文件的内容
Save All
Ctrl+Shift+S
文件全部保存
Find/Replace
Ctrl+F
调出查找/替换对话框
Find Next
F3
查找下一个
Build
Ctrl+B
编译当前项目
Start Debugging
F5
开始调试
Step Over
F10
调试状态下单步略过,即执行当前行程序语句
Step Into
F11
调试状态下跟踪进入,即如果当前行里有函数,就跟踪进入函数体
Toggle Breakpoint
F9
设置或取消当前行的断点设置
trl + M
当前行 添加/删除书签
Tab
补全,如同Linux的命令补全。
快捷键设置:工具-选项-环境-键盘-QtCreator
六、菜单栏、工具栏
redsize(600,400);
//菜单栏
QMenubar *bar=menuBar();//生成一个菜单栏,只能有一个
setMenuBar(bar);//将菜单栏放入窗口中,不显示是因为还没添加内容
Qmenu * fileMenu=bar->addMenu("文件");//创建菜单项
Qmenu * editMenu=bar->addMenu("编辑");
//fileMenu->addAction("新建");//创建菜单项
QMenu * newAction = fileMenu->addAction("新建");
fileMenu->addSeparator();//添加分隔线
//fileMenu->addAction("打开");
QMenu * openAction = fileMenu->addAction("打开");
//工具栏
QToolBar * toolBar=new QToolBar(this);//生成工具栏
addToolBar(Qt::TopToolBarArea,toolBar);//加入到窗口中,指定区域
toolBar->addAction(newAction);//将新建加入到工具栏中
toolBar->addSeparator();//加入分隔线
toolBar->addAction(openAction);
toolBar->setIconSize(QSize(45, 45));//设置图标大小
//工具栏中加入按钮
QPushButton *btn = new QPushButton("aaa",this);
toolBar->addWidget(btn);//加入窗体
/状态栏,只一个
QStatusBar * stBar = statusBar();
setStatusBar(stBar);//加入到窗口中
QLabel * label = new QLabel("左侧提示信息",this);
stBar->addWidget(label);
QLabel * label2 = new QLabel("右侧提示信息",this);
stBar->addPermanentWidget(label2);
铆接部件(浮动窗口),可多个
QDockWidget * dockWidget = new QDockWidget("浮动",this);
addDockWidget(Qt::LeftDockWidgetArea,dockWidget);//add说明可以有多个,set的只能有一个
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | RightDockWidgetArea);
///设置中心部件,只能有一个
QTextEdit * edit = new QTextEdit(this);
setCentralWidget(edit);
七、添加资源文件
1、将资源文件copy至项目目录中
2、项目导航栏中,右击项目->添加新文件->Qt->Qtresource File->给资源起名(如res),生成res.qrc文件
3、右击res.qrc->Open in editor即可编辑资源
4、添加前缀(如/)、添加文件
5、使用":+前缀名+文件名", ui->actionNew->setIcon(QIcon(“:/Image/butterfly.png”));ui->actionNew->setIcon(QIcon("E:/Image/anniu.png"));//另外机子必须拷贝文件
ui->actionNew->setIcon(QIcon(":/Image/butterfly.png"));
八、对话框
//创建模态对话框,阻塞,不能对其他窗口进行操作
QDialog dlg(this);
dlg.resize(200.100);
dlg.exec();
qDebug()<<"模态对话框弹出了";
//非模态对话框,不阻塞,可对其他窗口进行操作
QDialog * dlg2 = new QDialog(this);
dlg2->resize(200,100);
dlg2->show();
dlg2->setAttribute(Qt::WA_DeleteOnClose);//关闭时删除,防止内存泄漏
qDebug()<<"非模态对话框弹出了";
//错误对话框
QMessageBox::critical(this,"critical","错误");
//消息对话框
QMessageBox::information(this,"info","信息");
//提问对话框 参数1 父亲 2 标题 3 提示内容 4 按键类型 5 默认关联回车按键
if(QMessageBox::save == QMessageBox::question(this,"ques","提问",QMessageBox::Save|QMessageBox::Cancel),QMessageBox::Cancel))
{
qDebug()<<"选择的是保存";
}
else
{
qDebug()<<"选择的是取消";
}
//警告对话框
QMessageBox::warning(this,"warning","警告");
//其他标准对话框,颜色对话框
QClor color = QColorDialog::getColor(QColor(255,0,0));
qDebug()<<"r="<<color.red()<<"g="<<color.green()<<"b="<<color.blue();
//文件对话框 参数1 父亲 2 标题 3 默认打开路径 4 过滤文件类型
QString str=QFileDialog::getOpenFileName(this,"打开文件","c:\\Users\\pzs\\Desktop","(*.txt)");
qDebug()<<str;
//字体对话框
bool flag;
QFont font = QFontDialog::getFont(&flag,QFont("华文彩云",36));
qDebug()<<"字体:"<<font.family().toUtf8().data()<<"字号"<<font.pointSize()<<"是否加粗"<<font.bold()<<"是否倾斜"<<font.italic();
//单选按钮选中后
ui->rBtnWoman->setChecked(true);//设为选中
connect(ui->rBtnWoman,&QRadioButton::clicked,[=](){qDebug()<<"选中女了";}
//复选按钮选中后,0未选中,2选中
connect(ui->cBox,&QCheckBox::stateChanged,[=](int state){qDebug()<<state;}
//lisWidget
QListWidgetItem *item = new QListWidgetItem("锄禾日当午");
ui->listWidget->addItem(item);
item->setTextAlignment(Qt::AlignHCenter);
//用list一次添加,但不能居中
QStrignList list;
list<<"锄"<<"汗"<<"谁"<<"粒";
ui->listWidget->addItems(list);
//treeWidget树控件使用
ui->treeWidget->setHeaderLabels(QStringList()<<"英雄"<<"英雄介绍");//设置表头
QTreeWidgetItem * liItem = new QTreeWidgetItem(QStringList()<<"力量");
ui->treeWidget->addTopLevelItem(liItem);//添加顶层结点
QStringList heroL1;
heroL1<<"法师"<<"魔法值高";
QTreeWidgetItem *l1 = new QTreeWidgetItem(heroL1);
liItem->addChild(l1);//添加子结点
//下拉框
ui->comboBox->addItem("奔驰");
ui->comboBox->setCurrentIndex(0);
//QLable显示图片
ui->lbl_Image->setPixmap(QPixmap(":/Image/butterfly.png"));
//QLabel显示gif动态图片
QMovie * movie = new QMovie(":/Image/mario.gif");
ui->lbl_movie->setMovie(movie);
movie->start();
//关联QSpinBox和QSlider
void (QSpinBox:: * spinSignal)(int)=&QSpinBox::valuChanged;
connect(ui->spinBox,spinSignal,ui->horizontalSlider,&QSlider::setValue);//spin数字变化,slider移动
connecect(ui->horizontalSlider,&QSlider::valueChanged,ui->spinBox,&QSpinBox::setValue);//slider移动,spin数字变化
九、自定义控件
2、在新的界面窗体上布局组合控件,并编辑代码
3、在要使用的窗体上,放置一个Widget容器,右击->提升为->上一步组合的类名->添加->提升十、鼠标事件(可重载)
2、鼠标离开 leaveEvent
3、鼠标按下 mousePressEvent
4、鼠标释放 mouseReleaseEvent
5、鼠标移动 mouseMoveEvent(setMouseTracking(true)时不需要按下)
event->globalPos();//屏幕坐标
event->pos();//当前窗口坐标
event->x();
QPoint coursePoint = QCursor::pos();//获取当前光标的全局位置十一、定时器
QTimer、Timerevent、QBasicTimer 之间的区别//启动两个定时器,在定时器事件中根据ID判断是哪个定时器
int timerID1=startTimer(1000);
int timerID2=startTimer(2000);
void Widget::timerEvent(QTimerEvent * ev)
{
if(ev->timerId() == timerID1)
{}
else if(ev->timerId()==timerID2)
{}
}
/利用定时器类,直接连接信号槽即可
QTimer* timer = new QTimer(this);
timer->start(1000);
connet(timer,&QTimer::timeout,[=](){
static int num=1;
ui->label->setText(QString::number(num++));
});
timer->stop();
QTimer *myTimer=new QTimer(this);
if(myTimer->isActive()==false)
{
myTimer->start(100);
}
if(myTimer->isActive()==true)
{
myTimer->stop();
}
十二、事件的拦截
1、重写控件的事件处理函数:如重写keyPressEvent(),mousePressEvent()和paintEvent(),这是最常用的事件处理方法,我们已经看到过很多这样的例子了。
2、重写QObject::event(),在事件到达事件处理函数时处理它。在需要改变Tab键的惯用法时这样做。也可以处理那些没有特定事件处理函数的比较少见的事件类型(例如,QEvent::HoverEnter)。我们重写event()时,必须要调用基类的event(),由基类处理我们不需要处理的那些情况。
3、给QObject对象安装事件过滤器:对象用installEventFilter()后,所有达到目标控件的事件都首先到达监视对象的eventFilter()函数。如果一个对象有多个事件过滤器,过滤器按顺序激活,先到达最近安装的监视对象,最后到达最先安装的监视对象。
4、给QApplication安装事件过滤器,如果qApp(唯一的QApplication对象)安装了事件过滤器,程序中所有对象的事件都要送到eventFilter()函数中。这个方法在调试的时候非常有用,在处理非活动状态控件的鼠标事件时这个方法也很常用。
5、继承QApplication,重写notify()。Qt调用QApplication::nofity()来发送事件。重写这个函数是在其他事件过滤器处理事件前得到所有事件的唯一方法。通常事件过滤器是最有用的,因为在同一时间,可以有任意数量的事件过滤器,但是notify()函数只有一个。
许多事件类型,包括鼠标,键盘事件,是能够传播的。如果事件在到达目标对象的途中或者由目标对象处理掉,事件处理的过程会重新开始,不同的是这时的目标对象是原目标对象的父控件。这样从父控件再到父控件,知道有控件处理这个事件或者到达了最顶级的那个控件。//事件分发函数中处理
bool myLabel::event(QEvent *e)
{
if(e->type()==QEvent::MouseButtonPress)
{
return true;//代表用户处理,不向下分发
}
return QLabel::event(e);
}
//在事件分发之前进行过滤
ui->label->installEventFilter(this);//安装事件过滤器
//在所在窗体上重写eventFilter
bool Widget::eventFilter(QObject *obj, QEvent * e)
{
if(obj == ui->label)
{
if(e->type() == QEvent::MOuseButtonPress)
{
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
QString str =QString("事件过滤器中:鼠标按下了 x=%1, y=%2").arg(ev.x()).arg(ev.y());
qDebug()<<str;
return ture;//true代表用户自己处理这个事件,不向下分发
}
}
return QWidget::eventFilter(obj,e);//其他默认处理
}
十三、重载绘图函数(paintEvent)
Qt绘图:求圆和椭圆上任意角度点的坐标
Qt画一个太极
Qt实现路径渐变,绘制彩色的线条#include
//绘图的高级设置
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);//设置抗锯齿,但效率低
painter.drawRect(QRect(20,20,50,50));
painter.translate(100,0);//把画家抱起来,移动画家,以后的坐标以此为原点)
painter.save();//保存画家状态
painter.drawRect(QRect(20,20,50,50));
painter.translate(100,0);//把画家抱起来,再次移动画家,以后的坐标以此为原点)
painter.restore();//恢复画家状态,
painter.drawRect(QRect(20,20,50,50));
painter.drawPixmap(0,0,QPixmap(":/Image/123.png"));//利用画家画图
QBitmap是QPixmap的子类,它的色深为1,即只有黑白色
QImage可以访问到像素级
QPicture可以记录和重现QPainter的各条命令 绘图设备QPixmap
QPixmap pix(300,300);//生成绘图设备,相当于300*300的画布
pix.fill(QT::white);//填充颜色,默认黑色
QPainter painter(&pix);//生成一个画家,用pix这个画布
painter.setPen(QPen(Qt::green));//设置画笔
painter.drawEllipse(QPoint(150,150),100,100);//画圆
pix.save("E:\\pix.png");//保存
绘图设备QImage
QImage img(300,300,QImage::Format_RGB32);//生成绘图设备,相当于300*300的画布
img.fill(QT::white);//填充颜色,默认黑色
QPainter painter(&img);//生成一个画家,用pix这个画布
painter.setPen(QPen(Qt::blue));//设置画笔
painter.drawEllipse(QPoint(150,150),100,100);//画圆
img.save("E:\\pix.png");//保存
绘图设备QImage
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QImage img;//生成绘图设备
img.load(":/Image/Luffy.png");
for(int i=50;i<100;i++)
{
for(int j=50;j<100;j++)
{
QRgb value = qRgb(255,0,0);
img.setPixel(i,j,value);//修改像素点
}
}
painter.drawImage(0,0,img);
}
//QPicture绘图设备 记录和重现绘图指令
QPicture pic;
QPainter painter;
painter.begin(&pic);//开始往pic上画
painter.setPen(QPen(Qt::cyan));
painter.drawEllipse(QPoint(150,150),100,100);
painter.end();//结束画面
pic.save("E:\\pic.pzs");//后缀可自定义
//重现QPicture的绘图指令
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPicture pic;
pic.load("E:\\picpzs");//载入
painter.drawPicture(0,0,pic);//重现
}
十四、文件操作
14.1 文本读写
connect(ui->pushButton,&QPushButton::clicked,[=](){
QString path = QFileDialog::getOpenFileName(this,"打开文件","E:\\");
ui->lineEdit->setText(path);//将返回路径显示
QFile file(path);
file.open(QIODevice::ReadOnly);
// QByteArray array = file.readAll();//将文件内容读取到字节数组
QByteArray array;
while(!file.atEnd())
{
array+=file.readLine();//按行读
}
//ui->textEdit->setText(array);//默认的是utf-8编码
QTextCodec *codec = QTextCodec::codecForName("qbk");
ui->textEdit->setText(codec->toUnicode(array));
file.close();
});
//写文件操作
file.open(QIODevice::Append);//用追加的方式写
file.write("好的");
file.close();
//QFileInfo文件信息类
QFileInfo info(path);
qDebug()<<"大小"<<info.size()<<"后缀名:"<<info.suffix()<<"文件名称"<<info.fileName()<<"文件路径"<<info.filePath();
qDebug()<<"创建日期"<<info.created().toString("yyyy/MM/dd hh:mm:ss");//新版中是birthTime()
qDebug()<<"最后修改日期"<<info.lastModified().toString("yyyy-MM-dd hh:mm:ss");
14.2 二进制读写(并固定一次读入最大量)
//二进制读写
QFile file("file.data");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
file.open(QIODevice::ReadWrite);
QDataStream stream(&file);
stream.device()->seek(0);//游标移到开头
//利用QDataStream将大文件转化成二进制文件QBatyArray
QByteArray total_file;
QFile file("D:/jpeg.jpg");
int flag=file.open(QIODevice::ReadOnly);
QDataStream in(&file);
QFileInfo fileInfo("D:/jpeg.jpg");
int buffer_size=65535;
char datRawArray[buffer_size];
qDebug()<<"nomal"<<fileInfo.size()<<endl;
int total_size=0;
while(!in.atEnd())
{
int len = in.readRawData(datRawArray, buffer_size);
QByteArray block(datRawArray, len);
total_file = total_file + block;
}
qDebug()<<"read file finished,yotal size:"<<total_file.size()<<endl;
14.3 读文本(不同列)
QFile LocationFile("D:\\Test\\location.txt")
if(!LocationFile.open(QIODevice::ReadOnly)
qDebug() << "不能打开文件 location.txt";
QVector<double> vLocationX;
QVector<double> vLocationY;
QString strLine,xLocation,yLocation;
QStringList list;
QTextStream in(&LocationFile);
while(!in.atEnd())
{
#if 0
//使用QString::section()
strLine = in.readLine();
strXLocation = strLine.section(' ',0,0);
strYLocation = strLine.section(' ',1,1);
vLocationX.pushback(strXLocation .toDouble() );
vLocationY.pushback(strXLocation .toDouble());
#else
//使用QString::split()
list = strLine.split(' ');
if(list.size() >= 2)
{
strXLocation = list.at(0);
strYLocation = list.at(1);
vLocationX.pushback(strXLocation .toDouble());
vLocationY.pushback(strYLocation .toDouble());
}
#endif
}
十五、菜单栏按钮
setFixedSize(320,588);//设置固定大小
setWindowIcon(QIcon(":/res/***.png"));//设置程序图标
connect(ui->actionQuit,&QAction::triggered,[=](){
this->close();
};//关联菜单项按钮
十六、TCP、UDP
1、TCP服务器
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
tcpServer=NULL;
tcpSocket=NULL;
tcpServer = new QTcpServer(this);
tcpServer->listen(QHostAddress::Any,3000);
connect(tcpServer,&QTcpServer::newConnetction,[=](){
tcpSocket=tcpServer->nextPendingConnection();
QString ip = tcpSocket->peerAddress().toString();
qint port = tcpSocket->peerPort();
QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
ui->editRead->setText(temp);
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
QByteArray array = tcpSocket->readAll();
ui->editRead->append(array);
});
});
if(tcpSocket!=NULL)
{
QString str = ui->editWrite->toPlainText();
tcpSocket->write(str.toUtf8().data());//QString转char*
}
if(tcpSocket!=NULL)
{
tcpSocket->disconnectFromHost();
tcpSocket->close;
tcpSocket->NULL
}
2、TCP客户端
QTcpSocket *tcpSocket;
tcpSocket=NULL;
tcpSocket = new QTcpSocket(this);
connect(tcpSocket,&QTcpSocket::connected,[=]()[
ui->editRead->setText("成功和服务器连接");
]);
connect(tcpSocket,&QTcpSocket::readyRead,[=]()[
QByteArray array=tcpSocket->readAll();
ui->editRead->append(array);
]);
QString ip=ui->editIP->text();
qint16 port = ui->editPort->text().toInt();
tcpSocket->connectToHost(QHostAddress(ip),port);//#include
3、UDP
udp组播使用QUdpSocket * updSocket;
udpSocket = new QUdpSocket(this);
udpSocket->bind(8888);
///如果是是组播,加入组播,D类地址
//udpSocket->bind(QHostAddress::AnyIPv4,8888);
//udpSocket->joinMulticastGroup(QHostAddress("224.0.0.2");
//udpSocket->leaveMulticastGroup(QHostAddress("224.0.0.2");
connect(udpSocket,&QUdpSocket::readyRead,this,[=](){
char buf[1024]={0};
QHostAddress clientAddr;
quint16 clientPort;
qint64 len=udpSocket->readDatagram(buf,sizeof(buf),&clientAddr,&clientPort);
if(len>0)
{
QString str=QString("[%1:%2]%3")
.arg(clientAddr.toString()).arg(clientPort).arg(buff);
ui->editRead->setText(str);
}
});
///发送
QString ip=ui->lineEditIP->text();
qint16 port=ui->lineEditPort->text().toInt();
QString str = ui->textEdit->toPlainText();
udpSocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);
{
udpSocket=new QUdpSocket();
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(pushButton_clicked()));
connect(udpSocket,SIGNAL(hostFound()),this,SLOT(hasfindhost()));//先查看host是否存在
connect(udpSocket,SIGNAL(connected()),this,SLOT(hasconnected()));//判断如果连接上
connect(udpSocket,SIGNAL(disconnected()),this,SLOT(hasnotconnected()));//如果断开连接
connect(udpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(erro()));//显示错误
}
void MainWindow::pushButton_clicked()
{
QString string=ui->lineEdit->text();
udpSocket->connectToHost(string,6666,QIODevice::ReadWrite);
}
void MainWindow::hasfindhost()
{
qDebug()<<"HAS FOND HOST";
}
void MainWindow::hasconnected()
{
qDebug()<<"has connected";
}
void MainWindow::hasnotconnected()
{
qDebug()<<"has not connected";
}
void MainWindow::erro()
{
qDebug()<<"AN erro";
QString string=udpSocket->errorString();//此处为错误打印
qDebug()<<string;
}
(1)收不到数据
A、缓冲区有数据,触发未执行导致不再触发:
udp收不数据//在定时器里检查bytesAvailable(),属于QAbstractSocket类的成员函数
if(udpsocket->bytesAvailable()!=0)
{
qDebug()<<"接收不到数据,重启";
udpsocket->close ();
udpsocket=new QUdpSocket(this);
udpsocket->bind (1234,QUdpSocket::ShareAddress);
connect (udpsocket,&QUdpSocket::readyRead,this,&UdpCom::unicastRev);
}
ret<0 select函数出错
ret=0 超时,无事件发生,即没有数据可读
ret>0 有事件触发,则返回触发事件的描述符个数;
struct timeval tmOut;
tmOut.tv_sec = 0;
tmOut.tv_usec = 0;
fd_set fds;
FD_ZEROS( &fds );
FD_SET( skt, &fds );
int nRet;
char tmp[2];
memset(tmp, 0, sizeof( tmp ) );
while(1)
{
nRet = select( FD_SETSIZE, &fds, NULL, NULL, &tmOut );
if(nRet== 0)
break;
recv( skt, tmp, 1, 0 );
}
QUdpSocket接收槽不响应
udp丢包问题解决: QString recv = "";
QByteArray buff;
//使用while把前面接收的冲了,应使用if
//while(socket->hasPendingDatagrams())
if(socket->hasPendingDatagrams())
{
buff.resize(socket->pendingDatagramSize());
socket->readDatagram(buff.data(), buff.size());
recv = QVariant(buff).toString();
}
udpSocket捕获ICMP不可达错误
关于UDP接收ICMP端口不可达报文的两种方法
实际上,无连接UDP调用1次sendto( )发送UDP包,系统要做3件事:连接=>发送=>断开连接。而有连接UDP的send()由于已经连接好了,只需完成”发送”这一步,故有连接UDP在性能上要由于无连接UDP。
Windows UDP socket recvfrom返回10054错误的解决办法//为了不让recvfrom操作出错,在创建UDPsocket之后,设置I/O属性
BOOL bConnReset = FALSE;
DWORD dwBytesReturned = 0;
WSAIoctl(ReceivingSocket, SIO_UDP_CONNRESET, (void*)&bConnReset, sizeof(BOOL),
(void*)&Ret, sizeof(int), &dwBytesReturned, 0 ,0);
BOOL bEnableConnRestError = FALSE;
DWORD dwBytesReturned = 0;
WSAIoctl(iSock, SIO_UDP_CONNRESET, &bEnableConnRestError, sizeof(bEnableConnRestError), \
NULL, 0, &dwBytesReturned, NULL, NULL);
udp丢包-同机部署发送和接收
(3)调整udp缓冲区大小:
Ubuntu操作系统下,设置缓存大小的上限受到操作系统中某个文件的限制,此时需要手动修改默认的接收缓存最大值:
打开/proc/sys/net/core/rmem_max:改为4194304 (Ubuntu 16.0默认是212992)/proc/sys/net/ipv4/tcp_rmem //tcp接收缓冲区默认值
/proc/sys/net/ipv4/tcp_wmem //tcp发送缓冲区默认值
/proc/sys/net/core/rmem_default //udp接收缓冲区默认值
/proc/sys/net/core/wmem_default //udp发送缓冲区默认值
//临时
sysctl -w net.core.rmem_max=26214400
//永久 在/etc/sysctl.conf文件中加入,而后执行 sysctl -p 立即生效
net.core.rmem_max=26214400
//设置多个
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
udpsocket = new QUdpSocket(this);
udpsocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 4*1024*1024);//第一种方法,设置缓存
udpsocket->setReadBufferSize(16*1024*1024);//第二种方法
QUdpSocket *_socket;
......
//以下是解决QT发送QByteArray中有,中文字符会出出错的问题
QString sendtr = QString::fromLocal8Bit("QT令人发指的字符集问题");
QTextCodec* gbk = QTextCodec::codecForName("GBK");
QByteArray ary = gbk->fromUnicode(sendtr);
_socket->writeDatagram(ary, QHostAddress::LocalHost, m_port);//向m_port端口写数据
4、TCP发送文件
QTcpSetver *tcpServer;
QTcpSocket *tcpSocket;
QFile file;
QString fileName;
qint64 fileSize;
qint64 sendSize;
QTimer timer;
connect(&timer,&QTimer::timeout,[=](){
timer.stop;
sendData();
});//发完头部后间隔20ms再发文件数据
connect(&timer,&QTimer::timeout,[=](){
QByteArray buf= tcpSocket->readAll();
if(QString(buf) == "file done")
{
ui->textEdit->append("文件发送完毕");
file.close();
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
});//
void ServerWidger::on_buttonFile_clicked()
{
QString filePath=QFileDialog::getOpenFileName(this,"open","../");
if(false==filePath.isEmpty())
{
fileName.clear();
fileSize=0;
QFileInfo info(filePath);
fileName=info.fileName();
fileSize=info.size();
sendSize=0;
file.setFileName(filePath);
bool isOK=file.open(QIODevice::ReadOnly);
if(false==isOK)
{
qDebug()<<"打开文件失败";
}
ui->textEdit->append(filePath);
}
else
{
qDebug()<<"文件选择路径出错";
}
}
void ServerWidger::on_buttonSend_clicked()
{
//先发文件信息
QString head = QString("%1##%2").arg(fileName).arg(fileSize);
qint64 = tcpSocket->write(head.toUtf8());
if(len>0)//头部发送成功
{
//延时传文件,否则连包,对方不能及时处理
timer.start(20);
}
else
{
qDebug()<<"头部信息发送失败";
file.close();
ui->buttonFile->setEnabled(true);
ui->buttonSend->setEnabled(true);
}
}
void ServerWidget::sendData()
{
qint 64 len=0;
do
{
char buf[4*1024]={0};
len=0;
len=file.read(buf,sizeof(buf));
len=tcpSocket->write(buf,len);
sendSize+=len;
}while(len>0)//只要没有发送了才发完
if(sendSize==fileSize)
{
file.close();
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
ui->progressBar->setValue(0);
bool isStart=true;
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
QByteArray buf = tcpSocket->readAll();
if(true==isStart)
{
isStart=false;
fileName=QString(buf).section("##",0,0);//以##分隔的从第0段开始到第0段结束
fileSize=QString(buf).section("##",0,0).toInt();
recvSize=0;
file.setFileName(fileName);
bool isok=file.open(QIODevice::WriteOnly);
if(false)==isok
{
qDebug()<<"wrteonly error 40";
tcpSocket->sisconnectFromHost();
tcpSocket->close();
return;
}
QMessageBox::information(this,"文件信息",tr("接收的文件:[%1:%2kb]").arg(fileName).arg(fileSize));
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(fileSize/1024);
ui->setValue(0);
}
else
{
qint64 len=file.write(buf);
if(len>0)
{
recvSize+=len;
QString str = QString::number(recvSize);
tcpSocket->write(str.toUtf8().data());
}
ui->recvSize->setValue(recvSize/1024);
if(recvSize==fileSize)
{
tcpSocket->write("file done");
QMessageBox::information(this,"完成","文件接收完成");
file.close();
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
});
void clientWidget::on_buttonConnect_clicked()
{
QString ip=ui->lineEditIP->text();
quint16 port =ui->lineEditPort->text().toInt();
tcpSocket->connectToHost(QHostAddress(ip),port);
}
十七、SQL数据库
QSqlDatabase类:实现了数据库连接的操作
QSqlQuery类: 用来执行SQL语句
QSqlRecord类: 封装数据库所有记录qDebug()<<QSqlDatabase::drivers();
// ("QSQLITE", "QMYSQL", "QMYSQL3", "QODBC", "QODBC3", "QPSQL", "QPSQL7")
//(从 Qt5.12.4 开始默认没有 MySQL 的驱动插件,我们需要自己编译)
//pro文件中加入 :
QT += core gui sql
//头文件中:
#include
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(256) NOT NULL,
`password` varchar(256) NOT NULL,
`email` varchar(256) DEFAULT NULL,
`mobile` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
)
INSERT INTO `user` (`id`, `username`, `password`, `email`, `mobile`) VALUES
(1, 'Alice', 'passw0rd', NULL, NULL),
(2, 'Bob', 'Passw0rd', NULL, NULL),
(3, 'Josh', 'Pa88w0rd', NULL, NULL);
/**
* 输出 user 表里所有的 id, username, password
*/
void outputIdUsernamePassword() {
QSqlQuery query("SELECT id, username, password FROM user");
while (query.next()) {
qDebug() << QString("Id: %1, Username: %2, Password: %3")
.arg(query.value("id").toInt())
.arg(query.value("username").toString())
.arg(query.value("password").toString());
}
}
/**
* 输出 user 其 username 等于传入的参数 username
* @param username
*/
void outputUser(const QString &username) {
QString sql = "SELECT * FROM user WHERE username='" + username + "'";
QSqlQuery query(sql);
while (query.next()) {
qDebug() << QString("Id: %1, Username: %2, Password: %3")
.arg(query.value("id").toInt())
.arg(query.value("username").toString())
.arg(query.value("password").toString());
}
}
//这个是获得表头的例子
QSqlDatabase m_db;
m_db = QSqlDatabase::addDatabase("QMYSQL");
m_db.setHostName("127.0.0.1");
m_db.setPort(3306);
m_db.setDatabaseName("gradb");
m_db.setUserName("root");
m_db.setPassword("root");
if(!m_db.open()){
qDebug() << "error";
return;
}
m_db.exec("SET NAMES 'gbk'");
QString cmd = "SELECT * FROM gradb.`student`";
QSqlQuery sqlQuery;
if(!sqlQuery.exec(cmd))
return;
QStringList headList;
QSqlRecord sqlRecord(sqlQuery.record());
for(int i = 0; i < sqlRecord.count(); i++){
headList << sqlRecord.fieldName(i);//获得表头数据
}
qDebug() << headList;
while(sqlQuery.next()){
for(int i = 0; i < headList.size(); i++){
qDebug() << sqlQuery.value(headList[i]);
}
}
QStringList drivers=QSqlDatabase::drivers();//获取qt支持的数据库驱动类型
foreach(QString driver,drivers)
{
qDebug()<<drivers;
}
十八、QTableWidget
ui->tableWidger->setColumncount(3);
ui->tableWidger->setHorizontalHeaderLabels(QStringList()<<"姓名"<<"性别"<<"年龄";
ui->tableWidger->setRowCount(5);
//ui->tableWidger->setItem(0,0,new QTableWidgetItem("张三"));
QList<QString> nameList;
nameList<<"张三"<<"李四"<<"王五"<<"张龙"<<"赵虎";
QStringList sexList;
sexList<<"男"<<"男"<<"女"<<"男"<<"女";
for(int i=0; i<5; i++)
{
int col=0;
ui->tableWidger->setItem(i,col++,new QTableWidgetItem(nameList[i]));//[]会直接崩掉
ui->tableWidger->setItem(i,col++,new QTableWidgetItem(nameList.at(i)));//at()会抛出异常
ui->tableWidger->setItem(i,col++,new QTableWidgetItem(QString::number(18+i)));
}
十九、QSS
this->setStyleSheet("background-color:rgb(200,155,100)");//不能带空格
伪状态 描述
:checked button部件被选中
:disabled 部件被禁用
:enabled 部件被启用
:focus 部件获得焦点
:hover 鼠标位于部件上
:indeterminate checkbox或radiobutton被部分选中
:off 部件可以切换,且处于off状态
:on 部件可以切换,且处于on状态
:pressed 部件被鼠标按下
:unchecked button部件未被选中
子部件 描述
::down-arrow combo box或spin box的下拉箭头
::down-button spin box的向下按钮
::drop-down combo box的下拉箭头
::indicator checkbox、radio button或可选择group box的指示器
::item menu、menu bar或status bar的子项目
::menu-indicator push button的菜单指示器
::title group box的标题
::up-arrow spin box的向上箭头
::up-button spin box的向上按钮
margin是指从自身边框到另一个容器边框之间的距离,就是容器外距离。在CSS中padding是指自身边框到自身内部另一个容器边框之间的距离,就是容器内距离。 ui->pushButton->setStyleSheet(QString("QPushButton:pressed{
background-color:rgb(200,0,255);
color:rgb(0,255,0);
border-style:inset;}
QPushButton{
color:rgb(0,255,0)}"));
setStyleSheet("QPushButton:hover{background-color:blue}");
border-radius 规则:一个值: 四个圆角值相同
两个值: 第一个值为左上角与右下角,第二个值为右上角与左下角
三个值: 第一个值为左上角, 第二个值为右上角和左下角,第三个值为右下角
四个值: 第一个值为左上角,第二个值为右上角,第三个值为右下角,第四个值为左下角。
二十、只启动一个程序,并将已启动的提到最前并最大化(用vc的编译器可以)
win32{
LIBS+=-luser32
}
#include
QString winName=QString::fromLocal8Bit("新建文本文档.txt - 记事本");
HWND hw1=FindWindow(NULL,(LPCWSTR)winName.unicode());
if(hw1!=0)
ShowWindow(hw1,SW_MAXIMIZE);
else {
qDebug()<<"not find window";
}
二十一、操作XML文件
QString filename=QDir::currentPath()+"/config/config.xml";
QFile file(filename);
if(file.open(QFile::ReadOnly | QFile::Text))
{
return;
}
QDomDocument doc;//定义一个dom文件
if(!doc.setContent(&file)
{
file.close();
return;
}
QDomElement root = doc.docmentElement();//返回根节点
if(root.tagName() != "book")
{
.....
}
QDomNode node = root.firstChild();//获取第一个根节点
while(!node.isNull())
{
if(node.toElement.tagName=="你想读的nodeName")
{
QDomElement e = node.toElement();
if(e.text()!="")//内容不为空,读取值
{
QString str=e.text();
}
else //内容为空,寻找子节点if(e.text()=="")
{
QDomNodeList nodeList=e.childNodes();
for(int i=0;i<nodeList.count();i++)
{
QDomNode n=nodeList.at(i);
if(n.text()=="")
{
if(n.toElement.hasAttribute("statusName"))
{
QString title=n.toElement.attribute("Label");
int len=n.toElement.attribute("len").toInt();
}
}
}
}
}
node=node.nextSibling();//下一个兄弟节点
}
//遍历节点之一,while
QDomNode child = QDomElement element.firstChild();
while(!child.isNull())
{
if(child.toElement().tagName() == "myName")
{
}
child = child.nextSibling();
}
//遍历节点之二,一次全取出给QDomNodeList
QDomNodeLst nodeList = QDomElement element.firstChilds();
for(int i=0;i<nodeList.count(),i++)
{
if(nodeList.at(i).toElement().tagName()=="myName")
{
}
}
QDomDocument doc;
QDomProcessingInstruction instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
doc.appendChild(instruction);
QDomElement root = doc.createElement("HInfoData");//创建根节点
doc.appendChild(root);//添加根节点
QDomElement strMac = doc.createElement("Mac");//创建元素节点
root.appendChild(strMac);//添加元素节点到根节点
QDomText strMacNodeText = doc.createTextNode(data._strMac);//创建元素文本
strMac.appendChild(strMacNodeText);//添加元素文本到元素节点
QFile file("./test.xml");
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
return false;
QTextStream out(&file);
out.setCodec("UTF-8");
doc.save(out, 4, QDomNode::EncodingFromTextStream);
file.close();
//这两个的返回结果是一样的,将QDomNode转换为QDomElement,这两个函数返回的都是xml的节点名字。
QString QDomNode::nodeName() const
QString QDomElement::tagName() const
void QDomElement::setAttribute(name,value);
void QDomNode::setNodeValue(value);
void QDomNode::replaceChild(newNode,oldNode);
void
setAttribute(const QString &name, const QString &value)
void
setAttribute(const QString &name, qlonglong value)
void
setAttribute(const QString &name, qulonglong value)
void
setAttribute(const QString &name, int value)
void
setAttribute(const QString &name, uint value)
void
setAttribute(const QString &name, float value)
void
setAttribute(const QString &name, double value)
二十二、Qt显示编码格式
二十三、调整qtcreator界面字体大小
二十四、QMessageBox中文按钮
//指明了父对象为this
QMessageBox box(QMessageBox::Warning,QStringLiteral("标题"),QStringLiteral("弹出框按钮更改为中文!"),nullptr,this);
box.setStandardButtons (QMessageBox::Ok|QMessageBox::Cancel);
box.setButtonText (QMessageBox::Ok,QStringLiteral("确 定"));
box.setButtonText (QMessageBox::Cancel,QStringLiteral("取 消"));
box.exec ();
//简洁,但有两个按钮时关闭x不起作用
QMessageBox::information(this,"title",QStringLiteral("要提示的内容"),QStringLiteral("确定"));//只一个按钮可以close()
QMessageBox::information(this,"title",QStringLiteral("要提示的内容"),QStringLiteral("确定"));//X不起作用,故不能调用close()
if(0==QMessageBox::information(this,"title","你是要?","确定","取消"))
{
//0对应“确定”
//1对应“取消”
//2对应下一个按钮,以此类推,可添加多个自定义按钮
qDebug<<"确定";
}
//这个是查找并关闭MessageBox对话框,右上角的关闭有效才能用close()
QList<QMessageBox*> allbox = this->findChildren<QMessageBox*>();
qDebug()<<QStringLiteral("弹窗有:%1个").arg(allbox.count());
for(int i=0;i<allbox.count();i++)
{
allbox.at(i)->close();
}
二十五、Qt中使用printf()
#include
二十六、关闭窗口程序进程还在的解决方法
QApplication::quit();
二十七、Windows下中文乱码的解决方法
//保存为utf-8格式,下面两种只能用其一,加了#pragma就不需再用QStringLiteral
#pragma execution_character_set("utf-8") //头文件中加入
QStringLiteral("要提示的内容") //每个用到中文的地方
二十八、查找窗口并控制
//这个是延迟查找QMessageBox弹窗并关闭的(根据窗口类)
QTimer::singleShot(5000,this,[=](){
QList<QMessageBox*> allbox = this->findChildren<QMessageBox*>();
qDebug()<<tr("QMessageBox弹窗有:%1个").arg(allbox.count());
for(int i=0;i<allbox.count();i++)
{
allbox.at(i)->close();
}
});
//这个是根据窗口名查找并最大化,仅限于Windows,Linux上无windows.h不行
#include
//这个是QProcess打开程序,并控制其窗口(如按钮打开,再次点击把已打开的最大化前台显示)
QProcess process;
process.start();
QProcess::processId()
Q_PID QProcess::pid()
findWindow
QWindow::setWindowState;
二十九、嵌入窗口
三十、自写类中使用ui
31、网络状态获取
QList<QNetworkInterface> netfaceList = QNetworkInterface::allInterfaces();
for(int i=0; i<netfaceList.count(); i++)
{
QNetworkInterface interface = netfaceList.at(i);
if(!interface.isValid())
continue;
QNetworkInterface::InterfaceFlags interFlags = interfaces.flags();
QList<QNetworkAddressEntry> entryList = interface.addressEntries();
for(int j=0; j<entryList.count();j++)
{
QNetworkAddressEntry entry = entryList.at(j);
if(entry.ip().toString() == "192.168.1.33")
{
interFlags = interface.flags();
if(interFlags & QNetworkInterface::IsUP)
{}
if(interFlags & QNetworkInterface::IsRunning)
{}
if(interFlags & QNetworkInterface::CanBroadcast)
{}
if(interFlags & QNetworkInterface::CanMulticast)
{}
if(interFlags & QNetworkInterface::IsLoopback)
{}
}
}
}
QNetworConfigurationManager manager;
bool bOnline = manager.isOnline();
connect(&manager,SIGNAL(onlineStateChanged(bool)),this,SLOT(onlineStateChanged(bool)));
//configurationAdded
//configurationRemoved
//configurationChanged
//updateCompleted
32、获得桌面大小(双屏)
//单屏或双屏的主屏
int width = QApplication::desktop()->availableGeometry().width();
int height = QApplication::desktop()->availableGeometry().height();
//单屏或双屏(两个屏宽和)
int width = QApplication::desktop()->width();
33、编写动态库及其调用、调试
1、隐式调用//1、把 .h 与 .lib/.a 文件复制到程序当前目录下,把dll文件复制到程序的输出目录
//2、pro文件中添加 .lib 文件的位置: LIBS+= -L D:/hitempt/api/ -l myDLL
//3、include头文件(如果dll是用C写的,要加extern C)
extern "C" { #include "dll.h" }
显示调用需要的文件:.h头文件、.dll库文件。
通常Windows下程序显示调用dll的步骤分为三步(三个函数):LoadLibrary()、GetProcAdress()、FreeLibrary()#include
Qt调用dll(vs写的)有坑
Qt调用dll(vs写的)之调试
vs用qt插件调试Qt的dll工程34、修改默认构建目录为当前工程下
./%{CurrentBuild:Name}
../build-%{CurrentProject:Name}-%{CurrentKit:FileSystemName}-%{CurrentBuild:Name}
各部分元素的意义如下:
../ 当前目录的父目录(这部分用来指定构建目录处在什么位置,其中当前目录是指当前工程目录下)
build- 固定不变的字符,在目录名中原样显示
%{CurrentProject:Name} 变量值,即当前的工程名
- 固定不变的字符,在目录名中原样显示
%{CurrentKit:FileSystemName} 变量值,当前构建套件名,比如使用的是桌面版的MinGW进行编译,Qt版本为5.11,则为Desktop_Qt_5_11_1_MinGW_32bit-Debug
- 固定不变的字符,在目录名中原样显示
%{CurrentBuild:Name} 变量值,当前构建类型,比如是Debug还是Release
35、qt调用arm交叉编译链
Qt调用交叉编译环境搭建
Qt for ARM_Linux环境搭建
Qt5.14.0源码交叉编译
Qt creator设置交叉编译
1、安装交叉编译工具链
2、编译testlib电阻式触摸屏校准库
3、编译arm版qt库(qmake)
4、qtcreator设置环境
5、构建build
6、可执行文件传到arm板上执行36、界面类重命名
37、中标麒麟下qDebug()无输出
[Rules]
*.debug=true
qt.*.debug=false
38、qt多线程
qt自带的(只Qt)、posix pthread(linux)、std::thread(语言级别)38.1 Qt自身的多线程
Qt多线程及QtConcurrent使用
Qt的4种多线程
Qt好用的线程异步封装
QThread 一般有两种实现方式,一种是继承自QThread,并重载run函数,这种方式的缺陷是,所有的操作必须在run()中进行,并且不被官方建议如此使用;
另外一种是继承自QObject,然后moveToThread(),这样QObject的所有方法就会在次线程中运行,此种方式为官方所推荐。此外,如果需要多线程实现QTimer/QTcpSocket等,使用moveToThread方式是最为科学合理的。
另外两种:
qt多线程的三种方式
1、QThread::run()方式//mythread.h
#include
void MyThread::pushData(char *pbuf, int len)
{
QMutexLocker lock(&m_mutex);
m_ba.append(pbuf,len);
releaseSemaphore();
}
void MyThread::run()
{
while(m_bRun)
{
waitSemaphore();
if(!m_bRun)
break;
dosomthing();
}
}
这种方式只有发信号的是在多线程中执行,其他的还是在父线程中执行//.h
#include
QFuture的使用:多线程与进度条#include
QFutureWatcher<void> *pwatcher = nullptr;
pwatcher = new QFutureWatcher<void>;
//把扫描到的wifi信息输出到指定文件
QFuture<void> future = QtConcurrent::run([=]()
{
func(); //耗时操作
});
connect(pwatcher, &QFutureWatcher<void>::finished, this, [=]()
{
core(); //主线程操作
});
pwatcher->setFuture(future);
4、QRunnable
QRunnable的使用详解
QRunnable可以和QThreadPool结合使用。QThreadPool在调用QRunnable线程执行完后,确实会释放资源,但是并不会将对象置空。//.h-----
#include
//要调用的主界面函数
Q_INVOKABLE void setText(QString msg);
//QRunnable子类中
void CusRunnable::run()
{
qDebug() << __FUNCTION__ << QThread::currentThreadId();
QMetaObject::invokeMethod(m_pObj,"setText",Q_ARG(QString,"this is AA!")); //m_pObj为主界面指针
QThread::msleep(1000);
}
①Qt 要求QObject的所有子对象都必须和其父对象在同一线程。
这意味着:不能对有父对象(parent 属性)的对象使用QObject::moveToThread()函数
不能在QThread中以这个QThread本身作为父对象创建对象,,这是因为要创建该线程对象必然在其他的线程中创建,即该线程对象必然依附于其他线程对象,而以该线程对象为父类的子对向,在run函数中进行新建子类对象,若以其作为父对象,则与QT所定义的原则冲突,因此禁止。
class Thread : public QThread {
void run() {
QObject *obj = new QObject(this); // 错误!
}
};
这是因为QThread对象所依附的线程是创建它的那个线程,而不是它所代表的线程。
要达到这一点并不困难:我们只需在QThread::run()的栈空间(直接定义对象)上创建对象即可。
现在的问题是,既然线程创建的对象都只能在函数栈上,怎么能让这些对象与其它线程的对象通信呢?Qt 提供了一个优雅清晰的解决方案:我们在线程的事件队列中加入一个事件,然后在事件处理函数中调用我们所关心的函数。显然这需要线程有一个事件循环。这种机制依赖于 moc 提供的反射:因此,只有信号、槽和使用Q_INVOKABLE宏标记的函数可以在另外的线程中调用。
QMetaObject::invokeMethod()静态函数会这样调用:
QMetaObject::invokeMethod(object, “methodName”,
Qt::QueuedConnection,
Q_ARG(type1, arg1),
Q_ARG(type2, arg2));
上面函数调用中出现的参数类型都必须提供一个公有构造函数,一个公有的析构函数和一个公有的复制构造函数,并且要使用qRegisterMetaType()函数向 Qt 类型系统注册。38.2 linux上的POSIX Threads 或 Pthreads
#include
38.3 c++11之后的std::thread
// 演示多线程的CPP程序
// 使用三个不同的可调用对象
#include
38.4 多线程同步
38.4.1 信号量
acquire:减1计数,如果为负数则为阻塞,
release:加1计数,释放一个信号。QSemsphore m_semaphore;
void waitSemaphore(){m_semaphore.acquire();} //等信号
void releaseSemaphore(){m_semaphore.release();} //发信号
#include
int res = sem_init(&binSem, 0, 0);
sem_post(&binSem); //发信号
sem_wait(&binSem); //等信号
#include
通过互斥锁和条件变量实现。#include
39、QDirIterator
QString path = "目标路径";
QDirIterator iter(path, QStringList() << "*.jpg" << "*.png",QDir::Files | QDir::NoSymLinks,QDirIterator::Subdirectories);
while(iter.hasNext())
{
iter.next();
//QString curpath = iter.next(); //直接可返回目录名
qDebug() << "filePath:" << iter.filePath(); //包含文件名的文件的全路径
}
40、智能指针
/*------------- 实现单例 -------------*/
// cpp 中定义全局变量
QSharedPointer<MyObject> g_ptrMyObj;
QSharedPointer<MyObject> GetMyObj() {
if (g_ptrMyObj.data() == NULL) {
g_ptrMyObj.reset(new MyObject());
}
return g_ptrMyObj;
}
shared_ptr<vector<vector<float>>> data = std::make_shared<vector<vector<float>>>(samplesAtOnce, vector<float>(fftSize)); //(3, 2048)
emit signalData(data); //void signalData(shared_ptr
41、QProcess使用
41.1 Linux下使用QProcess
QProcess执行带管道的命令
linux中获得窗口id
shell获得窗口id//Qt中WinId在Windows平台上得到的是其句柄,并不是他的WindowsID
QProcess *process=new QProcess(this);
...
process.open()
... // wait until window appears
WId winId=PidToWid(process->processId()); // this function returns the Window ID in decimal format. I test this with xwininfo, it's always correct
//终端中: wmctrl -lp | grep processId | awk '{print $1}'
...
QWindow *window = QWindow::fromWinId(winId);
window->showMaximized();
//client app--------------------
widget->show(); //Widget had to be shown
widget->createWinId();
sendWinId(widget->winId()); //Post window handle to master app where is constructed container
//master app------------------------------------
QWindow* window = QWindow::fromWinId(clientWinId);
window->show(); //This show/hide toggle did trick in combination with show in client app
window->hide();
//通过container控制QWindow
QWidget* container = QWidget::createWindowContainer(window, parentWindowWidget);
QWindow *window = QWindow::fromWinId(125829124);
QWidget *widget = QWidget::createWindowContainer(window);
widget->setParent(this);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(widget);
this->setLayout(layout);
WId id = (WId)FindWindow(L"GUIClassName", L"ProgramName");
if(id == 0)
return;
//获取窗口
QWindow *window;
window = QWindow::fromWinId(id);
if(!window)
return;
//将第三方窗口放入widget中
QWidget* widget;
widget = QWidget::createWindowContainer(window, this, Qt::Widget);
ui->verticalLayout->addWidget(widget);
//创建进程
//QString cmd="C:/Program Files/R/R-3.3.1/bin/x64/Rgui.exe";
QString cmd = "C:/Windows/system32/calc.exe";
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = true;
bool bRet = CreateProcess(
NULL,
(LPWSTR)cmd.toStdWString().c_str(),
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL, &si, &pi);
Sleep(5000);
WId wid = (WId)FindWindow(L"CalcFrame", L"计算器");
//WId wid = (WId)FindWindow(L"Rgui Workspace",NULL);
QWindow *m_window;
m_window = QWindow::fromWinId(wid);
m_window->setFlags(m_window->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint); //
QWidget *m_widget;
m_widget = QWidget::createWindowContainer(m_window, this->ui->widget);
m_widget->setMinimumSize(400, 300);
41.2 windows下使用cmd
& 无条件执行&后的命令 cmd1 & cmd2 即cmd1,cmd2都会执行
&& 成功后执行 cmd1 && cmd2 即若cmd1执行成功则执行cmd2
|| 失败后执行 cmd1 || cmd2 即若cmd1执行失败则执行cmd2
void MainWindow::on_ptn_clicked()
{
QProcess p(0);
//这个会报错 p.start("copy C:\\Users\\Administrator\\Desktop\\lala.jpg C:\\Users\\Administrator\\Desktop\\aaa");
QString targetpath=QApplication::applicationDirPath();
targetpath.remove(QRegularExpression("debug")); //为了调用photoa文件
targetpath=targetpath+"photoa"; //目的路径
QString sourcepath="C:/Users/Administrator/Desktop/lala.jpg "; //源路径
QString command=QString("copy ")+sourcepath+targetpath; //命令
command=command.replace("/","\\"); //替换成\
qDebug()<<"命令是:"<
//设置系统日期/时间
void AppUtils::setSystemDateTime(const QString &year, const QString &month, const QString &day, const QString &hour, const QString &min, const QString &sec)
{
#ifdef Q_OS_WIN
QProcess process(0);
process.start("cmd");
process.waitForStarted();
//Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1编码是单字节编码,向下兼容ASCII
process.write(QString("date %1-%2-%3\n").arg(year).arg(month).arg(day).toLatin1());
process.closeWriteChannel();
process.waitForFinished(1000);
process.close();
process.start("cmd");
process.write(QString("time %1:%2:%3.00\n").arg(hour).arg(min).arg(sec).toLatin1());
process.waitForStarted();
process.closeWriteChannel();
process.waitForFinished(1000);
process.close();
#else
QString cmd = QString("date %1%2%3%4%5.%6").arg(month).arg(day).arg(hour).arg(min).arg(year).arg(sec);
system(cmd.toLatin1());
system("hwclock -w");
#endif
}
42、重启软件
//mainwindow中
qApp->quit();
QProcess processNew;
processNew.startDetached(qApp->applicationFilePath());
43、Qt在Linux下切换输入法
fcitx在qt中的使用
解决办法 把目录/usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/下的文件libfcitxplatforminputcontextplugin.so复制到Qt安装目录下…/Qtx.xx.x/Tools/QtCreator/lib/Qt/plugins/platforminputcontexts/.
qt安装目录下/Tools/QtCreator/bin/plugins/ 这个目录是qt creator自己调用插件的目录
Linux下关于Qt无法调用fcitx的中文输入 sudo apt install fcitx-frontedn-qt5
sudo cp /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.so /opt/Qt5.12/Tools/QtCreator/lib/Qt/plugins/platforminputcontexts
44、Qt获取Linux用户目录
QString strImagePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/justtake.jpg";
//-____________
#include
QString strFileName = QFileDialog::getOpenFileName(this,"select file", "/home");
QString strDir = QFileDialog::getExistingDirectory(this, "select dir", "/home");
45、Qt6使用
46、QTL、STL对比
47、Qt版本判断
void QUIWidget::setCode()
{
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
#if _MSC_VER
QTextCodec *codec = QTextCodec::codecForName("gbk");
#else
QTextCodec *codec = QTextCodec::codecForName("utf-8");
#endif
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
#else
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
}
48、界面风格控制
QApplication a(argc, argv);
// 设置整个窗口的风格 a.setStyle(QStyleFactory::create("fusion"));
//单个控件风格设置
ui->checkBox->setStyle(QStyleFactory::create("fusion"));
ui->progressBar->setStyle(QStyleFactory::create("windowsxp"));
ui->pushButton->setStyle(QStyleFactory::create("gtk"));
49、渐变色
50、windowState变化时不刷新
void TestDlg::changeEvent( QEvent* e )
{
if( e->type() == QEvent::WindowStateChange)
{
if(this->windowState() & Qt::WindowMinimized )
{
//do something after minimize
}
else
{
setWindowFlags(Qt::Window); //set normal window flag
setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint); //and return to your old flags
this->showNormal();
}
}
}
51、调用修改环境变量
QString envPath = qgetenv("PATH");
QString appDirPath = QApplication::applicationDirPath();
QString dependencePath = appDirPath + "/dependence";
envPath += QDir::toNativeSeparators(dependencePath).prepend(';');
qputenv("PATH", envPath.toStdString().c_str());
}
52、延时
#include
void mysleep(int msecond)
{
QElapsedTimer t;
t.start();
while(t.elapsed() < msecond)
{
QCoreApplication::processEvent();
QThread::usleep(100);
}
}
53、操作系统的判断
#if defined(Q_OS_WIN32)
#elif defined(Q_OS_LINUX)
#endif
#ifdef Q_OS_LINUX
#endif
54、qt中使用cin、cout
需要注意的一点是,这样的cin、cout、 cerr和我们在传统C++遇到的有一点不同,那就是你cout了一个QString之后,默认是不直接输出的,一般需要等到cout的缓冲区满之后,才向终端输出内部的字符串;如果你想在cout之后马上看到输出的内容,可以在输出之后在输出一个endl,或者调用cout的内部方法flush,强制情况缓冲区,例如://首先需要包含下列头文件:
#include
55、串口
56、获取程序目录及程序名
linux系统中有个符号链接:/proc/self/exe 它代表当前程序,所以可以用readlink读取它的源路径就可以获取当前程序的绝对路径。#include
57、大小端测试
bool isSmallIndain()
{
unsigned int val = 'A';
unsigned char* p = (unsigned char*)&val; //C/C++:对于多字节数据,取地址是取的数据对象的第一个字节的地址,也就是数据的低地址
return *p == 'A';
}
58、QSystemSemaphore和QSharedMemory
QSystemSemaphore用于进程间的信号量传递://一个进程创建
QSystemSemaphore sem("market", 3, QSystemSemaphore::Create); // resources available == 3
sem.acquire(); // resources available == 2
sem.acquire(); // resources available == 1
sem.acquire(); // resources available == 0
sem.release(); // resources available == 1
sem.release(2); // resources available == 3
//另一个进程打开
QSystemSemaphore sem("market", 3, QSystemSemaphore::Open);
//一个进程创建并写入图片
sharedMemory("QSharedMemoryExample"), //设置key_id
void Widget::loadFromFile()
{
if(sharedMemory.isAttached())
{
//将该进程与共享内存段分离
if(!sharedMemory.detach())
{
qDebug() << QString::fromLocal8Bit("无法从共享内存分离。");
}
}
QString fileName = QFileDialog::getOpenFileName(0,"Tip","",tr("Images (*.png *.xpm *.jpg)"));
QImage image;
if(!image.load(fileName))
{
qDebug() << QString::fromLocal8Bit("所选文件不是图像,请选择其他文件。");
return;
}
// 将数据加载到共享内存中
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << image;
int size = buffer.size();
// 创建共享内存段
if(!sharedMemory.create(size))
{
qDebug() << sharedMemory.errorString() << QString::fromLocal8Bit("\n 无法创建共享内存段.");
return;
}
sharedMemory.lock();
char *to = (char*)sharedMemory.data();
const char *from = buffer.data().data();
memcpy(to,from,qMin(sharedMemory.size(),size));
sharedMemory.unlock();
}
//另一个进程读取
sharedMemory("QSharedMemoryExample");
void Widget::loadFromMemory()
{
// 将共享内存与该进程绑定
if(!sharedMemory.attach())
{
qDebug() << "Unable to attach to shared memory segment.";
return;
}
// 从共享内存中读取数据
QBuffer buffer;
QDataStream in(&buffer);
QImage image;
sharedMemory.lock();
buffer.setData((char*)sharedMemory.constData(),sharedMemory.size());
buffer.open(QBuffer::ReadOnly);
in >> image;
sharedMemory.unlock();
sharedMemory.detach();
ui->label->setPixmap(QPixmap::fromImage(image));
}
//通过QBuffer写入字符串
{
QSharedMemory sharememory;
QString strKey = "share_memory";
QString strSharedString = "This is a sharememory";
QBuffer buffer; //缓冲区
QDataStream qdsm(&buffer); //数据流
sharememory.setKey(strKey);
//检测程序当前是否关联共享内存
if(sharememory.isAttached())
{
if(!sharememory.detach()) //解除关联
{
qDebug() << "Could not detach sharing memory";
return -1;
}
}
buffer.open(QBuffer::ReadWrite); //设置读取模式
qdsm << strSharedString; //输入共享字符串到数据流
//让共享内存创建一段内存空间,空间大小为缓冲区数据大小并检测是否创建成功
int size = buffer.size(); //获得字节大小
if(!sharememory.create(size) || size == 0) //检测共享内存段是否创建成功
{
qDebug() << "Could not create sharing memory";
return -1;
}
//锁定共享内存
sharememory.lock();
//分别获取创建后共享内存的数据的指针和要共享的字符串的数据的指针
char* memoryData = (char *)sharememory.data(); //共享内存的数据
const char* bufferData = buffer.data().data(); //被共享内存的数据
//利用内存拷贝函数(memcpy),把要共享的数据拷贝到共享数据的空间里,拷贝的数据大小是两者中小的数据
memcpy(memoryData,bufferData,qMin(sharememory.size(),size)); //把要共享的内存拷贝到被共享的内存
//解锁共享内存空间,使其能够被其他程序访问
sharememory.unlock();
qDebug() << "sharing memory key:" << strKey << "; sharing memory string:" << strSharedString;
}
//另一个进程打开并读出
{
QSharedMemory sharememory("share_memory");
if (!sharememory.attach())
{
qDebug() << "error 123" ;
return a.exec();
}
QString strContent;
QBuffer buffer; //构建缓冲区
QDataStream out(&buffer); //建立数据流对象,并和缓冲区关联
//对共享内存进行读写操作
sharememory.lock();
//初始化缓冲区中的数据,setData函数用来初始化缓冲区。
//该函数如果在open()函数之后被调用,则不起任何作用。
//buffer.open(QBuffer::ReadOnly); //解除注释,则setData函数不起作用,无法加载内存中数据
buffer.setData((char*)sharememory.constData(), sharememory.size());
buffer.open(QBuffer::ReadOnly);
out >> strContent; //将缓冲区的数据写入QString对象
sharememory.unlock();
sharememory.detach(); //解除程序和共享内存的关联
qDebug() << "string:" << strContent;
}
//一个程序写入文字
void Widget::on_textEdit_textChanged()
{
if(sharememory.isAttached()) {
sharememory.detach();
}
QByteArray arr = ui->textEdit->toPlainText().toLocal8Bit(); //放入QByteArray
int len = arr.length();
qDebug()<<ui->textEdit->toPlainText()<<len;
if(!sharememory.create(len)) {
qDebug() << sharememory.errorString();
return ;
}
sharememory.lock();
char *dest = reinterpret_cast<char *>(sharememory.data());
for (int i = 0; i < len; i++) {
dest[i] = arr[i];
}
sharememory.unlock();
}
//另一个程序读出文本
void Widget::timeout()
{
if (!sharememory.isAttached()) {
if (!sharememory.attach()) {
qDebug() << sharememory.errorString();
} else {
sharememory.lock();
QByteArray arr((char*)sharememory.data(), sharememory.size());
ui->textEdit->setPlainText(QString(arr));
sharememory.unlock();
sharememory.detach();
}
}
}
{
QSharedMemory shareMem; //1-实例化QSharedMemory类
shareMem.setKey("TestMem"); //1-通过函数setKey()设置标志名;
if(shareMem.isAttached()) //2-使用函数detach()将共享内存与主进程分离
shareMem.detach();
char str[100] = "hello,my share memory!";
if(!shareMem.create(100)) //3-使用函数create()创建共享内存段
{
qDebug() << shareMem.errorString();
return ;
}
//-------- 以下代码在需要的时候调用 ---------
shareMem.lock(); //4- 调用lock()将共享内存上锁
char *dest = reinterpret_cast<char *>(shareMem.data());
const char *source = str;
memcpy(dest, source, 100); //5-对共享内存进行数据写入
shareMem.unlock(); //6- 调用unlock()函数将共享内存解锁
}
//接收
{
QSharedMemory shareMem; //1-实例化QSharedMemory类
shareMem.setKey("TestMem"); //1-通过函数setKey()设置标志名;
if(!shareMem.attach()) //
{
qDebug() << "cann't attach shareMem!";
return ;
}
char str[100];
//-------- 以下代码在需要的时候调用 ---------
shareMem.lock(); //2- 调用lock()将共享内存上锁
const char *source = (char*)shareMem.constData();
char *dest = str;
memcpy(dest, source, 100); //3-对共享内存进行数据写入
shareMem.unlock(); //4- 调用unlock()函数将共享内存解锁
}
59、QGraphicsView、QGraphicsScene、QGraphicsItem
QGraphicsView显示地图
QGraphicsView实现地图按鼠标点放大缩小
坐标的原点:scene在中心,view在左上,item在图元中心。
坐标单位:像素。
//假设有一个200*200的图元,
//设置视图尺寸:
view->resize(400, 400);
//设置场景坐标系某点(0, 0)到视图原点(0, 0)的映射,及场景尺寸:
scene->setSceneRect(0, 0, 400, 400);
//设置图元原点在Scene中的位置:
item->setPos(0, 0);
如果这个item是小于view的,那么这个item会显示在view的中心。
如果scene的尺寸是小于view的,也就是说view可以完全包含scene,那么是不能够通过centerOn来移动scene。只有当scene大于view,以至于view不能完全展示scene时,才可以通过centerOn移动。这里要特别注意,容易踩坑。
pItem->setRect(20, 20, 60, 60);
pItem->setPos(50,50);
pItem->setScale(2);
pItem->setRotation(45);
pItem->setTransformOriginPoint(20,20);
on to the caller (i.e., QGraphicsScene will no longer delete item when destroyed).60、程序启动脚本start.sh
#!/bin/bash
curwd=$(cd "$(dirname "$0")";pwd) //获取可执行程序所在目录
export LD_LIBRARY_PATH=$curwd/Qt-5.13.0/lib:$LD_LIBRARY_PATH //设置Qt库目录
export QT_QPA_PLATFORM_PLUGIN_PATH=$curwd/Qt-5.13.0/plugins/ //设置Qt插件目录
$curwd/Software //启动程序,Software为可执行程序名称
61、同机复制Qt工程的步骤
62、不卡界面的局部事件循环
QEventLoop loop;
connect( qApp, &QCoreApplication::aboutToQuit, &loop, &QEventLoop::quit, Qt::DirectConnection );
connect( this, &QgsBlockingNetworkRequest::finished, &loop, &QEventLoop::quit, Qt::DirectConnection );
loop.exec();
QEventLoop eventLoop; //局部的事件循环,不卡主界面
//设置超时 5.15开始自带了超时时间函数 默认30秒
#if (QT_VERSION >= QT_VERSION_CHECK(5,15,0))
manager->setTransferTimeout(timeout);
#else
QTimer timer;
connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
timer.setSingleShot(true);
timer.start(timeout);
#endif
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
63、操作excel
64、窗体标题后显示程序名(包括QMessageBox)
QApplication a(argc, argv);
a.setApplicationDisplayName("程序名");
65、QUrl、QUrlQuery
网址后面带?(query)的是带query的url。//增加query部分
QUrl url("https://www.foo.com");
QUrlQuery query;
query.addQueryItem("email", "[email protected]");
query.addQueryItem("pass", "secret");
url.setQuery(query);
qDebug() << url;
//提取query
QUrl url("http://www.example.com/cgi-bin/drawgraph.cgi?type=pie&color=green");
QUrlQuery query(url.query());
QList<QPair<QString, QString> > list = query.queryItems();
//list[0]中存放了"type,pie",list[1]中存放了"color,green"
60. 安装消息处理器
qInstallMessageHandler( myMessageOutput );
void myMessageOutput( QtMsgType type, const QMessageLogContext &, const QString &msg )
{
switch ( type )
{
case QtDebugMsg:
myPrint( "%s\n", msg.toLocal8Bit().constData() );
if ( msg.startsWith( QLatin1String( "Backtrace" ) ) )
{
const QString trace = msg.mid( 9 );
dumpBacktrace( atoi( trace.toLocal8Bit().constData() ) );
}
break;
case QtCriticalMsg:
myPrint( "Critical: %s\n", msg.toLocal8Bit().constData() );
#ifdef QGISDEBUG
dumpBacktrace( 20 );
#endif
break;
case QtWarningMsg:
{
/* Ignore:
* - libpng iCPP known incorrect SRGB profile errors (which are thrown by 3rd party components
* we have no control over and have low value anyway);
* - QtSVG warnings with regards to lack of implementation beyond Tiny SVG 1.2
*/
if ( msg.contains( QLatin1String( "QXcbClipboard" ), Qt::CaseInsensitive ) ||
msg.startsWith( QLatin1String( "libpng warning: iCCP: known incorrect sRGB profile" ), Qt::CaseInsensitive ) ||
msg.contains( QLatin1String( "Could not add child element to parent element because the types are incorrect" ), Qt::CaseInsensitive ) ||
msg.contains( QLatin1String( "OpenType support missing for" ), Qt::CaseInsensitive ) )
break;
myPrint( "Warning: %s\n", msg.toLocal8Bit().constData() );
#ifdef QGISDEBUG
// Print all warnings except setNamedColor.
// Only seems to happen on windows
if ( !msg.startsWith( QLatin1String( "QColor::setNamedColor: Unknown color name 'param" ), Qt::CaseInsensitive )
&& !msg.startsWith( QLatin1String( "Trying to create a QVariant instance of QMetaType::Void type, an invalid QVariant will be constructed instead" ), Qt::CaseInsensitive )
&& !msg.startsWith( QLatin1String( "Logged warning" ), Qt::CaseInsensitive ) )
{
// TODO: Verify this code in action.
dumpBacktrace( 20 );
// also be super obnoxious -- we DON'T want to allow these errors to be ignored!!
if ( QgisApp::instance() && QgisApp::instance()->messageBar() && QgisApp::instance()->thread() == QThread::currentThread() )
{
QgisApp::instance()->messageBar()->pushCritical( QStringLiteral( "Qt" ), msg );
}
else
{
QgsMessageLog::logMessage( msg, QStringLiteral( "Qt" ) );
}
}
#endif
// TODO: Verify this code in action.
if ( msg.startsWith( QLatin1String( "libpng error:" ), Qt::CaseInsensitive ) )
{
// Let the user know
QgsMessageLog::logMessage( msg, QStringLiteral( "libpng" ) );
}
break;
}
case QtFatalMsg:
{
myPrint( "Fatal: %s\n", msg.toLocal8Bit().constData() );
#ifdef QGIS_CRASH
qgisCrash( -1 );
#else
dumpBacktrace( 256 );
abort(); // deliberately dump core
#endif
break; // silence warnings
}
case QtInfoMsg:
myPrint( "Info: %s\n", msg.toLocal8Bit().constData() );
break;
}
}
61. json解析
{
"Cross Platform": true,
"From": 1991,
"Name": "Qt"
}
// 构建 JSON 对象
QJsonObject json;
json.insert("Name", "Qt");
json.insert("From", 1991);
json.insert("Cross Platform", true);
// 构建 JSON 文档
QJsonDocument document;
document.setObject(json);
QByteArray byteArray = document.toJson(QJsonDocument::Compact);
QString strJson(byteArray);
qDebug() << strJson;
QJsonParseError jsonError;
// 转化为 JSON 文档
QJsonDocument doucment = QJsonDocument::fromJson(byteArray, &jsonError);
// 解析未发生错误
if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError))
{
if (doucment.isObject())
{
// JSON 文档为对象
QJsonObject object = doucment.object(); // 转化为对象
if (object.contains("Name"))
{ // 包含指定的 key
QJsonValue value = object.value("Name"); // 获取指定 key 对应的 value
if (value.isString())
{ // 判断 value 是否为字符串
QString strName = value.toString(); // 将 value 转化为字符串
qDebug() << "Name : " << strName;
}
}
if (object.contains("From"))
{
QJsonValue value = object.value("From");
if (value.isDouble())
{
int nFrom = value.toVariant().toInt();
qDebug() << "From : " << nFrom;
}
}
if (object.contains("Cross Platform"))
{
QJsonValue value = object.value("Cross Platform");
if (value.isBool())
{
bool bCrossPlatform = value.toBool();
qDebug() << "CrossPlatform : " << bCrossPlatform;
}
}
}
}
62. 百度AI开放平台使用
63. QBitArray使用
QBitArray QBitArray::fromBits(const char *data, qsizetype size)
bool QBitArray::testBit(int i) const
char ch=0x01;
QBitArray bits = QBitArray::fromBits(&ch, 8);
bool b0 = bits.testBit(0); //true
bool b7 = bits.testBit(7); //false
QBitArray ba(3);
ba.setBit(0, true);
ba.setBit(1, false);
ba.setBit(2, true);
64、QSignalMapper
它可以把一个无参的信号翻译成带int参数、QString参数、 QObject* 参数或者QWidget *参数的信号,并将之转发。//多个按钮关联到同一个槽函数,根据按钮不同进行不同业务处理
QSignalMapper * myMapper;
myMapper = new QSignalMapper(this);
QPushButton * button[8]={ui->pushButton_1,ui->pushButton_2,ui->pushButton_3,ui->pushButton_4,
ui->pushButton_5};
for(int i = 0;i<5;i++)
{
connect(button[i], SIGNAL(clicked(bool)), myMapper, SLOT(map())); //信号传给QSignalMapper
myMapper->setMapping(button[i], i); //设置转换规则
}
connect(myMapper, SIGNAL(mapped(int)), this, SLOT(getText(int))); //关联QSignalMapper的信号
//然后我们编写getText(int)这个槽函数即可
void MainWindow::setPushButton(int index)
{
switch(index)
{
case0:
//业务逻辑
break;
case1:
//业务逻辑
break;
case2:
//业务逻辑
break;
case3:
//业务逻辑
break;
case4:
//业务逻辑
break;
}
}
65、QWidgetAction
自定义菜单栏66、嵌入式Qt
关于嵌入式 Qt 最全最棒的教程(万字干货)67、Linux下无边框窗体拖动出界面解决方案
Qt开源作品38-无边框窗体方案(无抖动,支持win、linux、mac等系统,侧边半屏顶部全屏)
Qt linux下无法移动出屏幕(有效的)
Linux Qt 无边框窗体的移动以及禁止使用窗体的最大化setWindowFlags(Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
activateWindow();
只能设置一个的窗口标志对照表
Qt::Window 带有窗口系统框架和标题栏
Qt::Dialog 对话框(通常标题栏中没有最大化或最小化按钮)
Qt::Sheet macOS表单式窗口
Qt::Drawer macOS抽屉式窗口 Qt::Popup 弹出式顶层窗口
Qt::Tool 显示工具按钮的窗口
Qt::Tooltip 没有标题栏和窗口边框的窗口
Qt::SplashScreen 启动窗口类似于 QSplashScreen
Qt::X11BypassWindowManagerHint 无窗口边框的窗口,完全忽视窗口管理器和用户无法使用键盘进行输入 (除非手动调用QWidget::activateWindow()函数
Qt::FramelessWindowHint 无法移动和改变大小的无窗口边框的窗口
Qt::NoDropShadowWindowHint 禁用窗口阴影
Qt::WindowTitleHint 带标题栏的窗口
Qt::WindowSystemMenuHint 带系统菜单和尽可能地添加一个关闭按钮的窗口
Qt::CustomizeWindowHint 关闭默认窗口标题提示栏
Qt::WindowMinimizeButtonHint 窗口添加一个最小化按钮
Qt::WindowMaximizeButtonHint 窗口添加一个最大化按钮
Qt::WindowCloseButtonHint 窗口添加一个关闭按钮
Qt::WindowContextHelpButtonHint 窗口添加一个帮助按钮
Qt::WindowShadeButtonHint 如果窗口管理器支持,则在最小化按钮的位置添加一个阴影按钮
Qt::WindowStaysOnTopHint 通知窗口系统置顶窗口
Qt::WindowStaysOnBottomHint 通知窗口系统置于最底层窗口68、遮罩
69、某个控件全屏效果
70、QWidget不在任务栏显示
setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::SubWindow);