Hello! I'm trying to get title of a YouTube video and display it on main window. This operation is blocking my app second time when I press the button from main window so I created a class that represents a QObject and I moved it to another thread. But the same happens, when I start the thread second time my app is not responding.
My code:
title.h
#ifndef TITLE_H
#define TITLE_H
#include <QUrl>
#include <QWidget>
#include <QTextDocument>
#include <QFile>
{
Q_OBJECT
public:
~Title();
void searchTile
(const QUrl &);
void htmlGet
(const QUrl &);
signals:
private:
};
#endif // TITLE_H
#ifndef TITLE_H
#define TITLE_H
#include <QUrl>
#include <QWidget>
#include <QTextDocument>
#include <QFile>
class Title : public QObject
{
Q_OBJECT
public:
Title(QWidget *parent = nullptr);
~Title();
void searchTile(const QUrl &);
void htmlGet(const QUrl &);
signals:
void titleReady(QString);
void True(QString);
private:
QFile file = QFile("data.json");
QTextDocument h;
bool find(QJsonArray, QString, const QUrl &);
};
#endif // TITLE_H
To copy to clipboard, switch view to plain text mode
title.cpp
#include <title.h>
#include <QScopedPointer>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QRegularExpression>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
}
Title::~Title(){
}
void Title
::searchTile(const QUrl &url
){ if(file.exists() && file.size() != 0){
file.
open(QIODevice::ReadOnly |
QIODevice::Text);
//I have a json file where I save data like title and url of a video file.close();
QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
QJsonArray list = d.array();
bool checkUrl = this->find(list, "url", url);
if(checkUrl)
emit True("URL is already in download list!"); //this is for showing an error message box
else
this->htmlGet(url);
}
else
this->htmlGet(url);
}
void Title
::htmlGet(const QUrl &url
) { QScopedPointer<QNetworkAccessManager> manager(new QNetworkAccessManager);
QNetworkReply *response = manager->get(QNetworkRequest(url));
qDebug() << "titluuuu";
connect(response, &QNetworkReply::finished, [response, this]{
response->deleteLater();
response->manager()->deleteLater();
if (response->error() != QNetworkReply::NoError) return;
auto const contentType =
response->header(QNetworkRequest::ContentTypeHeader).toString();
static QRegularExpression re("charset=([!-~]+)");
auto const match = re.match(contentType);
if (!match.hasMatch() || 0 != match.captured(1).compare("utf-8", Qt::CaseInsensitive)) {
qWarning() << "Content charsets other than utf-8 are not implemented yet:" << contentType;
return;
}
auto const html
= QString::fromUtf8(response
->readAll
());
QRegularExpression rg("eow-title.*>");
auto const m = rg.match(html);
auto s = m.captured(0);
QRegularExpression n("title=.*");
auto a = n.match(s);
h.setHtml(a.captured(0).split("\"")[1]);
}) && manager.take();
}
bool Title
::find(QJsonArray arr,
QString key,
const QUrl &url
){ //this function is for searching if a url is already in the json file
for(const auto obj : arr){
if(obj.toObject().value(key) == url.toString().split("&")[0])
return true;
}
return false;
}
#include <title.h>
#include <QScopedPointer>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QRegularExpression>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
Title::Title(QWidget *parent) : QObject(parent){
}
Title::~Title(){
}
void Title::searchTile(const QUrl &url){
if(file.exists() && file.size() != 0){
file.open(QIODevice::ReadOnly | QIODevice::Text); //I have a json file where I save data like title and url of a video
QString val = file.readAll();
file.close();
QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
QJsonArray list = d.array();
bool checkUrl = this->find(list, "url", url);
if(checkUrl)
emit True("URL is already in download list!"); //this is for showing an error message box
else
this->htmlGet(url);
}
else
this->htmlGet(url);
}
void Title::htmlGet(const QUrl &url) {
QScopedPointer<QNetworkAccessManager> manager(new QNetworkAccessManager);
QNetworkReply *response = manager->get(QNetworkRequest(url));
qDebug() << "titluuuu";
connect(response, &QNetworkReply::finished, [response, this]{
response->deleteLater();
response->manager()->deleteLater();
if (response->error() != QNetworkReply::NoError) return;
auto const contentType =
response->header(QNetworkRequest::ContentTypeHeader).toString();
static QRegularExpression re("charset=([!-~]+)");
auto const match = re.match(contentType);
if (!match.hasMatch() || 0 != match.captured(1).compare("utf-8", Qt::CaseInsensitive)) {
qWarning() << "Content charsets other than utf-8 are not implemented yet:" << contentType;
return;
}
auto const html = QString::fromUtf8(response->readAll());
QRegularExpression rg("eow-title.*>");
auto const m = rg.match(html);
auto s = m.captured(0);
QRegularExpression n("title=.*");
auto a = n.match(s);
h.setHtml(a.captured(0).split("\"")[1]);
emit titleReady(QString(QChar(0x200E)) + h.toPlainText());
}) && manager.take();
}
bool Title::find(QJsonArray arr, QString key, const QUrl &url){
//this function is for searching if a url is already in the json file
for(const auto obj : arr){
if(obj.toObject().value(key) == url.toString().split("&")[0])
return true;
}
return false;
}
To copy to clipboard, switch view to plain text mode
mainwindow.h
#include <QWidget>
#include <QThread>
#include <QJsonArray>
{
Q_OBJECT
signals:
private:
int i = 0;
QJsonArray json;
void startWork();
void buttonPushed();
}
#include <QWidget>
#include <QThread>
#include <QJsonArray>
class mainWindow : public QWidget
{
Q_OBJECT
signals:
void titleReady(QUrl);
private:
int i = 0;
QThread th;
QJsonArray json;
void displayTitle(QString);
void startWork();
void buttonPushed();
}
To copy to clipboard, switch view to plain text mode
mainwindow.cpp
#include "mainwindow.h"
#include "title.h"
mainWindow
::mainWindow(QWidget *parent
) :{
title = new Title();
title->moveToThread(&th);
connect(title, &Title::True, this, &mainWindow::errorDialog);
connect(&th, &QThread::finished, title, [this] {qDebug() << "finished"; });
connect(this, &mainWindow::titleReady, title, &Title::searchTile);
connect(&th, &QThread::started, this, &mainWindow::startWork);
connect(title, &Title::titleReady, this, &mainWindow::displayTitle);
}
void mainWindow::buttonPushed(){
th.start()
}
void mainWindow::startWork(){
qDebug() << "Started";
emit titleReady
(QUrl(txt
->text
()));
}
void mainWindow
::displayTitle(QString html
){ QJsonObject info;
//I have a QComboBox modified with a QTreeView
QModelIndex index_type
= type_box
->currentView
()->rootIndex
();
QVariant data_type
= type_box
->currentView
()->model
()->data
(index_type
);
info.insert("type", data_type.toString());
QModelIndex index_ext
= type_box
->currentView
()->currentIndex
();
QVariant data_ext
= type_box
->currentView
()->model
()->data
(index_ext
);
info.insert("ext", data_ext.toString());
info.insert("loc", loc_txt->text());
info.insert("title", QJsonValue(html));
info.insert("url", txt->text().split("&")[0]);
json.push_back(info);
QJsonDocument doc(json);
text << doc.toJson();
file.close();
//On main window I have a table widget where I want to display some data in it
item1->setTextAlignment(Qt::AlignCenter);
item2->setTextAlignment(Qt::AlignCenter);
item3->setTextAlignment(Qt::AlignCenter);
tem4->setTextAlignment(Qt::AlignCenter);
table->setItem(i, 0, item);
table->setItem(i, 1, item1);
table->setItem(i, 2, item2);
table->setItem(i, 3, item3);
table->setItem(i, 4, item4);
i++;
title->thread()->quit();
}
#include "mainwindow.h"
#include "title.h"
mainWindow::mainWindow(QWidget *parent) :
QWidget(parent)
{
title = new Title();
title->moveToThread(&th);
connect(title, &Title::True, this, &mainWindow::errorDialog);
connect(&th, &QThread::finished, title, [this] {qDebug() << "finished"; });
connect(this, &mainWindow::titleReady, title, &Title::searchTile);
connect(&th, &QThread::started, this, &mainWindow::startWork);
connect(title, &Title::titleReady, this, &mainWindow::displayTitle);
}
void mainWindow::buttonPushed(){
th.start()
}
void mainWindow::startWork(){
qDebug() << "Started";
emit titleReady(QUrl(txt->text()));
}
void mainWindow::displayTitle(QString html){
QJsonObject info;
//I have a QComboBox modified with a QTreeView
QModelIndex index_type = type_box->currentView()->rootIndex();
QVariant data_type = type_box->currentView()->model()->data(index_type);
info.insert("type", data_type.toString());
QModelIndex index_ext = type_box->currentView()->currentIndex();
QVariant data_ext = type_box->currentView()->model()->data(index_ext);
info.insert("ext", data_ext.toString());
info.insert("loc", loc_txt->text());
info.insert("title", QJsonValue(html));
info.insert("url", txt->text().split("&")[0]);
json.push_back(info);
QJsonDocument doc(json);
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream text(&file);
text << doc.toJson();
file.close();
//On main window I have a table widget where I want to display some data in it
QTableWidgetItem *item = new QTableWidgetItem(QString(html));
QTableWidgetItem *item1 = new QTableWidgetItem(QString("%1(%2)").arg(data_type.toString(), data_ext.toString()));
QTableWidgetItem *item2 = new QTableWidgetItem(QString("-"));
QTableWidgetItem *item3 = new QTableWidgetItem(QString("-"));
QTableWidgetItem *item4 = new QTableWidgetItem(QString("Waiting..."));
item1->setTextAlignment(Qt::AlignCenter);
item2->setTextAlignment(Qt::AlignCenter);
item3->setTextAlignment(Qt::AlignCenter);
tem4->setTextAlignment(Qt::AlignCenter);
table->setItem(i, 0, item);
table->setItem(i, 1, item1);
table->setItem(i, 2, item2);
table->setItem(i, 3, item3);
table->setItem(i, 4, item4);
i++;
title->thread()->quit();
}
To copy to clipboard, switch view to plain text mode
How can I solve this? Only the second time I start the thread, the GUI is freezing and I'm wondering why this happens. I also tried displayTitle() like this:
void mainWindow:: displayTitle (){
qDebug << "test";
title->thread()->quit();
}
void mainWindow:: displayTitle (){
qDebug << "test";
title->thread()->quit();
}
To copy to clipboard, switch view to plain text mode
but it's the same.
I'm glad if you give me advice for optimization of my code if it's something wrong. Thank you!
Bookmarks