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

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.

Related

qt5: how to create and display custom qdialog from static function within a qthread

Let's say that you've created a new thread that then calls a static function after it has been started. Within that static function you need to create and display a custom qdialog. How can you create it so that it has no parent and is located in the proper thread?
The constructor sets the parent to 0 but it still reports an error about being unable to create children for a parent in a different thread. Since it's a static function I can't use the "this" object and without "this" I can't retrieve the current thread or thread id. I thought I might be able to call myCustomDialog->moveToThread() but I have no idea how to determine the correct thread from a static function.
If I use one of the QMessageBox static functions everything works fine. For example, calling QMessageBox::information(0, tr("Title"), tr("Message")) doesn't report any errors. How can I code my custom qdialog to function similar to the qmessagebox static function?
Is there any way to retrieve a list of all running threads from the qApp object? Any other suggestions?
static int myFunction();
int myObject::myFunction()
{
myCustomDialog *mcd = new myCustomDialog();
// as soon as I call exec() it reports an error and crashes
mcd->exec();
// QObject: Cannot create children for a parent that is in a different thread.
// can't call mcd->moveToThread() without knowing the current thread
// how can I determine the current thread from this static function?
// if parent = 0 then why is this error occurring?
return 0;
}
myCustomDialog(QWidget *parent = 0);
myCustomDialog::myCustomDialog(QWidget *parent) : QDialog(parent)
{
// create widgets and layout here
}
Don't. Creating QWidget objects from another thread is a bad idea. The Documentation states:
In GUI applications, the main thread is also called the GUI thread
because it's the only thread that is allowed to perform GUI-related
operations.
The way I normally get around this is to emit a signal from my object in the non-GUI thread that's connected to an object living in the main thread (often MainWindow for me). The receiving object then creates the dialog on the main thread.
As mentioned in the other answer, this connection can block your worker thread if needed by establishing the connection type as Qt::BlockingQueuedConnection.
For more information on invoking functions from other threads, see this post.
Sample... You may adapt it to make calls from static functions, but I don't think that it is necesary. It is good practice to work with threads in next way: You should create your dialog in GUI thread and connect it's exec() slot to your signal with Qt::BlockingQueuedConnection
Worker.h
#include <QObject>
class Worker
: public QObject
{
Q_OBJECT
signals:
void showDialog();
public:
Worker( QObject *parent = NULL );
~Worker();
public slots:
void doLongWork();
private:
};
Worker.cpp
#include <QThread>
#include <QMessageBox>
#include <QDebug>
#include <QCoreApplication>
#include <Windows.h>
Worker::Worker( QObject *parent )
: QObject( parent )
{
}
Worker::~Worker()
{
}
void Worker::doLongWork() // You may override QThread::run with same effect, but it is bad practice
{
qDebug() << "Worker thread id = " << QThread::currentThreadId();
::MessageBoxA( NULL, "Click to show dialog in 3 seconds", NULL, 0 );
::Sleep( 3000 );
emit showDialog(); // "Showing" dialog from non-GUI thread. And wait for close
::MessageBoxA( NULL, "Dialog closed!", NULL, 0 );
qApp->quit();
}
main.cpp
#include <QApplication>
#include <QDialog>
#include <QThread>
#include <QDebug>
#include "Worker.h"
int main(int argc, char *argv[])
{
QApplication a( argc, argv );
a.setQuitOnLastWindowClosed( false );
QDialog dlg;
QThread workerThread;
Worker worker;
qDebug() << "Main thread id = " << QThread::currentThreadId();
QObject::connect( &workerThread, SIGNAL( started() ), &worker, SLOT( doLongWork() ) );
QObject::connect( &worker, SIGNAL( showDialog() ), &dlg, SLOT( exec() ), Qt::BlockingQueuedConnection ); // !!!See connection type!!!
worker.moveToThread( &workerThread );
workerThread.start();
return a.exec();
}
Note: WinAPI MessageBoxes are used only to visualize that thread is really waiting for close of dialog.

(Qt) Unusable window after one button click

