Custom Symbian view system, segmentation fault at an unknown location, unknown cause - qt

I'm developing a Symbian application.
I've written a system for easily changing views, roughly like this:
class ViewManager : public QWidget {
public slots:
void changeView( const QString &id ) {
if( currentView_m ) {
delete currentView_m;
currentView_m = 0;
}
if( id == "main" ) {
currentView = new MainView( this );
}
else if( ... ) {
//etc..
layout_m->addWidget( currentView_m );
connect( currentView_m, SIGNAL( changeView( QString ) ),
this, SLOT( changeView( QString ) ) );
}
private:
View *currentView_m;
};
class View : public QWidget {
signals:
void ChangeView( const QString &id );
};
class MainView : public View {
public slots:
void onButtonClicked() {
emit changeView( "someview" );
}
};
Then as an example, I'm using the ViewManager in main:
int main( int argc, char *argv[] ) {
QApp app...
ViewManager man;
man.changeView( "main" );
app.exec();
}
When I change the view the first time, it works just fine, then when I change the view another time, it segfaults! You might think it segfaults when I delete the currentView_m pointer, but no! The segmentation fault happens right after the program exits the changeView-slot.
I have no idea how to debug this, as the program crashes and shows a disassembler dump, and the stack trace shows only gibberish.
Could it be that after the slot call, the program goes to the QApplication event loop and crashes there? I'm using a custom widgets inside View implementations that override some of the protected QWidget events.

You are deleting a object the signal of which you are processing. Instead of delete, just call deleteLater() on the object, deferring the deletion to a "safe" point.

Try removing the view from your layout first. Then delete the view. You can use removeWidget,removeItem methods of layout for this purpose
Layout might be trying to access a delete view.
Read this Qt - remove all widgets from layout? question as well. It might give you insight.

Related

Qpush Button -> click signal from QPushButton failed to fire up function in slot

i Guys ,
Qt Version 5.1
I am working on existing qt project and I failed to understand why when I click on button , it fails to fire up function in slot
What I am trying to do is my Qt application connects to the network and displays all the machine with their mac address using QTreewidget. This part works fine
my nest task is to select the mac-adrress from the QTree object created in above step AND then create a pushbutton to start the upgrade process on that machine.
Below is my source code
1) main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Regular_Work w;
w.show();
return a.exec();
}
2) regular_work.cpp
Regular_Work::Regular_Work(QWidget *parent)
: QMainWindow(parent),macAdd_tree_p_( 0 ), reg_upgrade_button_(0),
box_table_p_( 0 ),
udp_listner_p_( 0 )
{
ui.setupUi(this);
// Create the main view
create_main_view( this, macAdd_tree_p_, box_table_p_ , reg_upgrade_button_);
init(); // this function upgradels other signals and slots from other class to find the network and upgradel the slots which displays teh tree view of mac address connected to a network.
create_menu_actions();
}
Regular_Work::~Regular_Work()
{
}
// this function is called from another slot when itemClicked signal is received from QTreeWidgetItem
void Regular_Work::set_reg_upgrade_button_visible( Regular_Work* main_p )
{
QPushButton* reg_upgrade_button = new QPushButton ("Regular_upgradei");
reg_upgrade_button->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ;
QWidget* centralWidget = new QWidget( main_p );
centralWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
QHBoxLayout* layout = new QHBoxLayout(centralWidget);
layout->addWidget( reg_upgrade_button_ );
main_p->setCentralWidget(centralWidget);
reg_upgrade_button->setVisible( true );
connect(reg_upgrade_button, SIGNAL( clicked() ), main_p, SLOT( start_Work( "start Work" ) ) ); // this is teh problem ?
}
void Regular_Calibration::start_Work( const QString& error_message )
{
QMessageBox::information( this,
tr( "Push button works " ),
error_message );
}
Thanks a lot for the help
Your problem lies in the fact that you're trying to pass a parameter value in the connect statement. This can not work: -
SLOT( start_Work( "start Work" ) )
What you need to do is to create a slot that matches the arguments of the clicked() signal. Then in that slot function, you can call your start_Work("start Work") function. Something like this: -
class Regular_Work : public QMainWindow
{
Q_OBJECT
private:
void start_Work(const QString&);
private slots:
void ReceiveButtonClicked();
};
void RegularWork::ReceivedButtonClicked()
{
start_Work("start Work");
}
Connect the signal and slots: -
connect(reg_upgrade_button, SIGNAL( clicked() ), main_p, SLOT( ReceiveButtonClicked()));
If you use Qt 5, you can use the new connection syntax: -
connect(reg_upgrade_button, &QPushButton::clicked, main_p, &RegularWork::ReceiveButtonClicked);
This has the advantage of telling you if there's a problem at compile time, as well as taking pointers to functions, so you don't specify any arguments for the functions.

