我是Qt的新手,所以我遇到了GUI更新问题。
我有两个类:主线程中的ControlWidget
和单独线程中的CameraController
。
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;
}
所以每2秒我想从相机线程中获取图像并将它们发送到主线程(动作发生,所以我在main_window对象上有QImage
)。
然后我想把这个QImage放到cam1和cam2 QLabel
。在这里,我被困住了:
首先:当我使用setPixmap()
方法时,QLabel.width()
和QLabel.height()
与image.width()
和image.height()
或pixmap.width()
和{{1}不同}}
第二:我无法想象pixmap.height()
。如果我做QLabel
没有真正发生。 this->ImageLayout->addWidget(cam1)
也无济于事。
我有一个额外的GUI更新工作者吗?我究竟做错了什么?
更多信息的源代码:
CameraController.h
this->update
CameraController.cpp
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);
};
ControlWidget.h
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.cpp
class ControlWidget :public QDialog
{
Q_OBJECT
private:
QGLCanvas *osCanvas;
QGridLayout *mainLayout;
QGridLayout *buttonLayout;
QVBoxLayout *imageLayout, *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();
QLabel *cam1, *cam2;
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();
};
};
答案 0 :(得分:5)
好的,所以你在这里遇到一些设计问题:
tmp_label
已在堆栈上创建,并且会在displayImages
方法结束时被销毁
每次收到新的相机框架时,您都会尝试使用this->imageLayout->addWidget(this->cam1);
将QLabel添加回用户界面。改为在构建窗口小部件时添加一次,然后仅使用cam1->setPixmap(...)
。
也许我错过了,但我看不到你在QLabel中设置图像的位置。这通常使用QLabel::setPixmap
然后:
update()
,当您设置像素图时,QLabel会自动更新this->
Thread
类下面有什么,但是当使用QThread时你不需要传递Qt::QueuedConnection
参数来进行连接,这是自动完成的。QPixmap::save("image.jpg")
或QImage::save("image.jpg")
答案 1 :(得分:1)
除@basslo评论外,不要this->cam1 = &tmp_label;
。当tmp_label
被销毁(它是一个局部变量)时,它将从它所属的布局中删除,因此它将永远不会被实际显示。
使用this->cam1->setPixmap(...)
来分配新图片并定义尺寸政策,以便将构造扩展到扩展(this answer提供有关它的更多信息)。