Qt 5.12 Widget桌面开发

Qt基础

Qt编译安装

本次实验环境为VS2019+QT5.12.4

  1. 首先打开PowerShell,执行下面命令以创建编译环境:
    C:QtQt5.12.45.12.4msvc2017_64binqtenv2.bat
    C:"Program Files (x86)”"Microsoft Visual Studio”2019CommunityVCAuxiliaryBuildvcvars64.bat。
  2. 进入QT源代码文件夹:C:QtQt5.12.45.12.4Src。

  3. 进行配置:
    C:QtQt5.12.45.12.4Srcqtbaseconfigure.bat -prefix E:QT -hostprefix E:QT5.12.4\ -opensource -confirm-license -debug-and-release -developer-build -plugin-manifests -pch -silent -dbus-linked -dbus-runtime -accessibility -system-proxies -direct2d -gif -ico -sql-odbc -sql-sqlite
  4. 进行编译:C:QtQt5.12.4ToolsQtCreatorbinjom.exe

  5. 安装:C:QtQt5.12.4ToolsQtCreatorbinjom.exe install

  6. 清除构建文件:C:QtQt5.12.4ToolsQtCreatorbinjom.exe clean

Qt附加程序

程序发布程序:windeployqt

要完成应用程序的发布,请遵循以下步骤:

  1. 以Release模式编译项目。

image0

  1. 前往编译目录下获取编译文件,该命令通常与项目目录位于同一层次:

image1

│ .qmake.stash

│ Makefile

│ Makefile.Debug

│ Makefile.Release

├─debug

└─release

│ main.o

│ moc_predefs.h

│ moc_widget.cpp

│ moc_widget.o

│ widget.o

Widget_NoUI_Test.exe

└─stable.h.gch

  1. 将编译后的exe提取到一个空目录下。

  2. 从开始菜单中选择对应版本的环境工具:

image2

  1. 运行windeployqt命令:

image3

  1. 此时的程序运行库全部在该目录下,将目录打包发布即可。

Qml预览工具:qmlscene

qmlscene用于预览qml脚本文件:

  1. 打开Qt的环境工具:

image4

  1. 切换到qml文件目录下运行qmlscene命令:

image5

  • 你也可以直接打开qmlscene.exe,打开后按要求选择qml文件。

元对象系统

信号和槽

属性系统

事件系统

事件驱动模型

事件(Event)是由操作系统或程序自身发出的任务请求。当键盘点击窗口重绘鼠标移动计时结束……时都会产生对应事件。

事件驱动模型基本思路如下[1.]

  1. 由程序维护一个事件(消息)队列。

  2. 当事件产生时(如鼠标按下)向事件队列中添加事件。

  3. 事件循环不断从事件队列中取出事件。

  4. 根据取出事件的类别,调用对应的事件处理函数

事件驱动模型I/O编程范式(事件驱动模型单线程模型多线程模型)的一种,其目的是为了解决I/O交互问题。大多数GUI都应用了事件驱动模型。因此,可以说:

“GUI是由事件驱动的”

Qt中的事件

事件对象

Qt中的事件均继承自QEvent。常用事件对象的继承结构如下:

image6

当事件发生时,Qt将创建一个事件对象,并将其添加到事件循环中。

使用事件循环

要使用Qt应用程序中,你必须创建一个QApplication对象并调用其exec()函数:

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

return a.exec();

}

在调用QApplication的exec函数后,程序将进入事件循环并监听程序的事件。

回调函数

回调(CallBack)函数,用于处理特定事件。

消息循环不断从消息队列中取出事件,然后根据事件类型调用对应的事件处理函数。

要自定义事件处理,必须重写类的事件处理函数。例如QWidget的鼠标事件:

virtual void

mouseDoubleClickEvent(QMouseEvent *event)

virtual void

mouseMoveEvent(QMouseEvent *event)

virtual void

mousePressEvent(QMouseEvent *event)

virtual void

mouseReleaseEvent(QMouseEvent *event)

事件传递

添加事件

事件的添加可以调用以下函数:

QCoreApplication::postEvent(QObject *receiver, QEvent *event)

QCoreApplication::sendEvent(QObject *receiver, QEvent *event)

两个函数的不同在于:

postEvent将事件添加到事件循环末尾,而sendEvent则通过notify()将事件直接发送给receiver。

事件的传递

Qt中事件产生后首先加入事件循环,然后

  1. 进入QApplication::notify()进行第一次事件分发。

  2. 被分发的事件首先进入QObject对象的事件过滤器(EventFilter)中进行事件过滤。

  3. 被过滤的事件进入QObject::event(),并根据事件类型调用事件处理函数(CallBack)。

  4. 若事件被接受(通过调用Accpet()),则事件传递结束;若事件被忽略(ignore())则将事件传递给父控件处理。

传递过程如下:

这里写图片描述

处理事件的方法

Qt 提供了5个级别的事件处理和事件过滤方法。[5.]

  1. 重新实现特殊的事件处理器

重新实现像 mousePressEvent()、keyPressEvent()和paintEvent()这样的事件处理器是到现在为止最常用的事件处理方式。我们已经看到很多有关这种处理方式的例子了。

  1. 重新实现QObject::event

通过event()函数的、重新实现,可以在这些事件到达特定的事件处理器之前处理它们。这种方式常用于覆盖 Tab键的默认意义。

那些没有特定事件处理器的不常见类型的事件中(例如,Qevent::HoverEnter()。当重新实现event()时,必须对那些没有明确处理的情况调用其基类的event()函数。 1

  1. 在QObect中安装事件过滤器

对象一旦使用installEventFilter()注册过,用于目标对象的所有事件都会首先发送给这个监视对象的eventFilter()函数。如果在同一个对象上安装了多个事件处理器,那么就会按照安装顺序逆序,从最近安装的到最先安装的,依次激活这些事件处理器。

  1. 在QApplication 对象中安装事件过滤器

一且在qApp(唯一的那个QApplication对象)中注册了事件过滤器,那么应用程序中每个对象的每个事件都会在发送到其他事件过滤器之前,先发送给这个eventFilter()函数。这种处理方式对于调试是非常有用的。它也可以用来处理那些发送给失效窗口部件的鼠标事件,因为QApplication常都会忽略这些事件。

  1. 子类化QApplication 并且重新实现 notify()

Qt调用 Qapplication::notify()来发送一个事件。重新实现这个函数是在事件过滤器得到所有事件之前获得它们的唯一方式。但事件过滤器通常更有用,因为可以同时有多个事件过滤器,而notify()函数却只能有一个。

安装事件过滤器

每个Qobject都有一个eventFilter函数,重写该函数并为控件安装事件过滤器。 2

该函数的完整定义如下:

bool

eventFilter(QObject *watched, QEvent *event)

当watched的事件event被处理后,返回true,否则返回false。

// widget.h

class Widget : public QWidget

{

Q_OBJECT

public:

Widget(QWidget *parent = nullptr);

~Widget()override;

// QObject interface

bool eventFilter(QObject *watched, QEvent *event) override;

private:

QPushButton*pushButton=new QPushButton(“QPushButton”,this);

};

// widget.cpp

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

resize(500,500);

pushButton->installEventFilter(this);

this->installEventFilter(this);

}

Widget::~Widget()

{

}

bool Widget::eventFilter(QObject *watched, QEvent *event)

{

if(watched==pushButton){

if(event->type()==QEvent::MouseButtonPress){

QMouseEvent*e=static_cast<QMouseEvent*>(event);

qDebug()<<e->type();

}

}

return false;

}