QMainWindow - wait until 'show' function is done

Is there a signal that tells when 'show' function finishes?
I have a problem in my code: If I write:
QMainWinObj.show();
QMainWinObj.someGuiFunc();
the code doesn't work. But, if I write:
QMainWinObj.show();
sleep(3000);
QMainWinObj.someGuiFunc();
It does.
So I think the problem is that 'show' dosn't finish its jub before I call 'someGuiFunc'. That's why I want to have some kind of a sign that 'show' is finished..
This may be a bit dated but since nobody else answered it except the one:
Since there is no "Show" signal I suggest overriding the show event like this:
In your mainwindow.cpp file:
void MainWindow::show()
{
QMainWindow::show();
QApplication::processEvents();
emit windowShown();
}
In your mainwindow.h file, somewhere in MainWindow's declaration:
...
class MainWindow: public QMainWindow
{
...
signals:
void windowShown();
...
}
...
Then, when you go to the designer, right click on the main window (very top of the object tree), and select "Change signals/slots". In the "Signals" frame, click the "+" button, and you will need to add "windowShown()" and then press enter, and then the OK button (note that the elipses "..." denote other code that is already in your header).
That's it -- you can now use the signals/slots editor to link slots up to the 'windowShown' signal whenever you want. Now if you want something more like Microsoft's "Loaded" event which I think is used in .NET you will need to create some instance variable and flag it so that every time the window is shown, it isnt emitted, for example:
void MainWindow::show()
{
QMainWindow::show();
QApplication::processEvents();
emit windowShown();
if (firstTimeShown == true)
{
emit windowLoaded();
firstTimeShown = false;
}
}
Also, don't forget to initialize the variable to 'true' in your constructor:
MainWindow::MainWindow(QObject* parent)
...
{
firstTimeShown = true; // put this somewhere before ui->setupUi()
}
If you decide to put it in the initializer list however, make sure it is in proper order. The compiler will complain if the variables are not instantiated in a top-to-bottom fashion as declared in the class' header.
Now, make sure when you define firstTimeShown in your header, that you make it private. And lets not forget the added signals:
class MainWindow : public QMainWindow
{
...
signals:
void windowLoaded();
void windowShown();
private:
bool firstTimeShown;
...
That's about it. With the flexibility of signals and slots, its pretty easy to mimic any event that you might find from windows forms or from MFC. It just takes a little effort on the programmer's part. Once you get the hang of it however it it'll be like second nature.
note: there probably are optimizations or better and more precise ways of making the "Loaded" and "Shown" signals perform but I have left things like this out for simplicity's sake. And to come back to the question at hand, calling QApplication::processEvents() is most likely what you want to do instead of waiting a fixed amount of time because who knows how long it will take if the user is running 100 other things on top of it, etc, etc. Hope that helped, the extra explanation was included hoping that it might give you a better way to do the things that you want to do instead of waiting for something to be done, 'knowing' it is done is a much better alternative.
There is no such signal, but having QMainWindow subclassed you can override showEvent event.
void MainWindow::showEvent(QShowEvent *){
//your code
}
More info here: http://qt-project.org/doc/qt-4.8/qwidget.html#showEvent
Be aware it's called every time your window is about to be displayed.
Problem can decide without subclassing, just installing event filter like this:
class CWidgetIsPainting_EF : public QObject
{
bool m_bIsPainted = false;
public:
CWidgetIsPainting_EF( QObject * parent = 0 ) : QObject (parent) { }
inline bool IsPainted() const { return m_bIsPainted; }
inline void setIsPainted( bool bIsPainted ) { m_bIsPainted = bIsPainted; }
protected:
bool eventFilter( QObject * obj, QEvent *event )
{
if (event->type() == QEvent::Paint)
{
m_bIsPainted = true;
return true;
};
return QObject::eventFilter(obj, event);
}
};
...
...
CWidgetIsPainting_EF * pPaintingEF = new CWidgetIsPainting_EF( m_pWidget );
m_pWidget->installEventFilter( pPaintingEF );
...
...
while ( !pPaintingEF->IsPainted() )
QApplication::processEvents();
Override bool event(QEvent *event) and catch the Paint event. Works for me at least on Windows.
// MainWindow.h
class MainWindow : public QMainWindow
{
...
bool event(QEvent *event) override;
void functionAfterShown();
...
bool functionAfterShownCalled = false;
...
}
// MainWindow.cpp
bool MainWindow::event(QEvent *event)
{
const bool ret_val = QMainWindow::event(event);
if(!functionAfterShownCalled && event->type() == QEvent::Paint)
{
functionAfterShown();
functionAfterShownCalled = true;
}
return ret_val;
}

Question about Qt slots and multiple calls

I am just learning Qt and have a very basic question.
If there is a (function scope) variable in a slot, and the slot is called multiple times, each time before the last call has returned (is this even possible?), will the variable be overwritten each time? In the sense that, if the slot is called before the previous run has returned, wouldn't that cause errors?
Thanks.
Yes if the calls are made from different threads AND you are using direct connection.
If you use queued connections then the slot calls will be performed one after another on event loop which is ran on the thread your receiving object belongs to. (edit thanks to Idan K comment).
Checkout Signal and slots's queued connection or QMutexLocker to solve your problem.
If you truly use function scope variables, then it shouldn't matter. Example:
class WheelSpinner : public QThread
{
Q_OBJECT;
public:
WheelSpinner( QObject* receiver, const char* slot )
{
connect( this, SIGNAL( valueChanged( int ) ), receiver, slot,
Qt::DirectConnect );
}
void run()
{
for ( int i = 0; i < 100000; ++i )
{
emit ( valueChanged( i ) );
}
}
public signals:
void valueChanged( int value );
};
class ProgressTracker : public QObject
{
Q_OBJECT;
public:
ProgressTracker() { }
public slots:
void updateProgress( int value )
{
// While in this function, "value" will always be the proper
// value corresponding to the signal that was emitted.
if ( value == 100000 )
{
// This will cause us to quit when the *first thread* that
// emits valueChanged with the value of 100000 gets to this point.
// Of course, other threads may get to this point also before the
// program manages to quit.
QApplication::quit();
}
}
};
int main( int argc, char **argv )
{
QApplication app( argc, argv );
ProgressTracker tracker;
WheelSpinner spinner1( &tracker, SLOT( updateProgress( int ) ) );
WheelSpinner spinner2( &tracker, SLOT( updateProgress( int ) ) );
WheelSpinner spinner3( &tracker, SLOT( updateProgress( int ) ) );
spinner1.run();
spinner2.run();
spinner3.run();
return ( app.exec() );
}
As long as the function is reentrant there is no problem.

QT + How to call slot from custom C++ code running in a different thread

I am new to QT and I am doing some learning.
I would like to trigger a slot that modify a GUI widget from a C++ thread(Currently a Qthread).
Unfortunatly I get a: ASSERTION failed at: Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
here is some code:
(MAIN + Thread class)
class mythread : public QThread
{
public:
mythread(mywindow* win){this->w = win;};
mywindow* w;
void run()
{
w->ui.textEdit->append("Hello"); //<--ASSERT FAIL
//I have also try to call a slots within mywindow which also fail.
};
};
int main(int argc, char *argv[])
{
QApplication* a = new QApplication(argc, argv);
mywindow* w = new mywindow();
w->show();
mythread* thr = new mythread(w);
thr->start();
return a->exec();
}
Window:
class mywindow : public QMainWindow
{
Q_OBJECT
public:
mywindow (QWidget *parent = 0, Qt::WFlags flags = 0);
~mywindow ();
Ui::mywindow ui;
private:
public slots:
void newLog(QString &log);
};
So I am curious on how to update the gui part by code in a different thread.
Thanks for helping
stribika got it almost right:
QMetaObject::invokeMethod( textEdit, "append", Qt::QueuedConnection,
Q_ARG( QString, myString ) );
cjhuitt's right, though: You usually want to declare a signal on the thread and connect it to the append() slot, to get object lifetime management for free (well, for the price of a minor interface change). On a sidenote, the additional argument:
Qt::QueuedConnection ); // <-- This option is important!
from cjhuitt's answer isn't necessary anymore (it was, in Qt <= 4.1), since connect() defaults to Qt::AutoConnection which now (Qt >= 4.2) does the right thing and switches between queued and direct connection mode based on QThread::currentThread() and the thread affinity of the receiver QObject at emit time (instead of sender and receiver affinity at connect time).
In addition to stribika's answer, I often find it easier to use a signal/slot connection. You can specify that it should be a queued connection when you connect it, to avoid problems with the thread's signals being in the context of its owning object.
class mythread : public QThread
{
signals:
void appendText( QString );
public:
mythread(mywindow* win){this->w = win;};
mywindow* w;
void run()
{
emit ( appendText( "Hello" ) );
};
};
int main(int argc, char *argv[])
{
QApplication* a = new QApplication(argc, argv);
mywindow* w = new mywindow();
w->show();
mythread* thr = new mythread(w);
(void)connect( thr, SIGNAL( appendText( QString ) ),
w->ui.textEdit, SLOT( append( QString ) ),
Qt::QueuedConnection ); // <-- This option is important!
thr->start();
return a->exec();
}
You need to use QMetaObject::invokeMethod. For example:
void MyThread::run() {
QMetaObject::invokeMethod(label, SLOT(setText(const QString &)), Q_ARG(QString, "Hello"));
}
(The above code comes from here: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)
I don't think you are allowed to call directly things that results in paint events from any
other threads than the main thread. That will result in a crash.
I think you can use the event loop to call things asynchronously so that the main gui thread picks up and then does the updating from the main thread, which is what cjhuitt suggests.

