ImageView.cpp 7.2 KB

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