目录
(4) 读写锁:QReadLocker、QWriteLocker、QReadWriteLock
一、Qt 事件
1,事件的定义
事件是应用程序内部或者外部产生的事情或者动作的统称。在 Qt 中使用一个对象来表示一个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本身在不同的时刻发出的。 当用戶按下鼠标、敲下键盘 ,或者是窗口需要重新绘制的时候 ,都会发出一个相应的事件。
事件名称 |
描述 |
鼠标事件 |
鼠标左键、 鼠标右键、 鼠标滚轮 , 鼠标的移动 ,鼠标按键的按下和松开 |
键盘事件 |
按键类型、按键按下、按键松开 |
定时器事件 |
定时时间到达 |
进入离开事件 |
鼠标的进入和离开 |
滚轮事件 |
鼠标滚轮滚动 |
绘屏事件 |
重绘屏幕的某些部分 |
显示隐藏事件 |
窗口的显示和隐藏 |
移动事件 |
窗口位置的变化 |
窗口事件 |
是否为当前窗口 |
大小改变事件 |
窗口大小改变 |
焦点事件 |
键盘焦点移动 |
2,事件的处理
事件处理⼀般常⽤的⽅法为:重写相关的 Event 函数。
在 Qt 中,⼏乎所有的 Event 函数都是虚函数,所以可以重新实现。如:在实现⿏标的进⼊和离开事件时,直接重新实现 enterEvent() 和 leaveEvent() 即可。enterEvent() 和 leaveEvent() 函数原型如下:
3,鼠标事件
鼠标点击
void Label::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
qDebug()<<"按下左键";
}
else if(event->button() == Qt::RightButton)
{
qDebug()<<"按下右键";
}
// 当前 event 对象就包含了鼠标点击的坐标
qDebug() << event->x() << "," << event->y();
// 以屏幕左上角为原点的坐标
qDebug() << event->globalX() << "," << event->globalY();
}
void Label::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
qDebug()<<"释放左键";
}
else if(event->button() == Qt::RightButton)
{
qDebug()<<"释放右键";
}
}
void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
qDebug()<<"双击左键";
}
else if(event->button() == Qt::RightButton)
{
qDebug()<<"双击右键";
}
}
鼠标移动和滚轮移动
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 把这个选项设置为true,才能够追踪鼠标位置
this->setMouseTracking(true);
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << event->x() << event->y();
}
void Widget::wheelEvent(QWheelEvent *event)
{
qDebug() << event->delta();
}
4,按键事件
单键
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_A)
{
qDebug()<<"A键被按下";
}
}
组合键
Qt::NoModifier |
无修改键 |
Qt::ShiftModifier |
Shift 键 |
Qt::ControlModifier |
Ctrl 键 |
Qt::AltModifier |
Alt 键 |
Qt::MetaModifier |
Meta键(在Windows上指Windows键 ,在macOS上指Command键) |
Qt::KeypadModifier |
使用键盘上的数字键盘进行输入时 ,Num Lock键处于打开状态 |
Qt::GroupSwitchModifier |
用于在输入法组之间切换 |
5,定时器
Qt中的定时器分为QTimerEvent 和QTimer 这2个类。
QTimerEvent类
用来描述一个定时器事件。在使用时需要通过startTimer() 函数来开启一个定时器,这个函数需要输入一个以毫秒为单位的整数作为参数来表明设定的时间,它返回的整型值代表这个定时器。 当定时器溢出时(即定时时间到达)就可以在 timerEvent() 函数中获取该定时器的编号来进行相关操作。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 把这个选项设置为true,才能够追踪鼠标位置
this->setMouseTracking(true);
timer_id1 = startTimer(1000);
timer_id2 = startTimer(2000);
}
void Widget::timerEvent(QTimerEvent *event)
{
if(event->timerId() == timer_id1)
{
static int num1 = 1;
// lb1每隔1秒加一次
ui->label->setText(QString::number(num1++));
}
if(event->timerId() == timer_id2)
{
static int num2 = 1;
// lb2每隔2秒加一次
ui->label_2->setText(QString::number(num2++));
}
}
QTimer类
用来实现一个定时器,它提供了更高层次的编程接口,如:可以使用信号和槽,还可以设置只运行一次的定时器。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
connect(ui->pushButton, &QPushButton::clicked,[=](){
time->start(1000);
});
connect(time,&QTimer::timeout,[=](){
static int num = 1;
ui->label->setText(QString::number(num++));
});
connect(ui->pushButton_2, &QPushButton::clicked,[=](){
time->stop();
});
}
6,事件分发器
在 Qt 中,我们发送的事件都是传给了 QObject 对象,更具体点是传给了 QObject 对象的 event() 函数。所有的事件都会进⼊到这个函数⾥⾯,那么我们处理事件就要重写这个 event() 函数。event() 函数本⾝不会去处理事件,⽽是根据 事件类型(type值)调⽤不同的事件处理函数。
7,事件过滤器
在 Qt 中,⼀个对象可能经常要查看或拦截另外⼀个对象的事件,如对话框想要拦截按键事件,不让别的组件接收到,或者修改按键的默认值等。通过上⾯的学习,我们已经知道,Qt 创建了 QEvent事件对象之后,会调⽤QObject 的 event()函数 处理事件的分发。显然,我们可以在 event()函数 中实现拦截的操作。由于 event()函数是 protected 的,因此,需要继承已有类。如果组件很多,就需要重写很多个event()函数。这当然相当⿇烦,更不⽤说重写 event()函数还得⼩⼼⼀堆问题。好在 Qt 提供了另外⼀种机制来达到这⼀⽬的:事件过滤器。
二、Qt 文件
1,输入输出类
Qt 中,⽂件读写的类为 QFile 。QFile 的⽗类为 QFileDevice ,QFileDevice 提供了⽂件交互操作的底层功能。 QFileDevice 的⽗类是 QIODevice,QIODevice 的⽗类为 QObject 。
QIODevice 是 Qt 中所有输⼊输出设备(input/output device,简称 I/O 设备)的基础类,I/O 设备就是能进⾏数据输⼊和输出的设备,例如⽂件是⼀种 I/O 设备,⽹络通信中的 socket 是 I/O 设备,串⼝、蓝⽛等通信接⼝也是 I/O 设备,所以它们也是从 QIODevice 继承来的。Qt 中主要的⼀些 I/O 设备类的继承关系如下图所⽰
QFile 是⽤于⽂件操作和⽂件数据读写的类,使⽤ QFile 可以读写任意格式文件。
QSaveFile 是⽤于安全保存⽂件的类。使⽤ QSaveFile 保存⽂件时,它会先把数据写⼊⼀个临时⽂件,成功提交后才将数据写⼊最终的⽂件。如果保存过程中出现错误,临时⽂件⾥的数据不会被写⼊最终⽂件,这样就能确保最终⽂件中不会丢失数据或被写⼊部分数据。 在保存⽐较⼤的⽂件或复杂格式的⽂件时可以使⽤这个类,例如从⽹络上下载⽂件等。
QTemporaryFile 是⽤于创建临时⽂件的类。使⽤函数 QTemporaryFile::open() 就能创建⼀个⽂件名唯⼀的临时⽂件,在 QTemporaryFile 对象被删除时,临时⽂件被⾃动删除。
QTcpSocket 和 QUdpSocket 是分别实现了 TCP 和 UDP 的类。
QSerialPort 是实现了串⼝通信的类,通过这个类可以实现计算机与串⼝设备通信。
QBluetoothSocket 是⽤于蓝⽛通信的类。⼿机和平板计算机等移动设备有蓝⽛通信模块,笔记本电脑⼀般也有蓝⽛通信模块。通过QBluetoothSocket类,就可以编写蓝⽛通信程。如编程实现笔记本电脑与⼿机的蓝⽛通信。
QProcess 类⽤于启动外部程序,并且可以给程序传递参数。
QBuffer 以⼀个 QByteArray 对象作为数据缓冲区,将 QByteArray 对象当作⼀个 I/O 设备来读写。
2,文件读写类
在 Qt 中 ,文件的读写主要是通过 QFile 类来实现。在 QFile 类中提供了一些用来读写文件的方法。对 于文件的操作主要有:
读数据:QFile 类中提供了多个方法用于读取文件内容;如 read()、 readAll()、 readLine()等。
写数据:QFile 类中提供了多个方法用于往文件中写内容;如 write()、writeData等。
关闭文件:文件使用结束后必须用函数 close() 关闭文件。
访问一个设备之前 ,需要使用 open()函数 打开该设备 ,而且必须指定正确的打开模式 ,QIODevice 中 所有的打开模式由 QIODevice::OpenMode 枚举变量定义 ,其取值如下:
QIODevice::NotOpen |
没有打开设备 |
QIODevice::ReadOnly |
以只读方式打开设备 |
QIODevice::WriteOnly |
以只写方式打开设备 |
QIODevice::ReadWrite |
以读写方式打开设备 |
QIODevice::Append |
以追加方式打开设备 ,数据将写到文件末尾 |
QIODevice::Truncate |
每次打开文件后重写文件内容 ,原内容将被删除 |
QIODevice::Text |
在读文件时 ,行尾终止符会被转换为 '\n'; 当写入文件时 ,行尾终止符会被转换为 本地编码。如 Win32上为'\r\n'; |
QIODevice::Unbuffered |
无缓冲形式打开文件 ,绕过设备中的任何缓冲区 |
QIODevice::NewOnly |
文件存在则打开失败 ,不存在则创建文件 |
3,文件和目录信息类
QFileInfo 是 Qt 提供的一个用于获取文件和目录信息的类 ,如获取文件名、文件大小、文件修改日期等。QFileInfo类中提供了很多的方法 ,常用的有:
isDir() 检查该文件是否是目录;
isExecutable() 检查该文件是否是可执行文件;
fileName() 获得文件名;
completeBaseName() 获取完整的文件名;
suffix() 获取文件后缀名;
completeSuffix() 获取完整的文件后缀;
size() 获取文件大小;
isFile() 判断是否为文件;
fileTime() 获取文件创建时间、修改时间、最近访问时间等;
4,示例
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void handleAction1();
void handleAction2();
private:
Ui::MainWindow *ui;
QPlainTextEdit* edit;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("简单的记事本");
// 获取到菜单栏
QMenuBar* menuBar = this->menuBar();
// 添加菜单
QMenu* menu = new QMenu("文件");
menuBar->addMenu(menu);
// 添加菜单项
QAction* action1 = new QAction("打开");
QAction* action2 = new QAction("保存");
menu->addAction(action1);
menu->addAction(action2);
// 指定一个输入框
edit = new QPlainTextEdit();
QFont font;
font.setPixelSize(20);
edit->setFont(font);
this->setCentralWidget(edit);
// 连接QAction的信号槽
connect(action1,&QAction::triggered,this,&MainWindow::handleAction1);
connect(action2,&QAction::triggered,this,&MainWindow::handleAction2);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::handleAction1()
{
// 先弹出"打开文件"对话框,让用户选择打开哪个文件
QString path = QFileDialog::getOpenFileName(this);
// 把文件名显示到状态栏里
QStatusBar* statusBar = this->statusBar();
statusBar->showMessage(path);
// 根据用户选择的路径,构造一个QFile对象,并打开文件
QFile file(path);
bool ret = file.open(QIODevice::ReadOnly);
if(!ret)
{
statusBar->showMessage(path + "打开失败!");
return;
}
// 读取文件了
QString text = file.readAll();
// 关闭文件
file.close();
// 读到的内容设置到输入框中
edit->setPlainText(text);
}
void MainWindow::handleAction2()
{
// 先弹出"保存文件"对话框
QString path = QFileDialog::getSaveFileName(this);
// 在状态栏显示这个文件名
QStatusBar* statusBar = this->statusBar();
statusBar->showMessage(path);
// 根据用户选择的路径,构造一个QFile对象,并打开文件
QFile file(path);
bool ret = file.open(QFile::WriteOnly);
if(!ret)
{
statusBar->showMessage(path + "打开失败!");
return;
}
// 写文件
const QString& text = edit->toPlainText();
file.write(text.toUtf8());
// 关闭
file.close();
}
三、Qt 多线程
1 ,Qt 多线程概述
在 Qt 中 ,多线程的处理一般是通过 QThread类 来实现。
QThread 代表一个在应用程序中可以独立控制的线程 ,也可以和进程中的其他线程共享数据。
QThread 对象管理程序中的一个控制线程。
2 ,QThread 常用 API
run() |
线程的入口函数. |
start() |
通过调用 run() 开始执行线程。操作系统将根据优先级参数调度线程。 如果线程已经在运行 ,这个函数什么也不做。 |
currentThread() |
返回一个指向管理当前执行线程的 QThread的指针。 |
isRunning() |
如果线程正在运行则返回true;否则返回false。 |
sleep() / msleep() /usleep() |
使线程休眠 ,单位为秒 / 毫秒 / 微秒 |
wait() |
阻塞线程 ,直到满足以下任何一个条件: 与此 QThread 对象关联的线程已经完成执行(即当它从run()返回时)。 如果线程已 经完成 ,这个函数将返回 true。 如果线程尚未启动 ,它也返回 true。已经过了几毫秒。 如果时间是 ULONG_MAX(默认值) ,那么等待永远不会超时(线程 必须从run()返回)。 如果等待超时 ,此函数将返回 false。 这提供了与 POSIX pthread_join() 函数类似的功能。 |
terminate() |
终止线程的执行。线程可以立即终止 ,也可以不立即终止 ,这取决于操作系统的调 度策略。在terminate() 之后使用 QThread::wait() 来确保。 |
finished() |
当线程结束时会发出该信号 ,可以通过该信号来实现线程的清理工作。 |
3 ,使用线程
创建线程的步骤:
(1) 自定义一个类 ,继承于 QThread ,并且只有一个线程处理函数(和主线程不是同一个线程) ,这个线程处理函数主要就是重写父类中的 run() 函数。
(2) 线程处理函数里面写入需要执行的复杂数据处理;
(3) 启动线程不能直接调用 run() 函数 ,需要使用对象来调用 start() 函数实现线程启动;
(4) 线程处理函数执行结束后可以定义一个信号来告诉主线程;
(5) 最后关闭线程。
Qt::AutoConnection |
在 Qt 中 ,会根据信号和槽函数所在的线程自动选择连接类型。 如果信号和槽函 数在同一线程中 ,那么使用 Qt:DirectConnection 类型; 如果它们位于不同的 线程中 ,那么使用Qt::QueuedConnection 类型。 |
Qt::DirectConnection |
当信号发出时 ,槽函数会立即在同一线程中执行。这种连接类型适用于信号和 槽函数在同一线程中的情况 ,可以实现直接的函数调用 ,但需要注意线程安全 性。 |
Qt::QueuedConnection |
当信号发出时 ,槽函数会被插入到接收对象所属的线程的事件队列中 ,等待下 一次事件循环时执行。 这种连接类型适用于信号和槽函数在不同线程中的情况 ,可以确保线程安全。 |
Qt::BlockingQueuedConnec tion |
与 Qt:QueuedConnection 类似 ,但是发送信号的线程会被阻塞 ,直到槽函数执行完毕 ,这种连接类型适用于需要等待槽函数执行完毕再继续的场景 ,但需要注意可能引起线程死锁的风险。 |
Qt::UniqueConnection |
这是一个标志 ,可以使用位或与上述任何一种连接类型组合使用。 |
4 ,线程安全
实现线程互斥和同步常用的类有:
(1) 互斥锁:QMutex、QMutexLocker
互斥锁是一种保护和防止多个线程同时访问同一对象实例的方法 ,在 Qt 中 ,互斥锁主要是通过 QMutex类来处理。
特点:QMutex 是 Qt 框架提供的互斥锁类 ,用于保护共享资源的访问 ,实现线程间的互斥操作。
用途:在多线程环境下 ,通过互斥锁来控制对共享数据的访问 ,确保线程安全。
(2) 条件变量:QWaitCondition
在多线程编程中,假设除了等待操作系统正在执行的线程之外,某个线程还必须等待某些条件满足才能执行 ,这时就会出现问题。这种情况下,线程会很自然地使用锁的机制来阻塞其他线程 ,因为这只是线程的轮流使用,并且该线程等待某些特定条件 ,人们会认为需要等待条件的线程 ,在释放互斥锁或读写锁之后进入了睡眠状态 ,这样其他线程就可以继续运行。当条件满足时,等待条件的线程将被另一个线程唤醒。
在 Qt 中 ,专门提供了 QWaitCondition类 来解决像上述这样的问题。
特点:QWaitCondition 是 Qt 框架提供的条件变量类 ,用于线程之间的消息通信和同步。
用途:在某个条件满足时等待或唤醒线程 ,用于线程的同步和协调。
(3) 信号量:QSemaphore
有时在多线程编程中,需要确保多个线程可以相应的访问一个数量有限的相同资源。例如,运行程序 的设备可能是非常有限的内存 ,因此我们更希望需要大量内存的线程将这一事实考虑在内,并根据可用的内存数量进行相关操作,多线程编程中类似问题通常用信号量来处理。信号量类似于增强的互斥锁,不仅能完成上锁和解锁操作, 而且可以跟踪可用资源的数量。
特点:QSemaphore 是 Qt 框架提供的计数信号量类 ,用于控制同时访问共享资源的线程数量。
用途: 限制并发线程数量 ,用于解决一些资源有限的问题。
(4) 读写锁:QReadLocker、QWriteLocker、QReadWriteLock
特点:
QReadWriteLock 是读写锁类 ,用于控制读和写的并发访问。
QReadLocker 用于读操作上锁 ,允许多个线程同时读取共享资源。
QWriteLocker 用于写操作上锁 ,只允许一个线程写入共享资源。
用途:在某些情况下 ,多个线程可以同时读取共享数据 ,但只有一个线程能够进行写操作。读写锁提 供了更高效的并发访问方式。
四、Qt 网络
1, 核心 API 概览
核心类有两个:QTcpServer 和 QTcpSocket
名称 |
类型 |
说明 |
对标原生 API |
listen(const QHostAddress&, quint16 port) |
方法 |
绑定指定的地址和端口号, 并开始监 听. |
bind 和 listen |
nextPendingConnection() |
方法 |
从系统中获取到一个已经建立好的 tcp 连接. 返回一个 QTcpSocket , 表示这个 客户端的连接. 通过这个 socket 对象完成和客户端 之间的通信. |
accept |
newConnection |
信号 |
有新的客户端建立连接好之后触发. |
QTcpSocket 用户客户端和服务器之间的数据交互
名称 |
类型 |
说明 |
对标原生 API |
readAll() |
方法 |
读取当前接收缓冲区中的所有数据. 返回 QByteArray 对象. |
read |
write(const QByteArray& ) |
方法 |
把数据写入 socket 中. |
write |
deleteLater |
方法 |
暂时把 socket 对象标记为无效. Qt 会在下个事件循环中析构释放该对 象. |
无 (但是类似于 "半自动化的 垃圾回收") |
readyRead |
信号 |
有数据到达并准备就绪时触发. |
无 (但是类似于 IO 多路复用 中的通知机制) |
disconnected |
信号 |
连接断开时触发. |
无 (但是类似于 IO 多路复用 中的通知机制) |
2, 回显服务器和客户端
核心类是两个:QTcpServer 和 QTcpSocket。
QTcpServer 用于监听端口, 和获取客户端连接。
名称 |
类型 |
说明 |
对标原生 API |
listen(const QHostAddress&, quint16 port) |
方法 |
绑定指定的地址和端口号, 并开始监 听. |
bind 和 listen |
nextPendingConnection() |
方法 |
从系统中获取到一个已经建立好的 tcp 连接. 返回一个 QTcpSocket , 表示这个 客户端的连接. 通过这个 socket 对象完成和客户端 之间的通信. |
accept |
newConnection |
信号 |
有新的客户端建立连接好之后触发. |
无 (但是类似于 IO 多路复用 中的通知机制) |
QTcpSocket 用户客户端和服务器之间的数据交互.
名称 |
类型 |
说明 |
对标原生 API |
readAll() |
方法 |
读取当前接收缓冲区中的所有数据. 返回 QByteArray 对象. |
read |
write(const QByteArray& ) |
方法 |
把数据写入 socket 中. |
write |
deleteLater |
方法 |
暂时把 socket 对象标记为无效. Qt 会在下个事件循环中析构释放该对 象. |
无 (但是类似于 "半自动化的 垃圾回收") |
readyRead |
信号 |
有数据到达并准备就绪时触发. |
无 (但是类似于 IO 多路复用 中的通知机制) |
disconnected |
信号 |
连接断开时触发. |
无 (但是类似于 IO 多路复用 中的通知机制) |
3, HTTP Client
核心 的API,关键类主要有三个:
QNetworkAccessManager 和 QNetworkRequest 和 QNetworkReply
QNetworkAccessManager 提供了 HTTP 的核心操作
方法 |
说明 |
get(const QNetworkRequest& ) |
发起一个 HTTP GET 请求. 返回 QNetworkReply 对象. |
post(const QNetworkRequest& , const QByteArray& ) |
发起一个 HTTP POST 请求. 返回 QNetworkReply 对 象. |
QNetworkRequest 表示一个 HTTP 请求(不含 body)
方法 |
说明 |
QNetworkRequest(const QUrl& ) |
通过 URL 构造一个 HTTP 请求. |
setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value) |
设置请求头. |
取值 |
说明 |
ContentTypeHeader |
描述 body 的类型. |
ContentLengthHeader |
描述 body 的长度. |
LocationHeader |
用于重定向报文中指定重定向地址. (响应中使用, 请求 用不到) |
CookieHeader |
设置 cookie |
UserAgentHeader |
设置 User-Agent |
QNetworkReply 表示一个 HTTP 响应. 这个类同时也是 QIODevice 的子类.
方法 |
说明 |
error() |
获取出错状态. |
errorString() |
获取出错原因的文本. |
readAll() |
读取响应 body. |
header(QNetworkRequest::KnownHeaders header) |
读取响应指定 header 的值. |
五、Qt 音视频
1,Qt 音频
在 Qt 中 ,音频主要是通过 QSound 类来实现。但是需要注意的是 QSound 类只支持播放 wav 格式的音频文件。也就是说如果想要添加音频效果 ,那么首先需要将非wav格式 的音频文件转换为 wav 格式。
示例
#include "widget.h"
#include "ui_widget.h"
#include <QSound> //添加音频头文件
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//实例化对象
QSound *sound = new QSound(":/1.wav",this);
connect(ui->btn,&QPushButton::clicked,[=](){
sound->play(); //播放
});
}
2,Qt 视频
在 Qt 中 ,视频播放的功能主要是通过 QMediaPlayer类 和 QVideoWidget类 来实现。在使用这两个类 时要添加对应的模块 multimedia 和 multimediawidgets 。
示例
// widget.h
#include <QWidget>
#include <QHBoxLayout> //水平布局
#include <QVBoxLayout> //垂直布局
#include <QVideoWidget> //显示视频
#include <QMediaPlayer> //播放声音
#include <QPushButton> //按钮
#include <QStyle> //设置图标
#include <QFileDialog> //选择文件/文件夹
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void chooseVideo();
private:
QMediaPlayer *mediaPlayer;
QVideoWidget *videoWidget;
QVBoxLayout *vbox;
//创建两个按钮:选择视频按钮和开播放按钮
QPushButton *chooseBtn,*playBtn;
};
// widget.cpp
#include "widget.h"
#include <QMediaPlayer>
#include <QSlider>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//对象实例化
mediaPlayer = new QMediaPlayer(this);
videoWidget = new QVideoWidget(this);
//设置播放画面的窗口
videoWidget->setMinimumSize(600,600);
//实例化窗口布局---垂直布局
this->vbox = new QVBoxLayout(this);
this->setLayout(this->vbox);
//实例化选择视频按钮
chooseBtn = new QPushButton("选择视频 ",this);
//实例化播放按钮
playBtn = new QPushButton(this);
//设置图标代替文件
playBtn->setIcon(this->style()->standardIcon(QStyle::SP_MediaPlay)); 64
//实例化一个水平布局,将以上控件放入水平布局中
QHBoxLayout *hbox = new QHBoxLayout;
//添加控件
hbox->addWidget(chooseBtn);
hbox->addWidget(playBtn);
//将播放窗口和水平布局都添加到垂直布局中
vbox->addWidget(videoWidget);
//布局中添加布局
vbox->addLayout(hbox);
//将选择视频对应的按钮和槽函数进行关联
connect(chooseBtn,&QPushButton::clicked,this,&Widget::chooseVideo);
}
void Widget::chooseVideo()
{
//选择视频,返回一个播放视频的名字
QString name = QFileDialog::getSaveFileName(this,"选择视频",".","WMV(*.wmv)");
//设置媒体声音
mediaPlayer->setMedia(QUrl(name));
}