Qt 将特定信号和插槽连接一次,然后断开连接

Qt 将特定信号和插槽连接一次,然后断开连接,qt,Qt,我将保存一个连续捕获图像的相机的图像。为相机创建一个信号,该信号会持续发送图像,并为主窗口创建一个插槽,该窗口通过单击图像保存按钮保存实时图像。我得到的资料如下: //connection is triggered by button clicking connect(camera, SIGNAL(sendImage(Mat)), this, SLOT(saveImage(Mat)), Qt::UniqueConnection); qDebug()<<"Image saved";

我将保存一个连续捕获图像的相机的图像。为相机创建一个信号,该信号会持续发送图像,并为主窗口创建一个插槽,该窗口通过单击图像保存按钮保存实时图像。我得到的资料如下:

//connection is triggered by button clicking
connect(camera, SIGNAL(sendImage(Mat)), this, SLOT(saveImage(Mat)), Qt::UniqueConnection); 
qDebug()<<"Image saved";

//Here is my slot definition. An image of OpenCV Mat is saved, followed by signal-slot disconnection. 
void MainWindow::saveImage(Mat cvimg)
{
    Mat savedImage;
    savedImage =cvimg.clone();
    imwrite("C:/Debug/Data/Save.jpg", savedImage);
    imshow("SavedImage", savedImage);

    disconnect(camera, SIGNAL(sendImage(Mat)),this, SLOT(saveImage(Mat)));
}
//通过单击按钮触发连接
连接(摄像头、信号(sendImage(Mat))、此、插槽(saveImage(Mat))、Qt::UniqueConnection);

qDebug()虽然我没有发现当前使用的connect/disconnect方法有任何明显的错误或不协调之处,但这里有一些头脑风暴和建议

QObject::blockSignals 一种可能是在
摄像机上使用和调用它。您可以在构造函数中调用
connect
,然后在每次单击按钮和插槽结束时切换
blockSignals

MainWindow::MainWindow(/* QWidget* parent or whatever */)
{
    //  connect called once in constructor
    connect(camera, SIGNAL(sendImage(Mat)), this, SLOT(saveImage(Mat)), Qt::UniqueConnection);
}

void MainWindow::on_saveImageButton_clicked()
{
    camera.blockSignals(false);
}

void MainWindow::saveImage(Mat cvimg)
{
    //  save/write operations
    //  ...

    //  instead of disconnecting...
    camera.blockSignals(true);
}
但据我所知,这将阻止
摄像机发出的所有
信号。(你可能有其他信号从那里发出。)所以这可能不是一个完全可行的选择

布尔标志 另一种可能是使用私有成员变量
bool saveNextImage
过滤掉之前没有点击按钮的信号

MainWindow::MainWindow(/* QWidget* parent or whatever */)
{
    //  connect called once in constructor
    connect(camera, SIGNAL(sendImage(Mat)), this, SLOT(saveImage(Mat)), Qt::UniqueConnection);
}

void MainWindow::on_saveImageButton_clicked()
{
    //  toggle flag
    saveNextImage = true;
}

void MainWindow::saveImage(Mat cvimg)
{
    //  check flag was set
    if (!saveNextImage)
        return;

    //  save/write operations 
    //  ...

    //  instead of disconnecting...
    //  toggle flag
    saveNextImage = false;
}

我觉得这可能有点生涩,但是\_(ツ)_/“一个想法就是一个想法。

虽然我没有发现当前使用的连接/断开连接方法有任何明显的错误或不协调之处,但这里有一些头脑风暴和建议

QObject::blockSignals 一种可能是在
相机上使用并调用它。您可以在构造函数中调用
连接
,然后在每次单击按钮和插槽结束时切换
块信号

MainWindow::MainWindow(/* QWidget* parent or whatever */)
{
    //  connect called once in constructor
    connect(camera, SIGNAL(sendImage(Mat)), this, SLOT(saveImage(Mat)), Qt::UniqueConnection);
}

