What I'm trying to do is launch a program within another program using QProcess and then save the output from the launched program into a QTextEdit of the launcher program. Every time I launch this program I want it to add more text to the QTextEdit. Now I get the program to launch but then after the text is supposed to be written it crashes. Here is the code:
#include <QWidget>
#include <QPushButton>
#include <QTextEdit>
#include <QProcess>
#include <QVBoxLayout>
#include <QApplication>
class Widget : public QWidget
{
Q_OBJECT
QTextEdit* text;
public:
Widget() : text(new QTextEdit) {
QPushButton* addBtn = new QPushButton("Add Module");
text->setReadOnly(true);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(addBtn,0);
layout->addWidget(text);
connect(addBtn,SIGNAL(clicked()),SLOT(launchModule()));
}
Q_SLOT void launchModule() {
QString program = "C:/A2Q2-build-desktop/debug/A2Q1.exe";
QProcess *myProcess = new QProcess(this);
connect(myProcess, SIGNAL(finished(int)), SLOT(finished()));
connect(myProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(finished()));
myProcess->start(program);
}
Q_SLOT void finished() {
QProcess *process = qobject_cast<QProcess*>(sender());
QString out = process->readAllStandardOutput(); // will be empty if the process failed to start
text->append(out);
delete process;
}
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Widget w;
w.show();
app.exec();
}
#include "main.moc"
It's crashing because you're deleting the sender object while inside a slot. Instead of delete process, you should
process->deleteLater();
For logging purposes you should be using QPlainTextEdit instead of a QTextEdit. The former is faster. You're prematurely pessimizing by using the latter. Alas, even QPlainTextEdit becomes abysmally slow if you're sending about 100 lines/s (at least on Qt 4.8). If you want a really fast log view, you'll need to use QListWidget, with a caveat, or roll your own.
I have a complete example of how to send to and receive from a process in another answer.
The process is crashing because you're deleting the parent from within the finished slot.
Also, it's probably easier to do something like this:
QObject::connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(getOutput()));
instead of using the finished() slot. But that's more personal preference than anything.
Related
I use a QTimer object to scan computer memory to detect any data changed, and finally showing these data in GUI with QTableView.
But problem is when the program window is not focused, no changes are detected. As soon as the window is focused again, data changes in Gui in no time.
My question is how to let the tableview update content automatically?
To follow MVC style, I decided to use QTableView instead of QTableWidget. Indeed, it is convenient to update data as I only need to deal with a "model" but not QTableView after binding the model with it.
QTableView object is in Gui thread (view level), and QStandardItemModel is used in another thread (control level). For this issue, after googling, I tried :
QModelIndex t1 = index(i, 3);
QModelIndex t2 = index(i, 5);
emit dataChanged(t1, t2);
when doing dataChanged. It is not working and when I found no problem on the model side, then I also tried:
connect(&timer, &QTimer::timeout, this, [&]() {
ui.searchTableV->viewport()->update();
});
timer.start();
at the very beginning of GUI class construction. Sometimes it is working, but usually it raised "Access Violation".
Personally, I never expect there would be an issue like this, as everything was working fine with QTableWidget before. It seems that I need to do something with subclass QStyledItemDelegate to make the QTableView more robust after I found this on QT forum. But I don't want to do so, I think there should be a simpler way.
Also, I wonder if this issue is a bug or it is just designed to behave like this.
I also tried to reproduce your described behavior, but I was not able to do so. My app works as desired and it really does not matter if it will lose focus. There are also no crashes. Maybe you are doing something different.
Worker.h
#pragma once
#include <QObject>
#include <QThread>
#include <QStandardItemModel>
class Worker : public QObject {
Q_OBJECT
public:
Worker();
void setModel(QStandardItemModel* model);
public slots:
void addItems();
private:
QStandardItemModel* mModel{ nullptr };
};
Worker.cpp
#include "Worker.h"
Worker::Worker()
{
}
void Worker::setModel(QStandardItemModel* model)
{
mModel = model;
}
void Worker::addItems()
{
for (;;) {
mModel->appendRow(new QStandardItem("Item"));
QThread::currentThread()->msleep(1000);
}
}
main.cpp
#include <QApplication>
#include <QFrame>
#include <QHBoxLayout>
#include <QPushButton>
#include <QThread>
#include <QTreeView>
#include <QStandardItemModel>
#include "Worker.h"
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
auto frame = new QFrame;
frame->setLayout(new QHBoxLayout);
auto view = new QTreeView;
auto model = new QStandardItemModel;
view->setModel(model);
auto worker = new Worker;
worker->setModel(model);
auto thread = new QThread;
worker->moveToThread(thread);
thread->start();
frame->layout()->addWidget(view);
auto btnStart = new QPushButton("Start add items");
QObject::connect(btnStart, &QPushButton::clicked, worker, &Worker::addItems);
frame->layout()->addWidget(btnStart);
frame->show();
return a.exec();
}
I have the following Problem:
I have a Qt MainWindow which starts several Dialogs. Through an external source, I can hide and show the MainWindow. If a dialog is open, only the MainWindow is hidden, but the dialog is still visible. This is not nice but not my main problem. The main problem is, if i close the dialog while the MainWindow is hidden, the whole Application terminates. I do not want that, because I can make my main window visible again by external source.
I know it has something to do with QApplication quitOnLastWindowClosed. But if i set it true, my Application doesn't terminate if i normaly press "X".
Here is an example:
// MainApp.h
#include <QMainWindow>
#include "ui_MainWindow.h"
class MainApp : public QObject {
Q_OBJECT
public:
MainApp(QObject *parent = nullptr);
private slots:
void slotOpenDialog();
private:
QMainWindow mMainWindow;
Ui::MainWindow mUi;
};
// MainApp.cpp
#include "MainApp.h"
#include <QTimer>
#include <QMessageBox>
MainApp::MainApp(QObject *parent) {
mUi.setupUi(&mMainWindow);
mMainWindow.show();
connect(mUi.pushButton, &QPushButton::clicked, this, &MainApp::slotOpenDialog);
// simulate external hide and show mechanism
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout,
[=] {
if(mMainWindow.isHidden()) mMainWindow.show();
else mMainWindow.hide();
});
timer->start(3000);
}
void MainApp::slotOpenDialog() {
QMessageBox::information(nullptr, "Info", "text");
}
// main.cpp
#include <QApplication>
#include "MainApp.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainApp* mApp = new MainApp;
// if set true, I can't exit the application with "X"
//a.setQuitOnLastWindowClosed(false);
int error = a.exec();
delete mApp;
return error;
}
How can I prevent the program from quitting when it is hidden and a still visible dialog has been closed and how can I make it exit normally when the window is visible?
QApplication emits a signal "lastWindowClosed" and it has a quit() slot. As mentioned in the comments, the problem can be solved by connecting your own slot onLastWindowClosed() to that signal and quitting only when you want to.
I am working on a code that allows the user to control a piezo (PZ193E) in a MainWindow created with Qt Designer form.
However, when I call the function designed to connect the piezo to the computer (from an external library given by the constructor) my UI freeze until the connection is established.
I am trying to display a QDialog with a QLabel in it, telling the user to wait while the connection is processing, but when I do so, the QDialog shows up but without the label. It is only displayed when the connection is established and when the QDialog can close.
Here is how I coded my dialog :
In the .h :
QDialog *_waitQD = new QDialog;
QVBoxLayout *_waitQVBL = new QVBoxLayout;
QLabel *_waitQL = new QLabel("Loading...");
In the .cpp :
_waitQD->setMinimumSize(QSize(95,35));
_waitQVBL->addWidget(_waitQL);
_waitQD->setLayout(_waitQVBL);
And then I call :
_waitQD->show();
if (_piezo.connected()) // bool funtion that return true if the connection is established
_waitQD->close();
This is what it looks like:
The ideal solution is not blocking the main thread while establishing the connection; the workaround is adding QApplication::processEvents(); after the call to show
you need to call app.exec()
#include <QApplication>
#include <QDialog>
#include <QVBoxLayout>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QDialog *_waitQD = new QDialog;
QVBoxLayout *_waitQVBL = new QVBoxLayout;
QLabel *_waitQL = new QLabel("Loading...");
_waitQD->setMinimumSize(QSize(95,35));
_waitQVBL->addWidget(_waitQL);
_waitQD->setLayout(_waitQVBL);
_waitQD->show();
return app.exec();
}
I am writing a test Qt application in which everything works fine until I try to receive a signal by slot and then emit another signal (MyWidget::setValue doesn't cause an emission of MyWidget::valueChanged). What am I doing wrong?
#include <QApplication>
#include <QVBoxLayout>
#include <QSpinBox>
#include <QSlider>
class MyWidget: public QWidget {
Q_OBJECT
signals:
void valueChanged(int value);
public slots:
void setValue(int value){
emit valueChanged(value);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyWidget* win = new MyWidget;
QVBoxLayout* layout = new QVBoxLayout(win);
QSpinBox* spin =new QSpinBox();
QSlider* slider = new QSlider(Qt::Horizontal);
spin->setMinimum(-100);
spin->setMaximum(100);
slider->setMinimum(-100);
slider->setMaximum(100);
layout->addWidget(spin);
layout->addWidget(slider);
QObject::connect(spin, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
QObject::connect(slider, SIGNAL(valueChanged(int)), win, SLOT(setValue(int)));
QObject::connect(win, SIGNAL(valueChanged(int)), spin, SLOT(setValue(int)));
win->show();
return app.exec();
}
What am I doing wrong?
You've created a binding loop and would overflow the stack if Qt didn't protect you from yourself by forcibly breaking the loop. As this is only a protection mechanism, its only job is to prevent a freeze and a crash. It's not supposed to make your application functional.
You have to avoid creating the loop in the first place.
You could do so e.g. by not invoking the setValue slot of the originating widget - recall that your setValue slot is called from within the valueChanged signal's body.
I'm trying to write a simple Qt program which takes text inside a QLineEdit and appends it into a QTextEdit object when the return key is pressed.
Here is the code for my program:
#include <QApplication>
#include <QtGui>
#define WIDTH 640
#define HEIGHT 480
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTextEdit textArea;
textArea.setReadOnly(true);
QLineEdit lineEdit;
QPushButton quit("Quit");
QObject::connect(&quit, SIGNAL(clicked()), qApp, SLOT(quit()));
QHBoxLayout hLayout;
hLayout.addWidget(&lineEdit);
hLayout.addWidget(&quit);
QVBoxLayout vLayout;
vLayout.addWidget(&textArea);
vLayout.addLayout(&hLayout);
QWidget window;
window.setBaseSize(WIDTH, HEIGHT);
window.setLayout(&vLayout);
window.show();
//This is the line I can not get to work
QObject::connect(&lineEdit, SIGNAL(returnPressed()), &textArea, SLOT(append(lineEdit.text())));
return app.exec();
}
Essentially, the problem is connecting the QLineEdit returnPressed() SIGNAL to the QTextEdit append() SLOT. I am hoping someone can point out what is wrong with my code.
Thank you very much in advance for your time.
When you run your program, you should notice on the console the following Qt error output..
Object::connect: No such slot QTextEdit::append(lineEdit.text()) in ..
You would need to qualify the append reference in your call to connect with the QTextEdit variable name textArea.
But that's not going to help much because you can only specify signal and slot method names and parameter types when calling connect so you can't specify lineEdit.text() in there.
Since the append() slot expects a QString, ideally you would want to connect a signal that includes a QString but there is no such signal for QLineEdits.
You pretty much have to write a slot yourself that you can connect to returnPressed() and call textArea.append(lineEdit.text()) from there. You will need to subclass a QObject of some kind to write a slot which would usually mean subclassing QWidget and putting all of your UI building code in its constructor.
You might also notice that your program crashes when you close it. Since Qt likes to manage the destruction of most QObjects itself, it is usually best to allocate all QObject instances on the heap with new. This isn't technically necessary all the time but it is much easier :)
QObject::connect(&lineEdit, SIGNAL(returnPressed()), &textArea, SLOT(append(lineEdit.text())));
returnPressed() doesn't take any arguments, but append(QString) does take one argument; a QString. Thus, if this would work, you would theoretically call append(""), meaning you wouldn't append anything. Using lineEdit.text() wouldn't work either at this place.
I would recommend you to create a class for the widget:
class Widget : public QWidget
{
public:
Widget(QWidget parent = 0);
//Other public functions
private:
//Private functions and variables
public slots:
void boom();
};
Then you can just use
Widget w(0);
w.show();
in your main function.
void boom() would be called by returnPressed(), and it would take lineEdit.text() and append it to the QTextEdit.
I hope this helps.
here is the code it might be helpful.....
#include "hwidget.h"
Hwidget::Hwidget(QWidget *parent) :
QWidget(parent)
{
}
void Hwidget::mainform_init(void)
{
lineeditp = new QLineEdit;
quitp = new QPushButton("&Exit");
hboxlayoutp = new QHBoxLayout;
hboxlayoutp->addWidget(lineeditp);
hboxlayoutp->addWidget(quitp,0,0);
vboxlayoutp = new QVBoxLayout;
texteditp = new QTextEdit;
texteditp->setReadOnly(true);
vboxlayoutp->addWidget(texteditp,0,0);
vboxlayoutp->addLayout(hboxlayoutp);
QWidget *mywin = new QWidget;
mywin->setLayout(vboxlayoutp);
mywin->setWindowTitle("My Sig and Slot");
mywin->show();
lineeditp->setFocus();
}
void Hwidget::mcopy(void)
{
qDebug() <<"i am your copy slot";
texteditp->setText(lineeditp->text());
lineeditp->clear();
}
#include <QApplication>
#include "hwidget.h"
int main (int argc, char *argv[])
{
QApplication app(argc,argv);
Hwidget *hwin = new Hwidget;
hwin->mainform_init();
hwin->connect(hwin->quitp,SIGNAL(pressed()),
qApp,SLOT(quit()));
hwin->connect(hwin->lineeditp,SIGNAL(returnPressed()),
hwin,SLOT(mcopy()));
return app.exec();
return 0;
}
#ifndef HWIDGET_H
#define HWIDGET_H
#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QObject>
#include <QString>
#include <QDebug>
class Hwidget : public QWidget
{
Q_OBJECT
public:
explicit Hwidget(QWidget *parent = 0);
void mainform_init(void);
signals:
public slots:
void mcopy(void);
private:
QHBoxLayout *hboxlayoutp;
QVBoxLayout *vboxlayoutp;
public:
QPushButton *quitp;
QLineEdit *lineeditp;
QTextEdit *texteditp;
};
#endif // HWIDGET_H