PDA

View Full Version : QT label update. Different threads.



hagor
21st March 2017, 20:41
I got stuck with GUI update. I have 2 classes : ControlWidget in main thread and CameraController in the separate thread.


int main(int argc, char **argv)
{
QApplication app(argc, argv);
CameraController *cameraController = new CameraController;;
ControlWidget *main_window = new ControlWidget;
Thread getImageThread;
cameraController->moveToThread(&getImageThread);
getImageThread.start();
QTimer get_images_timer;
QObject::connect(&get_images_timer, SIGNAL(timeout()), cameraController, SLOT(onTimerOut()), Qt::QueuedConnection);
QObject::connect(cameraController, SIGNAL(sendLabel(QImage)), main_window, SLOT(getImage(QImage)), Qt::QueuedConnection);
QObject::connect(&get_images_timer, SIGNAL(timeout()), main_window, SLOT(update()), Qt::QueuedConnection);
get_images_timer.start(2000);
app.exec();
return 0;
}



so every 2 seconds i want to get images from camera thread and send them to main thread (that actionally happens, so I have QImage at the main_window object). Then I want to put this QImage to the cam1 and cam2 QLabels. And here I am stuck:

First: when I use setPixmap() method the QLabel.width() and QLabel.height() are different then image.width() and image.height() or pixmap.width() and pixmap.height().

Second: I can not visualize the QLabel. If I do this->ImageLayout->addWidget(cam1) nothing really happens. this->update doesn't help either.

Shall I have an extra worker for GUI Update?

What am I doing wrong?

Source code for more information :

CameraController.h




class CameraController : public QObject
{
Q_OBJECT

private:
CoreApi::InstanceHandle g_hApi;
CoreApi::DeviceCollectionHandle hDeviceCollection;
CoreApi::DeviceHandle hDevice;
CoreApi::CameraPortHandle first_cam;
Common::FrameHandle frame;

QPixmap pixmap;
QImage image;

public:
CameraController();
~CameraController();
QLabel outLabel;

public slots:
void onTimerOut();

signals:
QImage sendLabel(QImage image);
};


CameraController.cpp


CameraController::CameraController()
{
try
{
this->g_hApi = CoreApi::Instance::initialize();
this->hDeviceCollection = this->g_hApi->deviceCollection();
this->hDevice = hDeviceCollection->device(0);
this->first_cam = hDevice->cameraPort(0);
first_cam->autoConfigure();
first_cam->liveStart();
}
catch (GeneralException& e)
{
std::cout << e.what() << std::endl;
}
}

CameraController::~CameraController()
{
}

void CameraController::onTimerOut()
{
if (this->first_cam->liveFrameReady())
{
this->frame = first_cam->liveFrame();
this->image = QImage((uchar*)this->frame->buffer()->data(), this->frame->dataType()->width(), this->frame->dataType()->height(), QImage::Format::Format_RGB888);
this->image = this->image.scaled(QSize(this->image.width()/10, this->image.height()/10));
std::cout << "width = "<<this->image.width() << "height = " << this->image.height() << std::endl;
emit sendLabel(this->image.copy());
}
}

ControlWidget.h



class ControlWidget :public QDialog
{
Q_OBJECT
private:
QGLCanvas *osCanvas;
QGridLayout *mainLayout;
QGridLayout *buttonLayout;

QVBoxLayout *settingsLayout;
QHBoxLayout *controlLayout;
QListWidget *cameraListWidget, *devicesListWidget;
QLabel *cameraListLabel, *devicesListLabel, *cameraSettingsLabel, *fpsLabel, *shutterLabel;
QHBoxLayout *fpsLayout, *shutterLayout;
QLineEdit *fpsEdit, *shutterEdit;
QPushButton *saveButton, *saveSettingButton, *applySettingsButton, *chooseFolderButton;
QTimer* m_timer;
public:
ControlWidget(QWidget *parent = 0);
~ControlWidget();
QVBoxLayout *imageLayout = new QVBoxLayout;
QLabel *cam1 = new QLabel;
QLabel *cam2 = new QLabel;
QImage *camera_1, *camera_2;
void createWidgets();
public slots:
void getImage(QImage new_frame);
void displayImages();
signals:
void images_loaded();
private slots:
void onTimeout()
{
qDebug() << "Worker::onTimeout get called from controlWidget timer and ?: " << QThread::currentThreadId();
};
};

ControlWidget.cpp



ControlWidget::ControlWidget(QWidget *parent)
{
//this->createWidgets();
this->m_timer = new QTimer;
connect(this->m_timer, SIGNAL(timeout()),this, SLOT(update()));
m_timer->start(1000);
}

ControlWidget::~ControlWidget()
{
delete this->mainLayout;
}

void ControlWidget::createWidgets()
{
this->imageLayout->addWidget(cam1);
this->imageLayout->addWidget(cam2);
this->setLayout(this->imageLayout);
this->show();
}

void ControlWidget::displayImages()
{
QLabel tmp_label ;

std::cout << "************************************************** ******************************" << std::endl;
std::cout <<" camera height = " <<this->camera_1->height() << " camera width = " << this->camera_1->width() << std::endl;
std::cout << "************************************************** ******************************" << std::endl;
QPixmap tmp_pixmap = QPixmap::fromImage(this->camera_1->copy());
std::cout << "PIXMAP WIDTH = " << tmp_pixmap.width() << "Pixmap Height = " << tmp_pixmap.height() <<std::endl;
tmp_label.setGeometry(200, 200, tmp_pixmap.width(), tmp_pixmap.height());
std::cout << "LABELWIDTH = " << tmp_label.width() << "LabelHeight = " << tmp_label.height() << std::endl;
tmp_label.show();
this->cam1 = &tmp_label;
this->cam2 = &tmp_label;
std::cout << "CAM1 Width = " <<this->cam1->width() << std::endl;
this->createWidgets();
}
void ControlWidget::getImage(QImage img)
{
std::cout << "************************************************** ******************************" << std::endl;
std::cout << " img height = " << img.height() << " img width = " << img.width() << std::endl;
std::cout << "************************************************** ******************************" << std::endl;
this->camera_1 = &QImage(img);
this->camera_2 = &QImage(img);
this->displayImages();
}

d_stranz
21st March 2017, 23:09
I don't see any call to main_window->show() in your main(). That should happen just before app.exec().

Edit: Your code is extremely confused. I see now that you call show() in createWidgets(), but this method is commented out.

And this code:



this->camera_1 = &QImage(img);
this->camera_2 = &QImage(img);


is totally wrong. You are creating two QImage instances -on the stack (QImage(img))- and these instance are destroyed immediately when your method exits. So camera_1 and camera_2 are assigned pointer values which become invalid and dangling as soon as the method is done.

To do this correctly, you could change camera_1 and camera_2 from being QImage * to simply QImage and just assign the incoming image to them:



// .h:

QImage camera_1;
QImage camera_2;

// .cpp:

this->camera_1 = img;
this->camera_2 = img;


The same error occurs here:



this->cam1 = &tmp_label;
this->cam2 = &tmp_label;


You are assigning the address of a temporary QLabel variable which gets destroyed as soon as the method exits, so cam1 and cam2 end up pointing to a non-existent QLabel instance.

You need to go back to your C++ textbook and read about variables and scoping.