void MainWindow::on_saveImageButton_clicked()
{
    camera.blockSignals(false);
}

void MainWindow::saveImage(Mat cvimg)
{
    //  save/write operations
    //  ...

    //  instead of disconnecting...
    camera.blockSignals(true);
}
但据我所知,这将阻止
摄像机发出的所有信号(可能还有其他信号)。因此这可能不是一个完全可行的选择

布尔标志 另一种可能是使用私有成员变量
bool saveNextImage
过滤掉之前没有点击按钮的信号

MainWindow::MainWindow(/* QWidget* parent or whatever */)
{
    //  connect called once in constructor
    connect(camera, SIGNAL(sendImage(Mat)), this, SLOT(saveImage(Mat)), Qt::UniqueConnection);
}

void MainWindow::on_saveImageButton_clicked()
{
    //  toggle flag
    saveNextImage = true;
}

void MainWindow::saveImage(Mat cvimg)
{
    //  check flag was set
    if (!saveNextImage)
        return;

    //  save/write operations 
    //  ...

    //  instead of disconnecting...
    //  toggle flag
    saveNextImage = false;
}

我觉得这可能有点生涩,但是\_(ツ)_/“一个想法就是一个想法。

这是一个XY问题:你不应该弄乱短暂的联系,因为它们不应该这样使用。我想到了几种解决方案

您可以缓存相机的图像,并保存缓存的值:

Q_DECLARE_METATYPE(cv::Mat)

const char kImageCache[] = "imageCache";

// connect once, as soon as you have the camera available
connect(camera, &Camera::sendImage, [camera](const cv::Mat &image){
  camera->setProperty(kImageCache, image);
});
connect(saveAction, &QAction::triggered, camera, [camera]{
  auto const image = camera->property(kImageCache).value<cv::Mat>();
  cv::imshow("Saved Image", image);
  QtConcurrent::run([image]{
    static std::atomic_bool saving;
    static bool not_saving;
    if (saving.compare_exchange_strong(not_saving, true)) {
      cv::imwrite("foo", image);
      saving.store(not_saving);
    }
  });
});
同时保存映像是一个好主意:否则,在GUI线程中执行缓慢的磁盘I/O操作会破坏用户体验


最后:克隆
cv::Mat
通常是不必要的:该类型的全部要点是它的引用计数并隐式共享-它是一个写时复制类型。这在这方面就像
QImage

这是一个XY问题:你不应该弄乱短暂的连接,因为它们不是u就这样,我想到了几个解决方案

您可以缓存相机的图像,并保存缓存的值:

Q_DECLARE_METATYPE(cv::Mat)

const char kImageCache[] = "imageCache";

// connect once, as soon as you have the camera available
connect(camera, &Camera::sendImage, [camera](const cv::Mat &image){
  camera->setProperty(kImageCache, image);
});
connect(saveAction, &QAction::triggered, camera, [camera]{
  auto const image = camera->property(kImageCache).value<cv::Mat>();
  cv::imshow("Saved Image", image);
  QtConcurrent::run([image]{
    static std::atomic_bool saving;
    static bool not_saving;
    if (saving.compare_exchange_strong(not_saving, true)) {
      cv::imwrite("foo", image);
      saving.store(not_saving);
    }
  });
});
同时保存映像是一个好主意:否则,在GUI线程中执行缓慢的磁盘I/O操作会破坏用户体验


最后:克隆
cv::Mat
通常是不必要的:该类型的全部要点是它的引用计数并隐式共享-它是一个写时拷贝类型。在这方面就像
QImage
一样。

您如何/何时调用
connect(camera…Qt::UniqueConnection)
?我想应该是在单击“保存”按钮时,但没有明确说明。我想听听您的意见。:-@TrebuchetMS:您说得对。我已通过post更新。您是如何/何时拨打
连接(摄像头…Qt::UniqueConnection)的
?我想应该是在单击“保存”按钮时,但没有明确说明。我想听听你的意见。:-@TrebuchetMS:你说得对。我已经通过邮件更新了。