QComboBox->addItems() crashed application when using findChild() - qt

I have a question regarding using the findChild() function.
For instance, I have 2 slots:
QComboBox *comboBoxType;
QComboBox *comboBoxName;
void MainWindow::on_Start_clicked()
{
ui->stackedWidget->setCurrentIndex(1);
comboBoxType = ui->stackedWidget->findChild<QComboBox *>("typeComboBox", Qt::FindChildrenRecursively);
comboBoxType->addItem("Hash");
comboBoxType->addItem("Translate");
comboBoxName = ui->stackedWidget->findChild<QComboBox *>("nameComboBox", Qt::FindChildrenRecursively);
}
void MainWindow::on_typeComboBox_currentTextChanged(const QString &arg1)
{
comboBoxName->addItem("MD5");
}
Explaination:
When StartButton is clicked, on_Start_clicked() is triggered, setCurrentIndex() is called to switch the widget and findChild() is called to find a QComboBox named nameComboBox.
Right after that on_typeComboBox_currentTextChanged() is triggered and add an item to that QComboBox.
It should be noted that the 2 QComboBox is located inside the widget which was switched to at the start, and both signals (clicked() and currentTextChanged()) is activated (almost) together, or just very close.
But the application crashed:
11:06:08: The program has unexpectedly finished.
11:06:08: The process was ended forcefully.
11:06:08: D:\...\build-cryptog-Desktop_Qt_5_15_2_MinGW_64_bit-Debug\debug\cryptog.exe crashed.
But, if I moved the findChild() function upward:
void MainWindow::on_Start_clicked()
{
ui->stackedWidget->setCurrentIndex(1);
comboBoxName = ui->stackedWidget->findChild<QComboBox *>("nameComboBox", Qt::FindChildrenRecursively);
comboBoxType = ui->stackedWidget->findChild<QComboBox *>("typeComboBox", Qt::FindChildrenRecursively);
comboBoxType->addItem("Hash");
comboBoxType->addItem("Translate");
}
The program ran fine.
What seems to be the problem here? I suspected that is because the addItem() command somehow is ran before findChild() could located the QComboBox, but I might be wrong here.

Related

QT Process gets killed automatically when it hits in SLOT

I have written a QT code which starts a new process on a button click, that process have to execute a shell script and append the Std output/error on text Browser dynamically based upon the script result. The code gets failed in the custom Slot. This is what my window.h is
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
QPushButton *goButton;
QTextBrowser *statusWindow;
QProcess *process;
private slots:
void go_Button_Clicked();
void updateOutput();
};
And this is how my window.cpp is
Window::Window(QWidget *parent) : QWidget(parent)
{
// Text Browser
statusWindow = new QTextBrowser(this);
// Create the Go button, make "this" the parent
goButton = new QPushButton(this);
connect(goButton, SIGNAL (clicked()), this, SLOT (go_Button_Clicked()));
}
void Window::go_Button_Clicked()
{
// Step1 - Create a new process
QProcess *process = new QProcess(this);
// Step2 - Connect the Signals and slot
qDebug() << connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(updateOutput()));
// Step3 - Start the Script process
process->start("/home/root/script.sh");
qDebug() << "Process in main";
}
void Window::updateOutput()
{
qDebug() << "Process in update Output";
//statusWindow->append(process->readAllStandardOutput());
}
So whenever i uncommented lines in update Output the GUI crashes as soon as i hit the button. using qdebug i managed to find that the GUI crashes bcoz of the line "statusWindow->append(process->readAllStandardOutput());" .
If the line is commented the debug message keeps on printing on console, but with the un-commented line i get the debug message once and then GUI crashes.Here is the debug output.
true
true
Process in main
Process in update Output
Process killed by signal
Any idea whats going on here, and i am familiar with Debugging in QT
Replace:
QProcess *process = new QProcess(this);
by
process = new QProcess(this);
You are using uninitialized member variable process, because in Window::go_Button_Clicked() you are creating a local variable.
Edit
Actually, the code is very error prone. What happens, when the user presses the button multiple times. Then in the slot you may read the the output from wrong process.
One workaround could be: You don't define QProcess as member at all, but do it like now - as a local variable. Then in the slot, you can cast the sender to QProcess*, and unless it fails use this instance. It will be always the right one. Afterwards, don't forget to delete the sender. Use deleteLater() for this.
Inside your void Window::go_Button_Clicked() slote you hide QProcess *process declared at .h file with new variable
QProcess *process = new QProcess(this);
Replace this line with
process = new QProcess(this);
But when you click second time you'll get memory leak, and can not get more data from first process. So you chould change you design somehow.

Qt - Connected but doesn't work

