一、前言
1.在QT学习笔记(六)——①进度条可拖动、点击②有暂停按钮 的视频播放器的基础上构建。
2.因为实现的功能有点多,所以讲解的思路和前几篇不太一样了,先不把UI的设计一股脑儿列出来,而是一个功能一个功能的介绍。
3.实现的功能如下
(1)从本地选择播放源
(2)播放列表;选择过的视频文件列入播放列表(数据库)
(3)双击播放列表中的视频,播放
二、从本地选择播放源
1.UI设计
多加了一个PushButton
,起名为btnAdd.
2.mainwindow.h文件中槽函数的声明
private slots:
void onBtnAddClicked();
3.槽函数的编写、信号机制
//监听按钮,选择播放源
connect(ui->btnAdd,SIGNAL(clicked()),this,SLOT(onBtnAddClicked()));
void MainWindow::onBtnAddClicked()
{
//QString curPath="F:\\QT project\\res"; //绝对路径
QString curPath="..\\res"; //相对路径
QString dlgTitle="选择视频文件"; //对话框标题
QString filter="mp4文件(*.mp4);;所有文件(*.*)"; //文件过滤器
QString aFile=QFileDialog::getOpenFileName(this,dlgTitle,curPath,filter);
if (aFile.isEmpty())
return;
QFileInfo fileInfo(aFile);
//ui->LabCurMedia->setText(fileInfo.fileName());
player->setMedia(QUrl::fromLocalFile(aFile));//设置播放文件
player->play();
}
4.“构建个锤子”,运行!
如果不先构建的话,编写代码的时候不认识新加的btnAdd这个控件,所以先“构建个锤子”,没问题了再运行
5.效果
“大家中午好,我是铁矿幼儿nuan小二班的报菜nuan~”
三、连接数据库SQLITE测试工作(真正工作请看“四”)
SQLite是内置的,相当于已经把SQLite加入到DB的环境中了,所以后面我们只需要建立db文件就可以了
1.配置文件修改
在配置文件第一行加入sql
三个字母(其实以前加过了)
QT += coregui sql
2.UI设计
(1)加入一个tableView,用来显示播放列表
(2)创建个锤子
3.连接数据库测试工作
首先,先创建一个db文件看看行不行。在mainwindow的构造函数内加入以下代码:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
/*----------------------数据库--------------------*/
qDebug()<<QSqlDatabase::drivers(); //打印看看(已经存在的)驱动是什么
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); //说明使用的是SQLLITE这个数据库
db.setDatabaseName("videoplayer.db"); //创建db文件
db.open();
db.exec("create table if not exists playlist(id integer primary key autoincrement, name text, url text)");
db.close();
}
运行,然后去看能不能生成db文件。db文件可能生成在两个地方,分别是
(1)和项目源码同一个文件夹
(2)在这个项目的配置文件夹(build … MinGW_64_bit Debug)中
创建成功了。然后执行insert、select语句看看能不能成功。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
/*----------------------数据库--------------------*/
qDebug()<<QSqlDatabase::drivers(); //打印看看(已经存在的)驱动是什么
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); //说明使用的是SQLLITE这个数据库
db.setDatabaseName("videoplayer.db"); //创建db文件
db.open();
QSqlQuery query;
if(!query.exec("create table if not exists playlist(id integer primary key autoincrement, name text, url text)")){
qDebug()<<"Error 1 (create error)"<<query.lastError().text();
return;
}
if(!query.exec("insert into playlist(name,url) values('test','urltest')")){
qDebug()<<"Error 2 (insert error)"<<query.lastError().text();
return;
}
if(!query.exec("select * from playlist")){
qDebug()<<"Error 3 (select error)"<<query.lastError().text();
return;
}
while(!query.next()){
qDebug()<<query.value(0).toInt()<<query.value(1).toString()<<
query.value(2).toString();
}
db.close();
}
如果失败的话会输出规定的语句,程序输出窗口没有这些输出说明成功了,为了保险起见我们用DB Browser for SQLite
这个软件可视化一下db文件
看insert成功!
我们希望把数据库里的每一条记录都显示在tableView这个控件上,并且希望只显示它的name字段。
借助一个querymodel,就只需要3行代码
!考虑到后面还要用这个model,所以把他写在成员函数里设为全局变量了。
class MainWindow : public QMainWindow
{
private:
QSqlQueryModel *model;
}
如果这个样子呢,是把整个表弄过来了,虽然很丑,但是我们对于数据库的测试工作已经完成了。
model = new QSqlQueryModel;
model->setQuery("select * from playlist");
ui->tableView->setModel(model);
为什么说以上工作只是测试工作呢?因为我们要实现的是用户在本地文件选中一个mp4文件后,再把文件名插入数据库中,上面insert的只是瞎编的数据,而且把整个表全放进去tableview了,完全不符合项目要求。
四、连接数据库,设置播放列表
1.双击播放列表某一行,开始播放相应视频
声明槽函数
private slots:
void onItemDBCliked(const QModelIndex &index);
连接双击信号
//监听播放列表的双击
connect(ui->tableView,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(onItemDBCliked(QModelIndex)));
编写槽函数
/*
* 双击播放列表,播放相应视频
*/
void MainWindow::onItemDBCliked(const QModelIndex &index){
qDebug()<<index.row(); //打印用户点击的第几行
QSqlRecord record = model->record(index.row()); //得到在数据库表中是第几条记录
//测试,并且URL中的中文能够正常输出
//qDebug()<<record.value("id").toInt()<<record.value("name").toString()<<record.value(2).toString();
//播放相应视频,这里应该用绝对路径(否则选择播放源的功能就不能在整个文件管理器进行了)
player->setMedia(QMediaContent(QUrl::fromLocalFile(record.value(2).toString())));
player->play();
}
2.从本地选择某个文件后,数据库表中新增一行,播放列表也随着刷新
思路是,改写播放本地视频的函数onBtnAddClicked()。选择一个视频以后,立马像数据库中插入一行记录,同时刷新tableView.
这里遇到一个问题是,我们希望tableView只显示视频的名字,而不是把数据库一行记录的所有字段都显示出来,用到的方法是,再定义一个全局变量model2。
model = new QSqlQueryModel;
model2 = new QSqlQueryModel;
model->setQuery("select * from playlist");
model2->setQuery("select name from playlist");
ui->tableView->setModel(model2);
/*
* 点击右下角按钮,选择本地文件
*/
void MainWindow::onBtnAddClicked()
{
//QString curPath="F:\\QT project\\res"; //绝对路径
QString curPath=".\\res"; //相对路径
QString dlgTitle="选择视频文件"; //对话框标题
QString filter="mp4文件(*.mp4);;所有文件(*.*)"; //文件过滤器
QString aFile=QFileDialog::getOpenFileName(this,dlgTitle,curPath,filter);
if (aFile.isEmpty())
return;
QFileInfo fileInfo(aFile);
//ui->LabCurMedia->setText(fileInfo.fileName());
// qDebug()<<aFile; //是这样“F:/QT project/res/当幼儿园遇上万圣节.mp4”的字符串
player->setMedia(QUrl::fromLocalFile(aFile)); //用aFile这个绝对路径实现的播放
player->play();
/*--------选的哪个就存入数据库(先不考虑重复的问题)------*/
QSqlQuery query;
/*----获取视频文件的名字---*/
int index=-1, lastIndex;
do{
lastIndex = index;
index = aFile.indexOf('/',index+1);
}while(index!=-1);
QString name = aFile.right(aFile.length()-lastIndex-1);
/*---------------------*/
QString cmd = QString("insert into playlist(name,url) values('%1','%2')").arg(name).arg(aFile);
if(!query.exec(cmd)){
qDebug()<<"Error 2 (insert error)"<<query.lastError().text();
return;
}
/*-------刷新播放列表--------*/
model->setQuery("select * from playlist");
model2->setQuery("select name from playlist");
ui->tableView->setModel(model2);
}
问题与思考
- 如果有的时候你在ui里改了名字,并且也构建了,cpp文件还是不认识这个控件的话,那就再改一个新名字
- 用DB Browser fo Sqlite可视化时,运行期间可能会出现这个错误“database is locked Unable to fetch row”。原因是你在这个软件里手动删除了记录,但是没保存,如果再调用insert语句的话,是一种对文件的“
写写互斥
”。保存一下就好啦。 - 关于
中文字符向数据库存储和从数据库取出
的问题。定义数据库table的字段时,将那个字段写为text类型,插入的时候不用管;取出的时候要加一个toString()函数。 - 错误:QSqlQuery::value: not positioned on a valid record
因为我把上一段执行select的语句屏蔽了,query里是空的,所以query.next出错了
/*-------查询到的存在query里--------*/
// if(!query.exec("select * from playlist")){
// qDebug()<<"Error 3 (select error)"<<query.lastError().text();
// return;
// }
while(!query.next()){
qDebug()<<query.value(0).toInt()<<query.value(1).toString()<<
query.value(2).toString();
}
- 调试程序的时候,如果陷入死循环,点了下面“Stop Running Program”这个小红按钮暂停它以后,如果想要再次编译运行,会提示你.exe 这个程序没有权限打开。
是因为.exe这个程序上次只是终止了,没有被关掉,所以无法再次打开。我们可以WIN10的任务管理器
中找到它,停掉这个任务就可以了。 - 目前程序存在一个问题,db.close()以后,后面的数据库操作就进行不了(但不会报错),所以db.open()以后,我一直没有关上它。。。
- 数据库的操作如果报出“ not positioned on a valid record”说明query这个东西指向的地方不是你认为的地方。比如执行了select以后,结果存放在query中,query指向结果的最后一行的下一行,但是如果你用query.value(0).toInt()这样从query中取结果的话,就要先用一个
query.first()
或者query.next()
函数将指针指向结果集的第一行