QT学习笔记—— 实现①从本地选择播放源②连接数据库③带有播放列表的视频播放器

Posted 玛丽莲茼蒿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT学习笔记—— 实现①从本地选择播放源②连接数据库③带有播放列表的视频播放器相关的知识,希望对你有一定的参考价值。

一、前言

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);
}

问题与思考

  1. 如果有的时候你在ui里改了名字,并且也构建了,cpp文件还是不认识这个控件的话,那就再改一个新名字
  2. 用DB Browser fo Sqlite可视化时,运行期间可能会出现这个错误“database is locked Unable to fetch row”。原因是你在这个软件里手动删除了记录,但是没保存,如果再调用insert语句的话,是一种对文件的“写写互斥”。保存一下就好啦。
  3. 关于中文字符向数据库存储和从数据库取出的问题。定义数据库table的字段时,将那个字段写为text类型,插入的时候不用管;取出的时候要加一个toString()函数。
  4. 错误: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();
    }
  1. 调试程序的时候,如果陷入死循环,点了下面“Stop Running Program”这个小红按钮暂停它以后,如果想要再次编译运行,会提示你.exe 这个程序没有权限打开。

    是因为.exe这个程序上次只是终止了,没有被关掉,所以无法再次打开。我们可以WIN10的任务管理器中找到它,停掉这个任务就可以了。
  2. 目前程序存在一个问题,db.close()以后,后面的数据库操作就进行不了(但不会报错),所以db.open()以后,我一直没有关上它。。。
  3. 数据库的操作如果报出“ not positioned on a valid record”说明query这个东西指向的地方不是你认为的地方。比如执行了select以后,结果存放在query中,query指向结果的最后一行的下一行,但是如果你用query.value(0).toInt()这样从query中取结果的话,就要先用一个query.first()或者query.next()函数将指针指向结果集的第一行

以上是关于QT学习笔记—— 实现①从本地选择播放源②连接数据库③带有播放列表的视频播放器的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记——Mybatis中缓存机制

Python学习笔记

QT学习笔记——添加资源文件

QT学习笔记——实现简单的视频播放器

QT学习笔记—— 4行代码实现音乐播放器

[学习笔记] [数据分析] 01.Python入门