QPlainTextEdit() ->setPlainText() keeps crashing - c++

I'm trying to update a QPlainTextEdit() from either a button click, thread, etc. Somewhere from outside the MainThread and in Qt documentation it says it must used signals but I can't figure out how. If I try to do a CreateThread() or use a std::thread to update the
class MainWindow : public QMainWindow
{
Q_OBJECT
...
private slots:
handleButtonClick();
Thread();
...
private:
QPlainTextEdit *TextView;
}
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
...
TextView = new QPlainTextEdit();
TextView->setReadOnly(true);
TextView->setCursorWidth(0);
QPUshButton *UpdateButton = new QPushButton();
connect(UpdateButton, SIGNAL(released()), this, SLOT(handleButtonClick()));
....
}
MainWindow::handleButtonClick()
{
// eventually this will cause a crash, usually not imemdiately
TextView->insertPlainText("test");
}
MainWindow::Thread()
{
TextView->insertPlainText("test");
}
So as you can see, I want a way to update this QPlainTextEdit from outside the main thread without crashes. How can I do this? Thanks.

You are not allowed to do UI opeations like updating the text of a QTextEdit from outside the main thread. The solution to this is emitting a signal from the non-main thread, and have it connected to a slot in the main thread which does the UI work.

Related

Keep QDialog open when parent is minimized?

I have a QMainWindow opening a QDialog (not modal). When I minimize the main window, the dialog is closed as well. Can I somehow keep it open? (the other way round as in Keep QMainWindow minimized when QDialogs show() ).
One thing I have tried is to ignore the event, but to my surprise I never see such a state. Actually I only see ActivationChange (0n99) there.
void CMyDialog::changeEvent(QEvent *evt)
{
QEvent::Type t = evt->type();
if (t == QEvent::WindowStateChange)
{
evt->ignore();
hide();
}
else
{
QDialog::changeEvent(evt);
}
}
Question in Qt center dealing with a similar topic:
http://www.qtcentre.org/threads/24765-Intercept-minimize-window-event
Here I create it as member:
QScopedPointer<MyDialog> m_navigator{new MyDialog(this)}; // this here is the main application window
It is displayed by a public slot:
void MyDialog::toogleNavigator()
{
this->setVisible(!this->isVisible());
}
and is a QDialog derived class:
class MyDialog : public QDialog { ...
---- Edit 2 ------
First Wouter has mentioned it , then Alexander. It is like you guys say, if I pass no parent (as in Alexander`s minimal example), the dialog stays open - with parent it is minimized along with its parent. My apologizes Wouter.
However, in my case it does not work like that. So I did not turn Wouter`s comment without checking or in bad intention. Now it is my duty to find out why. I suspect some utility classes to alter the dialog. I will report back here when I have found the root cause.
Ok, it is the windows flags. If the dialog is a tool window, it is always minimized, as normal window it depends on the parent.
Try to create MyDialog without this(MainApplication) like parent
and may be play with a second parameter of the constructor.
new MyDialog(0/*, ?*/);
Addition It is working code
MainWindow.cpp
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QScopedPointer<Dialog> dialog;
};
MainWindow.hpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
dialog(new Dialog(0))
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
dialog->setVisible(!dialog->isVisible());
}

Update MainWindow for dialog

I have a MainWindow with a menu that opens a dialog for registration. How can I update the tableView in the MainWindow after the registration?
Here is my MainWindow implementation:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){
ui->setupUi(this);
}
void MainWindow::list()
{
qDebug() << "test";
QSqlQueryModel *model = new QSqlQueryModel();
//model->clear();
model->setQuery("SELECT test_qt FROM db_qt WHERE strftime('%Y-%m-%d', date)='"+dateTime.toString("yyyy-MM-dd")+"'");
model->setHeaderData(0, Qt::Horizontal, tr("qt_test"));
ui->tableView->setModel(model);
}
void MainWindow::on_actionMenu_triggered()
{
dialog_test->show();
}
Here is my Dialog implementation
Dialog_test::Dialog_test(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog_test)
{
ui->setupUi(this);
}
void Dialog_test::insert_date(){
QSqlQuery qry;
qry.prepare("INSERT INTO db_qt(test_qt) VALUES (?)");
qry.addBindValue(id);
if (qry.lastInsertId()>0){
QMessageBox::information(this,"test", "Success");
MainWindow *mw = new MainWindow(this);
mw->list(); // I call back list, but not update the tableView the MainWindow.
}
}
The following line in your code
MainWindow *mw = new MainWindow(this);
creates a new main window and updates the list of it. I assume this actually happens, but the window is never shown so you do not see any of it. What you actually want to do is update the list of your existing main window.
There are basically two ways of doing that. You can either obtain a pointer to the existing main window (which can be provided to the constructor of the dialog or a method of its own) or use the Signals and Slots concept of Qt which is the way to go in my opinion.
First of all, you define the signal in the header of the dialog:
...
signals:
void user_registered();
...
Then you emit the signal in your function
//MainWindow *mw = new MainWindow(this);
//mw->list();
emit this->user_registered();
Make sure the list() method is declared as a SLOT in the MainWindow header
Connect the signal in the MainWindow constructor to call the list() slot:
...
QObject::connect(this->dialog_test, SIGNAL(user_registered()), this, SLOT(list()));
...
With this approach, the dialog does not need to know the main window at all. It basically just tells anyone who is interested that a user registered and the main window acts on it completly by itself.