I have a window with many buttons. Each one triggers a sub-program (written using the Opencv API). Each sub-program displays images and stuff on windows.
The problem is, when I close these windows (via the little red cross), all the buttons become unclickable. So if I want to launch another program, I'll have to exit the main window and run it again.
In other words, I want to be able to run all the sub-programs without having to start over every time.
Here's the GUI's code :
.cpp
#include "fenprincipale.h"
#include "ui_fenprincipale.h"
#include<highgui.h>
#include<cv.h>
#include <moyenetmedian.h>
#include<morpho.h>
#include<tracking.h>
#include<contour.h>
#include<QApplication>
FenPrincipale::FenPrincipale(QWidget *parent) :
QWidget(parent),
ui(new Ui::FenPrincipale)
{
ui->setupUi(this);
MoyenEtMedian *moyenEtMedian = new MoyenEtMedian;
morpho * mor = new morpho;
tracking * tra= new tracking;
contour * cont= new contour;
QObject::connect(ui->bMoyMed, SIGNAL( clicked() ), moyenEtMedian, SLOT( exec() ), Qt::AutoConnection );
QObject::connect(ui->bMorph, SIGNAL( clicked() ), mor, SLOT( exec() ), Qt::AutoConnection );
QObject::connect(ui->bTrack, SIGNAL( clicked() ), tra, SLOT( exec() ), Qt::AutoConnection );
QObject::connect(ui->bCont, SIGNAL( clicked() ), cont, SLOT( exec() ), Qt::AutoConnection );
}
FenPrincipale::~FenPrincipale()
{
delete ui;
}
.h :
#ifndef FENPRINCIPALE_H
#define FENPRINCIPALE_H
#include <QWidget>
#include <QApplication>
namespace Ui {
class FenPrincipale;
}
class FenPrincipale : public QWidget
{
Q_OBJECT
public:
explicit FenPrincipale(QWidget *parent = 0);
void switch_callback(int);
void execMoyMed (void);
~FenPrincipale();
private:
Ui::FenPrincipale *ui;
};
#endif // FENPRINCIPALE_H
the main class :
#include <QCoreApplication>
#include <QApplication>
#include <QtGui>
#include <QWidget>
#include "fenprincipale.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FenPrincipale fenetre;
fenetre.show();
return a.exec();
}
Slot implementation for "moyenetmedian" :
void MoyenEtMedian::exec(void)
{
const char* name = "Filtres";
IplImage* img = cvLoadImage( "C:/Users/XELTINFO/ProjetVision/image.png" );
IplImage* out = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 3 );
cvNamedWindow( name, 1 );
cvShowImage(name, out);
// Create trackbar
cvCreateTrackbar2( "Filtre", name, &g_switch_value, 1, &MoyenEtMedian::switch_callback, this );
while( 1 ) {
switch( filterInt ){
case 0:
cvSmooth( img, out, CV_BLUR, 7, 7 );
break;
case 1:
cvSmooth( img, out, CV_MEDIAN, 7, 7 );
break;
}
if(filterInt != lastfilterInt){
cvShowImage(name, out);
lastfilterInt = filterInt;
}
if( cvWaitKey( 15 ) == 27 )
break;
}
cvReleaseImage( &img );
cvReleaseImage( &out );
cvDestroyWindow( name );
}
The class declaration :
#ifndef MOYENETMEDIAN_H
#define MOYENETMEDIAN_H
#include "ui_fenprincipale.h"
#include<QObject>
class MoyenEtMedian : public QObject
{
Q_OBJECT
public:
MoyenEtMedian();
static void switch_callback(int position, void*);
public slots :
void exec(void);
};
#endif // MOYENETMEDIAN_H
The class delcarations and slots implementations are very similar for all classes. I'll add the rest if this isn't enough.
You are blocking the event loop in your exec() slot, since it doesn't return immediately. You should instead subclass QWidget and override keyPressEvent() to get keyboard input from Qt's event loop instead of doing the busy-loop you currently have.
So when using Qt with OpenCV, I would setup the polling using Qt's timers instead of a while loop.
There is a pretty good tutorial of using QTimers to interact with OpenCV objects here:
http://www.youtube.com/watch?v=0ONxIy8itRA
Jump to 35 or 38 minutes into it to see how he writes his classes.
Basically, you let Qt do the waiting and timing, instead of having a while loop with a wait call doing the timing.
And if possible, let Qt create the windows, and nest the OpenCV windows into Qt's windows so that Qt can manage the events on the windows.
Hope that helps.

clicked() signal in a button

I've got some problem with signal for a button in Qt 4.8.0. I am using vs 2010 with Qt Designer. I have created a button in Designer with playButton name. But after that I tried to connect clicked() signal (in vs) with my function from CRenderArea (to start a timer), but it seems that it doesn't work (the function start() works when I put it in the constructor, so it's not the problem of the code itself). The code is compiling, the program is executing, but after clicking a button - nothing happens (it should move a line).
I would be really thankful for some help, just started a fun with Qt.
The codes are here (I hope the number of files won't scare you, these are the simplest codes ever :) ):
main.cpp
#include "ts_simulator.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TS_simulator w;
w.show();
return a.exec();
}
ts_simulator.cpp:
TS_simulator::TS_simulator(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
p_map = new CRenderArea();
ui.setupUi( this );
p_map->setParent( ui.renderArea );
// this doesn't work, why?
connect( ui.playButton, SIGNAL( clicked() ), this, SLOT( p_map->start() ) );
}
CRenderArea.h
#pragma once
#include <QtGui>
class CRenderArea : public QWidget {
Q_OBJECT // I think it's necessary?
int x;
QBasicTimer* timer;
public:
CRenderArea();
public slots: // this is necessary too, right?
void start();
private:
void timerEvent( QTimerEvent* );
void paintEvent( QPaintEvent* );
};
and CRenderArea.cpp:
#include "CRenderArea.h"
CRenderArea::CRenderArea() : x( 0 ) {
setBackgroundRole( QPalette::Base );
setMinimumSize( 591, 561 );
setAutoFillBackground( true );
timer = new QBasicTimer();
}
void CRenderArea::timerEvent( QTimerEvent* e ) {
++x;
update();
}
void CRenderArea::paintEvent( QPaintEvent* p ) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::darkGray);
painter.drawLine(2+x/10, 8, 60, 300);
}
void CRenderArea::start() {
timer->start( 0, this );
}
Greets.
The problem is here:
connect( ui.playButton, SIGNAL( clicked() ), this, SLOT( p_map->start() ) );
if p_map is the receiver of the signal, and it has Q_OBJECT, it should be written as:
connect( ui.playButton, SIGNAL( clicked() ), p_map, SLOT(start()) );

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

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.

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.

Resources