ImageView.cpp 7.2 KB

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