#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include "base/HGTime.h" #include "base/HGUtility.h" #include "base/HGBase64.h" #include "base/HGCrash.h" #include "imgproc/HGImgProc.h" #include "imgproc/HGOCR.h" #include "huagao/hgscanner_error.h" #include "dialog_scaninfo.h" #include "form_saveparam.h" #include "sqlite3.h" #include "cJSON.h" #include "HGString.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_dlgAdd(nullptr) , m_dlgScanInfo(nullptr) , m_devHandle(nullptr) , m_scanning(false) , m_dpi(200) , m_scanFileName("") , m_scanImgFmtWriter(nullptr) , m_ocrMsgPump(nullptr) , m_ocrThread(nullptr) , m_timerId(-1) { ui->setupUi(this); this->setWindowIcon(QIcon(":images/image_rsc/png/logo.png")); HGBase_RegisterCrashFunc(CrashFunc, this); ui->pushButtonScan->setEnabled(false); ui->pushButtonAdd->setEnabled(false); ui->pushButtonModify->setEnabled(false); m_trayIcon = new QSystemTrayIcon(this); m_trayIcon->setIcon(QIcon(":images/image_rsc/png/logo.png")); m_trayIcon->show(); m_trayIcon->setToolTip(tr("Scan Tool")); qRegisterMetaType("QSystemTrayIcon::ActivationReason"); connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::on_trayActivated); m_showAction = new QAction(tr("Show"), this); connect(m_showAction, &QAction::triggered, this, &MainWindow::on_showMainWindowDlg); m_quitAction = new QAction(tr("Exit"), this); connect(m_quitAction, &QAction::triggered, this, &QCoreApplication::quit); //应用程序的退出 //创建菜单,添加菜单项 m_trayIconMenu = new QMenu(this); m_trayIconMenu->addAction(m_showAction); //m_trayIconMenu->addSeparator(); //分割线 //m_trayIconMenu->addAction(m_quitAction); //给系统托盘添加右键菜单 m_trayIcon->setContextMenu(m_trayIconMenu); ui->tableWidget->setColumnCount(4); ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableWidget->setStyleSheet("selection-background-color:rgb(0, 120, 215)"); ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableWidget->horizontalHeader()->setFixedHeight(40); ui->tableWidget->horizontalHeader()->setStretchLastSection(true); ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem(tr("Device Type"))); ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Button Id"))); ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Device Config"))); ui->tableWidget->setHorizontalHeaderItem(3, new QTableWidgetItem(tr("Save Param"))); ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); ui->tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); ui->tableWidget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); LoadCfg(); ui->tableWidget->setRowCount((int)m_vScanParams.size()); for (int index = 0; index < (int)m_vScanParams.size(); ++index) { ui->tableWidget->setRowHeight(index, 30); ui->tableWidget->setItem(index, 0, new QTableWidgetItem(QString(m_vScanParams[index].deviceType.c_str()))); ui->tableWidget->item(index, 0)->setTextAlignment(Qt::AlignCenter); ui->tableWidget->item(index, 0)->setFlags(ui->tableWidget->item(index, 0)->flags() & ~Qt::ItemIsEditable); QStringList btnTypeStr = {tr("Manual"), tr("Button 1"), tr("Button 2"), tr("Button 3"), tr("Button 4"), tr("Button 5")}; ui->tableWidget->setItem(index, 1, new QTableWidgetItem(btnTypeStr[m_vScanParams[index].buttonId])); ui->tableWidget->item(index, 1)->setTextAlignment(Qt::AlignCenter); ui->tableWidget->item(index, 1)->setFlags(ui->tableWidget->item(index, 1)->flags() & ~Qt::ItemIsEditable); ui->tableWidget->setItem(index, 2, new QTableWidgetItem(GetDesc(m_vScanParams[index].deviceConfigs))); ui->tableWidget->item(index, 2)->setTextAlignment(Qt::AlignCenter); ui->tableWidget->item(index, 2)->setFlags(ui->tableWidget->item(index, 2)->flags() & ~Qt::ItemIsEditable); ui->tableWidget->setItem(index, 3, new QTableWidgetItem(GetDesc(m_vScanParams[index].saveParam))); ui->tableWidget->item(index, 3)->setTextAlignment(Qt::AlignCenter); ui->tableWidget->item(index, 3)->setFlags(ui->tableWidget->item(index, 3)->flags() & ~Qt::ItemIsEditable); } ui->tableWidget->selectRow(0); m_dlgScanInfo = new Dialog_ScanInfo(this); connect(this, SIGNAL(deviceArrive(QString)), this, SLOT(on_deviceArrive(QString))); connect(this, SIGNAL(deviceRemove(QString)), this, SLOT(on_deviceRemove(QString))); connect(this, SIGNAL(keyPress(unsigned int)), this, SLOT(on_keyPress(unsigned int))); connect(this, SIGNAL(scanWorking()), this, SLOT(on_scanWorking())); connect(this, SIGNAL(scanInfo(QString, bool)), this, SLOT(on_scanInfo(QString, bool))); connect(this, SIGNAL(scanImage(unsigned int)), this, SLOT(on_scanImage(unsigned int))); connect(this, SIGNAL(scanFinish()), this, SLOT(on_scanFinish())); connect(this, SIGNAL(saneEventCloseDevice(void*, bool)), this, SLOT(on_saneEventCloseDevice(void*, bool))); SANE_Int version_code = 0; sane_init_ex(&version_code, sane_ex_callback, this); } MainWindow::~MainWindow() { assert(nullptr == m_dlgAdd); if (NULL != m_devHandle) { StopScan(); sane_close(m_devHandle); m_devHandle = NULL; m_devName.clear(); } sane_exit(); delete m_dlgScanInfo; delete ui; } bool MainWindow::FindScanParam(const std::string &deviceType, unsigned int buttonId, int ignoreIndex) { for (int i = 0; i < (int)m_vScanParams.size(); ++i) { if (deviceType == m_vScanParams[i].deviceType && buttonId == m_vScanParams[i].buttonId) { if (-1 == ignoreIndex) // 表示均不忽略 { return true; } else if (i != ignoreIndex) { return true; } } } return false; } void MainWindow::StopScan() { if (m_scanning) { assert(NULL != m_devHandle); sane_cancel(m_devHandle); m_scanning = false; m_quitAction->setEnabled(true); ui->pushButtonAdd->setEnabled(true); ui->pushButtonModify->setEnabled(true); ui->pushButtonRemove->setEnabled(true); ui->comboBox->setEnabled(true); ui->pushButtonScan->setEnabled(true); m_dpi = 200; } } std::vector MainWindow::MakeDeviceConfigs(const std::string &str) { std::vector deviceConfigs; cJSON* json = cJSON_Parse(str.c_str()); if (NULL != json) { cJSON* p = json->child; while (NULL != p) { if (0 != strcmp(p->string, "device_configs")) { p = p->next; continue; } if (p->type != cJSON_Array) { break; } cJSON* pEx = p->child; while (NULL != pEx) { if (pEx->type != cJSON_Object) { pEx = pEx->next; continue; } std::string name; int valueType = 0; std::string stringValue; int intValue = 0; double doubleValue = 0; bool boolValue = false; cJSON* pEx2 = pEx->child; while (NULL != pEx2) { if (0 == strcmp(pEx2->string, "name") && pEx2->type == cJSON_String) { name = pEx2->valuestring; } else if (0 == strcmp(pEx2->string, "value")) { if (pEx2->type == cJSON_String) { stringValue = pEx2->valuestring; } else if (pEx2->type == cJSON_Number) { intValue = pEx2->valueint; doubleValue = pEx2->valuedouble; } else if (pEx2->type == cJSON_True) { boolValue = true; } else if (pEx2->type == cJSON_False) { boolValue = false; } } else if (0 == strcmp(pEx2->string, "value_type") && pEx2->type == cJSON_Number) { valueType = pEx2->valueint; } pEx2 = pEx2->next; } DeviceConfig deviceConfig; deviceConfig.name = name; deviceConfig.valueType = valueType; if (1 == deviceConfig.valueType) deviceConfig.stringValue = stringValue; else if (2 == deviceConfig.valueType) deviceConfig.intValue = intValue; else if (3 == deviceConfig.valueType) deviceConfig.doubleValue = doubleValue; else if (4 == deviceConfig.valueType) deviceConfig.boolValue = boolValue; else if (5 == deviceConfig.valueType) { HGSize length = 0; HGBase_Base64Decode((const HGByte*)stringValue.c_str(), stringValue.size(), NULL, &length); if (length == sizeof(SANE_Gamma)) { HGBase_Base64Decode((const HGByte*)stringValue.c_str(), stringValue.size(), (HGByte*)&deviceConfig.gammaValue, &length); } } deviceConfigs.push_back(deviceConfig); pEx = pEx->next; } break; } cJSON_Delete(json); } return deviceConfigs; } std::string MainWindow::GetDeviceConfigsStr(const std::vector &deviceConfigs) { std::string str; cJSON* json = cJSON_CreateObject(); if (NULL != json) { cJSON* array = cJSON_CreateArray(); for (int i = 0; i < deviceConfigs.size(); ++i) { cJSON* obj = cJSON_CreateObject(); cJSON_AddItemToObject(obj, "name", cJSON_CreateString(deviceConfigs[i].name.c_str())); cJSON_AddItemToObject(obj, "value_type", cJSON_CreateNumber(deviceConfigs[i].valueType)); if (1 == deviceConfigs[i].valueType) { cJSON_AddItemToObject(obj, "value", cJSON_CreateString(deviceConfigs[i].stringValue.c_str())); } else if (2 == deviceConfigs[i].valueType) { cJSON_AddItemToObject(obj, "value", cJSON_CreateNumber(deviceConfigs[i].intValue)); } else if (3 == deviceConfigs[i].valueType) { cJSON_AddItemToObject(obj, "value", cJSON_CreateNumber(deviceConfigs[i].doubleValue)); } else if (4 == deviceConfigs[i].valueType) { cJSON_AddItemToObject(obj, "value", deviceConfigs[i].boolValue ? cJSON_CreateTrue() : cJSON_CreateFalse()); } else if (5 == deviceConfigs[i].valueType) { HGSize base64Size = 0; HGBase_Base64Encode((const HGByte*)&deviceConfigs[i].gammaValue, sizeof(SANE_Gamma), nullptr, &base64Size); char *base64 = (char *)malloc(base64Size + 1); HGBase_Base64Encode((const HGByte*)&deviceConfigs[i].gammaValue, sizeof(SANE_Gamma), (HGByte*)base64, &base64Size); base64[base64Size] = 0; cJSON_AddItemToObject(obj, "value", cJSON_CreateString(base64)); free(base64); } cJSON_AddItemToArray(array, obj); } cJSON_AddItemToObject(json, "device_configs", array); char* resp = cJSON_Print(json); if (NULL != resp) { str = resp; free(resp); } cJSON_Delete(json); } return str; } SaveParam MainWindow::MakeSaveParam(const std::string &str) { SaveParam saveParam = Form_SaveParam::GetDefSaveParam(); cJSON* json = cJSON_Parse(str.c_str()); if (NULL != json) { cJSON* p = json->child; while (NULL != p) { if (0 != strcmp(p->string, "save_param")) { p = p->next; continue; } if (p->type != cJSON_Object) { break; } cJSON* pEx = p->child; while (NULL != pEx) { if (0 == strcmp(pEx->string, "save_path") && pEx->type == cJSON_String) { saveParam.savePath = Utf8ToStdString(pEx->valuestring); } else if (0 == strcmp(pEx->string, "use_subfolder_by_time") && pEx->type == cJSON_True) { saveParam.isUseSubfolderByTime = true; } else if (0 == strcmp(pEx->string, "use_subfolder_by_time") && pEx->type == cJSON_False) { saveParam.isUseSubfolderByTime = false; } else if (0 == strcmp(pEx->string, "use_subfolder_by_blank_pages") && pEx->type == cJSON_True) { saveParam.isUseSubfolderByBlankPages = true; } else if (0 == strcmp(pEx->string, "use_subfolder_by_blank_pages") && pEx->type == cJSON_False) { saveParam.isUseSubfolderByBlankPages = false; } else if (0 == strcmp(pEx->string, "use_subfolder_by_color") && pEx->type == cJSON_True) { saveParam.isUseSubfolderByColor = true; } else if (0 == strcmp(pEx->string, "use_subfolder_by_color") && pEx->type == cJSON_False) { saveParam.isUseSubfolderByColor = false; } else if (0 == strcmp(pEx->string, "jpeg_quality") && pEx->type == cJSON_Number) { saveParam.jpegQuality = pEx->valueint; } else if (0 == strcmp(pEx->string, "tiff_compression_bw") && pEx->type == cJSON_Number) { saveParam.tiffCompressionBW = pEx->valueint; } else if (0 == strcmp(pEx->string, "tiff_compression") && pEx->type == cJSON_Number) { saveParam.tiffCompression = pEx->valueint; } else if (0 == strcmp(pEx->string, "tiff_quality") && pEx->type == cJSON_Number) { saveParam.tiffQuality = pEx->valueint; } else if (0 == strcmp(pEx->string, "filename_prefix") && pEx->type == cJSON_String) { saveParam.fileNamePrefix = Utf8ToStdString(pEx->valuestring); } else if (0 == strcmp(pEx->string, "filename_start_index") && pEx->type == cJSON_Number) { saveParam.fileNameStartIndex = pEx->valueint; } else if (0 == strcmp(pEx->string, "filename_digits") && pEx->type == cJSON_Number) { saveParam.fileNameDigits = pEx->valueint; } else if (0 == strcmp(pEx->string, "filename_odd_even_type") && pEx->type == cJSON_Number) { saveParam.fileNameOddEvenType = pEx->valueint; } else if (0 == strcmp(pEx->string, "filename_ext") && pEx->type == cJSON_String) { saveParam.fileNameExt = Utf8ToStdString(pEx->valuestring); } else if (0 == strcmp(pEx->string, "ocr") && pEx->type == cJSON_True) { saveParam.isOcr = true; } else if (0 == strcmp(pEx->string, "ocr") && pEx->type == cJSON_False) { saveParam.isOcr = false; } else if (0 == strcmp(pEx->string, "save_as_multi_page") && pEx->type == cJSON_True) { saveParam.isSaveAsMultiPage = true; } else if (0 == strcmp(pEx->string, "save_as_multi_page") && pEx->type == cJSON_False) { saveParam.isSaveAsMultiPage = false; } else if (0 == strcmp(pEx->string, "multi_pages_type") && pEx->type == cJSON_Number) { saveParam.multiPagesType = pEx->valueint; } else if (0 == strcmp(pEx->string, "custom_multi_pages") && pEx->type == cJSON_Number) { saveParam.customMultiPages = pEx->valueint; } pEx = pEx->next; } break; } cJSON_Delete(json); } return saveParam; } std::string MainWindow::GetSaveParamStr(const SaveParam &saveParam) { std::string str; cJSON* json = cJSON_CreateObject(); if (NULL != json) { cJSON* obj = cJSON_CreateObject(); cJSON_AddItemToObject(obj, "save_path", cJSON_CreateString(StdStringToUtf8(saveParam.savePath).c_str())); cJSON_AddItemToObject(obj, "use_subfolder_by_time", saveParam.isUseSubfolderByTime ? cJSON_CreateTrue() : cJSON_CreateFalse()); cJSON_AddItemToObject(obj, "use_subfolder_by_blank_pages", saveParam.isUseSubfolderByBlankPages ? cJSON_CreateTrue() : cJSON_CreateFalse()); cJSON_AddItemToObject(obj, "use_subfolder_by_color", saveParam.isUseSubfolderByColor ? cJSON_CreateTrue() : cJSON_CreateFalse()); cJSON_AddItemToObject(obj, "jpeg_quality", cJSON_CreateNumber(saveParam.jpegQuality)); cJSON_AddItemToObject(obj, "tiff_compression_bw", cJSON_CreateNumber(saveParam.tiffCompressionBW)); cJSON_AddItemToObject(obj, "tiff_compression", cJSON_CreateNumber(saveParam.tiffCompression)); cJSON_AddItemToObject(obj, "tiff_quality", cJSON_CreateNumber(saveParam.tiffQuality)); cJSON_AddItemToObject(obj, "filename_prefix", cJSON_CreateString(StdStringToUtf8(saveParam.fileNamePrefix).c_str())); cJSON_AddItemToObject(obj, "filename_start_index", cJSON_CreateNumber(saveParam.fileNameStartIndex)); cJSON_AddItemToObject(obj, "filename_digits", cJSON_CreateNumber(saveParam.fileNameDigits)); cJSON_AddItemToObject(obj, "filename_odd_even_type", cJSON_CreateNumber(saveParam.fileNameOddEvenType)); cJSON_AddItemToObject(obj, "filename_ext", cJSON_CreateString(StdStringToUtf8(saveParam.fileNameExt).c_str())); cJSON_AddItemToObject(obj, "ocr", saveParam.isOcr ? cJSON_CreateTrue() : cJSON_CreateFalse()); cJSON_AddItemToObject(obj, "save_as_multi_page", saveParam.isSaveAsMultiPage ? cJSON_CreateTrue() : cJSON_CreateFalse()); cJSON_AddItemToObject(obj, "multi_pages_type", cJSON_CreateNumber(saveParam.multiPagesType)); cJSON_AddItemToObject(obj, "custom_multi_pages", cJSON_CreateNumber(saveParam.customMultiPages)); cJSON_AddItemToObject(json, "save_param", obj); char* resp = cJSON_Print(json); if (NULL != resp) { str = resp; free(resp); } cJSON_Delete(json); } return str; } void MainWindow::LoadCfg() { m_vScanParams.clear(); HGChar cfgPath[256]; HGBase_GetConfigPath(cfgPath, 256); char dbPath[256]; sprintf(dbPath, "%s%s", cfgPath, "config.db"); sqlite3 *sqlite = nullptr; sqlite3_open_v2(dbPath, &sqlite, SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL); if (NULL == sqlite) { return; } sqlite3_stmt* stmt = NULL; char sql[256]; sprintf(sql, "select * from scan_params"); int ret = sqlite3_prepare(sqlite, sql, -1, &stmt, NULL); if (0 != ret) { sqlite3_close(sqlite); return; } ret = sqlite3_step(stmt); while (SQLITE_ROW == ret) { int id = sqlite3_column_int(stmt, 0); const char* deviceType = (const char*)sqlite3_column_text(stmt, 1); int buttonId = sqlite3_column_int(stmt, 2); const char* deviceConfigs = (const char*)sqlite3_column_text(stmt, 3); const char* saveParam = (const char*)sqlite3_column_text(stmt, 4); ScanParam scanParam; scanParam.deviceType = deviceType; scanParam.buttonId = buttonId; scanParam.deviceConfigs = MakeDeviceConfigs(deviceConfigs); scanParam.saveParam = MakeSaveParam(saveParam); m_vScanParams.push_back(scanParam); ret = sqlite3_step(stmt); } ret = sqlite3_finalize(stmt); assert(0 == ret); sqlite3_close(sqlite); } void MainWindow::SaveCfg() { HGChar cfgPath[256]; HGBase_GetConfigPath(cfgPath, 256); HGBase_CreateDir(cfgPath); char dbPath[256]; sprintf(dbPath, "%s%s", cfgPath, "config.db"); HGBase_DeleteFile(dbPath); sqlite3 *sqlite = nullptr; sqlite3_open_v2(dbPath, &sqlite, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL); if (NULL == sqlite) { return; } int ret = sqlite3_exec(sqlite, "create table scan_params (id integer primary key autoincrement, device_type text, " "button_id integer, device_configs text, save_param text)", NULL, NULL, NULL); if (0 != ret) { sqlite3_close(sqlite); return; } for (int i = 0; i < (int)m_vScanParams.size(); ++i) { std::string deviceConfigsStr = GetDeviceConfigsStr(m_vScanParams[i].deviceConfigs); std::string saveParamStr = GetSaveParamStr(m_vScanParams[i].saveParam); char *sql = new char [1024 + deviceConfigsStr.size() + saveParamStr.size()]; sprintf(sql, "insert into scan_params (device_type, button_id, device_configs, save_param) values ('%s', '%d', '%s', '%s')", m_vScanParams[i].deviceType.c_str(), m_vScanParams[i].buttonId, deviceConfigsStr.c_str(), saveParamStr.c_str()); sqlite3_exec(sqlite, sql, NULL, NULL, NULL); } sqlite3_close(sqlite); } QString MainWindow::GetDesc(const std::vector &deviceConfigs) { QString desc = "-"; return desc; } QString MainWindow::GetDesc(const SaveParam &saveParam) { QString desc = "-"; return desc; } void MainWindow::StartScan(unsigned int buttonId) { if (nullptr == m_devHandle) { QMessageBox::information(this, tr("Tips"), tr("Device is offline")); return; } if (m_scanning || nullptr != m_dlgAdd) { return; } std::string deviceType = m_devName.toStdString(); char v[256] = {0}; SANE_Status status = sane_control_option(m_devHandle, (SANE_Int)0x886D, SANE_ACTION_GET_VALUE, v, NULL); if (SANE_STATUS_GOOD == status) { deviceType = v; } ScanParam scanParam; bool find = false; for (int i = 0; i < (int)m_vScanParams.size(); ++i) { if (deviceType == m_vScanParams[i].deviceType && buttonId == m_vScanParams[i].buttonId) { scanParam = m_vScanParams[i]; find = true; } } if (!find) { Show(); ShowAddDialog(buttonId); return; } // 1.恢复默认 SANE_Int num_dev_options = 0; sane_control_option(m_devHandle, 0, SANE_ACTION_GET_VALUE, &num_dev_options, NULL); for (int i = 1; i < num_dev_options; ++i) { const SANE_Option_Descriptor* desp = sane_get_option_descriptor(m_devHandle, i); if (NULL == desp) continue; const char* name = desp->name; while (' ' == *name) ++name; if (0 == strcmp(SANE_STD_OPT_NAME_RESTORE, name) && SANE_TYPE_BUTTON == desp->type) { sane_control_option(m_devHandle, i, SANE_ACTION_SET_VALUE, NULL, NULL); break; } } // 2.设置新的属性 for (int i = 0; i < (int)scanParam.deviceConfigs.size(); ++i) { if (5 == scanParam.deviceConfigs[i].valueType) { sane_control_option(m_devHandle, SANE_OPT_ID_CUSTOM_GAMMA, SANE_ACTION_SET_VALUE, &scanParam.deviceConfigs[i].gammaValue, NULL); continue; } for (int j = 1; j < num_dev_options; ++j) { const SANE_Option_Descriptor* desp = sane_get_option_descriptor(m_devHandle, j); if (NULL == desp) continue; const char* name = desp->name; while (' ' == *name) ++name; if (0 == strcmp(scanParam.deviceConfigs[i].name.c_str(), name)) { if (SANE_TYPE_STRING == desp->type) { sane_control_option(m_devHandle, j, SANE_ACTION_SET_VALUE, (void*)scanParam.deviceConfigs[i].stringValue.c_str(), NULL); } else if (SANE_TYPE_INT == desp->type) { SANE_Int value = scanParam.deviceConfigs[i].intValue; sane_control_option(m_devHandle, j, SANE_ACTION_SET_VALUE, &value, NULL); } else if (SANE_TYPE_FIXED == desp->type) { SANE_Fixed value = SANE_FIX(scanParam.deviceConfigs[i].doubleValue); sane_control_option(m_devHandle, j, SANE_ACTION_SET_VALUE, &value, NULL); } else if (SANE_TYPE_BOOL == desp->type) { SANE_Bool value = (SANE_Bool)scanParam.deviceConfigs[i].boolValue; sane_control_option(m_devHandle, j, SANE_ACTION_SET_VALUE, &value, NULL); } break; } } } // 3. 获取DPI for (int i = 1; i < num_dev_options; ++i) { const SANE_Option_Descriptor* desp = sane_get_option_descriptor(m_devHandle, i); if (nullptr == desp) continue; if (SANE_TYPE_INT == desp->type) { SANE_Int value = 0; sane_control_option(m_devHandle, i, SANE_ACTION_GET_VALUE, &value, nullptr); if (0 == strcmp(desp->name, SANE_STD_OPT_NAME_RESOLUTION)) { m_dpi = (HGUInt)value; } } } // 4.保存配置 assert(m_scanFileName.isEmpty()); assert(nullptr == m_scanImgFmtWriter); m_aquireIntoSaveParam = scanParam.saveParam; m_aquireIntoInBlank = true; m_aquireIntoBatchStartIndex = 0; m_aquireIntoPageIndex = 0; m_aquireIntoMultiPageCount = 0; QDateTime dateTime = QDateTime::currentDateTime(); if (m_aquireIntoSaveParam.isUseSubfolderByTime) { #ifdef HG_CMP_MSC std::string newPath = m_aquireIntoSaveParam.savePath + dateTime.toString("yyyy-MM-dd").toStdString() + "\\"; #else std::string newPath = m_aquireIntoSaveParam.savePath + dateTime.toString("yyyy-MM-dd").toStdString() + "/"; #endif m_aquireIntoSaveParam.savePath = newPath; } if (m_aquireIntoSaveParam.isOcr) { HGBase_CreateMsgPump(&m_ocrMsgPump); HGBase_OpenThread(ocrThreadFunc, this, &m_ocrThread); } m_scanning = true; m_quitAction->setEnabled(false); ui->pushButtonAdd->setEnabled(false); ui->pushButtonModify->setEnabled(false); ui->pushButtonRemove->setEnabled(false); ui->comboBox->setEnabled(false); ui->pushButtonScan->setEnabled(false); status = sane_start(m_devHandle); if (SANE_STATUS_GOOD != status) { if (NULL != m_ocrMsgPump) { HGBase_ExitMsgPump(m_ocrMsgPump); HGBase_CloseThread(m_ocrThread); m_ocrThread = NULL; HGBase_DestroyMsgPump(m_ocrMsgPump); m_ocrMsgPump = NULL; } m_scanning = false; m_quitAction->setEnabled(true); ui->pushButtonAdd->setEnabled(true); ui->pushButtonModify->setEnabled(true); ui->pushButtonRemove->setEnabled(true); ui->comboBox->setEnabled(true); ui->pushButtonScan->setEnabled(true); m_dpi = 200; emit scanWorking(); emit scanInfo((const char*)sane_strstatus(status), true); emit scanFinish(); return; } } void MainWindow::SaveImage(HGImage image) { if (m_aquireIntoSaveParam.isSaveAsMultiPage) { if (nullptr == m_scanImgFmtWriter) { assert(m_scanFileName.isEmpty()); HGBase_CreateDir(m_aquireIntoSaveParam.savePath.c_str()); QString scanFileName; while (1) { scanFileName = QString::fromLocal8Bit(m_aquireIntoSaveParam.savePath.c_str()) + QString::fromLocal8Bit(m_aquireIntoSaveParam.fileNamePrefix.c_str()) + QString("%1.%2").arg(m_aquireIntoSaveParam.fileNameStartIndex, m_aquireIntoSaveParam.fileNameDigits, 10, QLatin1Char('0')) .arg(QString::fromLocal8Bit(m_aquireIntoSaveParam.fileNameExt.c_str())); QFileInfo fileInfo(scanFileName); if (fileInfo.isFile()) { ++m_aquireIntoSaveParam.fileNameStartIndex; } else { break; } } HGUInt fmtType = 0; if (nullptr != m_ocrMsgPump) { fmtType = HGIMGFMT_TYPE_TIFF; } HGImgFmt_OpenImageWriter(scanFileName.toLocal8Bit().toStdString().c_str(), fmtType, &m_scanImgFmtWriter); if (nullptr != m_scanImgFmtWriter) { m_scanFileName = scanFileName; } } if (nullptr != m_scanImgFmtWriter) { HGImgFmtSaveInfo saveInfo; saveInfo.jpegQuality = (HGUInt)m_aquireIntoSaveParam.jpegQuality; saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE; saveInfo.tiffJpegQuality = (HGUInt)m_aquireIntoSaveParam.tiffQuality; HGImageInfo imgInfo; HGBase_GetImageInfo(image, &imgInfo); if (HGBASE_IMGTYPE_BINARY == imgInfo.type) { if (1 == m_aquireIntoSaveParam.tiffCompressionBW) saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW; else if (2 == m_aquireIntoSaveParam.tiffCompressionBW) saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_CCITTFAX4; } else { if (1 == m_aquireIntoSaveParam.tiffCompression) saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW; else if (2 == m_aquireIntoSaveParam.tiffCompression) saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_JPEG; } if (nullptr != m_ocrMsgPump) { saveInfo.jpegQuality = 100; saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE; saveInfo.tiffJpegQuality = 100; } if (HGBASE_ERR_OK == HGImgFmt_SaveImageToWriter(m_scanImgFmtWriter, image, &saveInfo)) { ++m_aquireIntoMultiPageCount; if (1 == m_aquireIntoSaveParam.multiPagesType && m_aquireIntoMultiPageCount == m_aquireIntoSaveParam.customMultiPages) { HGImgFmt_CloseImageWriter(m_scanImgFmtWriter); m_scanImgFmtWriter = nullptr; if (nullptr != m_ocrMsgPump) { QString *filePath = new QString(m_scanFileName); HGMsg msg; msg.id = 1; msg.data = filePath; if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_ocrMsgPump, &msg)) { delete filePath; } } m_scanFileName.clear(); ++m_aquireIntoSaveParam.fileNameStartIndex; m_aquireIntoMultiPageCount = 0; } } } } else { assert(nullptr == m_scanImgFmtWriter); QString savePath = QString::fromLocal8Bit(m_aquireIntoSaveParam.savePath.c_str()); if (m_aquireIntoSaveParam.isUseSubfolderByBlankPages) { HGBool isBlank = HGFALSE; HGImgProc_ImageBlankCheck(image, nullptr, &isBlank); if (isBlank) { m_aquireIntoInBlank = true; } else { if (m_aquireIntoInBlank) { ++m_aquireIntoBatchStartIndex; } m_aquireIntoInBlank = false; } char batchDir[20]; sprintf(batchDir, "batch%d", m_aquireIntoBatchStartIndex); #ifdef HG_CMP_MSC savePath = savePath + batchDir + "\\"; #else savePath = savePath + batchDir + "/"; #endif } if (m_aquireIntoSaveParam.isUseSubfolderByColor) { QString colorModeName; HGImageInfo imgInfo; HGBase_GetImageInfo(image, &imgInfo); if (HGBASE_IMGTYPE_BINARY == imgInfo.type) colorModeName = tr("binary"); else if (HGBASE_IMGTYPE_GRAY == imgInfo.type) colorModeName = tr("gray"); else colorModeName = tr("rgb"); #ifdef HG_CMP_MSC savePath = savePath + colorModeName + "\\"; #else savePath = savePath + colorModeName + "/"; #endif } HGBase_CreateDir(savePath.toLocal8Bit().toStdString().c_str()); while (1) { m_scanFileName = savePath + QString::fromLocal8Bit(m_aquireIntoSaveParam.fileNamePrefix.c_str()) + QString("%1.%2") .arg(m_aquireIntoSaveParam.fileNameStartIndex, m_aquireIntoSaveParam.fileNameDigits, 10, QLatin1Char('0')) .arg(QString::fromLocal8Bit(m_aquireIntoSaveParam.fileNameExt.c_str())); QFileInfo fileInfo(m_scanFileName); if (fileInfo.isFile()) { ++m_aquireIntoSaveParam.fileNameStartIndex; } else { break; } } HGImgFmtSaveInfo saveInfo; saveInfo.jpegQuality = (HGUInt)m_aquireIntoSaveParam.jpegQuality; saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE; saveInfo.tiffJpegQuality = (HGUInt)m_aquireIntoSaveParam.tiffQuality; HGImageInfo imgInfo; HGBase_GetImageInfo(image, &imgInfo); if (HGBASE_IMGTYPE_BINARY == imgInfo.type) { if (1 == m_aquireIntoSaveParam.tiffCompressionBW) saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW; else if (2 == m_aquireIntoSaveParam.tiffCompressionBW) saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_CCITTFAX4; } else { if (1 == m_aquireIntoSaveParam.tiffCompression) saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW; else if (2 == m_aquireIntoSaveParam.tiffCompression) saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_JPEG; } HGUInt fmtType = 0; if (nullptr != m_ocrMsgPump) { fmtType = HGIMGFMT_TYPE_TIFF; saveInfo.jpegQuality = 100; saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE; saveInfo.tiffJpegQuality = 100; } if (HGBASE_ERR_OK == HGImgFmt_SaveImage(image, fmtType, &saveInfo, m_scanFileName.toLocal8Bit().toStdString().c_str())) { if (nullptr != m_ocrMsgPump) { QString *filePath = new QString(m_scanFileName); HGMsg msg; msg.id = 1; msg.data = filePath; if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_ocrMsgPump, &msg)) { delete filePath; } } ++m_aquireIntoSaveParam.fileNameStartIndex; } m_scanFileName.clear(); } } void MainWindow::Show() { show(); if (isMaximized()) showMaximized(); else showNormal(); raise(); } void MainWindow::ShowAddDialog(unsigned int buttonId) { if (nullptr == m_devHandle) { QMessageBox::information(this, tr("Tips"), tr("Device is offline")); return; } std::string deviceType = m_devName.toStdString(); char v[256] = {0}; SANE_Status status = sane_control_option(m_devHandle, (SANE_Int)0x886D, SANE_ACTION_GET_VALUE, v, NULL); if (SANE_STATUS_GOOD == status) { deviceType = v; } assert(nullptr == m_dlgAdd); m_dlgAdd = new Dialog_Add(m_devHandle, this, deviceType, buttonId); connect(this, SIGNAL(closeDevice()), m_dlgAdd, SLOT(on_closeDevice())); if (m_dlgAdd->exec()) { ScanParam scanParam = m_dlgAdd->GetScanParam(); m_vScanParams.push_back(scanParam); SaveCfg(); ui->tableWidget->setRowCount((int)m_vScanParams.size()); int index = (int)m_vScanParams.size() - 1; ui->tableWidget->setRowHeight(index, 30); ui->tableWidget->setItem(index, 0, new QTableWidgetItem(QString(m_vScanParams[index].deviceType.c_str()))); ui->tableWidget->item(index, 0)->setTextAlignment(Qt::AlignCenter); ui->tableWidget->item(index, 0)->setFlags(ui->tableWidget->item(index, 0)->flags() & ~Qt::ItemIsEditable); QStringList btnTypeStr = {tr("Manual"), tr("Button 1"), tr("Button 2"), tr("Button 3"), tr("Button 4"), tr("Button 5")}; ui->tableWidget->setItem(index, 1, new QTableWidgetItem(btnTypeStr[m_vScanParams[index].buttonId])); ui->tableWidget->item(index, 1)->setTextAlignment(Qt::AlignCenter); ui->tableWidget->item(index, 1)->setFlags(ui->tableWidget->item(index, 1)->flags() & ~Qt::ItemIsEditable); ui->tableWidget->setItem(index, 2, new QTableWidgetItem(GetDesc(m_vScanParams[index].deviceConfigs))); ui->tableWidget->item(index, 2)->setTextAlignment(Qt::AlignCenter); ui->tableWidget->item(index, 2)->setFlags(ui->tableWidget->item(index, 2)->flags() & ~Qt::ItemIsEditable); ui->tableWidget->setItem(index, 3, new QTableWidgetItem(GetDesc(m_vScanParams[index].saveParam))); ui->tableWidget->item(index, 3)->setTextAlignment(Qt::AlignCenter); ui->tableWidget->item(index, 3)->setFlags(ui->tableWidget->item(index, 3)->flags() & ~Qt::ItemIsEditable); ui->tableWidget->selectRow(index); } disconnect(this, SIGNAL(closeDevice()), m_dlgAdd, SLOT(on_closeDevice())); delete m_dlgAdd; m_dlgAdd = nullptr; } int MainWindow::sane_ex_callback(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param) { (void)hdev; (void)len; MainWindow* p = (MainWindow*)param; switch (code) { case SANE_EVENT_DEVICE_ARRIVED: { SANE_Device* sane_dev = (SANE_Device*)data; emit p->deviceArrive(sane_dev->name); } break; case SANE_EVENT_DEVICE_LEFT: { SANE_Device* sane_dev = (SANE_Device*)data; emit p->deviceRemove(sane_dev->name); } break; case SANE_EVENT_WORKING: { emit p->scanWorking(); emit p->scanInfo((const char*)data, false); } break; case SANE_EVENT_SCAN_FINISHED: { emit p->scanInfo((const char*)data, (0 != *len)); emit p->scanFinish(); } break; case SANE_EVENT_STATUS: { //emit p->scanInfo((const char*)data, false); } break; case SANE_EVENT_ERROR: { //emit p->scanInfo((const char*)data, (0 != *len)); } break; case SANE_EVENT_DEV_KEY_PRESSED: { emit p->keyPress(*len); } break; case SANE_EVENT_START_AS_SERVICE: { return 1; } break; case SANE_EVENT_SCANNER_CLOSED: { bool isOnline = *(bool*)data; emit p->saneEventCloseDevice((void*)hdev, isOnline); } break; case SANE_EVENT_IMAGE_OK: { ++p->m_aquireIntoPageIndex; emit p->scanImage(p->m_aquireIntoPageIndex); if ((1 == p->m_aquireIntoSaveParam.fileNameOddEvenType && 1 != p->m_aquireIntoPageIndex % 2) || (2 == p->m_aquireIntoSaveParam.fileNameOddEvenType && 0 != p->m_aquireIntoPageIndex % 2)) { // 跳过 } else { SANE_Image* sane_img = (SANE_Image*)data; HGUInt imgType = 0; if (sane_img->header.format == SANE_FRAME_GRAY) { if (1 == sane_img->header.depth) imgType = HGBASE_IMGTYPE_BINARY; else if (8 == sane_img->header.depth) imgType = HGBASE_IMGTYPE_GRAY; } else if (sane_img->header.format == SANE_FRAME_RGB) imgType = HGBASE_IMGTYPE_RGB; HGByte* data = sane_img->data; HGImageInfo imgInfo = { (HGUInt)sane_img->header.pixels_per_line, (HGUInt)sane_img->header.lines, imgType, (HGUInt)sane_img->header.bytes_per_line, HGBASE_IMGORIGIN_TOP }; HGImage img = NULL; HGBase_CreateImageFromData(data, &imgInfo, NULL, 0, HGBASE_IMGORIGIN_TOP, &img); if (NULL != img) { HGBase_SetImageDpi(img, p->m_dpi, p->m_dpi); p->SaveImage(img); HGBase_DestroyImage(img); } } } break; } return 0; } void MainWindow::ocrThreadFunc(HGThread thread, HGPointer param) { MainWindow *p = (MainWindow*)param; HGBase_RunMsgPump(p->m_ocrMsgPump, ocrMsgPumpFunc, param); } void MainWindow::ocrMsgPumpFunc(HGMsgPump msgPump, const HGMsg *msg, HGPointer param) { MainWindow *p = (MainWindow*)param; if (msg->id == 1) { QString *filePath = (QString *)msg->data; HGOCRMgr ocrMgr = NULL; HGImgProc_CreateOCRMgr(HGIMGPROC_OCRALGO_DEFAULT, &ocrMgr); if (NULL != ocrMgr) { HGImgFmtReader reader = NULL; HGImgFmt_OpenImageReader(filePath->toLocal8Bit().toStdString().c_str(), 0, &reader); if (NULL != reader) { HGUInt count = 0; HGImgFmt_GetImagePageCount(reader, &count); for (HGUInt i = 0; i < count; ++i) { HGImage image = NULL; HGImgFmt_LoadImageFromReader(reader, i, NULL, 0, 0, &image); if (NULL != image) { HGImgProc_AddToImageOCRList(ocrMgr, image); HGBase_DestroyImage(image); } } HGImgFmt_CloseImageReader(reader); } //HGBase_DeleteFile(filePath->toLocal8Bit().toStdString().c_str()); HGImgProc_ImageListOCRToFile(ocrMgr, 0, filePath->toLocal8Bit().toStdString().c_str(), NULL, NULL); HGImgProc_DestroyOCRMgr(ocrMgr); } delete filePath; } } void MainWindow::CrashFunc(HGPointer crashAddr, HGPointer param) { HGChar crashName[256]; HGBase_GetLogFilePath(crashName, 256); strcat(crashName, "crash.dmp"); if (HGBASE_ERR_OK == HGBase_MakeCrashFile(crashName)) { HGChar excpStr[64]; #ifdef HG_64BIT sprintf(excpStr, "0x%016p", crashAddr); #else sprintf(excpStr, "0x%08p", crashAddr); #endif } } void MainWindow::closeEvent(QCloseEvent *e) { if (m_trayIcon->isVisible()) //托盘是显示的 { hide(); // 隐藏主窗口 e->ignore(); //忽略关闭事件,这样才不会关闭程序 } } void MainWindow::timerEvent(QTimerEvent *e) { if (e->timerId() == m_timerId) { SANE_Status status = sane_open(ui->comboBox->currentText().toStdString().c_str(), &m_devHandle); if (SANE_STATUS_GOOD == status) { m_devName = ui->comboBox->currentText(); ui->pushButtonScan->setEnabled(true); ui->pushButtonAdd->setEnabled(true); ui->pushButtonModify->setEnabled(true); this->killTimer(m_timerId); m_timerId = -1; } } } void MainWindow::on_deviceArrive(QString devName) { if (devName.contains("306") || devName.contains("307") || devName.contains("358")) ui->comboBox->addItem(devName); } void MainWindow::on_deviceRemove(QString devName) { if (devName == m_devName) { assert(nullptr != m_devHandle); StopScan(); emit closeDevice(); sane_close(m_devHandle); m_devHandle = NULL; m_devName.clear(); ui->pushButtonScan->setEnabled(false); ui->pushButtonAdd->setEnabled(false); ui->pushButtonModify->setEnabled(false); } for (int i = 0; i < ui->comboBox->count(); ++i) { if (ui->comboBox->itemText(i) == devName) { ui->comboBox->removeItem(i); break; } } } void MainWindow::on_keyPress(unsigned int buttonId) { assert(nullptr != m_devHandle); StartScan(buttonId); } void MainWindow::on_scanWorking() { m_dlgScanInfo->Start(); } void MainWindow::on_scanInfo(QString info, bool error) { m_dlgScanInfo->SetScanInfo(info, error); } void MainWindow::on_scanImage(unsigned int count) { m_dlgScanInfo->SetScanCount(count); } void MainWindow::on_scanFinish() { if (nullptr != m_scanImgFmtWriter) { HGImgFmt_CloseImageWriter(m_scanImgFmtWriter); m_scanImgFmtWriter = nullptr; if (nullptr != m_ocrMsgPump) { QString *filePath = new QString(m_scanFileName); HGMsg msg; msg.id = 1; msg.data = filePath; if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_ocrMsgPump, &msg)) { delete filePath; } } m_scanFileName.clear(); ++m_aquireIntoSaveParam.fileNameStartIndex; m_aquireIntoMultiPageCount = 0; } if (NULL != m_ocrMsgPump) { HGBase_ExitMsgPump(m_ocrMsgPump); HGBase_CloseThread(m_ocrThread); m_ocrThread = NULL; HGBase_DestroyMsgPump(m_ocrMsgPump); m_ocrMsgPump = NULL; } StopScan(); m_dlgScanInfo->Finish(); } void MainWindow::on_comboBox_currentIndexChanged(const QString &arg1) { if (-1 != m_timerId) { this->killTimer(m_timerId); m_timerId = -1; } if (NULL != m_devHandle) { StopScan(); emit closeDevice(); sane_close(m_devHandle); m_devHandle = NULL; m_devName.clear(); ui->pushButtonScan->setEnabled(false); ui->pushButtonAdd->setEnabled(false); ui->pushButtonModify->setEnabled(false); } SANE_Status status = sane_open(arg1.toStdString().c_str(), &m_devHandle); if (SANE_STATUS_GOOD == status) { m_devName = arg1; ui->pushButtonScan->setEnabled(true); ui->pushButtonAdd->setEnabled(true); ui->pushButtonModify->setEnabled(true); } else { m_timerId = this->startTimer(5000); } } void MainWindow::on_pushButtonScan_clicked() { assert(!m_scanning && nullptr == m_dlgAdd); StartScan(0); } void MainWindow::on_trayActivated(QSystemTrayIcon::ActivationReason reason) { if (QSystemTrayIcon::Trigger == reason) { } else if (QSystemTrayIcon::DoubleClick == reason) { Show(); } else if (QSystemTrayIcon::MiddleClick == reason) { } } void MainWindow::on_showMainWindowDlg() { Show(); } void MainWindow::on_saneEventCloseDevice(void* devHandle, bool isOnline) { assert(nullptr != m_devHandle || nullptr != devHandle); if (devHandle != m_devHandle) return; StopScan(); emit closeDevice(); sane_close(m_devHandle); m_devHandle = NULL; m_devName.clear(); ui->pushButtonScan->setEnabled(false); ui->pushButtonAdd->setEnabled(false); ui->pushButtonModify->setEnabled(false); if (-1 != m_timerId) { this->killTimer(m_timerId); m_timerId = -1; } if (isOnline) m_timerId = this->startTimer(5000); } void MainWindow:: on_pushButtonAdd_clicked() { ShowAddDialog(0); } void MainWindow::on_pushButtonModify_clicked() { int index = ui->tableWidget->currentRow(); if (-1 == index) { QMessageBox::information(this, tr("Tips"), tr("No item selected")); return; } if (nullptr == m_devHandle) { QMessageBox::information(this, tr("Tips"), tr("Device is offline")); return; } std::string deviceType = m_devName.toStdString(); char v[256] = {0}; SANE_Status status = sane_control_option(m_devHandle, (SANE_Int)0x886D, SANE_ACTION_GET_VALUE, v, NULL); if (SANE_STATUS_GOOD == status) { deviceType = v; } if (deviceType != m_vScanParams[index].deviceType) { QMessageBox::information(this, tr("Tips"), tr("Device type mismatch")); return; } assert(nullptr == m_dlgAdd); m_dlgAdd = new Dialog_Add(m_devHandle, this, m_vScanParams[index], index); connect(this, SIGNAL(closeDevice()), m_dlgAdd, SLOT(on_closeDevice())); if (m_dlgAdd->exec()) { ScanParam scanParam = m_dlgAdd->GetScanParam(); m_vScanParams[index] = scanParam; SaveCfg(); ui->tableWidget->item(index, 0)->setText(QString::fromStdString(m_vScanParams[index].deviceType)); QStringList btnTypeStr = {tr("Manual"), tr("Button 1"), tr("Button 2"), tr("Button 3"), tr("Button 4"), tr("Button 5")}; ui->tableWidget->item(index, 1)->setText(btnTypeStr[m_vScanParams[index].buttonId]); ui->tableWidget->item(index, 2)->setText(GetDesc(m_vScanParams[index].deviceConfigs)); ui->tableWidget->item(index, 3)->setText(GetDesc(m_vScanParams[index].saveParam)); } disconnect(this, SIGNAL(closeDevice()), m_dlgAdd, SLOT(on_closeDevice())); delete m_dlgAdd; m_dlgAdd = nullptr; } void MainWindow::on_pushButtonRemove_clicked() { int index = ui->tableWidget->currentRow(); if (-1 == index) { QMessageBox::information(this, tr("Tips"), tr("No item selected")); return; } QMessageBox msg(QMessageBox::Question, tr("Question"), tr("Are you sure you want to remove the item?"), QMessageBox::Yes | QMessageBox::No, this); msg.exec(); if (msg.clickedButton() != msg.button(QMessageBox::Yes)) { return; } m_vScanParams.erase(m_vScanParams.begin() + index); SaveCfg(); ui->tableWidget->removeRow(index); }