Image not getting displayed/update in QLabel using SIGNAL-SLOT in ROS node - multithreading

I am implementing the Qt code in ROS node. I have a header file in which i have defined all the members, Q_SIGNAL and Q_SLOTS. In my .cpp file i want to display an image when i press a button(assignButton). But when i press the button, nothing shows up.
To test whether the connect function is working properly or not, i tried to display an image in the imageLabel which is stored in my laptop..and it worked.
PROBLEM:- I am taking the images from simulator in ROS through the
void SelectionInterface::imageCallback(const sensor_msgs::ImageConstPtr& msg) and i want to display those images in imageLabel by SIGNAL-SLOT..but its not getting displayed..no error
My code is following:-
1. Header file-- SelectionInterface.h
class SelectionInterface : public QMainWindow
{
Q_OBJECT
public:
SelectionInterface(ros::NodeHandle *nh, RosThread *rt, QMainWindow *parent = 0);
~SelectionInterface();
private:
RosThread *rosThread;
ros::NodeHandle *nodeHandle;
// ROS Subscribers
image_transport::Subscriber image_sub;
void imageCallback(const sensor_msgs::ImageConstPtr& msg);
// More Memberfunctions and Variables
QWidget *newCentralWidget;
QPushButton *quitButton;
QPushButton *assignButton;
QVBoxLayout *layout;
QLabel *imageLabel;
QImage image;
// ...
protected:
void closeEvent(QCloseEvent *event);
Q_SIGNALS:
void windowClosedSignal();
private Q_SLOTS:
void quitInterface();
void assignImage();//QImage
};
2. .cpp file
#include "SelectionInterface.h"
#include <iostream>
SelectionInterface::SelectionInterface(ros::NodeHandle *nh, RosThread *rt, QMainWindow *parent): QMainWindow (parent)
{
rosThread = rt;
nodeHandle = nh;
// Subscribing and Publishing
image_transport::ImageTransport it(*nh);
// Setup user interface here
newCentralWidget = new QWidget;
quitButton = new QPushButton("Quit");
assignButton = new QPushButton("Assign Image");
layout = new QVBoxLayout;
imageLabel = new QLabel;
imageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(imageLabel);
layout->addWidget(quitButton);
layout->addWidget(assignButton);
newCentralWidget->setLayout(layout);
this->setCentralWidget(newCentralWidget);
// Signal-Slot Connections
connect(this, SIGNAL(windowClosedSignal()), this, SLOT(quitInterface()));
connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
connect(assignButton, SIGNAL(clicked()), this, SLOT(assignImage()));
// ...
}
void SelectionInterface::imageCallback(const sensor_msgs::ImageConstPtr& msg)
{
QImage image(&(msg->data[0]), msg->width, msg->height, QImage::Format_RGB888);
}
SelectionInterface::~SelectionInterface()
{
//destructer (leave empty)
}
void SelectionInterface::closeEvent(QCloseEvent *event)
{
Q_EMIT windowClosedSignal();
}
void SelectionInterface::quitInterface()
{
rosThread->stop();
rosThread->wait();
std::cout << "Good bye.\n";
}
void SelectionInterface::assignImage()
{
imageLabel->setPixmap(QPixmap::fromImage(image));
}

I doubt QImage can replace ~ to your home path. Try to specify full path e.g. '/home/user/Pictures/wallpapers/buddha.jpg'.

Related

QT programming, QtConcurrent run function

I have a program which has class MainWindow that inherited from QMainWindow.
I want to run a specific function in a new thread.
Since I can't inherit from QThread so the best solution is to use QtConcurrent.
I stored QtConcurrent result in a QFuture but as mentioned in the QT documentation, the result of QtConcurrent can not be canceled by QFuture::cancel.
I see some questions like mine but the answers are to create a class which inherit from QThread that I can't.
So what is the solution?
Here is my codes:
mainwindow.h:
using namespace std;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
...
private:
Ui::MainWindow *ui;
...
QFuture<void> future;
QFutureWatcher< void > futureWatcher;
QPushButton *stop_pushButton_=new QPushButton;
private slots:
...
void on_graph_pushButton_clicked();
void generateGraph();
void stopPushButtonClicked();
};
mainwindow.cpp:
void MainWindow::stopPushButtonClicked()
{
futureWatcher.setFuture(future);
futureWatcher.cancel();
futureWatcher.waitForFinished();
}
...
void MainWindow::on_graph_pushButton_clicked()
{
loadingOn();
future = QtConcurrent::run(this,&MainWindow::generateGraph);
}
void MainWindow::generateGraph()
{
InsertLogs::getInstance()->printStatus(USER_GENERATE_GRAPH);
GenGraph* gr=new GenGraph;
connect(this,&MainWindow::loadingOffSignal,this,&MainWindow::loadingOff);
graphType_=gr->generateGraph(persons_comboBox_->currentText(),
ui->graphResource1_comboBox->currentText(),
ui->graphResource2_comboBox->currentText(),
ui->graphType_comboBox->currentText());
InsertLogs::getInstance()->printSuccess(SYSTEM_GENERATE_GRAPH);
emit loadingOffSignal();
}
When I click on graph_pushButton, generatedGraph is called in a new thread, but when I click on stop_pushButton the future does not stop and the generatedGraph function executes completely.

MFC on form create event