I have problem with one class in my project, after click appears new window with QTableWidget and QPushButton, after clicking the button I should have "test" on stdout, but nothing shows, here are parts of this code:
Header:
class ClientsSelector : public QWidget {
Q_OBJECT
public:
ClientsSelector(InvoiceTab* parent);
QWidget *window;
private:
QPushButton *accept;
public slots:
void loadData();
Constructor:
window = new QWidget();
layout = new QGridLayout();
layout->addWidget(table, 0, 0);
/*code*/
accept = new QPushButton(QString::fromUtf8("Load data"));
connect(accept, SIGNAL(clicked()), this, SLOT(loadData()));
layout->addWidget(accept, 0, 1);
/*code*/
window->setLayout(layout);
window->show();
Method:
void ClientsSelector::loadData() {
QTextStream std(stdout);
std << "test" << endl;
}
I have not even one warning nor error. I have nothing on stdout, it looks like button was connected to wrong object(?)
How do you instantiate ClientsSelector? Isn't it a singleton or global variable by chance? Try moving the connect call to a separate init function which is called after the ClientsSelector constructor. It helped me in similar WTF situations. It has something to do with the fact that each QObject inheritor has a static metadata member and you can't be sure about when it is fully initialized until the constructor finishes. connect won't work without that metadata.
See for example here: http://www.qtcentre.org/threads/9479-connect-in-constructor
If still lost, go through this checklist. Qt signals are so easy to use, everybody sometimes forgets it also has some requirements.
Seems like you forgot a closing " on the test printout.
Try using
qDebug() << "test";
instead of QTextstream
You can do following to make sure that the connection was made and slot is called.
connect function returns status of connection. Check if the connection was made properly.
put a breakpoint and see if the loadData() is called when button is pressed.
This might help to find the cause.

Qthread - trouble shutting down threads

For the last few days, I've been trying out the new preferred approach for using QThreads without subclassing QThread. The trouble I'm having is when I try to shutdown a set of threads that I created. I regularly get a "Destroyed while thread is still running" message (if I'm running in Debug mode, I also get a Segmentation Fault dialog). My code is very simple, and I've tried to follow the examples that I've been able to find on the internet.
My basic setup is as follows: I've a simple class that I want to run in a separate thread; in fact, I want to run 5 instances of this class, each in a separate thread. I have a simple dialog with a button to start each thread, and a button to stop each thread (10 buttons). When I click one of the "start" buttons, a new instance of the test class is created, a new QThread is created, a movetothread is called to get the test class object to the thread...also, since I have a couple of other members in the test class that need to move to the thread, I call movetothread a few additional times with these other items. Note that one of these items is a QUdpSocket, and although this may not make sense, I wanted to make sure that sockets could be moved to a separate thread in this fashion...I haven't tested the use of the socket in the thread at this point.
Starting of the threads all seem to work fine. When I use the linux top command to see if the threads are created and running, they show up as expected.
The problem occurs when I begin stopping the threads. I randomly (or it appears to be random) get the error described above.
Class that is to run in separate thread:
// Declaration
class TestClass : public QObject
{
Q_OBJECT
public:
explicit TestClass(QObject *parent = 0);
QTimer m_workTimer;
QUdpSocket m_socket;
Q_SIGNALS:
void finished();
public Q_SLOTS:
void start();
void stop();
void doWork();
};
// Implementation
TestClass::TestClass(QObject *parent) :
QObject(parent)
{
}
void TestClass::start()
{
connect(&m_workTimer, SIGNAL(timeout()),this,SLOT(doWork()));
m_workTimer.start(50);
}
void TestClass::stop()
{
m_workTimer.stop();
emit finished();
}
void TestClass::doWork()
{
int j;
for(int i = 0; i<10000; i++)
{
j = i;
}
}
Inside my main app, code called to start the first thread (similar code exists for each of the other threads):
mp_thread1 = new QThread();
mp_testClass1 = new TestClass();
mp_testClass1->moveToThread(mp_thread1);
mp_testClass1->m_socket.moveToThread(mp_thread1);
mp_testClass1->m_workTimer.moveToThread(mp_thread1);
connect(mp_thread1, SIGNAL(started()), mp_testClass1, SLOT(start()));
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(quit()));
connect(mp_testClass1, SIGNAL(finished()), mp_testClass1, SLOT(deleteLater()));
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));
connect(this,SIGNAL(stop1()),mp_testClass1,SLOT(stop()));
mp_thread1->start();
Also inside my main app, this code is called when a stop button is clicked for a specific thread (in this case thread 1):
emit stop1();
Sometimes it appears that threads are stopped and destroyed without issue. Other times, I get the error described above.
Any guidance would be greatly appreciated.
Thanks,
Bryan
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
"Finally, to prevent nasty crashes because the thread hasn’t fully shut down yet when it is deleted, we connect the finished() of the thread (not the worker!) to its own deleteLater() slot. This will cause the thread to be deleted only after it has fully shut down."
Please try replacing:
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));
with:
connect(mp_thread1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));

Qt can not respond key Press event immediately