image8

保证密集事件时主线程的相应

当处理事件时,可能会由于某个特定的事件造成阻塞,导致程序无反应,解决这个问题的办法为:[5.]

  1. 多线程

使用多线程将耗时的事件放入子线程处理,从而防止了主线程阻塞。

  1. 调用processEvents()

在耗时代码中频繁调用 Qapplication::processEvents()。这个函数告诉Qt。处理所有那些还没有被处理的各类事件,然后再将控制权返还给调用者。实际上,Qapplication::èxec() 就是一个不停调用processEvents()函数的while循环。 3

事件与信号和槽机制的区别

  1. 信号发射后,立即调用槽函数,没有消息队列。而事件发生后,要经过消息队列排序和消息传递过程。

  2. 自定义事件处理必须重写对应回调函数(CallBack),而信号和槽无需重写类。

其他组件

添加应用图标

image9

调试和日志系统

调试函数

qDebug()

要使用qDebug() [4]_函数,你需要包含QDebug头文件。 5

qDebug有两种使用方式:

  1. qDebug(const char *message, …)

和普通的printf()类似,只是输出数字、文本到调试器。

  1. qDebug()<<

后面可以接Qobject对象用于打印对象信息,也可以接字符串和数字。

QWidget widget;

qDebug()<<”&widget信息:”<<&widget;

效果如下:

image10

qWarning

使用方法与qDebug()6.1.1 相同。具体行为与宏QT_FATAL_WARNINGS的值有关。

qCritical()

使用方法与qDebug()6.1.1 相同 6。具体行为与宏QT_FATAL_CRITICALS的值有关。

qFatal()函数

qFatal()函数的使用方式与printf()相同,但是qFatal()函数在调用后终止程序运行。 7

只有当程序发生严重错误、不得不退出时才建议使用qFatal()。

qInfo

使用方法与qDebug()6.1.1 相同 8。具体行为与宏QT_NO_INFO_OUTPUT的值有关。

调试宏

Q_ASSERT(bool test)宏

若test为false,将输出断言警告,并终止程序:

int a=1;

Q_ASSERT(a==0);

效果如下:

image11

Q_ASSERT_X()

该宏的完整定义如下:

Q_ASSERT_X(bool test, const char *where, const char *what)。

当test为false是发出断言警告并终止程序。

int a=1;

Q_ASSERT_X(a==0,”a的值”,”a的值不为0”);

效果如下:

image12

CHECK_PTR()

检查指针的值。

image13

消息句柄

QtMessageHandler

文件读取

QFileInfo

#include <QCoreApplication>

#include <QFileInfo>

#include <QDebug>

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

QString filename=R”(C:/Users/31951/Desktop/2.txt)”;

QFileInfo fileinfo(filename);

qDebug()<<”fileName: “<<fileinfo.fileName();

qDebug()<<”filePath: “<<fileinfo.filePath();

qDebug()<<”baseName: “<<fileinfo.baseName();

qDebug()<<”bundleName: “<<fileinfo.bundleName();

qDebug()<<”completeBaseName: “<<fileinfo.completeBaseName();

qDebug()<<”absolutePath: “<<fileinfo.absolutePath();

qDebug()<<”absoluteFilePath: “<<fileinfo.absoluteFilePath();

qDebug()<<”canonicalPath: “<<fileinfo.canonicalPath();

qDebug()<<”canonicalFilePath: “<<fileinfo.canonicalFilePath();

qDebug()<<”completeSuffix: “<<fileinfo.completeSuffix();

qDebug()<<”suffix: “<<fileinfo.suffix();

return a.exec();

}

image14

Model/View结构

Qt对传统的MVC结构进行改动,生成了适用于Qt的Model-View-Delegate(模型-视图-委托)。

Model用于储存数据,View用于显示数据,Delegate用于修改数据。

View和ViewWidget

QlistWidget

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

QHBoxLayout*HLlayout=new QHBoxLayout(this); // 布局

QListWidget*LWwidget=new QListWidget(this); // ListWidget

QStringList SLlist;

// 设置布局

this->setLayout(HLlayout);

this->setWindowTitle(“ListWidget”);

HLlayout->addWidget(new QLabel(“浏览器”,this));

HLlayout->addWidget(LWwidget);

// 添加元素

LWwidget->addItem(“Chrome”); // 第一种方法

SLlist<<”Chrome”<<”Firefox”<<”IE”<<”Maxthon”; // 第二种方法

LWwidget->addItems(SLlist);

// 第三种方法

QListWidgetItem *LWIitem=new QListWidgetItem(QIcon(“C:\FireFox.ico”),”FireFox”);

LWwidget->addItem(LWIitem);

// LWwidget->setViewMode(QListView::IconMode); // 以图标形式显示 10

}

显示效果如下:

ListWidget

QtreeWidget

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

QHBoxLayout*HLlayout=new QHBoxLayout(this);

QTreeWidget*TWwidget=new QTreeWidget(this);

// 设置布局

this->setLayout(HLlayout);

this->setWindowTitle(“TreeWidget”);

HLlayout->addWidget(new QLabel(“TreeWidget”,this));

HLlayout->addWidget(TWwidget);

// 添加元素

QTreeWidgetItem*root=new QTreeWidgetItem(

TWwidget, QStringList(“Node1”));

QTreeWidgetItem*Node1=new QTreeWidgetItem(

root,QStringList(“Node1.1”));

new QTreeWidgetItem(

Node1,QStringList(“Node1.1.1”));

// 设置选择框

Node1->setCheckState(0,Qt::Checked);

// 设置表头

TWwidget->setHeaderLabel(“章节”);

//TWwidget->setHeaderHidden(true); // 隐藏表头

}

显示效果如下:

ListWidget2

QtableWidget

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

QHBoxLayout*HLlayout=new QHBoxLayout(this);

QTableWidget*TabWwidget=new QTableWidget(this);

QStringList headers;

// 设置布局

this->setLayout(HLlayout);

this->setWindowTitle(“TableWidget”);

HLlayout->addWidget(new QLabel(“TableWidget”,this));

HLlayout->addWidget(TabWwidget);

// 设置表格大小

TabWwidget->setColumnCount(3);

TabWwidget->setRowCount(5);

// 添加元素

TabWwidget->setItem(0,0,new QTableWidgetItem(QString(“001”)));

TabWwidget->setItem(0,1,new QTableWidgetItem(QString(“002”)));

TabWwidget->setItem(1,0,new QTableWidgetItem(QString(“小明”)));

// 设置表头

headers<<”ID”<<”Name”<<”Age”;

TabWwidget->setHorizontalHeaderLabels(headers);

}

显示效果如下:

TableWidget

View

View和ViewWidget的继承关系如下:

image18

View的使用需要结合模型(Model)使用,而ViewWidget不需要使用模型,适用于少量数据的显示。

模型和模型索引

QstringListModel

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

QHBoxLayout*HLlayout=new QHBoxLayout(this);

QListView*LVview=new QListView(this);

QStringListModel *model=new QStringListModel;

// 设置布局

this->setLayout(HLlayout);

this->setWindowTitle(“TableWidget”);

HLlayout->addWidget(new QLabel(“TableWidget”,this));

HLlayout->addWidget(LVview);

// 添加模型数据

QStringList data{

“Appel”,

“HuaWei”,

“XiaoMi”,

“Vivo”,

“OPPO”

};

model->setStringList(data);

LVview->setModel(model); // 设置View的模型

