226 lines
8.2 KiB
C++
Raw Permalink Normal View History

2025-12-10 00:01:32 +08:00
#include "Widget.h"
#include "ui_Widget.h"
#include <QFileDialog>
#include <QDebug>
#include <QMessageBox>
#include <QDateTime>
#include <QLabel>
#include <QMdiSubWindow>
/// \~chinese 用于限制显示帧率的时间戳 \~english Time stamp to limit the rate of display
QMap<QString, QDateTime> gLastDisplay;
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ui->tableWidget_cameras->setSelectionBehavior(QAbstractItemView::SelectRows);
mCtrlThread = DeviceControlThread::instance();
connect(mCtrlThread, &DeviceControlThread::signalControlFinish, this, &Widget::onControlFinish);
connect(mCtrlThread, &DeviceControlThread::signalSelectGrabConfig, this, &Widget::onSelectGrabConfig, Qt::BlockingQueuedConnection);
/// \~chinese 连接采图回调到主线程,需要等待显示完成后再释放缓冲区数据。主线程的耗时操作影响界面刷新时,会对采集速度造成影响
connect(mCtrlThread, &DeviceControlThread::signalImageGrabbed, this, &Widget::onImageGrabbed, Qt::BlockingQueuedConnection);
ui->tableWidget_cameras->setColumnCount(3);
ui->tableWidget_cameras->setHorizontalHeaderLabels({"Name", "Open Status", "Grab Status"});
ui->tableWidget_cameras->setEditTriggers(QTableWidget::NoEditTriggers);
}
Widget::~Widget()
{
delete ui;
}
/// \~chinese 扫描相机按钮的槽函数 \~english Slot function of probe push button
void Widget::on_pushButton_probe_clicked()
{
mCtrlThread->StartProbe();
}
/// \~chinese 打开相机按钮的槽函数 \~english Slot function of open camera push button
void Widget::on_pushButton_openCamera_clicked()
{
QList<int> select_index;
for (int i = 0; i < ui->tableWidget_cameras->rowCount(); ++i) {
if (ui->tableWidget_cameras->item(i,0)->checkState() != Qt::Checked)
continue;
select_index << i;
mCtrlThread->StartOpen(i);
}
if (select_index.isEmpty()) {
QMessageBox::critical(this, "Critical", "Please select the camera to operate");
return;
}
}
/// \~chinese 开始采集按钮的槽函数 \~english Slot function of start acquisitio push button
void Widget::on_pushButton_startGrab_clicked()
{
QList<int> select_index;
for (int i = 0; i < ui->tableWidget_cameras->rowCount(); ++i) {
if (ui->tableWidget_cameras->item(i, 0)->checkState() != Qt::Checked)
continue;
select_index << i;
mCtrlThread->StartGrab(i);
}
if (select_index.isEmpty()) {
QMessageBox::critical(this, "Critical", "Please select the camera to operate");
return;
}
}
/// \~chinese 关闭相机按钮的槽函数 \~english Slot function of close camera push button
void Widget::on_pushButton_closeCamera_clicked()
{
QList<int> select_index;
for (int i = 0; i < ui->tableWidget_cameras->rowCount(); ++i) {
if (ui->tableWidget_cameras->item(i, 0)->checkState() != Qt::Checked)
continue;
select_index << i;
mCtrlThread->StartClose(i);
}
if (select_index.isEmpty()) {
QMessageBox::critical(this, "Critical", "Please select the camera to operate");
return;
}
}
/// \~chinese 停止采集按钮的槽函数 \~english Slot function of stop acquisitio push button
void Widget::on_pushButton_stopGrab_clicked()
{
QList<int> select_index;
for (int i = 0; i < ui->tableWidget_cameras->rowCount(); ++i) {
if (ui->tableWidget_cameras->item(i, 0)->checkState() != Qt::Checked)
continue;
select_index << i;
mCtrlThread->StartStopGrab(i);
}
if (select_index.isEmpty()) {
QMessageBox::critical(this, "Critical", "Please select the camera to operate");
return;
}
}
void Widget::onControlFinish(int nIndex, ITK_DEVICE_CONTROL_TYPE nType, bool bSuccess)
{
QString devName;
if (nType != ITK_DEVICE_CONTROL_PROBE)
devName = ui->tableWidget_cameras->item(nIndex, 0)->text();
switch (nType) {
case ITK_DEVICE_CONTROL_PROBE:
{
if (!bSuccess) {
QMessageBox::critical(this, "Critical", "Probe failed!");
return;
}
QStringList camList = mCtrlThread->GetDeviceList();
ui->tableWidget_cameras->clearContents();
ui->tableWidget_cameras->setRowCount(camList.size());
for (int i = 0; i < camList.size(); ++i) {
ui->tableWidget_cameras->setItem(i, 0, new QTableWidgetItem(camList[i]));
ui->tableWidget_cameras->setItem(i, 1, new QTableWidgetItem("0"));
ui->tableWidget_cameras->setItem(i, 2, new QTableWidgetItem("0"));
ui->tableWidget_cameras->item(i, 0)->setCheckState(Qt::Checked);
}
}
break;
case ITK_DEVICE_CONTROL_OPEN:
{
if (!bSuccess) {
QMessageBox::critical(this, "Critical", tr("Failed to open camera: %1!").arg(devName));
return;
}
ui->pushButton_probe->setEnabled(!mCtrlThread->IsCamOpened());
ui->tableWidget_cameras->item(nIndex, 1)->setText("1");
// check if exist a sub-window
bool exist = false;
auto list = ui->mdiArea_image->subWindowList();
for (int i = 0; i < list.size(); ++i) {
if (list[i]->windowTitle() != devName)
continue;
exist = true;
break;
}
if (exist)
break;
QLabel* label = new QLabel(ui->mdiArea_image);
label->setWindowTitle(devName);
label->setAttribute(Qt::WA_DeleteOnClose);
label->setMinimumSize(240, 160);
ui->mdiArea_image->addSubWindow(label, Qt::WindowMinMaxButtonsHint); // disable close manually
label->show();
}
break;
case ITK_DEVICE_CONTROL_CLOSE:
{
if (!bSuccess) {
QMessageBox::critical(this, "Critical", tr("Failed to close camera: %1!").arg(devName));
return;
}
ui->pushButton_probe->setEnabled(!mCtrlThread->IsCamOpened());
ui->tableWidget_cameras->item(nIndex, 1)->setText("0");
ui->tableWidget_cameras->item(nIndex, 2)->setText("0");
auto list = ui->mdiArea_image->subWindowList();
for (int i = 0; i < list.size(); ++i) {
if (list[i]->windowTitle() != devName)
continue;
list[i]->close();
break;
}
}
break;
case ITK_DEVICE_CONTROL_GRAB:
if (!bSuccess) {
QMessageBox::critical(this, "Critical", tr("Failed to start grab: %1!").arg(devName));
return;
}
ui->tableWidget_cameras->item(nIndex, 2)->setText("1");
break;
case ITK_DEVICE_CONTROL_STOP:
if (!bSuccess) {
QMessageBox::critical(this, "Critical", tr("Failed to stop grab: %1!").arg(devName));
return;
}
ui->tableWidget_cameras->item(nIndex, 2)->setText("0");
break;
}
}
QString Widget::onSelectGrabConfig(const QString &devName)
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Select Vlcf for %1").arg(devName), "", "*.vlcf");
if (fileName.isEmpty()) {
QMessageBox::information(this, "Info", tr("No config file selected, %1 will grab with default paramter").arg(devName));
}
return fileName;
}
void Widget::onImageGrabbed(const QString& devName, const QImage &img)
{
QDateTime now = QDateTime::currentDateTime();
/// \~chinese 控制刷新帧率小于5 \~english Limit the rate of diaply less than 5
if (gLastDisplay[devName].isValid() && gLastDisplay[devName].msecsTo(now) < 200)
return;
gLastDisplay[devName] = now;
QLabel* label = nullptr;
auto list = ui->mdiArea_image->subWindowList();
for (int i = 0; i < list.size(); ++i) {
if (list[i]->windowTitle() != devName)
continue;
label = qobject_cast<QLabel*>(list[i]->widget());
}
if (label == nullptr)
return;
label->setPixmap(QPixmap::fromImage(img).scaled(label->size()));
}