[Solve]Strange behavior program with this code
-
Hello!
I have one classes which is the successor of QThread, i use it for geting icon.
But when i try to use it my program compyle without any mistakes, but it is not visible and does not work.
This is my class(sory for big code, RDownloader is auxiliary class) :
@#ifndef RICONMANAGER_H
#define RICONMANAGER_H#include <QThread>
#include <QIcon>
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QSslError>
#include <QStringList>
#include <QTimer>
#include <QUrl>
#include <QSettings>
#include <QFileIconProvider>
#include <QDir>
#include <QVariant>#include <Classes/RDataItemModel/RDataItemModel.h>
#include <Classes/RDataItemModel/RDataItem/RDataItem.h>//---------Downloader
class RDownloader: public QObject
{
Q_OBJECT
public:
explicit RDownloader(RDataItem *);
private:
QNetworkAccessManager manager;
RDataItem *item;QString clearWebAdress(QString str);
public slots:
void downloadFinished(QNetworkReply *reply);
};
//---------RIconManager
class RIconManager : public QThread
{
Q_OBJECT
public:
explicit RIconManager(RDataItem *parent);
private:
void chooseIconWithData(const QString &data);
void chooseIconWithType(const RDataItemModel::itemType &type);RDataItem *item;
protected:
void run();
};#endif // RICONMANAGER_H@
@#include "RIconManager.h"//------Downloader
RDownloader::RDownloader(RDataItem it)
{
item = it;
QNetworkRequest request(QUrl(clearWebAdress(it->text())));
manager.get(request);
connect(&manager, SIGNAL(finished(QNetworkReply)),
SLOT(downloadFinished(QNetworkReply*)));
}QString RDownloader::clearWebAdress(QString str)
{
return str;
}void RDownloader::downloadFinished(QNetworkReply *reply)
{
if (!reply->error())
if (QVariant(reply->readAll()).convert(QVariant::Icon))
{
QIcon icon = qvariant_cast<QIcon>(QVariant(reply->readAll()));
item->setIcon(icon);
}reply->deleteLater(); deleteLater();
}
//-------RIconManager
RIconManager::RIconManager(RDataItem *parent)
{
item = parent;
run();
}void RIconManager::run()
{
QSettings settings(QDir::currentPath() + "/settings.ini", QSettings::IniFormat);
QIcon icon;if (settings.value("design/iconMode", "simple").toString() == "advanced") chooseIconWithData(item->text()); if (settings.value("design/iconMode", "simple").toString() == "simple") chooseIconWithType(RDataItemModel::chooseTypeOfItem(item->text())); exec();
}
void RIconManager::chooseIconWithData(const QString &data)
{
RDataItemModel::itemType type = RDataItemModel::chooseTypeOfItem(data);
QIcon icon;
//Internet site
if (type == RDataItemModel::WebAddress)
{
RDownloader *downloader = new RDownloader(item);
return;
}}
void RIconManager::chooseIconWithType(const RDataItemModel::itemType &type)
{
//Choose simply icon
}
@
RDataItem is successor of QStandardItem
RDataItemModel is successor of QStandartItemModel
I think that problem due to the fact that the RIconManager is QThread
RIconManager called with this code:
@new RIconManager(dataItem);@ -
I don't believe you can use QIcon in a thread other than the main thread, as it's a GUI element.
With that said, What is the reason to make this its own thread? QNetworkAccessManager is inherently asynchronous and should be easy to integrate into the main thread.
[Edit: On second thought, I might be on the wrong path here... need to read the code a little closer.]
-
In downloadFinished, you have 2 calls to reply->readAll() where you should only have one (the first one removes all the available data from the device and returns it, and the second one has nothing left to read).
And I'm pretty sure you can convert a QByteArray to a QIcon by using QVariant, but you could use the buffer to create a QPixmap and then get a QIcon from it:
@void RDownloader::downloadFinished(QNetworkReply *reply)
{
if (reply->error() == QNetworkReply::NoError)
QByteArray data = reply->readAll();
// The slot, or at least the following part has to execute in the main thread,
// because QPixmap (and QIcon) are GUI elements
QPixmap pixmap;
pixmap.loadFromData(data);
if (pixmap.isValid()) {
item->setIcon(QIcon(pixmap));
}
}
reply->deleteLater();
deleteLater();
}@ -
Thank you for you help!
-
By the way, your code does not start the thread:
@
RIconManager::RIconManager(RDataItem *parent)
{
item = parent;
run();
}
@You call the run method inside the constructor, this is not how threads work.
A thread is started by calling start(); -
[quote author="Gerolf" date="1335440000"]By the way, your code does not start the thread:
@
RIconManager::RIconManager(RDataItem *parent)
{
item = parent;
run();
}
@You call the run method inside the constructor, this is not how threads work.
A thread is started by calling start();[/quote]
Thank you for your note!