// 在尾部插入数据

model->insertRow(model->rowCount());

QModelIndex index=model->index(model->rowCount()-1,0);

model->setData(index,”Google”);

// 排序

model->sort(5,Qt::AscendingOrder);

}

效果如下:

TableWidget2

模型索引和角色

自定义委托

// spinboxdelegate.h文件

class SpinBoxDelegate : public QStyledItemDelegate

{

Q_OBJECT

public:

SpinBoxDelegate(QObject*parent=nullptr);

~SpinBoxDelegate()override=default;

// QAbstractItemDelegate interface

QWidget *createEditor(QWidget *parent,

const QStyleOptionViewItem &option,

const QModelIndex &index) const override;

// QAbstractItemDelegate interface

void setEditorData(QWidget *editor,

const QModelIndex &index) const override;

void setModelData(QWidget *editor,

QAbstractItemModel *model,

const QModelIndex &index) const override;

void updateEditorGeometry(QWidget *editor,

const QStyleOptionViewItem &option,

const QModelIndex &index) const override;

};

// spinboxdelegate.cpp文件

SpinBoxDelegate::SpinBoxDelegate(QObject*parent):

QStyledItemDelegate (parent)

{

}

QWidget *SpinBoxDelegate::createEditor(QWidget *parent,

const QStyleOptionViewItem &option,

const QModelIndex &index) const

{

Q_UNUSED(option)

Q_UNUSED(index)

QSpinBox*editor=new QSpinBox(parent);

editor->setMinimum(0);

editor->setMaximum(100);

return editor;

}

void SpinBoxDelegate::setEditorData(QWidget *editor,

const QModelIndex &index) const

{

QVariant value=index.model()->data(index,Qt::EditRole);

QSpinBox*spinbox=static_cast<QSpinBox*>(editor);

spinbox->setValue(value.toInt());

}

void SpinBoxDelegate::setModelData(QWidget *editor,

QAbstractItemModel *model,

const QModelIndex &index) const

{

QSpinBox*spinbox=static_cast<QSpinBox*>(editor);

spinbox->interpretText();

model->setData(index,spinbox->value(),Qt::EditRole);

}

void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,

const QStyleOptionViewItem &option,

const QModelIndex &index) const

{

Q_UNUSED(index);

editor->setGeometry(option.rect);

}

设置委托:

// 设置委托

SpinBoxDelegate*SBDdelegate=new SpinBoxDelegate(this);

LVview->setItemDelegate(SBDdelegate);

效果如下:

image20

视图选择

视图的选择使用了QItemSelectionModel类,View和ViewWidget已经内置了选择模型,可以使用selectionModel()来获取选择模型。

选择模式

内置的选择模式有以下几种:

枚举:SelectionMode

常数

描述

QAbstractItemView:

1

能且仅能选择一项,可以不选

SingleSelection

QAbstractItemView:

4

只能连续选取。可以不选

ContiguousSelection

QAbstractItemView:

3

按中Shift键时为连续选择,按中Ctrl键时为间隔选择

ExtendedSelection

QAbstractItemView:

2

一次选择一项,可选择多项,再次点击取消选择

MultiSelection

QAbstractItemView:

0

不可选择

NoSelection

要设置选择模式,请使用setSelectionMode()函数。

排序过滤

模型内置了两种排序方式:

枚举:Qt::SortOrder

常数

描述

Qt::AscendingOrder

0

按字母升序排列

Qt::DescendingOrder

1

按字母降序排列

要进行排序,请使用QstringListModel:: sort()函数。

代理

更高级的排序过滤功能由代理类:QSortFilterProxyModel提供。

QSortFilterProxyModel提供了基于正则表达式、Unix通配符、普通文本的过滤功能和基于函数的排序功能。

在使用代理后,MVC的显示机理变为:

QListView*LVview=new QListView(this);

QStringListModel *model=new QStringListModel;

QSortFilterProxyModel*filtermodel=new QSortFilterProxyModel;

LVview->setModel(filtermodel);

// 添加模型数据

QStringList data{

“Appel”,

“HuaWei”,

“XiaoMi”,

“Vivo”,

“OPPO”

};

model->setStringList(data);

// 过滤数据

filtermodel->setSourceModel(model);

filtermodel->setFilterRegExp(R”(^A)”);

显示效果如下:

TableWidget3

自定义模型

自定义只读模型

SQL

进程通信

剪切板

MIME数据类型

MIME是一种类型标准,MIME定义的标准可以获取数据的形式,进而进行解析,常用的MIME类型如下 11

MIME类型

数据类型

text/html

Html

text/plain

纯文本

text/uri-list

Url

application/x-color

颜色

video/x-msvideo

Avi视频

image/jpg

Jpg格式图片

Qt通过QMimeData类实现对MIME数据的储存与获取。事实上,只要保证数据可以解析,可以人为规定一个MIME数据类型,即使没有标准库会的承认。

剪切板

QClipboard类通过储存MIME类型数据储存数据,实现了剪切板的操作。通过QApplication::clipboard()可以获取应用程序的剪切板指针,从而对剪切板进行操作。

不同的系统对剪切板概念的支持不尽相同,在Windows和macOS中,剪切板属于全局资源,任何对剪切板的操作都是对全局剪切板的操作。 12

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

QHBoxLayout*HLlayout=new QHBoxLayout(this);

this->setLayout(HLlayout);

QLabel*lbl=new QLabel;

HLlayout->addWidget(lbl);

QMimeData*mimedata=new QMimeData;

mimedata->setData(“text/plain”,”<h1>Hello</h1>”);

QClipboard*clipboard=QApplication::clipboard();

clipboard->setMimeData(mimedata);

lbl->setText(clipboard->text());

}

效果如下:

Widget_NoUI_Testimage23

拖放

从拖放中读取数据

// widget.h

class Widget : public QWidget

{

Q_OBJECT

public:

Widget(QWidget *parent = nullptr);

~Widget()override;

// QWidget interface

protected:

void dragEnterEvent(QDragEnterEvent *event)override;

void dropEvent(QDropEvent *event)override;

private:

QTextBrowser*textbrown=new QTextBrowser(this);

QHBoxLayout*layout=new QHBoxLayout(this);

};

// widget.cpp

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

layout->addWidget(textbrown);

setLayout(layout);

setAcceptDrops(true);

textbrown->setAcceptDrops(false);

}

Widget::~Widget()

{

}

void Widget::dragEnterEvent(QDragEnterEvent *event)

{

if(event->mimeData()->hasText()){

event->acceptProposedAction();

}

}

void Widget::dropEvent(QDropEvent *event)

{

QList<QUrl>urls=event->mimeData()->urls();

if(urls.isEmpty())return;

QString filename=urls.first().toLocalFile();

if(filename.isEmpty()) return;

QFile file(filename);

file.open(QFile::ReadOnly);

if(!file.isOpen()){

qDebug()<<”文件打开失败”;

return;

}

textbrown->setText(file.readAll());

file.close();

}

效果如下:

image24

该软件在加载时没有读取文件,又没有定义打开文件的接口,且无法编辑。只能通过拖放来更改窗口内容。

自定义拖放数据

要自定义拖放数据,有以下几种方法:[4.]

  1. 将自定义数据作为 QByteArray 对象,使用 QMimeData::setData()函数作为二进制

  2. 数据存储到 QMimeData 中,然后使用 QMimeData::data()读取

  3. 继承 QMimeData,重写其中的 formats()和 retrieveData()函数操作自定义数据

  4. 如果拖放操作仅仅发生在同一个应用程序,可以直接继承 QMimeData,然后使用任

