Hi I already asked my question here and understand why it's not working, now I have modified source code by moving the Smptp object as class variable , but still not working.
What I need to implement is send mail from a thread I chose QtConcurrent::run() for doing this but the slot not getting called after sending button clicked.
mainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QSettings"
#include "QFuture"
#include "QtConcurrent/QtConcurrent"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->sendBtn, SIGNAL(clicked()),this, SLOT(test()));
connect(ui->exitBtn, SIGNAL(clicked()),this, SLOT(close()));
connect(ui->browseBtn, SIGNAL(clicked()), this, SLOT(browse()));
}
void MainWindow::browse()
{
files.clear();
QFileDialog dialog(this);
dialog.setDirectory(QDir::homePath());
dialog.setFileMode(QFileDialog::ExistingFiles);
if (dialog.exec())
files = dialog.selectedFiles();
QString fileListString;
foreach(QString file, files)
fileListString.append( "\"" + QFileInfo(file).fileName() + "\" " );
ui->file->setText( fileListString );
}
void MainWindow::test(){
QFuture<void> f4 = QtConcurrent::run(this,&MainWindow::sendMail); // this not work
//sendMail(); // this works
}
void MainWindow::sendMail()
{
smtp = new Smtp(ui->uname->text(), ui->paswd->text(), ui->server->text(), ui->port->text().toInt());
connect(smtp, SIGNAL(status(QString)), this, SLOT(mailSent(QString)));
if( !files.isEmpty() )
smtp->sendMail(ui->uname->text(), ui->rcpt->text() , ui->subject->text(),ui->msg->toPlainText(), files );
else
smtp->sendMail(ui->uname->text(), ui->rcpt->text() , ui->subject->text(),ui->msg->toPlainText());
}
void MainWindow::mailSent(QString status)
{
if(status == "Message sent")
QMessageBox::warning( 0, tr( "Qt Simple SMTP client" ), tr( "Message sent!\n\n" ) );
delete smtp;
}
MainWindow::~MainWindow()
{
delete ui;
}
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "smtp.h"
#include <QtWidgets/QMessageBox>
#include <QFileDialog>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void sendMail();
void mailSent(QString);
void browse();
void test();
private:
Ui::MainWindow *ui;
QStringList files;
Smtp* smtp ;
};
#endif // MAINWINDOW_H
If I call sendMail(); directly it works, but using QFuture<void> f4 = QtConcurrent::run(this,&MainWindow::sendMail); it's not working, not working means the slot not get called, how can I resolve this issue?
I am referring the code from here https://github.com/xcoder123/SimpleSmtp_SSL_QT5/tree/master/smtp_attachements
Thanks
Haris
A solution as I already mentioned here is to use a QThread instead of QtConcurrent::run.
There is a detailed example contained in the Qt documentation: http://doc.qt.io/qt-5/qthread.html#details
The following code adapts this example to your use case.
smtp is moved to the workerThread. The communication between the main thread and the workerThread is done using signals and slots.
Be aware that you are not allowed to call any GUI related functions (such as showing message boxes etc.) in Smtp anymore!
This has to be done in the main thread.
User name, password etc. should probably also be passed through the signal to Smtp::sendMail.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets/QMessageBox>
#include <QFileDialog>
#include <QThread>
namespace Ui {
class MainWindow;
}
class Smtp;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void sendMailButtonClicked();
void mailSent(QString);
void browse();
private:
Ui::MainWindow *ui;
QStringList files;
Smtp* smtp;
QThread workerThread;
signals:
void sendMail(const QString &from, const QString &to, const QString &subject, const QString &body, QStringList files);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "smtp.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->sendBtn, SIGNAL(clicked()),this, SLOT(sendMailButtonClicked()));
connect(ui->exitBtn, SIGNAL(clicked()),this, SLOT(close()));
connect(ui->browseBtn, SIGNAL(clicked()), this, SLOT(browse()));
smtp = new Smtp(ui->uname->text(), ui->paswd->text(), ui->server->text(), ui->port->text().toInt());
smtp->moveToThread(&workerThread);
connect(this, SIGNAL(sendMail(QString,QString,QString,QString,QStringList)), smtp, SLOT(sendMail(QString,QString,QString,QString,QStringList)));
connect(smtp, SIGNAL(status(QString)), this, SLOT(mailSent(QString)));
workerThread.start();
}
void MainWindow::browse()
{
files.clear();
QFileDialog dialog(this);
dialog.setDirectory(QDir::homePath());
dialog.setFileMode(QFileDialog::ExistingFiles);
if (dialog.exec())
files = dialog.selectedFiles();
QString fileListString;
foreach(QString file, files)
fileListString.append( "\"" + QFileInfo(file).fileName() + "\" " );
ui->file->setText( fileListString );
}
void MainWindow::mailSent(QString status)
{
if(status == "Message sent")
QMessageBox::warning( 0, tr( "Qt Simple SMTP client" ), tr( "Message sent!\n\n" ) );
}
MainWindow::~MainWindow()
{
workerThread.quit();
workerThread.wait();
delete ui;
}
void MainWindow::sendMailButtonClicked()
{
emit sendMail(ui->uname->text(), ui->rcpt->text() , ui->subject->text(),ui->msg->toPlainText(), files );
}
in smtp.h: set sendMail to be a slot:
public slots:
void sendMail( const QString &from, const QString &to,
const QString &subject, const QString &body,
QStringList files = QStringList());
Related
I have a timer/clock that displays a message X amounts of seconds (usually 10) after it has been clicked. I attempted to set up an int that one could set easily to change what X is, however I am having trouble with displaying the message, which includes the value of X, in a message box.
What I want:
Where the value "10" is changed by an int.
The specific line of code for the messagebox:
void MainWindow::messageBox(){
QMessageBox::information(this, "Warning!", "You clicked the button of doom " + timerLength/1000 + " seconds ago!");
} //timerLength is an int.
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <qDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer *timer = new QTimer(this); //Set up timer.
connect(timer, SIGNAL(timeout()), this, SLOT(showtime()));
//showtime();
timer->start();
messageBox();
otherTimer = new QTimer(this);
otherTimer->setSingleShot(true);
connect(otherTimer, SIGNAL(timeout()), this, SLOT(messageBox()));
}
void MainWindow::showtime(){ //Displays current time. Needs to be manually updated.
QTime time = QTime::currentTime();
QString lcdText = time.toString("mm:ss");
ui->lcdNumber->QLCDNumber::display(lcdText);
}
MainWindow::~MainWindow(){
delete ui;
}
void MainWindow::on_pushButton_clicked(){
int timerLength = 10000;
otherTimer->start(timerLength);
QPropertyAnimation *progresBar = new QPropertyAnimation(ui->graphicsView, "geometry");
progresBar->setDuration(timerLength);
QRect barLocation =ui->graphicsView->geometry();
progresBar->setStartValue(QRect(barLocation.x(), barLocation.y(), 0, barLocation.height()));
progresBar->setEndValue(barLocation);
progresBar->start();
}
void MainWindow::messageBox(){
QMessageBox::information(this, "Warning!", "You clicked the button of doom " + timerLength/1000 + " seconds ago!");
}
main.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include <QDateTime>
#include <QLCDNumber>
#include <QMessageBox>
#include <QPropertyAnimation>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
int timerLength;
public slots:
void showtime();
void messageBox();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QTimer *otherTimer;
};
#endif // MAINWINDOW_H
Please let me know if more information or explanation is required.
You can convert your number to QString like
void MainWindow::messageBox(){
QMessageBox::information(this, "Warning!", "You clicked the button of doom " + QString::number(timerLength/1000) + " seconds ago!");
} //timerLength is an int.
I tried it works in my app.
so i am writing a simple video player program and i did the same steps as the lesson i am taking but when i run the program and click on functionalities like end (which is close()) and open (open file) they dont work, i used the slot triggering as per the lesson although i saw different ways of using the menubar here but i must follow this format, here is my code:
header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QVideoWidget>
#include <QStyle>
#include <QMediaPlayer>
#include <QFileDialog >
namespace Ui {
class videoWidget;
}
class videoWidget : public QMainWindow
{
Q_OBJECT
QMediaPlayer *meinPlayer;
QPushButton *playButton;
QPushButton *stopButton;
public:
explicit videoWidget(QWidget *parent = 0);
~videoWidget();
private slots:
void listeUndTitelAktualisieren();
void on_action_End_triggered();
void on_action_ffnen_triggered();
void on_action_Stop_triggered();
void on_action_PlayBack_triggered();
void on_action_Pause_triggered();
private:
Ui::videoWidget *ui;
};
#endif // MAINWINDOW_H
cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
videoWidget::videoWidget(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::videoWidget)
{
ui->setupUi(this);
meinPlayer = new QMediaPlayer(this);
meinPlayer->setMedia(QUrl::fromLocalFile("/beispiele/topologien.wmv"));
meinPlayer->play();
}
void videoWidget::listeUndTitelAktualisieren()
{
QString titel = meinPlayer->media().canonicalUrl().toLocalFile();
ui->listWidget->addItem(titel);
this->setWindowTitle("Multimedia-Player – " + titel);
connect(meinPlayer, SIGNAL(mediaChanged(QMediaContent)), this, SLOT(listeUndTitelAktualisieren()));
}
void videoWidget::on_action_End_triggered()
{
this->close();
}
void videoWidget::on_action_ffnen_triggered()
{
QFileDialog *meinDialog = new QFileDialog(this);
meinDialog->setAcceptMode(QFileDialog::AcceptOpen);
meinDialog->setWindowTitle("Datei öffnen");
meinDialog->setNameFilters(QStringList() << "Videos (*.mp4 *.wmv)" << "Audios (*.mp3)" << "Alle Dateien (*.*)");
meinDialog->setDirectory(QDir::currentPath());
meinDialog->setFileMode(QFileDialog::ExistingFile);
if (meinDialog->exec() == QDialog::Accepted) {
QString datei = meinDialog->selectedFiles().first();
meinPlayer->setMedia(QUrl::fromLocalFile(datei));
/*QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Image"), "/home/jana", tr("Video & Audio Files (*.mp3 *.mp4 *.wmv)"));
*/
meinPlayer->play();
}
}
void videoWidget::on_action_Stop_triggered()
{
meinPlayer->pause();
}
void videoWidget::on_action_PlayBack_triggered()
{
meinPlayer->play();
}
void videoWidget::on_action_Pause_triggered()
{
meinPlayer->pause();
}
am pretty sure this instruction here:
connect(meinPlayer, SIGNAL(mediaChanged(QMediaContent)), this, SLOT(listeUndTitelAktualisieren()));
is not located where it should coz you are connecting the signal toa slot INSIDE of the SLOT implementation....
try moving that to the constructor of dein videoWidget
How do I send a message from a child widget to a parent window in qt?
I tried sending a signal from the child widget to the parent window in qt. When I call the function test in subwidget.cpp, the signal is sent but the mainwindow slot does not execute. How can I send the message?
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QStackedWidget>
#include <QPushButton>
#include <QProcess>
#include <QDebug>
#include <subwidget.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void check_adb_exists();
private:
Ui::MainWindow *ui;
QStackedWidget *stack;
QPushButton *start_btn;
SubWidget *f2;
private slots:
void StartApplication();
void ReceiveCustomMessage(const QString &msg);
};
#endif // MAINWINDOW_H
subwidget.h
#define SUBWIDGET_H
#include <QWidget>
namespace Ui {
class SubWidget;
}
class SubWidget : public QWidget
{
Q_OBJECT
public:
explicit SubWidget(QWidget *parent);
~SubWidget();
void test();
private:
Ui::SubWidget *ui;
signals:
void SendCustomMessage(const QString& msg);
};
#endif // SUBWIDGET_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
// #include <formcustomnew.h>
#include <subwidget.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
stack = MainWindow::findChild<QStackedWidget *>("stackedWidget");
start_btn = MainWindow::findChild<QPushButton *>("start_btn");
stack->setCurrentIndex(0);
connect(start_btn,SIGNAL(released()),this,SLOT(StartApplication()));
f2 = new SubWidget(this);
//connect(f2,SIGNAL(SendCustomMessage(QString)),this,SLOT(ReceiveCustomMessage(QString)));
//f2->test();
//auto f1 = new FormCustomNew(this);
//connect(f1,SIGNAL(sendMessageNewMessage(QString)),this,SLOT(receiveMessage(QString)));
//f1->test();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::StartApplication(){
//check_adb_exists();
f2->test();
}
void MainWindow::ReceiveCustomMessage(const QString &msg){
qDebug("Recieved message from child");
qDebug("Message: " + msg.toLatin1());
}
void MainWindow::check_adb_exists(){
QProcess *p = new QProcess();
connect(p,&QProcess::readyReadStandardOutput,[&](){
auto data = p->readAllStandardOutput();
qDebug("Stdout: " + data);
});
connect(p,&QProcess::readyReadStandardError,[&](){
auto data = p->readAllStandardError();
qDebug("Error: " + data);
if(data.toStdString().compare("File Not Found")){
qDebug("File Not Found is the error");
}
});
QStringList args;
args << "/c dir C:\\Users\\%USERNAME%\\AppData\\Local\\Android\\Sdk";
p->setArguments(args);
p->setProgram("C:\\Windows\\System32\\cmd.exe");
p->start();
}
subwidget.cpp
#include "subwidget.h"
#include "ui_subwidget.h"
SubWidget::SubWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::SubWidget)
{
ui->setupUi(this);
qDebug("parent: " + parent->objectName().toLatin1());
connect(this,SIGNAL(SendCustomMessage(QString)),parent,SLOT(ReceiveCustomMessage(QString)));
}
SubWidget::~SubWidget()
{
delete ui;
}
void SubWidget::test(){
emit SendCustomMessage("trial message");
}
void SubWidget::SendCustomMessage(const QString &msg){
qDebug("Sending Message: " + msg.toLatin1());
}
Signals must not be defined in Qt.
From the Qt wiki on Signal & Slots:
Signals are automatically generated by the moc and must not be implemented in the .cpp file
Remove your implementation and this should work. However you should not be binding the signal within subclass as that reduces encapsulation and reusability (parent must have a ReceiveCustomMessage(QString) slot). Instead bind it outside, as you have in your commented out code.
hello everyone I use python send a string to qt but i do not know how show the string on a label can anyone help me ???
my mainwindow.cpp is
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer *timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(showTime()));
timer->start();
tcpServer.listen(QHostAddress::Any,42207);
//QByteArray Msg= tcpSocket->readAll();
readMessage();
}
void MainWindow::showTime()
{
QTime time=QTime::currentTime();
QString time_text=time.toString("hh:mm:ss");
ui->Digital_clock->setText(time_text);
QDateTime dateTime = QDateTime::currentDateTime();
QString datetimetext=dateTime.toString();
ui->date->setText(datetimetext);
}
void MainWindow::readMessage()
{
ui->receivedata_2->setText("no connection yet");
if(!tcpServer.listen(QHostAddress::Any,42207))
ui->receivedata_2->setText("waitting!");
//QByteArray Msg= tcpSocket->readAll();
}
every time i try to put socket->readall() it will get crashed when i debug
The connection between sockets is not necessarily sequential, can occur at any time so that QtcpServer handles appropriate signals, when creating a new connection we must use the signal newConnection.
In the slot that connects to the previous signal we must use nextPendingConnection that returns a pending connection through a socket.
This socket issues the readyRead signal when there is pending information, and in that task you get the data you want.
Also when disconnected this emits the signal disconnected, in that slot we must eliminate the socket.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void newConnection();
void readyRead();
void disconnected();
private:
Ui::MainWindow *ui;
QTcpServer* tcpServer;
};
#endif // MAINWINDOW_H
mainwindow.h
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QTcpSocket>
#include <QLabel>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
tcpServer = new QTcpServer(this);
connect(tcpServer, &QTcpServer::newConnection, this, &MainWindow::newConnection);
if(!tcpServer->listen(QHostAddress::Any,42207)){
qDebug() << "Server could not start";
}
else{
qDebug() << "Server started!";
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::newConnection()
{
QTcpSocket *socket = tcpServer->nextPendingConnection();
connect(socket, &QTcpSocket::readyRead, this, &MainWindow::readyRead);
connect(socket, &QTcpSocket::disconnected, this, &MainWindow::disconnected);
}
void MainWindow::readyRead()
{
QTcpSocket* socket = qobject_cast<QTcpSocket *>(sender());
ui->receivedata_2->setText(socket->readAll());
}
void MainWindow::disconnected()
{
sender()->deleteLater();
}
Hi I am using the code from here https://github.com/xcoder123/SimpleSmtp_SSL_QT5/tree/master/smtp_attachements to send mail from my qt application and it's work fine, but when I use future wacht to run the mail sender in another thread it does'nt work
QFuture<void> f4 = QtConcurrent::run(this,&MainWindow::sendMail); // this doesnot work
//sendMail(); //this work
Here is the mainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QSettings"
#include "QFuture"
#include "QtConcurrent/QtConcurrent"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->sendBtn, SIGNAL(clicked()),this, SLOT(test()));
connect(ui->exitBtn, SIGNAL(clicked()),this, SLOT(close()));
connect(ui->browseBtn, SIGNAL(clicked()), this, SLOT(browse()));
}
void MainWindow::browse()
{
files.clear();
QFileDialog dialog(this);
dialog.setDirectory(QDir::homePath());
dialog.setFileMode(QFileDialog::ExistingFiles);
if (dialog.exec())
files = dialog.selectedFiles();
QString fileListString;
foreach(QString file, files)
fileListString.append( "\"" + QFileInfo(file).fileName() + "\" " );
ui->file->setText( fileListString );
}
void MainWindow::test(){
QFuture<void> f4 = QtConcurrent::run(this,&MainWindow::sendMail);
//sendMail();
}
void MainWindow::sendMail()
{
Smtp* smtp = new Smtp(ui->uname->text(), ui->paswd->text(), ui->server->text(), ui->port->text().toInt());
connect(smtp, SIGNAL(status(QString)), this, SLOT(mailSent(QString)));
if( !files.isEmpty() )
smtp->sendMail(ui->uname->text(), ui->rcpt->text() , ui->subject->text(),ui->msg->toPlainText(), files );
else
smtp->sendMail(ui->uname->text(), ui->rcpt->text() , ui->subject->text(),ui->msg->toPlainText());
}
void MainWindow::mailSent(QString status)
{
if(status == "Message sent")
QMessageBox::warning( 0, tr( "Qt Simple SMTP client" ), tr( "Message sent!\n\n" ) );
}
MainWindow::~MainWindow()
{
delete ui;
}
and mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "smtp.h"
#include <QtWidgets/QMessageBox>
#include <QFileDialog>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void sendMail();
void mailSent(QString);
void browse();
void test();
private:
Ui::MainWindow *ui;
QStringList files;
};
#endif // MAINWINDOW_H
The smtp class is as shown here, I haven't touch anything
https://github.com/xcoder123/SimpleSmtp_SSL_QT5/blob/master/smtp_attachements/smtp.h
https://github.com/xcoder123/SimpleSmtp_SSL_QT5/blob/master/smtp_attachements/smtp.cpp
Any one know why it's not working when running in a thread using future watcher.
Thanks
Haris
The problem is that QtConcurrent::run just runs a single function, in your case sendMail, in a separate thread. As soon as this function returns, the thread is not active anymore and the slots in Smtp will not be called.
Either change your function sendMail to not return until the mail is sent or use a QThread and move Smtp* stmp to it using QObject::moveToThread.