When I setup font for Qt application, it has no effect on the part of code executed on QTimer's timeout() signal.
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QFontDatabase>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
int id = QFontDatabase::addApplicationFont(":/Blackbird.ttf");
qDebug() << "Initial font:" << qApp->font();
qApp->setFont(QFontDatabase::applicationFontFamilies(id).at(0));
qDebug() << "Set font:" << qApp->font();
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFontDatabase>
#include <QTime>
#include <QTimer>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer *t = new QTimer(this);
t->start(1000);
connect(t, &QTimer::timeout, [=]{
qDebug() << "Timer font:" << qApp->font();
ui->label->setText(QTime::currentTime().toString());
});
}
MainWindow::~MainWindow()
{
delete ui;
}
Output of this code:
Initial font: QFont(Liberation Sans,11,-1,5,50,0,0,0,0,0)
Set font: QFont(Blackbird,12,-1,5,50,0,0,0,0,0)
Timer font: QFont(Liberation Sans,11,-1,5,50,0,0,0,0,0)
Timer font: QFont(Liberation Sans,11,-1,5,50,0,0,0,0,0)
...
But when I add some the code
QTimer *t = new QTimer(this);
t->setSingleShot(true);
connect(t, &QTimer::timeout, [=]{
qApp->setFont(QFontDatabase::applicationFontFamilies(0).at(0));
});
t->start(0);
t->setSingleShot(false);
t->start(1000);
connect(t, &QTimer::timeout, [=]{
qDebug() << "Timer font:" << qApp->font();
ui->label->setText(QTime::currentTime().toString());
});
everything works:
Initial font: QFont(Liberation Sans,11,-1,5,50,0,0,0,0,0)
Set font: QFont(Blackbird,12,-1,5,50,0,0,0,0,0)
Timer font: QFont(Blackbird,12,-1,5,50,0,0,0,0,0)
Timer font: QFont(Blackbird,12,-1,5,50,0,0,0,0,0)
It looks like the main thread and QTimer use different QCoreApplication::instance, but I checked qApp->applicationPid(), it is the same.
Is there a possibility to set the same font for all application at once?
UPD: I have just noticed, that the problem exists with Qt 5.14.1, which is currently default on Gentoo Linux.
With Qt 5.12.8, compiled from source with 'debug' option, it works properly.
Related
I have been facing issues with a simple C++ group project I am working on. I am trying to create a thread that does a background job while my UI and the main app is working perfectly fine. I tried to the same thing on a test file before and it worked fine, however doing it in the Qt Project doesn't works somehow. I do not have much idea about Qt for ref. Here's my code. I am trying to update the progress bar repeatedly till my app runs.
Here's my code for more over view
test code
#include <thread>
#include <iostream>
#include <windows.h>
int getRamUsage() {
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
GlobalMemoryStatusEx (&statex);
return statex.dwMemoryLoad;
}
void ramUsage() {
while (true) {
std::cout << "RAM usage: " << getRamUsage() << "%" << std::endl;
Sleep(1000);
}
}
int main() {
auto ramLoop = [=]() {
while (true) {
std::cout << "RAM usage: " << getRamUsage() << "%" << std::endl;
Sleep(1000);
}
};
std::thread t1(ramLoop);
t1.join();
}
It works, But it doesn't in the Front Ended Qt one I mentioned. May I know any other ideas to make this work.
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ramUsage.h"
#include <thread>
#include <windows.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto ramLoop = [=]() {
while (true) {
ui->ramBar->setValue(getRamUsage());
Sleep(1000);
}
};
std::thread t(ramLoop);
t.join();
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp
#include "mainwindow.h"
#include <stdio.h>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
ramUsage.cpp
#include <windows.h>
#include "../ramUsage.h"
int getRamUsage() {
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
GlobalMemoryStatusEx (&statex);
return statex.dwMemoryLoad;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
ramUsage.h
#pragma once
#ifndef RAMUSAGE_H
#define RAMUSAGE_H
int getRamUsage();
#endif // RAMUSAGE_H
I tried using QProcess and the basic threading options for windows which doesn't seem to work
//Work.h
#ifndef WORK_H
#define WORK_H
#include <QDebug>
#include <QObject>
#include <QThread>
class Work : public QObject {
Q_OBJECT
public:
explicit Work(QObject *parent = nullptr);
public slots:
void snap();
void setStatus();
signals:
private:
bool status;
};
#endif // WORK_H
//Work.cpp
#include "Work.h"
Work::Work(QObject *parent) : QObject(parent) { status = true; }
void Work::snap() {
status = true;
while (true) {
if (status) {
qDebug() << "Work thread: " << QThread::currentThreadId();
} else {
qDebug() << "STOP";
break;
}
}
}
void Work::setStatus() { status = false; }
//MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include "Work.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
Work *work;
QThread thread;
};
#endif // MAINWINDOW_H
//MainWindow.cpp
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
work = new Work();
work->moveToThread(&thread);
thread.start();
connect(ui->startButton, SIGNAL(clicked()), work, SLOT(snap()));
connect(ui->stopButton, SIGNAL(clicked()), work, SLOT(setStatus()));
}
MainWindow::~MainWindow() {
thread.terminate();
delete ui;
}
//main.cpp
#include <QApplication>
#include "MainWindow.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
qDebug() << QThread::currentThreadId();
w.show();
return a.exec();
}
I use MainWindow to display, Work to do something. And I use work->moveToThread(&thread).
Click start button to execute snap function in Work, what I want to do is when I click stop button, the snap function output STOP. And I can still start and stop whenever I like.
But I fail. It seems impossible to change the status during the while loop. Work doesn't get the stopButton clicked signal. Is it because of priority?
Could anyone give me some advices?
Firstly consider your Work::snap implementation...
void Work::snap() {
status = true;
while (true) {
if (status) {
qDebug() << "Work thread: " << QThread::currentThreadId();
} else {
qDebug() << "STOP";
break;
}
}
}
Once started it never yields control to the Qt event loop. Now consider the connect call...
connect(ui->stopButton, SIGNAL(clicked()), work, SLOT(setStatus()));
Since ui->stopButton and work have different thread affinities this is effectively a queued connection and requires the receiver to have an active event loop. Hence the call to setStatus will remain pending forever.
A better way to achieve your goal might be to make use of a simple atomic bool...
std::atomic<bool> status;
and change the connect call to modify status directly using a lambda (untested)...
connect(ui->stopButton, &QPushButton::clicked, [this]{ work->setStatus(); });
I solve it.
I add a slot and a signal in MainWindow and change stop slot.
connect(ui->startButton, &QPushButton::clicked, this, &MainWindow::start);
connect(this, &MainWindow::startSnap, work, &Work::snap);
// start slot
void MainWindow::start() {
thread.start();
emit startSnap();
}
void MainWindow::stop() {
if (thread.isRunning()) {
thread.requestInterruption();
}
}
And change the codes in Work::snap
void Work::snap() {
while (true) {
if (QThread::currentThread()->isInterruptionRequested()) {
qDebug() << "STOP";
QThread::currentThread()->exit();
return;
} else {
qDebug() << "Work thread: " << QThread::currentThreadId();
}
}
}
The key codes are:
thread.requestInterruption();(MainWindow::stop)
QThread::currentThread()->exit();(Work::snap)
thread.start();(MainWindow::start)
My program automatically run at startup. My programs start minimized.
Example:
I use this commands to do this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QRect r1(QApplication::desktop()->screenGeometry(this).center().x()-300,
QApplication::desktop()->screenGeometry(this).center().y()-300, 100, 200);
MainWindow::setGeometry(r1);
srand(std::time(0));
ui->setupUi(this);
MainWindow::showMinimized();
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlots()) );
timer->start(5000);
}
But if it's now eight o'clock pm (20:00), I want to see the program in its normal size. I want to see something like that:
My attempt to find solution:
I use this command MainWindow::showNormal(); but without success
void MainWindow::MyTimerSlots()
{
qDebug() << "Timer..."<<QTime::currentTime().hour();
if (QTime::currentTime().hour() == 20 ){
//MainWindow::showFullScreen();
MainWindow::showNormal();
}
}
How can I change the size of a window from minimized to normal at 20 p.m.?
Update:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QTimer *timer;
public slots:
void MyTimerSlots();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QStyle>
#include <QDesktopWidget>
#include <QTime>
#include <QDate>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QRect r1(QApplication::desktop()->screenGeometry(this).center().x()-300,
QApplication::desktop()->screenGeometry(this).center().y()-300, 100, 200);
setGeometry(r1);
srand(std::time(0));
showMinimized();
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlots()) );
timer->start(5000);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::MyTimerSlots()
{
qDebug() << "Timer..."<<QTime::currentTime().minute();
//MainWindow::showFullScreen();
showNormal();
MainWindow::activateWindow();
MainWindow::raise();
//MainWindow::activateWindow();
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a problem with accessing progressBar from another class.
Here's the method that does not work.
I have progress bar in UI(mainwindow.ui) with name progressBar.
void QtDownload::downloadProgress(qint64 recieved, qint64 total) {
ui->progressBar->setMaximum(total);
ui->progressBar->setValue(recieved);
}
Here are all parts of the code:
downloader.pro
#-------------------------------------------------
#
# Project created by QtCreator 2017-01-12T15:22:17
#
#-------------------------------------------------
QT += core gui
QT += network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = downloader
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QObject>
#include <QString>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
class QtDownload : public QObject {
Q_OBJECT
public:
explicit QtDownload();
QNetworkAccessManager manager;
QString target;
void setTarget(const QString& t);
private:
signals:
void done();
public slots:
void download();
void downloadFinished(QNetworkReply* data);
void downloadProgress(qint64 recieved, qint64 total);
};
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QtCore>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QUrl>
#include <QtNetwork/QNetworkRequest>
#include <QFile>
#include <QDebug>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkReply>
#include <QByteArray>
#include <QObject>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// QCoreApplication app(argc, argv);
QtDownload *dl = new QtDownload();
dl->setTarget( "http://media09.vbox7.com/s/21/21bbc2dca3r3634e3389.mp4");
dl->download();
//quit when the download is done.
// QObject::connect(&dl, SIGNAL(done()), &app, SLOT(quit()));
}
MainWindow::~MainWindow()
{
delete ui;
}
QtDownload::QtDownload() : QObject(0) {
QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(downloadFinished(QNetworkReply*)));
}
void QtDownload::setTarget(const QString &t) {
this->target = t;
}
void QtDownload::downloadFinished(QNetworkReply *data) {
QFile localFile("C:/downloadedfile.mp4");
if (!localFile.open(QIODevice::WriteOnly))
return;
const QByteArray sdata = data->readAll();
localFile.write(sdata);
qDebug() << sdata;
localFile.close();
emit done();
}
void QtDownload::download() {
QUrl url = QUrl::fromEncoded(this->target.toLocal8Bit());
QNetworkRequest request(url);
QObject::connect(manager.get(request), SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
}
void QtDownload::downloadProgress(qint64 recieved, qint64 total) {
ui->progressBar->setMaximum(total); // DOES NOT WORK
ui->MainWindow.progressBar->setValue(recieved); // DOES NOT WORK
}
That's because your slot shouldn't be inside the QtDownload, it should be inside the MainWindow.
You should pass the MainWindow inside its constructor (just as a parent widget), and reuse this MainWindow in your connect, instead of uthing this.
Edits in your QtDownload :
Header
QtDownload(QObject* parent = 0); //Don't forget to make it in the source file
signals:
void done();
void downloadProgress(qint64 recieved, qint64 total);
public slots:
void download();
void downloadFinished(QNetworkReply* data);
private:
MainWindow* parent; //Set it in the new constructor
Source
QtDownload::QtDownload(QObject *parent) : QObject(parent)
{
//The code that was initially inside QtDownload::QtDownload()
}
void QtDownload::download() {
QUrl url = QUrl::fromEncoded(this->target.toLocal8Bit());
QNetworkRequest request(url);
QObject::connect(manager.get(request), SIGNAL(downloadProgress(qint64,qint64)), parent, SLOT(downloadProgress(qint64,qint64)));
}
Edits in your MainWindow
Header
public slots:
void downloadProgress(qint64 recieved, qint64 total);
Source
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// QCoreApplication app(argc, argv); (Remove this line, it should be in the main.cpp
QtDownload *dl = new QtDownload(this); //Pass this as parameter
dl->setTarget( "http://media09.vbox7.com/s/21/21bbc2dca3r3634e3389.mp4");
dl->download();
//quit when the download is done.
// QObject::connect(&dl, SIGNAL(done()), &app, SLOT(quit()));
}
void MainWindow::downloadProgress(qint64 recieved, qint64 total) {
ui->progressBar->setMaximum(total);
ui->progressBar->setValue(recieved);
}
everyone. First I want to apologize for my bad English. Here is the code of one of my personal project and I need help. The current code at execution should download this video - http://media09.vbox7.com/s/21/21bbc2dca3r3634e3389.mp4, but does not work. The video is downloaded only when the following code be placed in
// main.cpp
int main (int argc, char * argv [])
{
QApplication a (argc, argv);
MainWindow w;
w.show ();
QtDownload dl;
dl.setTarget ( "http://media09.vbox7.com/s/21/21bbc2dca3r3634e3389.mp4");
dl.download ();
// Quit when the download is done.
// QObject :: connect (& dl, SIGNAL (done ()), & app, SLOT (quit ()));
return a.exec ();
}
and I want to run in the method MainWindow - example:
// mainwindow.cpp
MainWindow :: MainWindow (QWidget * parent):
QMainWindow (parent),
ui (new Ui :: MainWindow)
{
QtDownload dl;
dl.setTarget ( "http://media09.vbox7.com/s/21/21bbc2dca3r3634e3389.mp4");
dl.download ();
// Quit when the download is done.
// QObject :: connect (& dl, SIGNAL (done ()), & app, SLOT (quit ()));
........
}
Here is the current code of the program.
// downloader.pro
#-------------------------------------------------
#
# Project created by QtCreator 2017-01-12T15:22:17
#
#-------------------------------------------------
QT += core gui
QT += network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = downloader
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QObject>
#include <QString>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
class QtDownload : public QObject {
Q_OBJECT
public:
explicit QtDownload();
QNetworkAccessManager manager;
QString target;
void setTarget(const QString& t);
private:
signals:
void done();
public slots:
void download();
void downloadFinished(QNetworkReply* data);
void downloadProgress(qint64 recieved, qint64 total);
};
#endif // MAINWINDOW_H
//main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QtCore>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QUrl>
#include <QtNetwork/QNetworkRequest>
#include <QFile>
#include <QDebug>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkReply>
#include <QByteArray>
#include <QObject>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// QCoreApplication app(argc, argv);
QtDownload dl;
dl.setTarget("http://media09.vbox7.com/s/21/21bbc2dca3r3634e3389.mp4");
dl.download();
//quit when the download is done.
// QObject::connect(&dl, SIGNAL(done()), &app, SLOT(quit()));
}
MainWindow::~MainWindow()
{
delete ui;
}
QtDownload::QtDownload() : QObject(0) {
QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(downloadFinished(QNetworkReply*)));
}
void QtDownload::setTarget(const QString &t) {
this->target = t;
}
void QtDownload::downloadFinished(QNetworkReply *data) {
QFile localFile("C:/downloadedfile.mp4");
if (!localFile.open(QIODevice::WriteOnly))
return;
const QByteArray sdata = data->readAll();
localFile.write(sdata);
qDebug() << sdata;
localFile.close();
emit done();
}
void QtDownload::download() {
QUrl url = QUrl::fromEncoded(this->target.toLocal8Bit());
QNetworkRequest request(url);
QObject::connect(manager.get(request), SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
}
void QtDownload::downloadProgress(qint64 recieved, qint64 total) {
qDebug() << recieved << total;
}
I have tried your code, I had the same problem that you report, only change the creation of the object to a pointer and magically arranged, I still do not understand the reason for error, I will continue to search for reason.
You must be:
...
ui->setupUi(this);
QtDownload *dl = new QtDownload();
dl->setTarget( "http://media09.vbox7.com/s/21/21bbc2dca3r3634e3389.mp4");
dl->download();
...
So.. if you want to run the download at QMainWindowthe object QtDownload dl should be a pointer property of MainWindow or it will not be destroyed (unless dl, as a QObject, hasMainWindow` as parent).
Run it into main() function does not work in this case because the application will run when exec() was called, so the download
So it will be something like this:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
// Delete the `dl` object
~MainWindow() { delete dl; }
private:
Ui::MainWindow *ui;
QtDownload *dl; // Declare it here
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
dl(nullptr)
{
ui->setupUi(this);
// QCoreApplication app(argc, argv);
dl = new QtDownload();
dl->setTarget("http://media09.vbox7.com/s/21/21bbc2dca3r3634e3389.mp4");
dl->download();
// connect the signal `done()` to save the file or anything like that
QObject::connect(dl, SIGNAL(done()), this, SLOT(downloadFinished()));
}