意合适的数据结构进行存储

数据库

数据解析

解析XML

使用DOM解析XML

使用SAM解析XML

解析JSON

使用Qjson解析JSON

使用QjsonDocument解析JSON

网络

线程

绘图

双缓冲

请查看C++ GUI Qt4编程(第二版)第五章

Qt基本组件

菜单

QMenu用于提供主界面菜单、菜单栏菜单、弹出菜单。

QMenu的非继承属性共有五个:

属性名

作用

icon

菜单图标

title

菜单标题

separatorsCollapsible

连续的分割线是否折叠(默认为true) 13

toolTipsVisible

是否显示toolTips

tearOffEnabled

菜单是否可分离出一个副本(默认为false)

QMenu常用的函数有以下几种:

返回值

函数

作用

QAction*

addAction()

重载函数,用于添加菜单项

QMeun*

addMenu()

重载函数,用于添加子菜单

QAction*

addSeparator()

添加一个分割线

QAction*

insertMenu()

插入一个菜单

QAction*

insertSeparator()

插入一个分割线

void

popup()

在指定位置弹出菜单

常用信号:

信号名

何时发射

aboutToHide()

用户尝试隐藏菜单前

aboutToShow()

用户尝试显示菜单前

hovered()

有菜单项处于活动前

triggered()

有菜单项被激活时

按钮

QPushButton

QPushButton常用的属性如下:

属性名

作用

autoDefault

当为true时 ,将会有更大的“推荐尺寸”,Dialog下的按钮默认为true

default

当为ture时,按钮获 取焦点后将按Enter键视为鼠左键单击。Dialog默认为true

checkable

按钮是否是可勾选的

checked

按钮是否是勾选过的

shortcut

设置按钮快捷键

text

按钮上的文字

autoExclusive

处于同一个parent的按钮是否是互斥的,默认为false

down

按钮是否可以被按下

flat

按钮是否为扁平的

常用函数

返回值

函数

作用

void

setMenu()

设置按钮菜单

QButtonGroup*

group()

返回按钮所在的按钮组

常用信号:

信号名

何时发射

clicked()

按钮点击后

pressed()

按钮按下时

released()

按钮释放时

toggled()

勾选状态改变时

公有槽:

槽名

作用

showMenu()

显示菜单

QCheckBox

QCheckBox定义了一个带有QLabel的复选框。

主要属性如下:

属性名

作用

tristate

tri-state,复选框是否有三个状态,默认为false,仅有两个状态。

枚举类型:

Qt::CheckState

描述

解释

Qt::Unchecked

0

未选中状态

Qt::PartiallyChecked

1

半选中状态

Qt::Checked

2

选中状态

常用函数

返回值

函数

作用

void

setCheckState()

设置checkbox的复选状 态,该函数适用于tristate为true时使用。

void

setChecked()

设置checkbox 是否已选择,适用于tristate为false时使用

常用信号:

信号名

何时发射

clicked()

按钮点击后

pressed()

按钮按下时

released()

按钮释放时

toggled()

勾选状态改变时

stateChanged()

状态改变时

QRadioButton

QRadioButton提供了带有QLabel的单选框,其除了继承QAbstractButton的属性和函数外,没有额外的属性与函数。

QToolButton

QToolbutton提供了命令或选项的快捷方式,通常用于工具栏。

枚举:

QToolButton::ToolButtonPopupMode

描述

解释

QToolButton::DelayedPopup

0

点击 时触发默认动作,长按显示菜单

QToolButton::MenuButtonPopup

1

显示一 个箭头代表该按钮提供一个菜单

QToolButton::InstantPopup

2

当按下工具按钮时, 菜单会立即显示出来。在此模式 下,不会触发按钮本身的操作。

Qt::ArrowType

描述

描述

Qt::NoArrow

0

无箭头

Qt::UpArrow

1

向上箭头

Qt::DownArrow

2

向下箭头

Qt::LeftArrow

3

向左箭头

Qt::RightArrow

4

向右箭头

Qt::ToolButtonStyle

描述

解释

Qt::ToolButtonIconOnly

0

仅显示图标

Qt::ToolButtonTextOnly

1

仅显示文字

Qt::ToolButtonTextBesideIcon

2

文字显示在图标旁边

Qt::ToolButtonTextUnderIcon

3

文字显示在图标下面

Qt::ToolButtonFollowStyle

4

样式跟随QStyle::StyleHint

主要属性如下:

属性名

作用

arrowType

设置箭头属性

autoRaise

定义了auto-raising是否可用,默认未false。

popupMode

定义了菜单的弹出方式

toolButtonStyle

定义了按钮风格

常用函数

返回值

函数

作用

void

setMenu()

设置按钮菜单

QAction*

defaultAction()

返回默认动作

Qt::ToolButtonStyle

toolButtonStyle()

返回按钮风格

常用信号:

信号名

何时发射

triggered(QAction*action)

指定action被触发时

toolButtonStyle

定义了按钮风格

常用槽

返回值

函数

作用

void

QToo lButton::setDefaultAction()

设置按钮的默认动作,若已 有动作,则设置以下属性的一 种:checkable、checked、ena bled、font、icon、popupMode (assuming the action has a menu)、statusTi p、text、toolTip、whatsThis

void

showMenu()

显示菜单

QCommandLinkButton

QCommandLinkButton继承自QPushButton,用于提供一个链接按钮,用于指示打开新的页面。常用于一组互斥选项,其功能与“单选+下一步”按钮组合的作用相同。

image25

主要属性如下:

属性名

作用

description

为按钮选项提供描述,其文本通常比按钮的Text小。

flat

按钮是否扁平化,默认为false 14

按钮组合

按钮组合实现了对一组按钮的控制,主要用于按钮组件的互斥和关联。按钮组合由QButtonGroup类实现,其继承自QObject,本质为按钮容器。 15

主要属性如下:

属性名

作用

exclusive

容器内按钮是否互斥,默认为true,仅有一个按钮可以被选中

常用函数

返回值

函数

作用

QAbstractButton *

QB uttonGroup::button()

返回指定id的按钮,如 按钮不存在,则返回0

Q List<QAbstractButton *>

QBu ttonGroup::buttons()

返回容器内的所有按钮

QAbstractButton *

QButtonGr oup::checkedButton()

返回被点击过的按钮, 若无,则返回0 18

int

QButt onGroup::checkedId()

返回被点击的按钮 的id,若无,则返回-1

int

QButtonGroup::id()

返回指定按钮的id

void

Q ButtonGroup::setId()

设置指定 按钮的id,id不能为-1

void

QButtonG roup::removeButton()

从按 钮组合中移除指定按钮

常用信号:

信号名

何时发射

buttonClicked(QAbstractButton *button)

button被点击时

buttonClicked(int id)

任何按钮被点击时

buttonPressed(QAbstractButton *button)

button被按下时

buttonPressed(int id)

任何按钮被按下时

buttonReleased(QAbstractButton *button)

任何按钮被释放时

buttonReleased(int id)

任何按钮被释放时

buttonToggled(QAbstractButton *button, bool checked)

button状态切换时

buttonToggled(int id, bool checked)

任何按钮状态被切换时

滚动条

使用QScrollArea创建滚动

使用QScrollArea作为Widget容器可以对Widget附加水平和垂直滚动条。

QScrollArea的继承关系如下:

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

