Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

Qt学习笔记

发表于 2019-10-12

记录开发过程中好用的知识点。

  • 安全地删除QObject派生类请使用deleteLater()。

  • 批量删除对象列表可以使用qDeleteAll()。

  • 所有派生于QObject的类都不能拷贝构造和赋值操作。例如使用QList与QList<QObject*>前者会编译报错。如需要在自定义类启用该功能可以使用Q_DISABLE_COPY宏标记。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Object : QObject
{
Q_OBJECT
public:
Object()
{
connect(this, SIGNAL(send()), this, SLOT(onHandle()));
Q_EMIT send();
}

Q_SIGNAL void send();
Q_SLOT void onHandle() {}
};
  • 在上面例子中,可以使用Q_SIGNAL单独定义某个信号,或使用Q_SLOT单独定义某个槽函数,另外还可以使用Q_EMIT代替emit。

  • 私有继承可以直接写类不需要写private(如:class Object : QObject)。

  • 使用foreach对容器进行遍历。

    1
    2
    3
    4
    QStringList list;
    foreach(QString each, list) {
    qDebug() << "...";
    }
  • 使用Q_FOREVER代替无限循环。

    1
    2
    3
    Q_FOREVER {
    qDebug() << "...";
    }
  • 快速设置程序自定义图标可以在项目文件中添加下列语句(注:my.ico放在项目目录下)。

    1
    RC_ICONS = my.ico

QProcess实时读取命令输出

发表于 2019-10-11

大多数情况下我们使用QProcess都是直接等待命令执行完成返回结果,但是有些情况下需要在获取命令运行中的输出。那该怎么做呢?先上代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Process : public QObject
{
Q_OBJECT
public:
Process()
{
connect(&m_process,
SIGNAL(readyReadStandardOutput()),
this,
SLOT(onReadData()));
m_process.setReadChannel(QProcess::StandardOutput);
m_process.start("cmd /c ping /t www.qt.io");
}

private slots:
void onReadData()
{
qDebug() << m_process.readAllStandardOutput();
}

private:
QProcess m_process;
};

  例子中关键的操作是设置setReadChannel与绑定readyReadStandardOutput信号(用于读数据通知)。

插图

插图

  由于QProcess继承于QIODevice类,可以使用read,readAll,readLine等接口。

汉字编码历史

发表于 2019-10-10

Qt君最近在处理字符乱码的问题,顺便看了下关于汉字字符编码的历史,总结分享给大家。

  早期美国计算机显示字符采用数字映射字母的方式,感觉挺好用,在60年代就做出了ASCII编码,从0-127共128个字符(包含不可见字符)。

  眼巴巴地看着美国又是用计算机技术助力登月,又发展民用科技。于是我们国家在80年代大力发展计算机技术,可是出现的问题是,汉字显示不了。不行,我们要和世界接轨,于是GB2312编码横空出世,囊括了六千多个常用汉字。

  随着信息化的发展,GB2312似乎也不满足日常使用了,特别是生僻字。由于汉字编码的限制身份证显示不了生僻字,需要特殊处理,有的人甚至是改名字。于是在90年代在GB2312的基础上扩展到两万多个汉字的字符编码GBK。

  不得不说中华文化博大精深,两万多个汉字似乎也是不够用,继续发展汉字编码。GB2312编码进化为GB18030编码,扩展到了七万多文字,还包含了少数少民族文字。

  历史的车轮不断前进,文化相互融合与碰撞。由于各国都自制字符编码,没有统一标准,不同的系统中显示各国文字互相乱码,你眼看我眼,大家对着乱码挠头。

  不行,我们要统一起来,于是一个叫ISO的国际标准化组织制定Unicode编码。随着Unicode编码规范的建立,其实现方式有UTF-8,UTF-16,UTF-32。由于UTF-8采用变长的编码方式实现,其节省空间,兼容ASCII标准的优点, 在互联网上使用最广的一种Unicode的实现方式。

结构体位域

发表于 2019-10-09

C语言允许在结构体中以位为单位设置成员所占的内存空间。以位为单位的成员,简称为位域或位段(Bit field)。其优点是较少的位数存储数据从而节省空间,还可以进行内存对齐。

节省空间

  例如下列结构体内的变量使用了位域,占用空间只有1字节(8bit)。相对于不使用位域的缩少了3字节(24bit)的数据。