Handling multiple windows in Qt

I use QStackedWidget to handle multiple windows/forms in a Qt application
according to this question.
I use this pattern:
Add all widget objects to the QStackedWidget in mainwindow.cpp
Get signal from sub-window on request to change window
mainwindow replaces the window (it updates the QStackedWidget in the right slot)
My question :
is this the right way to do this? I have a lot of windows in my applications and want to ensure this is the common best practice.
This pattern means that i have pointers to all of the windows in my main window.
piece of my code:
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mnuWin = new Menu();
singlePulseWin = new SinglePulse();
repetitive = new Repetitive();
treatmentType = new TreatmentType();
//... and so on ....
connect(mnuWin,&Menu::updateMainWindowStackWidget,this,&MainWindow::onChangeWindowRequested);
connect(singlePulseWin,&SinglePulse::updateMainWindowStackWidget,this,&MainWindow::onChangeWindowRequested);
connect(repetitive,&Repetitive::updateMainWindowStackWidget,this,&MainWindow::onChangeWindowRequested);
connect(treatmentType,&TreatmentType::updateMainWindowStackWidget,this,&MainWindow::onChangeWindowRequested);
//... and so on ....
ui->pagesWidget->addWidget(mnuWin);
ui->pagesWidget->addWidget(singlePulseWin);
ui->pagesWidget->addWidget(repetitive);
ui->pagesWidget->addWidget(treatmentType);
//... and so on ....
ui->pagesWidget->setCurrentIndex(0);
}
void MainWindow::onChangeWindowRequested(int ind) //slot
{
ui->pagesWidget->setCurrentIndex(ind);
}
menu.cpp :
void Menu::on_btnMenuSinglePulse_clicked()
{
emit updateMainWindowStackWidget(1);
}
void Menu::on_btnMenuRepetitive_clicked()
{
emit updateMainWindowStackWidget(2);
}
void Menu::on_btnMenuBurst_clicked()
{
emit updateMainWindowStackWidget(3);
}
QStackedWidget is a good way to deal with Multi-window .why not put the buttons in the mainWindow ,so that you can change the pagesWidget's currentWidget more convenient instead of create signal-slot

Emit signal between two classes in Qt

A am trying to make a program that takes a signal from one class and with activation of that signal I want to activate a slot in second class.
In my case the first class is the mainWindow class, this class is subClass of QMainWindow, and in this class is the slot that I want to activate.
This is mainWindow.cpp:
mainWindow::mainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::mainWindow)
{
ui->setupUi(this);
}
mainWindow::~mainWindow()
{
delete ui;
}
void mainWindow::slotForStatusBarMessage(QString string)
{
statusBar()->showMessage(string);
}
The second class is the mainWidget class and it is a subclass of QWidget.
This is mainWidget.cpp:
mainWidget::mainWidget(QWidget *parent) :
QWidget(parent)
{
buttonAddNewRecord=new QPushButton("Add new record", this);
layoutButton=new QHBoxLayout();
layoutButton->addWidget(buttonAddNewRecord);
layoutMain=new QVBoxLayout();
layoutMain->addLayout(layoutButton);
functionDatabaseOpen();
setLayout(layoutMain);
}
The signal is emited from functionDatabaseOpen() function:
if (sqlDatabase.open())
{
emit signalForShowMessageInStatusBar("true");
}
else
{
emit signalForShowMessageInStatusBar("false");
}
I have made all the settings to the database but i didnt copy here because of space.
I have tried to make connection inside main.cpp but it seems it dosent work.
QObject::connect(mw, SIGNAL(signalForShowMessageInStatusBar(QString)), w, SLOT(slotForStatusBarMessage(QString)));
I cant make this signal/slot connection between classes to work. Can you give me any help.
If you have any question about the code please ask. Sorry for the bad english,I am not a native english speaker.
Thank you very much for your help.
You are emitting the signal from the constructor of mainWidget, and since the connection is only done after you return from that constructor, the signal doesn't go anywhere.
The easiest fix, not knowing what the rest of the code looks like, would be to move the call to functionDatabaseOpen() in main() after the signal/slot connection is made.

Is there a way to implement OnReady() callback in Qt4?

I want to do something which will access network when a QMainWindow is ready.
I suppose I should not do it in the constructor, so I try to find a signal the widget will get and try to implement something like a OnReady() call back in other UI library. But I still can not find a way to do this.
Thanks a lot in advance.
If I understand correctly, you need to do something as soon as the application's event loop is ready to process events.
The reason you can't do it in the constructor because the application's event loop isn't ready until some time after the constructor has finished running.
What you can do is create a slot in your MainWindow class containing the code you want to run, set up a single-shot timer in the constructor, and have that timer call your slot. For example:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void doStuff(); // This slot will contain your code
// ...
// ...
// ...
}
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer::singleShot(0, this, SLOT(doStuff())); // This will call your slot when the event loop is ready
// ...
// ...
// ...
}
void MainWindow::doStuff()
{
// This code will run as soon as the event loop is ready
}
Alternative way is to use QMetaObject::invokeMethod with a queued connection. If you use invokeMethod you can also pass an argument.
QMetaObject::invokeMethod(
this,
"onReady",
Qt::QueuedConnection,
Q_ARG(QString, argument));