QHBoxLayout*layout=new QHBoxLayout;

setLayout(layout);

QScrollArea*scrollarea=new QScrollArea(this);

layout->addWidget(scrollarea);

QLabel*lbl=new QLabel(this);

lbl->resize(600,600);

scrollarea->setWidget(lbl);

}

效果如下:

Widget_NoUI_Test2

在无需滚动条时,QScrollArea的滚动条会自动隐藏。QScrollArea的滚动条仅在需要的方向上出现(水平或垂直方向)。这种方式又被称为“按需滚动”。

使用QScrollBar创建滚动条

容器

QToolBox

QToolBox对QWidget提供了列状组织,每次只显示QWidget列表中的一个:

image27

QToolBox以item组织列表,每个item代表了一个QWidget。其继承关系如下:

主要属性如下:

属性名

作用

count

QToolBox item的总数

currentIndex

QToolBox当前显示的item的索引

常用函数

返回值

函数

作用

int

addItem()

添加item

QWidget*

currentWidget()

返回当前显示的item对应的QWidget。

int

indexof()

返回特定QWidget对应的索引

int

insertItem()

将item插入带特定位置,若越 界则插入到底部。返回插入的item的索引

bool

isItemEnabled()

如果启用了位 置索引项,则返回true;否则返回false。

常用信号:

信号名

何时发射

currentChanged(int index)

显示的item发生改变时

customContextMenuRequested(const QPoint &pos)

请求上下文菜单时 19

QTabBar

QTabBar提供了一个标签栏(tab bar)。Qt提供了一个更简便的的类:QTabWidget。两者均继承自QWidget。

枚举:

  1. QTabBar::ButtonPosition

描述

解释

QTabBar::LeftSide

0

widget位于标签栏左侧

QTabBar::RightSide

1

widget位于标签栏右侧

  1. QTabBar::SelectionBehavior

描述

解释

QTabBar::SelectLeftTab

0

当标签被移除时切换到左侧标签

QTabBar::SelectRightTab

1

当标签被移除时切换到右侧标签

  1. QTabBar::Shape

描述

解释

QTabBar::RoundedNorth

0

阴影边界。expanding为false时横线位于下方

QTabBar::RoundedSouth

1

阴影边界。expanding为false时横线位于下方

QTabBar::RoundedWest

2

阴影边界。标签栏左侧竖排显示,文字从右向左看

QTabBar::RoundedEast

3

阴影边界。标签栏左侧竖排显示,文字从左向右看

QTabBar::TriangularNorth

4

线条边界。expanding为false时横线位于下方

QTabBar::TriangularSouth

5

线条边界expanding为false时横线位于下方

QTabBar::TriangularWest

6

线条边界标签栏左侧竖排显示,文字从右向左看

QTabBar::TriangularEast

7

线条边界标签栏左侧竖排显示,文字从左向右看

主要属性如下:

属性名

作用

autoHide

标签栏少于两个时自动隐藏,默认为false

expanding

自动 调正大小以占满所有可用空间,默认为true

changeCurrentOnDrag

当接受拖放事 件时自动切换到被drop的标签。默认为false

count

标签栏的数量

movable

标签栏是 否可以通过拖动调整显示顺序。默认为false

currentIndex

返回当前 显示的标签页,若没有显示的标签页返回-1

selectionBehaviorOnRemove

设定移除后显示的标签页,与 QTabBar::SelectionBehavior有关

documentMode

该属性用于提示标签栏的绘制

shape

根据

QTabBar::Shape设定标签栏显示位置

drawBase

标签栏是否绘制底线,默认为true

tabsClosable

是否在标签栏显示关闭按钮,默认为false

elideMode

越界时如何省略文本,与Qt::T extElideMode有关,默认值依赖于style

usesScrollButtons

标签栏过多时是否显示按钮 以滚动显示标签栏。默认值依赖于style设置

常用函数

返回值

函数

作用

int

addTab()

添加标签页

int

insertTab()

插入标签页

void

setTabButton()

在指定索引的QTabBar::But tonPosition位置上添加一个QWidget

void

setTabData()

为指定位置设置数据

int

tabAt()

返回 指定坐标处的标签页索引,若无则返回-1

QWidget *

tabButton()

常用槽

返回值

函数

作用

void

setCurrentIndex(int index)

切换当前标签

常用信号:

信号名

何时发射

currentChanged(int index)

当前标签页改变时

tabBarClicked(int index)

标签页被点击时

tabBarDoubleClicked(int index)

标签页被双击时

tabCloseRequested(int index)

标签页被关闭前

tabMoved(int from, int to)

标签页被移动时

QTabWidget

QTabWidget是Qt根据QTabBar为用户提供的便利类。

枚举:

  1. QTabWidget::TabPosition

描述

解释

QTabWidget::North

0

QTabWidget::South

1

QTabWidget::West

2

QTabWidget::East

3

  1. QTabWidget::TabShape

描述

解释

QTabWidget::Rounded

0

圆形标签,默认选项

QTabWidget::Triangular

1

三角形标签

主要属性如下:

属性名

作用

count

标签栏的数量

currentIndex

当前标签的索引

documentMode

该属性用于提示标签栏的绘制

elideMode

越界时如何省略文本,与

Qt::TextElideMode有关,默认值依赖于style

movable

标签栏是否可以通过拖动调整显示顺序。默认为false

tabBarAutoHide

标签栏少于两个时自动隐藏,默认为false

tabPosition

描述了标签栏的位置,与

QTabWidget::TabPosition有关,默认为North

tabShape

根据 QTabWidget::TabShape设定标签栏显示位置

tabsClosable

是否在标签栏显示关闭按钮,默认为false

usesScrollButtons

标签栏过多时是否 显示按钮以滚动显示标签栏。默认值依赖于style设置

常用函数

返回值

函数

作用

int

addTab()

添加标签页

int

insertTab()

插入标签页

QWidget *

cornerWidget()

返回位于Qt::Corner处的标签widget

int

currentIndex()

返回当前标签页索引

QWidget *

currentWidget()

返回当前标签的widget

void

removeTab(int index)

移除指定标签

常用槽

返回值

函数

作用

void

setCurrentIndex(int index)

切换当前标签

void

setCurrentWidget(QWidget *widget)

切换当前标签

常用信号:

信号名

何时发射

currentChanged(int index)

当前标签页改变时

tabBarClicked(int index)

标签页被点击时

tabBarDoubleClicked(int index)

标签页被双击时

tabCloseRequested(int index)

标签页被关闭前

示例:

添加QTabWidget的关闭标签功能:

QTabWidget*tw=new QTabWidget(this);

tw->addTab(new QPushButton(this),”btn1”);

tw->addTab(new QPushButton(this),”btn2”);

tw->setTabsClosable(true);

connect(tw,&QTabWidget::tabCloseRequested,

tw,&QTabWidget::removeTab); // 添加关闭标签功能

image28

QStackedWidget

QStackedWidget继承自QFrame。为widget提供了栈式显示,同一时刻仅显示一个widget。

主要属性如下:

属性名

作用

count

储存了栈内widget的数量

currentIndex

当前显示的widget的索引

常用函数

返回值

函数

作用

int

addWidget()

添加widget

int

indexOf()

插入widget

void

removeWidget()

删除widget

QWidget *

currentWidget()

当前显示的widget

int

indexOf()

指定widget的索引

QWidget *

widget

指定索引的widget

常用槽

返回值

函数

作用

void

setCurrentIndex(int index)

设定显示的index

void