Scientific Visualization with OpenGL and Qt

I am trying to write an OpenGL visualization program for some scientific data using Qt. I would like to be able to use my existing program unchanged and simply be able to call the glwidget and tell it to update the data at the end of each time step. However in order to run a Qt program it appears you have to use QApplication and then qt.run() which blocks the cpu.
Here is the pseudo code
main()
{
..set up stuff
myVisualizer = new myGLWidget();
for(int i=0;i<1000;i++)
{
..do calculations
myVisualizer.update(new data)
}
}
I realize that I could put all of my existing code in to a QThread and have it send a signal whenever it is done to connect to an update. It would just be easier this way. Does anybody have an idea how to solve this?
If you really don't want to investigate the threaded solution, which would be nicer all around, you can use the special-case timeout with 0. Basically, when you run a timer with a timeout of 0, it runs the appropriate code after processing the events that are currently on the event queue. So, you could set up something like this:
class MyDialog : public QDialog
{
Q_OBJECT
public:
MyDialog()
{
m_step = 0;
QTimer::singleShot( 0, this, SLOT( Process() ) );
}
public slots:
void Process()
{
// do calculations
m_step++;
QTimer::singleShot( 0, this, SLOT( Redraw() ) );
if ( m_step != 1000 )
QTimer::singleShot( 0, this, SLOT( Process() ) );
}
void Redraw() { // do redrawing code here }
private:
int m_steps;
};
And then combine it with the Qt-proper main code:
int main( int argc, char** argv )
{
QApplication app( argc, argv );
MyDialog dialog;
dialog.show();
return ( app.exec() );
}
You can use QThread in your application and do the calculations in a seperate thread.
What you have to do is to subclass the QThread and implement the run() method.
You can create a calculator class and add some signals in that class and connect the signal to your display widget's update slot (in this case QGLWidget::updateGL()).
Here is a rough example: (All you have to is to create a thread and DisplayWidget in your main() function and set the thread's DisplayWidget.)
class Calculator: public QObject
{
Q_OBJECT
public:
Calculator();
void start();
signals:
void updateDisplayWidget(/* you can put the resulting data */);
};
class DisplayWidget(): public QGLWidget
{
Q_OBJECT
// override paint methods here
public slots:
void slotUpdateDisplayWidget(/* you can receive the resulting data*/);
};
class MyThread : public QThread
{
public:
void run();
void setDisplayWidget(DisplayWidget* displayWidget);
private:
Calculator mCalculator;
};
void MyThread::run()
{
mCalculator.start();
exec();
}
MyThread::setDisplayWidget(DisplayWidget* displayWidget)
{
displayWidget->moveToThread(this);
connect(&mCalculator, SIGNAL(updateDisplayWidget()), displayWidget, SLOT(slotUpdateDisplayWidget()));
}

Resources