// ***************************************************************************** // 版权所有(C)2023~2099 上海骄成超声波技术有限公司 // 保留所有权利 // ***************************************************************************** // 作者 : 杨坚 // 版本 : 1.0 // 功能说明: // 鼠标监控-全局的,可能后面还有其他地方使用,所以.. // ***************************************************************************** #include "JMouseMonitorThread.h" #include JMouseMonitorThread::JMouseMonitorThread(QObject* parent /*= nullptr*/) : QThread(parent), m_locked(false), m_running(true) { } void JMouseMonitorThread::setLockCenter(const QPoint center) { QMutexLocker locker(&m_mutex); m_lockCenter = center; m_locked = true; } void JMouseMonitorThread::unlock() { QMutexLocker locker(&m_mutex); m_locked = false; } void JMouseMonitorThread::stop() { m_running = false; wait(); } void JMouseMonitorThread::ConvertUIClickToImagePixel(int uiX, int uiY, int& imageX, int& imageY) { int uiwidth = 493;//imageLabel->width(); 480 493 int uiheight = 493;// imageLabel->height();360 int imagewidth = 640; int imageheight = 480; // 步骤1:转换为左上原点坐标系 float uiX_topLeft = uiX + uiwidth / 2.0f; float uiY_topLeft = uiY + uiheight / 2.0f; // UI的Y轴向下为正 // 步骤2:计算缩放比例 float scaleX = (float)imagewidth / uiwidth; // 640/480 ≈ 1.333 float scaleY = (float)imageheight / uiheight; // 480/360 ≈ 1.333 // 步骤3:映射到原始图像 int imageXA = (int)(uiX_topLeft * scaleX); int imageYA = (int)(uiY_topLeft * scaleY); // 确保坐标在图像范围内 imageX = std::max(0, std::min(imagewidth - 1, imageXA)); imageY = std::max(0, std::min(imageheight - 1, imageYA)); } void JMouseMonitorThread::ConvertUIClickToImagePixel2(int uiX, int uiY, int& imageX, int& imageY) { const int uiWidth = 493; // UI控件实际宽度 const int uiHeight = 493; // UI控件实际高度 const int imgWidth = 640; // 原始图像宽度 const int imgHeight = 480; // 原始图像高度 // 1. 计算保持宽高比的缩放比例 const float scale = std::min( static_cast(uiWidth) / imgWidth, static_cast(uiHeight) / imgHeight ); // 2. 计算实际显示区域尺寸 const int displayWidth = static_cast(imgWidth * scale); const int displayHeight = static_cast(imgHeight * scale); // 3. 计算显示区域在控件中的偏移(居中) const int offsetX = (uiWidth - displayWidth) / 2; const int offsetY = (uiHeight - displayHeight) / 2; // 4. 将UI坐标转换为显示区域坐标 const int uiClickX = uiX + uiWidth / 2; // 转换到控件坐标系 const int uiClickY = uiY + uiHeight / 2; // 5. 有效性检查(点击是否在显示区域内) const int displayX = std::max(0, std::min(displayWidth - 1, uiClickX - offsetX)); const int displayY = std::max(0, std::min(displayHeight - 1, uiClickY - offsetY)); // 6. 映射到原始图像坐标 imageX = static_cast(displayX / scale); imageY = static_cast(displayY / scale); // 最终有效性检查 imageX = std::max(0, std::min(imgWidth - 1, imageX)); imageY = std::max(0, std::min(imgHeight - 1, imageY)); } void JMouseMonitorThread::run() { QPoint lastPos = QCursor::pos(); while (m_running) { if (m_locked) { QPoint currentPos; QPoint center; { QMutexLocker locker(&m_mutex); center = m_lockCenter; } currentPos = QCursor::pos(); QPoint delta = currentPos - center; if (delta != QPoint(0, 0)) { int imageX, imageY; ConvertUIClickToImagePixel2(delta.x(), delta.y(),imageX, imageY); //qDebug() << "image POS" << imageX << " " << imageY; delta.setX(imageX); delta.setY(imageY); emit MouseMovedSlg(delta); emit RequestCursorMoveSlg(center); } } msleep(15); } }