#include "WaffleGraphicsView.h" #include #include # WaffleGraphicsView::WaffleGraphicsView(QGraphicsScene* scene, QWidget* parent) : QGraphicsView(scene, parent), selecting(false), selectionRect(nullptr), scaleFactor(1.0), isDragging(false), thumbnailLabel(nullptr), thumbnailVisible(false) { setRenderHint(QPainter::Antialiasing); // setDragMode(QGraphicsView::ScrollHandDrag); // 支持拖动视图 setTransformationAnchor(QGraphicsView::AnchorUnderMouse); // 缩放时以鼠标为中心 // 初始化缩略图标签 thumbnailLabel = new QLabel(this); thumbnailLabel->setFixedSize(150, 150); thumbnailLabel->move(0, 0); // 默认左上角位置 thumbnailLabel->setStyleSheet("background-color: white; border: 1px solid gray;"); thumbnailLabel->installEventFilter(this); thumbnailLabel->hide(); topLeftIndex = qMakePair(-1, -1); bottomRightIndex = qMakePair(-1, -1); } // 事件过滤器用于处理缩略图拖动 bool WaffleGraphicsView::eventFilter(QObject *obj, QEvent *event) { static QPoint dragStartPosition; if (obj == thumbnailLabel) { if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *me = static_cast(event); dragStartPosition = me->pos(); return true; } else if (event->type() == QEvent::MouseMove) { QMouseEvent *me = static_cast(event); // 计算新位置 QPoint newPos = thumbnailLabel->pos() + (me->pos() - dragStartPosition); // 限制在视图范围内 int maxX = this->width() - thumbnailLabel->width(); int maxY = this->height() - thumbnailLabel->height(); // 使用qBound限制坐标范围(0 <= x <= maxX,0 <= y <= maxY) newPos.setX(qBound(0, newPos.x(), maxX)); newPos.setY(qBound(0, newPos.y(), maxY)); thumbnailLabel->move(newPos); return true; } } return QGraphicsView::eventFilter(obj, event); } void WaffleGraphicsView::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) { // 清空选中的 WaffleItem for (auto& item : selectedItems) { WaffleItem* die = dynamic_cast(item); if (die) { die->setSelected(false); // 取消选中状态 } } selectedItems.clear(); if (topLeftItem && topLeftItem->scene()) { topLeftItem->setRightSelected(false); } topLeftItem.clear(); if (bottomRightItem && bottomRightItem->scene()) { bottomRightItem->setRightSelected(false); } bottomRightItem.clear(); // 获取点击位置的 WaffleItem if (selectedItem && selectedItem->scene()) { selectedItem->setLeftSelected(false); } selectedItem.clear(); QGraphicsItem* item = itemAt(event->pos()); if (item) { if (typeid(*item) == typeid(WaffleItem)) { selectedItem = static_cast(item); selectedItem->setLeftSelected(true); } } setCursor(Qt::OpenHandCursor); // 按下时设置为小手 selecting = true; lastPos = event->pos(); // 记录鼠标位置 } else if (event->button() == Qt::RightButton) { // 开始框选 selecting = true; selectionStart = mapToScene(event->pos()); isDragging = false; if (!selectionRect) { selectionRect = new QGraphicsRectItem(); selectionRect->setPen(QPen(Qt::NoPen)); selectionRect->setBrush(QBrush(QColor(0, 0, 255, 50))); // 半透明蓝色 scene()->addItem(selectionRect); } selectionRect->setRect(QRectF(selectionStart, QSizeF())); } QGraphicsView::mousePressEvent(event); } void WaffleGraphicsView::mouseMoveEvent(QMouseEvent* event) { if (selecting && selectionRect) { QPointF currentPos = mapToScene(event->pos()); selectionRect->setRect(QRectF(selectionStart, currentPos).normalized()); isDragging = true; } else if (selecting) { // 计算鼠标当前位置与上次位置的差值 QPointF delta = event->pos() - lastPos; // 平移视图 horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x()); verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y()); lastPos = event->pos(); // 更新鼠标位置 } QGraphicsView::mouseMoveEvent(event); } void WaffleGraphicsView::mouseReleaseEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) { setCursor(Qt::ArrowCursor); // 松开时恢复为箭头 selecting = false; } else if (event->button() == Qt::RightButton && selecting) { selecting = false; if (selectionRect && isDragging) { if (selectedItem && selectedItem->scene()) { selectedItem->setLeftSelected(false); } selectedItem.clear(); if (topLeftItem && topLeftItem->scene()) { topLeftItem->setRightSelected(false); } topLeftItem.clear(); if (bottomRightItem && bottomRightItem->scene()) { bottomRightItem->setRightSelected(false); } bottomRightItem.clear(); QRectF selectedArea = selectionRect->rect(); scene()->removeItem(selectionRect); delete selectionRect; selectionRect = nullptr; QList items = scene()->items(selectedArea, Qt::IntersectsItemShape); for (QGraphicsItem* item : items) { WaffleItem* die = dynamic_cast(item); if (die) { // 将 WaffleItem 添加到 map 中 selectedItems.append(die); die->setSelected(true); // 设置选中状态 } } } if (selectionRect) { scene()->removeItem(selectionRect); delete selectionRect; selectionRect = nullptr; } // 如果没有进行拖动,则弹出右键菜单 if (!isDragging) { QGraphicsItem* item = itemAt(event->pos()); WaffleItem* die = dynamic_cast(item); QMenu menu; QAction* showThumb = menu.addAction(thumbnailVisible ? tr("Hide thumbnails", "隐藏缩略图") : tr("Show thumbnails", "显示缩略图")); connect(showThumb, &QAction::triggered, [this]{ thumbnailVisible ? hideThumbnail() : showThumbnail(); }); //menu.addAction(tr("Send Location", "发送位置"), [this] { // if (selectedItem) { // selectedItem->setLeftSelected(false); // selectedItem = nullptr; // } //}); if (die) { menu.addAction(tr("move to current location","移动到该位置"), [this, die] { for (auto& item : selectedItems) { WaffleItem* die = dynamic_cast(item); if (die) { die->setSelected(false); } } selectedItems.clear(); if (topLeftItem && topLeftItem->scene()) { topLeftItem->setRightSelected(false); } topLeftItem.clear(); if (bottomRightItem && bottomRightItem->scene()) { bottomRightItem->setRightSelected(false); } bottomRightItem.clear(); if (selectedItem && selectedItem->scene()) { selectedItem->setLeftSelected(false); } selectedItem.clear(); selectedItem = die; selectedItem->setLeftSelected(true); m_pCViewInterface->GetViewMatrix()->MoveWafflePackToPoint(die->getPoint().iDieIndex); qDebug() << "move to point" << die->getPoint().iDieIndex; }); // 设置区域边界点菜单 menu.addAction(tr("set Top left point","设为左上点"), [this, die] { if (topLeftItem && topLeftItem->scene()) { topLeftItem->setRightSelected(false); } topLeftItem.clear(); topLeftItem = die; topLeftItem->setRightSelected(true); if (bottomRightItem && bottomRightItem->scene()){ if (bottomRightItem->getPoint().nPackMatrixId == topLeftItem->getPoint().nPackMatrixId && bottomRightItem->getPoint().nDieMatrixId == topLeftItem->getPoint().nDieMatrixId) checkAndCreateRegion(); } }); menu.addAction(tr("set bottom right point","设为右下点"), [this, die] { if (bottomRightItem && bottomRightItem->scene()) { bottomRightItem->setRightSelected(false); } bottomRightItem.clear(); bottomRightItem = die; bottomRightItem->setRightSelected(true); if (topLeftItem && topLeftItem->scene()) { if (bottomRightItem->getPoint().nPackMatrixId == topLeftItem->getPoint().nPackMatrixId && bottomRightItem->getPoint().nDieMatrixId == topLeftItem->getPoint().nDieMatrixId) checkAndCreateRegion(); } }); } menu.addAction(tr("clear the selected area","清除选中区域"), [this] { clearRegion(); }); menu.addAction(tr("set area","设置区域"), [this] { setRegion(); }); menu.exec(event->globalPos()); } } QGraphicsView::mouseReleaseEvent(event); } void WaffleGraphicsView::wheelEvent(QWheelEvent* event) { if (event->orientation() == Qt::Vertical) { event->ignore(); // 忽略竖直滚轮事件(即禁用滚动条滑动) return; } event->accept(); } // 缩略图功能实现 void WaffleGraphicsView::showThumbnail() { ImageInfo image; m_pCViewInterface->GetViewMatrix()->GetWafflePackRefImage(image); QPixmap thumb = convertToPixmap(image); if (!thumb.isNull()) { // 如果图片加载成功,设置为缩略图 thumbnailLabel->setPixmap(thumb.scaled(150, 150, Qt::KeepAspectRatio)); thumbnailLabel->show(); thumbnailVisible = true; } else { // 如果加载图片失败,显示"图片加载失败" thumbnailLabel->setText("图片加载失败"); thumbnailLabel->setAlignment(Qt::AlignCenter); // 居中显示文本 thumbnailLabel->show(); thumbnailVisible = true; } } void WaffleGraphicsView::hideThumbnail() { thumbnailLabel->hide(); thumbnailVisible = false; thumbnailLabel->move(0, 0); } void WaffleGraphicsView::checkAndCreateRegion() { // 确定行列范围 int startRow = topLeftItem->getPoint().nDieRow; int endRow = bottomRightItem->getPoint().nDieRow; int startCol = topLeftItem->getPoint().nDieCol; int endCol = bottomRightItem->getPoint().nDieCol; // 遍历场景中的所有项 foreach (QGraphicsItem* item, scene()->items()) { if (WaffleItem* die = dynamic_cast(item)) { // 判断是否在区域内 if (die->getPoint().nDieMatrixId == topLeftItem->getPoint().nDieMatrixId && die->getPoint().nPackMatrixId == topLeftItem->getPoint().nPackMatrixId) { if (die->getPoint().nDieRow >= startRow && die->getPoint().nDieRow <= endRow && die->getPoint().nDieCol >= startCol && die->getPoint().nDieCol <= endCol) { // 更新选中状态 die->setSelected(true); selectedItems.append(die); } } } } } void WaffleGraphicsView::clearRegion() { // 清空选中的 WaffleItem for (auto& item : selectedItems) { WaffleItem* die = dynamic_cast(item); if (die) { die->setSelected(false); // 取消选中状态 } } selectedItems.clear(); if (selectedItem && selectedItem->scene()) { selectedItem->setLeftSelected(false); } if (topLeftItem && topLeftItem->scene()) { topLeftItem->setRightSelected(false); } topLeftItem.clear(); if (bottomRightItem && bottomRightItem->scene()) { bottomRightItem->setRightSelected(false); } bottomRightItem.clear(); selectedItem.clear(); bottomRightItem.clear(); topLeftIndex = qMakePair(-1, -1); bottomRightIndex = qMakePair(-1, -1); // 清除缩略图 hideThumbnail(); } void WaffleGraphicsView::setRegion() { int maxRow = 1; int maxCol = 1; int minRow = 1; int minCol = 1; WaffleItem* dieItem; for (auto it = selectedItems.begin(); it != selectedItems.end(); ++it) { dieItem = dynamic_cast(*it); if (dieItem) { if (dieItem->getPoint().nDieRow > maxRow) maxRow = dieItem->getPoint().nDieRow; if (dieItem->getPoint().nDieCol > maxCol) maxCol = dieItem->getPoint().nDieCol; if (dieItem->getPoint().nDieRow < minRow) minRow = dieItem->getPoint().nDieRow; if (dieItem->getPoint().nDieRow < minCol) minCol = dieItem->getPoint().nDieCol; } } m_pCViewInterface->GetViewMatrix()->SetWafflePackRectBorder(dieItem->getPoint().nPackMatrixId, dieItem->getPoint().nDieMatrixId, minRow, minCol, maxRow, maxCol); qDebug() << dieItem->getPoint().nPackMatrixId << " " << dieItem->getPoint().nDieMatrixId << " " << minRow << " " << minCol << " " << maxRow << " " << maxCol; // 清空选中的 WaffleItem for (auto& item : selectedItems) { WaffleItem* die = dynamic_cast(item); if (die) { die->setSelected(false); // 取消选中状态 } } selectedItems.clear(); if (selectedItem && selectedItem->scene()) { selectedItem->setLeftSelected(false); } if (topLeftItem && topLeftItem->scene()) { topLeftItem->setRightSelected(false); } topLeftItem.clear(); if (bottomRightItem && bottomRightItem->scene()) { bottomRightItem->setRightSelected(false); } bottomRightItem.clear(); } void WaffleGraphicsView::setCViewInterface(ns_module::CViewInterface* CViewInterface) { m_pCViewInterface = CViewInterface; } void WaffleGraphicsView::yuv422_to_rgb888(const unsigned char* src, unsigned char* dst, int width, int height) { for (int i = 0; i < width * height; i += 2) { unsigned char y0 = src[0]; unsigned char u = src[1]; unsigned char y1 = src[2]; unsigned char v = src[1]; // 简单反色度插值,适用于 U/V 在相邻像素间共享的情况 int r, g, b; // YUV to RGB 转换公式 #define CLIP(x) qBound(0, int(x), 255) // Pixel 0 r = CLIP(y0 + 1.402 * (v - 128)); g = CLIP(y0 - 0.344 * (u - 128) - 0.714 * (v - 128)); b = CLIP(y0 + 1.772 * (u - 128)); *dst++ = r; *dst++ = g; *dst++ = b; // Pixel 1 r = CLIP(y1 + 1.402 * (v - 128)); g = CLIP(y1 - 0.344 * (u - 128) - 0.714 * (v - 128)); b = CLIP(y1 + 1.772 * (u - 128)); *dst++ = r; *dst++ = g; *dst++ = b; src += 4; } } QPixmap WaffleGraphicsView::convertToPixmap(const ImageInfo& imgData) { QImage::Format qFormat = QImage::Format_Invalid; switch (imgData.format) { case ImageFormat::GRAY8: qFormat = QImage::Format_Grayscale8; break; case ImageFormat::RGB888: qFormat = QImage::Format_RGB888; break; case ImageFormat::ARGB32: qFormat = QImage::Format_ARGB32; break; case ImageFormat::RGB32: qFormat = QImage::Format_RGB32; break; case ImageFormat::YUV422: { // 需要先转换为 RGB888 int byteCount = imgData.width * imgData.height * 3; unsigned char* rgbData = new unsigned char[byteCount]; yuv422_to_rgb888(imgData.data, rgbData, imgData.width, imgData.height); QImage tmp(rgbData, imgData.width, imgData.height, QImage::Format_RGB888); QPixmap pixmap = QPixmap::fromImage(tmp); delete[] rgbData; return pixmap; } default: qDebug() << "Unsupported image format!"; return QPixmap(); } QImage qImg(imgData.data, imgData.width, imgData.height, imgData.width * imgData.channel, qFormat); return QPixmap::fromImage(qImg); } WaffleItem::WaffleItem(ns_mat::WAFFLE_MATRIX_POINT_STRUCT point, double penSize, QGraphicsItem* parent) : QGraphicsRectItem(parent), point(point), penSize(penSize){ setBrush(getColorByStatus()); setPen(QPen(QColor(0, 0, 0), penSize)); } void WaffleItem::setSelected(bool selected) { if (selected) { setPen(QPen(Qt::red, penSize*2)); } else { setPen(QPen(Qt::black, penSize)); // 未选中时恢复为黑色边框 } } void WaffleItem::setLeftSelected(bool selected) { if (selected) { setPen(QPen(Qt::green, penSize*2)); } else { setPen(QPen(Qt::black, penSize)); // 未选中时恢复为黑色边框 } } ns_mat::WAFFLE_MATRIX_POINT_STRUCT WaffleItem::getPoint() { return point; } void WaffleItem::hoverEnterEvent(QGraphicsSceneHoverEvent*) { setZValue(1); // 悬停时提升Z值 update(); } void WaffleItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*) { setZValue(0); update(); } QColor WaffleItem::getColorByStatus() { ns_mat::PICK_DIE_STATUS status = point.eStatus; switch (status) { case ns_mat::PICK_DIE_STATUS::DIE_EXIST: return QColor(0, 102, 255); // 蓝色 case ns_mat::PICK_DIE_STATUS::NO_EXIST: return QColor(200, 200, 200); // 浅灰 case ns_mat::PICK_DIE_STATUS::PICK_ING: return QColor(255, 255, 0); // 黄色 case ns_mat::PICK_DIE_STATUS::SKIP_DIE: return QColor(128, 128, 128); // 深灰 case ns_mat::PICK_DIE_STATUS::EDGE_DIE: return QColor(255, 165, 0); // 橙色 default: return QColor(0, 0, 0); // 默认黑色 } } void WaffleItem::setRightSelected(bool selected) { if (selected) { setPen(QPen(QColor("#00F5FF"), penSize*2)); } else { setPen(QPen(Qt::black, penSize)); // 未选中时恢复为黑色边框 } // qDebug() << "DieItem clicked: Row:" << row << "Col:" << col; }