1
2
3
4
5
6
7
8
struct {
unsigned char x1 : 2;
unsigned char x2 : 2;
unsigned char x3 : 2;
unsigned char x4 : 2;
} Bunch;

/* sizeof(Bunch) => 1 */

内存对齐

  无名位域(没有给出标识符名字),无名位域可用于填充内存布局,使得下一个位域内存分配边界对齐。

1
2
3
4
5
6
7
struct {
unsigned char x1: 2;
unsigned char x2: 2;
unsigned char : 0; /* 下一个位域在内存分配边界对齐 */
unsigned char x4: 2;
} Bunch;
/* sizeof(Bunch) => 2 */

QProcess使用waitForFinished的小坑

发表于 2019-10-08

  我们使用以下接口都会有超时机制,主要是避免长时间的阻塞。但有些类似有超时机制的接口在使用上就需要注意了。

1
2
3
4
bool QAbstractSocket::waitForBytesWritten(int msecs = 30000)
bool QAbstractSocket::waitForConnected(int msecs = 30000)
bool QAbstractSocket::waitForDisconnected(int msecs = 30000)
bool QAbstractSocket::waitForReadyRead(int msecs = 30000)

  一般我们使用QProcess执行命令时都会执行waitForFinished等待程序执行完成。细看接口可以看到它有默认的超时时间(30s),如果超过30s就会中断执行。如果我们执行某些耗时操作又没有设置超时时间则会导致一直中断执行从而得不到想要的结果。

1
bool QProcess::waitForFinished(int msecs = 30000)

  下列例子由于没有设置waitForFinished超时时间,如果gzip解压时间超过30s就得不到想要的结果。

1
2
3
4
5
6
7
8
9
QProcess gzip;
gzip.start("gzip –d /opt/etc.zip.gz");
if (!gzip.waitForStarted())
return false;

if (!gzip.waitForFinished())
return false;

QByteArray result = gzip.readAll();

  应该设置可预计的超时时间或不可预计的执行时间就应该设置waitForFinished(-1)参数(直到执行完成)。

分享一个Qt的pdf查看器

发表于 2019-10-07

使用Qt的WebEngine和javascript的pdf.js模块构建的PDF查看器。

演示图

  这个基于qmake的项目定义了两个构建目标:qpdf共享库(ppdflib)和pdfviewer基于qpdf库的示例PDF查看器。

如何编译

  • 仅支持Qt 5.9.x或更高版本;
  • qpdf.pro在QtCreator中打开项目文件;
  • 构建并运行。

如何使用

  qpdfli库提供了两种打开PDF文件的方式:

1
2
QPdfWidget::loadData(const QByteArray &pdfData);
QPdfWidget::loadFile(const QString &filePath);

  loadData方法将PDF数据序列化为base64字符串,并将其注入JavaScript环境。注意:在加载巨大的PDF文件时,这可能会失败。

  loadFile可以加载任何大小的PDF,但是由于跨域安全限制,默认情况下该方法被阻止,因为它使用WebEngine的加载URL方法。为了使此方法有效,您必须通过将–disable-web-security参数传递给QApplication实例来禁用Web安全性(请参阅pdfviwer示例中的操作)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main(int argc, char **argv)
{
#ifdef QPDF_WIDGET_USE_CORS
// Disable web security when using cross-origin URL fetch.

int nargs = argc + 1;
char** args = new char*[nargs];
for (int i = 0; i < argc; i++) {
args[i] = argv[i];
}
args[argc] = (char*)"--disable-web-security";

QApplication app(nargs, args);
#else
QApplication app(argc, argv);
#endif

...
}

源码地址

1
https://github.com/Archie3d/qpdf

linux终端快捷键

发表于 2019-10-06

介绍一些终端常用到的快捷键。

快捷键 作用
ctrl + a 切换到命令行开始
ctrl + e 切换到命令行末尾
ctrl + c 终止进程
ctrl + d 结束输入
ctrl + l 清屏
ctrl + q 恢复屏幕输出
ctrl + s 暂停屏幕输出
ctrl + z 进程挂起

QImage实用接口

发表于 2019-10-05

介绍QImage的图像缩放,转换,镜像等接口功能。

图像缩放