setCurrentWidget(QWidget *widget)

设定显示的widget

常用信号:

信号名

何时发射

currentChanged(int index)

当前显示的widget改变时

widgetRemoved(int index)

widget被移除时

演示:

QHBoxLayout*HL_layout=new QHBoxLayout(this);

QStackedWidget*sw=new QStackedWidget(this);

HL_layout->addWidget(sw);

sw->addWidget(new QPushButton(“btn1”,this));

sw->addWidget(new QPushButton(“btn2”,this));

sw->addWidget(new QPushButton(“btn3”,this));

sw->addWidget(new QPushButton(“btn4”,this));

auto btn_remove=new QPushButton(“remove”,this);

auto btn_pre=new QPushButton(“pre”,this);

auto btn_next=new QPushButton(“next”,this);

HL_layout->addWidget(btn_pre);

HL_layout->addWidget(btn_next);

HL_layout->addWidget(btn_remove);

connect(btn_remove,&QPushButton::clicked,[sw](){

sw->removeWidget(sw->currentWidget());

});

connect(btn_pre,&QPushButton::clicked,[sw](){

int index=sw->currentIndex()-1;

if(index<0) index=sw->count()-1;

qDebug()<<”pre:”<<index;

sw->setCurrentIndex(index);

});

connect(btn_next,&QPushButton::clicked,[sw](){

int index=sw->currentIndex()+1;

if(index>sw->count()-1) index=0;

qDebug()<<”next:”<<index;

sw->setCurrentIndex(index);

});

image29

QDockWidget

QDockWidget继承自QWidget,提供了一个dock widget,其既可以作为程序的一部分,又可单独分离成为一个桌面顶级窗口。

常用枚举

  1. QDockWidget::DockWidgetFeature

描述

解释

QDockWidget ::DockWidgetClosable

0x01

dock widget可以被关闭

QDockWidge t::DockWidgetMovable

0x02

dock wid get可以在docks中移动

QDockWidget: :DockWidgetFloatable

0x04

dock widget可 以分离成一个独立窗口

QDockWidget::DockWi dgetVerticalTitleBar

0x08

dock widget将 标题栏垂直显示在左侧

QDockWidget::A llDockWidgetFeatures

DockWidgetClosab le|DockWidgetMovable |DockWidgetFloatable

(过时)该窗口可 以被移动、附加、分离

QDockWidget:: NoDockWidgetFeatures

0x00

该dock widget无 法被移动、附加、分离

主要属性如下:

属性名

作用

allowedAreas

dock widget可以被停靠的区域,其值与Qt::DockWi dgetArea有关,默认为Qt::AllDockWidgetAreas

features

dock wi dget的特征,与QDockWidget::DockWidgetFeature有关,默认为QDockWidget::AllDockWidgetFeatures

floating

dock widget是否可分离为一个独立的窗口

windowTitle

窗口标题

常用函数

返回值

函数

作用

void

setTitleBarWidget()

使用一个自定义的widget作为dock widget的标题栏

void

setWidget()

设置dock widget的默认组件

QAction *

toggleViewAction()

该QAction可用于控制该dock widget

常用信号:

信号名

何时发射

allowedAreasChanged()

允许停靠区域发生改变时

dockLocationChanged()

停靠区域发生改变时

featuresChanged()

dock widget特征发生改变时

topLevelChanged()

floating属性改变时

visibilityChanged()

dock widget被隐藏/显示时

例:

QHBoxLayout*HL_layout=new QHBoxLayout(this);

QDockWidget*dw=new QDockWidget(this);

HL_layout->addWidget(dw);

dw->setWidget(new QPushButton(“btn1”,this));

dw->setTitleBarWidget(new QPushButton(“btn_bar”,this));

效果如下:

image30

QMdiArea

QMdiArea中文译为“多文档界面”,其提供了一个类似桌面的区域,其区域内可显示多个子窗口。并且所有子窗口的最大化、最小化等效果以QMdiArea为基准。其继承关系如下:

  1. QMdiArea::AreaOption

描述

解释

QMdiArea::DontM aximizeSubWindowOnActivation

0x1

当活动 子窗口最大化时,最大化下一个 被激活的子窗口。默认为true。

  1. QMdiArea::ViewMode

描述

解释

QMdiArea::SubWindowView

0

带有frames的子窗口(默认)

QMdiArea::TabbedView

1

带有标签栏的子窗口

  1. QMdiArea::WindowOrder

描述

解释

QMdiArea::CreationOrder

0

按子窗口的创造顺序返回

QMdiArea::StackingOrder

1

按子窗口的前 后顺序返回,最靠前的排在最后

QMd iArea::ActivationHistoryOrder

2

按子窗口的活动顺序返回

主要属性如下:

属性名

作用

activationOrder

该属性储存了子窗 口列表的属性,与QMdiArea::WindowOrder有关

background

该属性定义了子窗口的背景画刷。默认为灰色

documentMode

此属性定义选项 栏是否在选项视图模式中设置为文档模式。默认为true

tabPosition

定义了标签模式下标签 栏的位置,与QTabWidget::TabPosition有关。

tabShape

定义了标签形状,与QTabWi dget::TabShape有关。默认为QTabWidget::Rounded

tabsClosable

标签是否可关闭,默认为false

tabsMovable

标签是否可移动,默认为false

viewMode

该属性定义了子 窗口的显示方式,与QMdiArea::ViewMode有关

常用函数

返回值

函数

作用

QMdiSubWindow *

addSubWindow()

添加子窗口

void

removeSubWindow()

移除子窗口

QMdiSubWindow *

activeSubWindow()

返回当前被激 活的子窗口.若无返回0

QMdiSubWindow *

currentSubWindow()

返回当 前子窗口,若无则返回0

QList<QMdiSubWindow *>

subWindowList()

按照

**QMdiArea::WindowOr

der**的顺序返回列表

常用槽

返回值

函数

作用

void

activateNextSubWindow()

激活下一个子窗口

void

activatePreviousSubWindow()

激活上一个子窗口

void

cascadeSubWindows()

层叠子窗口

void

closeActiveSubWindow()

关闭活动的子窗口

void

closeAllSubWindows()

关闭所有子窗口

void

setActiveSubWindow()

设置活动子窗口

void

tileSubWindows()

以平铺模式排列所有子窗口

常用信号:

信号名

何时发射

subWindowActivated(QMdiSubWindow *window)

window被激活后,, 若windows=0,则QMdiArea反激活最 后一个活动窗口,此时没有激活窗口

例:

QHBoxLayout*HL_layout=new QHBoxLayout(this);

QMdiArea*ma=new QMdiArea(this);

HL_layout->addWidget(ma);

ma->addSubWindow(new QPushButton(“btn1”,this));

ma->addSubWindow(new QPushButton(“btn2”,this));

ma->addSubWindow(new QPushButton(“btn3”,this));

ma->addSubWindow(new QPushButton(“btn4”,this));

ma->tileSubWindows();

image31

QMdiSubWindow

QMdiSubWindow继承自QWidget,代表了QMdiArea中的一个子窗口。

  1. QMdiSubWindow::SubWindowOption

描述

解释

QMd iSubWindow::RubberBandResize

0x4

如果启用此选项 ,则使用rubber来表示子窗口的 大纲,用户将调整此选项的大小 ,而不是子窗口本身的大小。因 此,子窗口将保持其原始位置和 大小,直到完成调整大小操作, 此时它将接收一个QResizeEvent 。默认情况下,此选项是禁用的