I have simple FMC dialog form. Can't find how to manage event that should be called on form create moment. Something like onFormCreate like it is in VB or Delphi.
How to create such functionality?
My simple form header:
#pragma once
// CMFCApplicationUPTDlg dialog
class CMFCApplicationUPTDlg : public CDialog
{
// Construction
public:
CMFCApplicationUPTDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
enum { IDD = IDD_MFCAPPLICATIONUPT_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedOk();
afx_msg void OnBnClickedButton1();
};
You want to handle it in the OnInitDialog() member function. At the point that OnInitDialog() is called, the dialog and all of its child windows will have been created. However, the dialog will still be invisible to the user. After exiting OnInitDialog(), the dialog will be shown to the user.
So, it is the place where you would want to do initialization of your dialog.
You need to implement OnInitDialog in your own derived class.
BOOL CMFCApplicationUPTDlg::OnInitDialog()
{
// this will create the controls you defined in the resources.
BOOL retValue = __super::OnInitDialog();
// initialize (or add new controls to ) your dialog content here.
// ...
return retValue;
}

How to call a slot, that belongs to a QThread, within that same QThread?

I have a QThread that starts an external Linux binary. I use connect() to call a slot(), which is part of the QThread, whenever I get an output from that external Linux binary. This seems not to work for me. Can anyone tell me what is wrong in the below code?
class ThreadPowerSubSystem : public QThread
{
public:
ThreadPowerSubSystem(){ }
private slots:
void checkForTwoSecPress()
{
qWarning("button pressed");
}
private:
void run()
{
QProcess *powerProcess = new QProcess();
powerProcess->start("/home/testApp/button");
connect(powerProcess, SIGNAL(readyRead()), this, SLOT(checkForTwoSecPress()));
exec();
}
};
Also I need to call a function to display a dialog inside that slot. Can anyone show me an example on how to do it?

keyboard events OSG (open scene graph)

I would like to know how I can enter keyboard events to control a sphere?I would want a sphere and move it around the screen with keyboard events
OSG uses event handlers. Just create one like this:
// KeyboardEventHandler.h
#pragma once
#include <osgGA/GUIEventHandler>
class KeyHandler : public osgGA::GUIEventHandler
{
public:
KeyHandler()
{}
public:
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&)
{
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::KEYDOWN):
{
// Place your code here...
}
default:
return false;
}
}
virtual void accept(osgGA::GUIEventHandlerVisitor& v)
{
v.visit(*this);
}
};
Now connect it to your view:
m_osgViewer->addEventHandler(new KeyHandler());
You can pass "this"-pointer to KeyboardHandler and call viewer's methods from inside.

Crashing while executing GetParent(). Closing of a modeless dialog box

I am creating a modeless dialog box. The dialog box is called from the menu item of main frame window.
MainFrm.h
CModeless* modeless;
bool modelessDlgOpen;
MainFrm.cpp
void CMainFrame::OnDatabaseMLdlg()
{
// TODO: Add your command handler code here
if (modelessDlgOpen == TRUE)
return;
modelessDlgOpen = TRUE;
modeless = new CModeless(this);
//modeless->Create(IDD_MLDLG, GetDesktopWindow());
modeless->Create(IDD_MLDLG, this);
mbPoll->ShowWindow(SW_SHOW);
}
When menu item is clicked, OnDatabaseMLdlg() function is called and a modeless dialog box with resource ID IDD_MLDLG appears.
The issue is while closing the modeless dialog box.
I am not able to find out the correct method to have a clean closure / destroy of this modeless dialog box. Upon clicking the cross button in right-top corner, which message gets
generated?
My current code which I have tried is as follows. (producing code related only to the closure of the dialog box)
MLDLG.h
#pragma once
#define WM_MLDLG_CLOSED (WM_USER + 555)
// CModeless dialog
class CModeless : public CDialog
{
DECLARE_DYNAMIC(CModeless)
public:
CModeless(CWnd* pParent = NULL); // standard constructor
virtual ~CModeless();
// Dialog Data
enum { IDD = IDD_MLDLG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
virtual BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = NULL);
afx_msg void OnNcDestroy();
virtual void PostNcDestroy();
CWnd* mParent;
afx_msg void OnBnClickedCancel();
};
MLDLG.cpp
void CModeless::OnNcDestroy()
{
CDialog::OnNcDestroy();
// TODO: Add your message handler code here
}
void CModeless::PostNcDestroy()
{
CDialog::PostNcDestroy();
GetParent()->PostMessage(WM_MLDLG_CLOSED,0,0); // **CRASHES HERE**
delete this;
}
void CModeless::OnBnClickedCancel()
{
// TODO: Add your control notification handler code here
//CDialog::OnCancel();
DestroyWindow();
}
Not able to understand what am I doing wrong or what am I missing?
I can provide additional details in case required.
Thanks in advance.
EDIT-20130612: Additional information:
My constructor is as follows:
CModeless::CModeless(CWnd* pParent /*=NULL*/)
: CDialog(CModeless::IDD, pParent)
{
mParent = pParent;
if (mParent == NULL)
{
MessageBox(L"mParent is NULL");
}
else
{
MessageBox(L"mParent is not NULL");
}
}
Here, I have verified that mParent is not NULL.
PostNCDestroy() is called VERY late and most of the useful state of the MFC window is not valid at that point. GetParent() is probably returning NULL, which will cause a crash the way you are using it.
Try moving the PostMessage call to OnDestroy() before calling the base class implementation there.
Another option is to cache the parent's hWnd and call ::PostMessage() on that hWnd;

Resources