Environment: Ubuntu, Qt Creator
In my Qt app, I found that sometimes Qt doesn't respond to my key press event immediately, but if I wait a while, it eventually responds.
I think something is blocking the UI.
As I know, if a Qt's component (QWidget etc.) is being destroyed, the Qt UI will be blocked. I have checked my code, there is no component being destroyed at the time I'm pressing the up/down key.
I really want to know is there any other things can block Qt UI.
{
...
connect(webViewWidget, SIGNAL(loadfinished()), this, SLOT(addItem()));
...
}
void addItem()
{
delete webViewWidget; // will this delete block UI?
mListWidget = new ScrollWidget();
mScrollArea = new ScrollArea(this);
for(int i=0; i<Datalen; i++)
{
mListWidget->addSubItem(itemWidget);
}
}
void keyPressEvent(QKeyEvent *event)
{
switch(event->key)
{
case UP_KEY:
scroll up;
break;
case DOWN_KEY:
scroll down;
break;
default:
break;
}
}
In general, your key press event will not be processed before all other events which were put into the application's event queue before pressing your key are processed.
Therefore it could be any kind of event which has not finished processing. Maybe you can figure out if there are any events, e.g. by using QApplication::hasPendingEvents or by inheriting from QApplication and adding debug output whenever an event is added or fully processed.
Destruction of objects is usually not a concern, unless you are doing a lot of work in the destructor. Destroying a webview may take long. You probably should not be destroying it like you do. Instrument that delete (see code below) and see how long it takes.
Your own code may be calling APIs that block. Are you calling any third party libraries? Are you calling any wait... methods in Qt's own API?
If you're unsure, you can instrument every slot and every reimplemented virtual method like xxxEvent(...). You'd need to instrument only slots and reimplemented QObject/QWidget methods, not every method in your code.
You may be producing an event storm, perhaps by posting lots of events in a loop, or by sending a lot of signals that are hooked up to slots connected via a Qt::QueuedConnection. Make sure you're not calling repaint() from within paintEvent() for example.
The instrumentation example below uses RAII and is very easy to apply. Alternatively, you can use a profiler.
#include <QElapsedTimer>
#define INSTRUMENT() Instrument instr__ument(__FUNCTION__)
#define INSTRUMENTLIM(lim) Instrument instr__ument(__FUNCTION__, (lim))
class Instrument {
QElapsedTimer timer;
int limit;
const char * function;
public:
Instrument(const char * name, int timeLimitMs = 20) :
function(name), limit(timeLimitMs) { timer.start(); }
~Instrument() {
if (timer.elapsed() > limit) {
qDebug("%s was slow, took %d ms", function, timer.elapsed());
}
}
}
void slot(...)
{
INSTRUMENT();
...
}
void addItem()
{
INSTRUMENT();
delete webViewWidget; // will this delete block UI?
mListWidget = new ScrollWidget();
mScrollArea = new ScrollArea(this);
for(int i=0; i<Datalen; i++)
{
mListWidget->addSubItem(itemWidget);
}
}

Help me understand the QThread usage

I have the MainWindow w windows and TestThread testThread as a member of w. I know it i simple, but I cannot run the testThread.foo() method in testThread thread (not in window thread). In another words: I don't understand the QThread behavior.
Please help correct the next test application. There is a QProgressBar *MainWindow::ui::progressBar and QPushButton *MainWindow::ui::startButton (write simply). I want to start (by startButton click) TestThread::foo(int* progress) which will increment int progress each second.
MainWindow:
MainWindow::MainWindow(QWidget *parent) : // ...
{
// ...
ui->progressBar->setRange(0, 5);
progress = 0; // int MainWindow::progress
this->connect(ui->startButton, SIGNAL(clicked()), SLOT(startFoo()));
connect(this, SIGNAL(startFooSignal(int*)), &testThread, SLOT(foo(int*)));
// TestThread MainWindow::testThread
testThread.start();
}
// ...
void MainWindow::timerEvent(QTimerEvent *event)
{
ui->progressBar->setValue(progress);
}
void MainWindow::startFoo() // this is a MainWindow SLOT
{
startTimer(100);
emit startFooSignal(&progress);
// startFooSignal(int*) is a MainWindows SIGNAL
}
TestThread:
void TestThread::foo(int *progress) // this is a TestThread SLOT
{
for (unsigned i = 0; i < 5; ++i) {
sleep(1);
++*progress; // increment MainWindow::progress
}
}
I know, this is simple. I am doing something wrong :)
P.S. I want to run the simpliest (as possible) example to understand the QThread behavior.
Thanks!
The critical issue is to have the object containing the foo()-function be owned by that thread, so that slot calls are dispatched from the right thread's event-loop.
(Note that there's no need to actually have foo() on the TestThread object. You can use separate objects for QThread and WhatEver::foo() function. It might be easier too, I'm not sure..)
IIUC, this is what you have to do:
Use QObject::moveToThread() to assign the object containing the foo-function to TestThread (that means that Qt::AutoConenction (the default) signal/slots calls will run correctly across thread, being dispatched from each thread's own event loop).
By having the object "owned" by the right thread, slots calls will be scheduled on that thread's event loop, rather than executed directly.
Hope it helps. :)
One alternative solution: If you just want to run a function in another thread, and don't insist using QThread, you should check out the QT Concurrent Namespace.
The following example will run the function foo() in separate thread and will not block on the line where calling the function. Of course there are mechanisms to understand when a function ends, to get a result, to wait for it, to control execution.
void foo(int &progress) {...}
int progress;
QtConcurrent::run(foo, progress);
Hope this helps
See QThread::start and QThread::run.

Resources