Q MdiSubWindow::RubberBandMove

0x8

如果启用此选项,则使 用rubber来表示子窗口的大纲, 用户将移动此控件而不是子窗口 本身。因此,子窗口将保持在原 来的位置,直到移动操作完成, 此时将向窗口发送QMoveEvent。 默认情况下,此选项是禁用的。

主要属性如下:

属性名

作用

keyboardPageStep

使用page键移动窗口时的步长,默认为20px

keyboardSingleStep

使用键盘箭头移动窗口时的步长,默认为5px

常用函数

返回值

函数

作用

QMdiArea *

mdiArea()

返回控件所处的MdieArea

void

setSystemMenu()

设置子窗口的默认系统菜单

void

setOption()

设置子窗口的选项,与QMdi SubWindow::SubWindowOption相关

常用槽

返回值

函数

作用

void

showShaded()

调用此函数使子窗口进入阴影模式。 当子窗口为阴影时,只有标题栏是可见的。

void

showSystemMenu()

显示系统菜单

常用信号:

信号名

何时发射

aboutToActivate()

子窗口被激活前

windowStateChanged()

windows state改变后

例:

QHBoxLayout*HL_layout=new QHBoxLayout(this);

QMdiArea*ma=new QMdiArea(this);

HL_layout->addWidget(ma);

ma->addSubWindow(new QPushButton(“btn1”,this));

ma->addSubWindow(new QPushButton(“btn2”,this));

ma->addSubWindow(new QPushButton(“btn3”,this));

ma->addSubWindow(new QPushButton(“btn4”,this));

ma->tileSubWindows();

foreach(QMdiSubWindow* x,ma->subWindowList()){

connect(x,&QMdiSubWindow::aboutToActivate,[x](){

qDebug()<<”子窗口”<<x<<”即将被激活”;

QTest::qSleep(5000);

});

}

image32

也由此可见:QMdiArea在创建时会逐个激活所有子窗口

输入组件

QLineEdit

QVBoxLayout*layout=new QVBoxLayout(this);

QLineEdit*username=new QLineEdit(this);

QLineEdit*passwd=new QLineEdit(this);

QPushButton*itOk=new QPushButton(this);

///

setLayout(layout);

layout->addWidget(username);

layout->addWidget(passwd);

layout->addWidget(itOk);

// 设置QLineEdit的属性

username->setClearButtonEnabled(true);

username->setAcceptDrops(true);

passwd->setEchoMode(QLineEdit::Password);

passwd->setClearButtonEnabled(true);

connect(username,&QLineEdit::editingFinished,[this](){

passwd->setFocus();

});

connect(passwd,&QLineEdit::editingFinished,[this](){

emit itOk->clicked();

});

connect(itOk,&QPushButton::clicked,[](){

qDebug(“clicked”);

});

定时器

布局管理

QBoxLayout

QFormLayout

QGridLayout

QStackedLayout

数据

QCache

QDataWidgetMapper

Qt美化

QSS

QStyleOption

QStyleOptionButton

QStyleOptionButton

QStyleOptionComplex

QStyleOptionDockWidget

QStyleOptionFocusRect

QStyleOptionFrame

QStyleOptionGraphicsItem

QStyleOptionHeader

QStyleOptionMenuItem

QStyleOptionProgressBar

QStyleOptionRubberBand

QStyleOptionTab

QStyleOptionTabBarBase

QStyleOptionTabWidgetFrame

QStyleOptionToolBar

QStyleOptionToolBox

QStyleOptionViewItem

QStyle

帮助系统

请查阅C++ GUI Qt4编程(第二版)第17章

Qt国际化

多媒体

录音

使用QAudioRecorder录制音频

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include <QMainWindow>

#include <QAudioRecorder>

#include <QDebug>

#include <QFileDialog>

#include <QLabel>

namespace Ui {

class MainWindow;

}

class MainWindow : public QMainWindow

{

Q_OBJECT

public:

explicit MainWindow(QWidget *parent = nullptr);

~MainWindow();

void audioRecord();

void startRecord();

private:

Ui::MainWindow *ui;

QAudioRecorder record;

QString fileName;

QLabel statusFileName;

};

#endif // MAINWINDOW_H

#include “mainwindow.h”

#include “ui_mainwindow.h”

MainWindow::MainWindow(QWidget *parent) :

QMainWindow(parent),

ui(new Ui::MainWindow)

{

ui->setupUi(this);

ui->statusBar->addWidget(&statusFileName);

audioRecord();

connect(ui->action_Open,&QAction::triggered,[&](){

fileName=QFileDialog::getOpenFileName(this,tr(“选择文件”));

statusFileName.setText(fileName);

});

connect(ui->btn_Stop,&QPushButton::clicked,[this](){

record.stop();

});

connect(ui->btn_Pause,&QPushButton::clicked,[this](){

record.pause();

});

connect (ui->btn_Start,&QPushButton::clicked,this,&MainWindow::startRecord);

}

MainWindow::~MainWindow()

{

delete ui;

}

void MainWindow::audioRecord()

{

foreach(auto&str,record.audioInputs())

ui->comBox_AudioList->addItem(str);

connect(ui->btn_Start,&QPushButton::clicked,[&](){

});

QAudioEncoderSettings settings;

settings.setBitRate(96000);

settings.setCodec(“audio/pcm”);

settings.setQuality(QMultimedia::EncodingQuality::VeryHighQuality);

settings.setChannelCount(8);

record.setAudioSettings(settings);

record.setAudioInput(record.defaultAudioInput());

}

void MainWindow::startRecord()

{

record.setOutputLocation(QFileDialog::getOpenFileUrl());

record.record();

}

image33

自定义插件和库

自定义Qt Designer Widget插件

加载ActiveX控件

QAxWidget

Qt枚举

  1. Qt::TextElideMode

描述

解释

Qt::ElideLeft

0

省略开头

Qt::ElideRight

1

省略结尾

Qt::ElideMiddle

2

省略中间

Qt::ElideNone

3

不显示省略号

  1. Qt::Corner

描述

解释

Qt::TopLeftCorner

0x00000

矩形左上角

Qt::TopRightCorner

0x00001

矩形右上角

Qt::BottomLeftCorner

0x00002

矩形左下角

Qt::BottomRightCorner

0x00003

矩形右下角

  1. Qt::DockWidgetArea

描述

解释

Qt::LeftDockWidgetArea

0x1

Qt::RightDockWidgetArea

0x2

Qt::TopDockWidgetArea

0x4

Qt::BottomDockWidgetArea

0x8

Qt::AllDockWidgetAreas

DockWidgetArea_Mask

Qt::NoDockWidgetArea

0

常见错误

undefined reference to `vtable for’

方法一:

“QT中,类要支持信号与槽机制,需要继承自QObject并在头文件开头添加Q_OBJECT宏.

如果使用QtCreator创建类时,没有选择继承自QObject类或其子类,而在创建后手工修改继承自QObject并手工添加Q_OBJECT宏,则在编译时有可能会出现”undefined reference to `vtable for’…….”错误.

解决方法: 把新创建的类从项目中移除(主要不要从磁盘上删除),然后再添加进功能,QtCreator就会重新解析此类,再编译就不再会出现上述错误. [2.]

方法二:

使用QT编程时,当用户自定义了一个类,只要类中使用了信号或槽。Code::Blocks编译就会报错(undefined reference to `vtable for)。Google上有很多这个问题的回答,但很多说的很模糊,或者根本就不可行.其实,QT有自己的编译方法.

不用IDE写一个类,QT的编译步骤是:

  1. cd 源代码目录

  2. qmake -project 20

  3. qmake project_name.pro

  4. make (如果你装的是minGW的话,就用mingw32-make.exe)[3.]

undefined reference to

image34

错误原因:函数仅定义,未实现

incomplete type

完整错误显示如下:

widget.h:19:20: error: allocation of incomplete type ‘QMenu’

qabstractitemview.h:56:7: note: forward declaration of ‘QMenu’

原因:未包含QMenu的头文件。

connect没有匹配的函数

image35

原因:

信号或槽有重载

使用msvc编译

image36

解决办法:msvc在编译UTF-8文件时,会将无BOM的文件当做本地编码(GB2312)处理,有BOM的才当作UTF-8文件,因此,,将文件改为UTF-8+BOM的即可:

image37

然后重新保存文件。[6.]

MSVC qDebug()输出乱码

image38

解决方法:[7.]

在头文件内添加一句宏 21

#pragma execution_character_set(“utf-8”)

QDesktopServices打开中文路径乱码

代码如下:

void MainWindow::openFile(const QModelIndex &modelindex)

{

QString filePath=FileLists->at(modelindex.row());

qDebug()<<filePath;

QDesktopServices::openUrl(filePath);

}

效果如下:

image39

解决方法如下:

将QDesktopServices::openUrl(filePath);替换为

QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));

Fault tolerant heap shim applied to current process

问题原因:以前程序崩溃导致操作系统“记上了”。要解决,需要:

打开注册表,找到 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows  NT\CurrentVersion\AppCompatFlags\Layers\ ,选中Layers键值,从右侧列表中删除自己的那个程序路径即可。。

但是根本原因是程序的业务逻辑错了。我在使用connect+lambda表达式时出错了,后来换成connect+槽函数就没问题了

附录

优秀资源

如何理解Qt的viewport视图区?

https://jingyan.baidu.com/article/7082dc1c073a49e40a89bd9c.html

viewport视图区表示描述一个任一矩形的物理坐标系,而“window”窗口描述的是同样的矩形的逻辑坐标系。通常逻辑和物理坐标系是重合的,并且与绘图设备的矩形是一样的。

如何理解Qt的viewport视图区?

工具/原料

  • QtCreator4.4.1

  • Qt5.9.2

方法/步骤

  1. 通过窗口-视图变换,我们可以定制逻辑坐标系。同时使得绘图代码独立于绘图设备。譬如,逻辑坐标上从(-50,-50)到(50,50),(0,0)点在中心。那么painter的绘图窗口就可以如下图设置:

如何理解Qt的viewport视图区?2

  1. 这样逻辑坐标(-50,-50)就对应到绘图设备的物理坐标(0,0)了。setViewport()函数和setWindow()函数是一对姐妹函数,一个设置物理设备坐标系,一个设置逻辑坐标系。默认情况,两者是一样的。通过设置“window”或者viewport矩形区域,我们就可以对这两个坐标系进行线性变换了。因此,一般我们为了防止变形,viewport和”window“会保持一个相同的宽高比。我们通常的绘图操作是在viewport坐标系实现的,独立于绘图设备的。这里窗口-视图区的转换仅仅是一个线性转换,并不会进行裁剪动作。意思就是如果你在当前设置的window中绘图,图形依然会通过同样的线性代数方式被转换到viewport。

视图区,窗口,和转换矩阵决定了逻辑QPainter坐标如何映射到绘图设备坐标系的方式。通常,world转换矩阵是唯一的矩阵,窗口和视图区的设置等价于绘图设备的设置。如同上图所描述的,虽然world,window和device的坐标系等价,但是因为我们可以进行转换,所以他们的坐标系是可以改变的。

这里我来看一个例子,说明一下window和viewport具体的区别。

如何理解Qt的viewport视图区?3

  1. 上图中,我设置了Painter画一条对角线,先设置widget窗口的大小(600,600),然后画一条线,这里没有设置window和viewport,于是这条线该是多长就多长。

如何理解Qt的viewport视图区?4

  1. 接下来,我设置painter的window区域(200,200),然后无论我怎么拉伸窗口,对角线都是跟随窗口变化的,如下图。

如何理解Qt的viewport视图区?5

如何理解Qt的viewport视图区?6

  1. 然后我设置window区域(600,600)。这时候,和我们刚开始看到的图形就是一样的了,也就是说刚才设置了window以后,窗口window被放大到铺满整个widget了。

如何理解Qt的viewport视图区?7

如何理解Qt的viewport视图区?8

  1. 通过打印widget的大小,我们发现widget的大小依然是(600,600),也就是说window没有设置成(200,200),经查证,Qt这里是会自动转换坐标系的,所以我们需要按下图这样设置一下坐标转换不使能。setViewTransformEnabled(false);

如何理解Qt的viewport视图区?9

如何理解Qt的viewport视图区?10

  1. 接下来,我再设置viewport。Viewport表示设备的坐标系。如下图,可以看到,viewport大小是(100,100),而drawLine是(600,600),但是线条并没有600,而是被viewport限制了,Painter画线按照设备viewport-window的转换的某种线性关系画了。

如何理解Qt的viewport视图区?11

如何理解Qt的viewport视图区?13

END

注意事项

  • 这里要注意视图区即物理设备绘图区,窗口是指逻辑绘图区

参考文献

  1. 博客园:事件驱动模型

  2. undefined reference to vtable for 问题的原因及解决方法

  3. Qt的“undefined reference to vtable for”错误解决(手动解决,加深理解)

  4. Qt 学习之路 2(53):自定义拖放数据

  5. C++ GUI Qt4编程(第二版)

  6. Qt系列 :用MSVC2015编译常见编译错误及解决方案

  7. Qt与MSVC中文乱码问题的解决方案_imxiangzi的专栏-CSDN博客

1

事实上,调用event->ignore()也可以

2

被控制的空间都要安装事件过滤器

3

在调用processEvents时最好加上QeventLoop::ExcludeUserInputEvents参数以忽略鼠标和键盘事件,防止由于用户操作导致的不可知后果。

事实上,只有在使用qDebug()第二中输出方式时才需要包含头文件,只使用第一种时无需包含。

5

在Windows下,qDebug()将信息输出到调试器,而不是stdout。

6

qCritical将信息打印到stderr。

7

qFatal()函数将信息输出到stderr。

8

qCritical将信息打印到stderr。

注:当QlistWidget显示模式为QListView::IconMode时,图标是可拖动的

10

注:当QlistWidget显示模式为QListView::IconMode时,图标是可拖动的

11

附录18.1 列举了大部分的MIME类型

12

当你在Win10下开启“剪贴板历史记录”时,你在剪切板中储存的数据可以使用win+V键在剪切板历史记录中看到(只支持部分数据)。

13

当separatorsCollapsible设置为true时,菜单开始、菜单结束的分割线会被隐藏,连续的分割线仅显示一个。

14

在Win10 1903 + Qt 5.12.3 环境下测试时,扁平化与非扁平化表现形式相同。

15

简单的一组按钮互斥可以通过设置autoExclusive属性实现。

该函数必须保证至少一个按钮的Checkable属性为true。

18

该函数必须保证至少一个按钮的Checkable属性为true。

19

该信号可用于实现右键菜单

20

若已有项目文件(.pro)此步骤可省略。

21

所有含中文的文件都要添加此宏,为了方便,将其写入头文件中。

该宏Mingw也支持