1
2
3
QImage scaled(const QSize &size, 
Qt::AspectRatioMode aspectRatioMode,
Qt::TransformationMode transformMode) const

图像转换

1
2
QImage convertToFormat(QImage::Format format, 
Qt::ImageConversionFlags flags) const &

图像镜像

  在水平/垂直方向镜像,具体取决于水平和垂直设置为true还是false。

1
QImage mirrored(bool horizontal, bool vertical) const &

图像保存

1
2
3
bool save(const QString &fileName, 
const char *format,
int quality) const

BGR转RGB

1
QImage rgbSwapped() const &

取消宏定义

发表于 2019-10-04

今天遇到一个问题是:重复宏定义。想到的解决方法是使用undef取消该重复宏。

解决方法

1
2
3
#ifdef xxx
#undef xxx
#endif

或

1
2
3
#ifndef xxx
#define xxx
#endif

Qt官方示例-可拖拽本文

发表于 2019-10-03

可对文本进行拖动到指定位置。

演示

部分主要代码

  • 当被鼠标拖动的对象进入其容器范围内时触发此事件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void DragWidget::dragEnterEvent(QDragEnterEvent *event)
    {
    if (event->mimeData()->hasText()) {
    if (event->source() == this) {
    event->setDropAction(Qt::MoveAction);
    event->accept(); /* 接受拖拽事件 */
    } else {
    event->acceptProposedAction();
    }
    } else {
    event->ignore();
    }
    }

在一个拖动过程中,释放鼠标键时触发此事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void DragWidget::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasText()) {
const QMimeData *mime = event->mimeData();
QStringList pieces = mime->text().split(QRegularExpression(QStringLiteral("\\s+")),
QString::SkipEmptyParts);
QPoint position = event->pos();
QPoint hotSpot;

QByteArrayList hotSpotPos = mime->data(hotSpotMimeDataKey()).split(' ');
if (hotSpotPos.size() == 2) {
/* 松开拖拽设置为当前位置 */
hotSpot.setX(hotSpotPos.first().toInt());
hotSpot.setY(hotSpotPos.last().toInt());
}

for (const QString &piece : pieces) {
QLabel *newLabel = createDragLabel(piece, this);
newLabel->move(position - hotSpot);
newLabel->show();
newLabel->setAttribute(Qt::WA_DeleteOnClose);

position += QPoint(newLabel->width(), 0);
}

if (event->source() == this) {
event->setDropAction(Qt::MoveAction);
event->accept(); /* 接受拖拽事件 */
} else {
event->acceptProposedAction();
}
} else {
event->ignore();
}
for (QWidget *widget : findChildren<QWidget *>()) {
if (!widget->isVisible())
widget->deleteLater();
}
}

  • 捕获鼠标按下事件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    void DragWidget::mousePressEvent(QMouseEvent *event)
    {
    QLabel *child = qobject_cast<QLabel*>(childAt(event->pos()));
    if (!child)
    return;

    QPoint hotSpot = event->pos() - child->pos();

    QMimeData *mimeData = new QMimeData;
    mimeData->setText(child->text());
    mimeData->setData(hotSpotMimeDataKey(),
    QByteArray::number(hotSpot.x()) + ' ' + QByteArray::number(hotSpot.y()));

    qreal dpr = window()->windowHandle()->devicePixelRatio();
    QPixmap pixmap(child->size() * dpr);
    pixmap.setDevicePixelRatio(dpr);
    child->render(&pixmap);

    QDrag *drag = new QDrag(this);
    drag->setMimeData(mimeData);
    drag->setPixmap(pixmap);
    drag->setHotSpot(hotSpot);

    Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);

    if (dropAction == Qt::MoveAction)
    child->close();
    }

关于更多

  • 在QtCreator软件可以找到:

插图

  • 或在以下Qt安装目录找到

    1
    C:\Qt\{你的Qt版本}\Examples\{你的Qt版本}\widgets\draganddrop\draggabletext
  • 相关链接

    1
    https://doc.qt.io/qt-5/qtwidgets-draganddrop-draggabletext-example.html
  • Qt君公众号后台回复『Qt示例』获取更多内容。

1…456…32
Qt君

Qt君

313 日志
41 标签
© 2019 Qt君
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4
粤ICP备 - 16070052号