qt记录
不清楚多看qt帮助文档,介绍非常详细
常用函数使用
QString的arg()函数可以自动替换掉QString中出现的占位符。
QString("[%1, %2]").arg(x).arg(y); // 加粗居中 QString("<center><h1>Press:(%1, %2)</h1></center>").arg(QString::number(event->x()),QString::number(event->y())); // 数字转字符串也可以用 QString::number(num);
打印
打印出错信息#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ <<"]"
\n正常表示(换行)
qDebug().noquote() << str; //直接用qDebug() \r和\n都不能正常显示
event事件
event()函数主要用于事件的分发事件处理之后一定要调用父类相应事件处理函数,不然信号就不会继续往后穿,或者使用ignore()函数,如果使用accept()函数就相当如接受信号,不继续传
事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是将这些事件对象按照它们不同的类型,分发给不同的事件处理器(event handler)
bool CustomWidget::event(QEvent *e) { if (e->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);//强制类型转换 if (keyEvent->key() == Qt::Key_Tab) { qDebug() << "You press tab."; return true; } } return QWidget::event(e);//必要的,重新处理其他事件 }
- 如果传入事件被处理,需要返回true,否则返回false,那么 Qt 会认为这个事件已经处理完毕,不会再将这个事件发送给其它对象,而是会继续处理事件队列中的下一事件。
在event()函数中,调用事件对象的accept()和ignore()函数是没有作用的,不会影响到事件的传播。
可以通过使用QEvent::type()函数可以检查事件的实际类型,其返回值是QEvent::Type类型的枚举。我们处理过自己感兴趣的事件之后,可以直接返回 true,表示我们已经对此事件进行了处理;对于其它我们不关心的事件,则需要调用父类的event()函数继续转发,否则这个组件就只能处理我们定义的事件了。
注意:QWidget中有一个mouseTracking属性,该属性用于设置是否追踪鼠标,默认是false(至少鼠标点击一次才会追踪).只有鼠标被追踪时,mouseMoveEvent()才会发出.
EventLabel *label = new EventLabel;
label->setMouseTracking(true);
控制调用触发信号
比如模拟按钮点击效果ui.pushButton->clicked();
获取所有button
QList<QPushButton *> m_button_list = this->findChildren<QPushButton *>();
绘图
Qt 的绘图系统: 使用QPainter在QPainterDevice上进行绘制,它们之间使用QPaintEngine进行通讯(也就是翻译QPainter的指令)。
绘图设备是指继承QPainterDevice的子类.
- QPixmap 针对屏幕进行了优化,和平台相关,不能对图片进行修改
- QBitmap QBitmap是QPixmap的一个子类,它的色深限定为1(只有两种状态,黑白),可以使用 QPixmap的isQBitmap()函数来确定这个QPixmap是不是一个QBitmap.
- QImage 和平台无关,可以对图片进行修改,可以在线程中绘图,专门为图像的像素级访问做了优化。
- QPicture 保存绘图的状态(二进制文件),记录和重现
QImage与QPixmap之间的转换:
fromImage
toImage
Graphics View Framework:提供了一种接口,用于管理大量自定义的 2D 图形元素,并与之进行交互
如果你的图像中包含了成千上万的直线、多边形之类,管理这些对象要比管理QPainter的绘制语句容易得多。并且,
这些图形对象也更加符合面向对象的设计要求:一个很复杂的图形可以很方便的复用。
非模态对话框析构
设置对话框属性即可,避免子函数结束造成对话框对象析构,
或者堆上创建对象一直存在(设置父对象容易造成对话框一直占用资源)
dialog->setAttribute(Qt::WA_DeleteOnClose);
文件
读取:
- QDataStream:二进制文件读取
- QTextStream:自动将 Unicode 编码同操作系统的编码进行转换;也会将换行符进行转换
有关文件本身信息,可以通过QFileInfo获取
QFileInfo info(file);
qDebug() << info.baseName();
// 获取应用程序执行时的当前路径
QDir::currentPath()
最好使用 Qt 整型来进行读写,比如程序中的qint32.
这保证了在任意平台和任意编译器都能够有相同的行为.
魔术数字
二进制输出中经常使用的一种技术,放在文件开头用于标示文件
二进制格式是人不可读的,并且通常具有相同的后缀名(比如 dat 之类),
因此我们没有办法区分两个二进制文件哪个是合法的.
所以,我们定义的二进制格式通常具有一个魔术数字,用于标识文件的合法性.
tcp实现简单文件传输
数字和特定长度字符串相互转换
QString str = QString("%1").arg(10, 4, 10, QChar('0'));
qDebug() <<str<<"num "<<str.toInt();
为防止TCP粘包,通常在开头增加一个或一组固定长度数字表示数据包的大小,类型(类型可用enum+switch)等
//封包
quint16 totalLen = numLen + buff.size(); //数据位长度可自定义,和一次读取大小有关
QString lenStr = QString("%1").arg(totalLen, numLen, 10, QChar('0'));
buffSend.append(lenStr).append(buff);
tcpsocket->write(buffSend);
buffSend.clear();
//解包
quint16 lenMsg = QString(mybuffer.left(4)).toInt();
QByteArray msg = mybuff.mid(numLen, lenMsg-numLen);
mybuff = mybuff.right(mybuff.size()-lenMsg); //总缓存区
其实这里有考虑过使用QDataStream,但是由于通过”<<”写入会有其他信息,
导致大小不是想要的,通常使用writeRawData来避免
多线程
robotarm = new robotArm(); //robotArm继承QObject
connect(ui.pushButton, &QPushButton::clicked, robotarm, &robotArm::InitPos);
QThread *pthread = new QThread(this);
robotarm->moveToThread(pthread);
pthread->start();
Qt信号自定义数据类型
原生的信号与槽连接传参,只支持基本的数据类型,比如char,int, float,double.
直接使用自定义信号,比如结构体,类等编译不会报错,执行会报错
有两种方法
注册自定义类型
#include<QMetaType> qRegisterMetaType<joydata>("joydata"); //自定义类型对应的变量和名称
使用直接连接方式
Qt::DrectConnection
,这种方式在需要把耗时槽函数放在子线程不适用(队列连接)connect(&subThread,SIGNAL(ui.pushButton, &QPushButton::clicked, robotarm, &robotArm::InitPos, Qt::DrectConnection);
QSharedMemory实现进程间通信
分享端的逻辑:
1.创建一个QSharedMemory,并设置一个key值;
2.查看这个内存是不是被使用,如果被使用就断开;
3.调用create进行创建;(即使报已经存在也没关系,连接上照样使用)
4.使用memcpy把要写入的数据放入QSharedMemory中(内部一般会使用互斥锁技术,锁住资源)
读取端逻辑:
1.创建一个QSharedMemory,把key值设置为分享端相同的key值;
2.使用attach连接上这个QSharedMemory;(先调用isAttached()判断是否需要attach,如果已经attach则再调用attach会返回false)
3.以读取字节的方式读取QSharedMemory中的数据(内部一般会使用互斥锁技术,锁住资源);
4.使用detach端口对这个QSharedMemory的连接。
注意:分享端create后会自动attach上,不用调用detach,否则共享内存直接释放掉了.
接收端每次attach,detach.需要保证始终有一个进程attach在sharedmemory上,通常是分享的一端
分享端:
m_shared_memory = new QSharedMemory("shared", this);
if(m_shared_memory->isAttached()){
if(!m_shared_memory->detach()){
qDebug() << "shared memory detach failed";
return;
}
}
if(!m_shared_memory->create(1)){
qDebug()<<m_shared_memory->errorString()<<" created failed!";
return;
}
m_shared_memory->lock();
char *to = static_cast<char*>(m_shared_memory->data());
char msg = 'L';
memcpy(to, &msg, 1);
m_shared_memory->unlock();
数据接受端:
m_shared_memory = new QSharedMemory("shared", this);
if(!m_shared_memory->isAttached()){
if(!m_shared_memory->attach()){
qDebug() << "attach shared memory failed";
return;
}
}
m_shared_memory->lock();
char *to = static_cast<char*>(m_shared_memory->data());
char msg = 'L';
memcpy(to, &msg, 1);
m_shared_memory->unlock();
m_shared_memory->detach();
引用
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 yangbenbo@whu.edu.cn
文章标题:qt记录
本文作者:杨本泊
发布时间:2019-11-22, 22:23:21
最后更新:2023-07-09, 07:10:11
原始链接:http://yangbenbo.github.io/2019/11/22/qt纪要/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。