ImageView.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #include "ImageView.h"
  2. #include <QPainter>
  3. #include <QDebug>
  4. #include <QGraphicsPixmapItem>
  5. #include <QScrollBar>
  6. #include <QMenu>
  7. #include <QFileDialog>
  8. #include <QDateTime>
  9. #include <QMessageBox>
  10. #define VIEW_CENTER viewport()->rect().center()
  11. #define VIEW_WIDTH viewport()->rect().width()
  12. #define VIEW_HEIGHT viewport()->rect().height()
  13. ImageView::ImageView(QWidget* parent) :
  14. QGraphicsView(parent),
  15. m_imageOffset(0, 0),
  16. m_bMouseTranslate(false),
  17. m_isDrawing(false),
  18. m_curDrawing(false),
  19. m_currentPathItem(nullptr)
  20. {
  21. m_pRuleLine = nullptr;
  22. setScene(new QGraphicsScene(this));
  23. setRenderHint(QPainter::SmoothPixmapTransform);
  24. setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
  25. this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  26. this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  27. }
  28. ImageView::~ImageView()
  29. {
  30. }
  31. void ImageView::setPixmap(const QPixmap& newPixmap) {
  32. this->m_pixmap = newPixmap;
  33. scene()->clear();
  34. m_pixmapItem = scene()->addPixmap(m_pixmap);
  35. m_pixmapItem->setZValue(1);
  36. QPointF pixmapCenter(m_pixmap.width() / 2.0, m_pixmap.height() / 2.0);
  37. m_pixmapItem->setPos(-pixmapCenter);
  38. QRectF sceneRect(-pixmapCenter.x(), -pixmapCenter.y(), m_pixmap.width(), m_pixmap.height());
  39. scene()->setSceneRect(sceneRect);
  40. setSceneRect(scene()->itemsBoundingRect());
  41. this->resize(m_pixmap.width(), m_pixmap.height());
  42. m_imageOffset = QPoint(0, 0); // 重置图片偏移量为(0, 0)
  43. setCursor(Qt::ArrowCursor);
  44. update(); // 触发重绘
  45. }
  46. void ImageView::setCurPixmap(const QPixmap& newPixmap) {
  47. this->m_pixmap = newPixmap;
  48. m_pixmapItem->setPixmap(m_pixmap);
  49. }
  50. void ImageView::startRuler()
  51. {
  52. if (nullptr == m_pRuleLine) {
  53. m_pRuleLine = new DraggableLine(QLineF(0, 0, 50, 50));
  54. m_pRuleLine->setPen(QPen(Qt::red, 2));
  55. m_pRuleLine->setZValue(2);
  56. scene()->addItem(m_pRuleLine);
  57. }
  58. }
  59. void ImageView::endRuler()
  60. {
  61. if (nullptr != m_pRuleLine) {
  62. scene()->removeItem(m_pRuleLine);
  63. delete m_pRuleLine;
  64. m_pRuleLine = nullptr;
  65. }
  66. }
  67. bool ImageView::rulerVisibale()
  68. {
  69. if (nullptr == m_pRuleLine)
  70. return false;
  71. else
  72. return true;
  73. }
  74. void ImageView::paintEvent(QPaintEvent* event) {
  75. QGraphicsView::paintEvent(event);
  76. }
  77. void ImageView::mousePressEvent(QMouseEvent* event) {
  78. if (event->button() == Qt::LeftButton) {
  79. // 当光标底下没有 item 时,才能移动
  80. QPointF point = mapToScene(event->pos());
  81. if (scene()->itemAt(point, transform()) != m_pRuleLine) {
  82. setCursor(Qt::OpenHandCursor);
  83. m_bMouseTranslate = true;
  84. m_lastMousePos = event->pos();
  85. }
  86. }
  87. else if (event->button() == Qt::RightButton) {
  88. m_rightClickPressPos = event->pos();
  89. m_rightButtonPressed = true;
  90. }
  91. QGraphicsView::mousePressEvent(event);
  92. }
  93. void ImageView::mouseMoveEvent(QMouseEvent* event) {
  94. if (m_bMouseTranslate) {
  95. // 计算鼠标当前位置与上次位置的差值
  96. QPointF delta = event->pos() - m_lastMousePos;
  97. // 平移视图
  98. horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x());
  99. verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y());
  100. m_lastMousePos = event->pos(); // 更新鼠标位置
  101. }
  102. else if ((event->buttons() & Qt::RightButton) && m_isDrawing && m_rightButtonPressed) {
  103. if (!m_curDrawing && (event->pos() - m_rightClickPressPos).manhattanLength() > 5) {
  104. m_curDrawing = true;
  105. // 根据初始位置开始绘制路径
  106. QPointF scenePos = mapToScene(m_rightClickPressPos);
  107. m_currentPath = QPainterPath(scenePos);
  108. m_currentPathItem = new QGraphicsPathItem();
  109. m_currentPathItem->setPen(QPen(Qt::red, 2));
  110. m_currentPathItem->setPath(m_currentPath);
  111. m_currentPathItem->setZValue(2);
  112. scene()->addItem(m_currentPathItem);
  113. m_drawnPaths.append(m_currentPathItem);
  114. }
  115. // 如果已经处于绘制状态,则继续添加点
  116. if (m_curDrawing && m_currentPathItem) {
  117. QPointF scenePos = mapToScene(event->pos());
  118. m_currentPath.lineTo(scenePos);
  119. m_currentPathItem->setPath(m_currentPath);
  120. }
  121. event->accept();
  122. return;
  123. }
  124. QGraphicsView::mouseMoveEvent(event);
  125. }
  126. void ImageView::mouseReleaseEvent(QMouseEvent* event) {
  127. if (event->button() == Qt::LeftButton) {
  128. setCursor(Qt::ArrowCursor); // 松开时恢复为箭头
  129. m_bMouseTranslate = false;
  130. }
  131. else if (event->button() == Qt::RightButton && m_rightButtonPressed) {
  132. if (!m_curDrawing) {
  133. // 右键点击(无拖动),弹出菜单
  134. QMenu menu(this);
  135. QAction* act1 = menu.addAction(tr("保存当前窗口图片"));
  136. QAction* act2 = menu.addAction(tr("清除"));
  137. connect(act1, &QAction::triggered, this, [this]() {
  138. saveImage();
  139. });
  140. connect(act2, &QAction::triggered, this, [this]() {
  141. clearDrawnLines();
  142. });
  143. menu.exec(event->globalPos());
  144. }
  145. else {
  146. // 绘制结束
  147. m_currentPathItem = nullptr;
  148. m_curDrawing = false;
  149. }
  150. // 恢复状态
  151. m_rightButtonPressed = false;
  152. event->accept();
  153. return;
  154. }
  155. QGraphicsView::mouseReleaseEvent(event);
  156. }
  157. void ImageView::wheelEvent(QWheelEvent* event)
  158. {
  159. if (event->orientation() == Qt::Vertical) {
  160. event->ignore(); // 忽略竖直滚轮事件(即禁用滚动条滑动)
  161. return;
  162. }
  163. event->accept();
  164. }
  165. void ImageView::saveImage()
  166. {
  167. // 使用当前时间生成默认文件名
  168. QString defaultFileName = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss") + ".png";
  169. QString fileName = QFileDialog::getSaveFileName(
  170. this,
  171. tr("保存图片"),
  172. QDir::homePath() + "/" + defaultFileName, // 默认路径为用户目录,文件名为当前时间
  173. tr("PNG 文件 (*.png);;JPEG 文件 (*.jpg);;所有文件 (*)")
  174. );
  175. if (!fileName.isEmpty()) {
  176. QImage image(viewport()->size(), QImage::Format_ARGB32);
  177. image.fill(Qt::white);
  178. QPainter painter(&image);
  179. this->render(&painter);
  180. if (!image.save(fileName)) {
  181. QMessageBox::warning(this, tr("保存失败"), tr("无法保存图片到指定路径。"));
  182. }
  183. else {
  184. QMessageBox::information(this, tr("保存成功"), tr("图片已成功保存到:") + fileName);
  185. }
  186. painter.end();
  187. }
  188. }
  189. void ImageView::clearDrawnLines()
  190. {
  191. qDeleteAll(m_drawnPaths);
  192. m_drawnPaths.clear();
  193. }