ImageView.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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. #include <QApplication>
  11. #define VIEW_CENTER viewport()->rect().center()
  12. #define VIEW_WIDTH viewport()->rect().width()
  13. #define VIEW_HEIGHT viewport()->rect().height()
  14. ImageView::ImageView(QWidget* parent) :
  15. QGraphicsView(parent),
  16. m_imageOffset(0, 0),
  17. m_bMouseTranslate(false),
  18. m_isDrawing(false),
  19. m_curDrawing(false),
  20. m_isCreating(false),
  21. m_currentPathItem(nullptr)
  22. {
  23. // m_rubberBand = nullptr;
  24. m_bRulerState = false;
  25. m_pRuleLine = nullptr;
  26. setScene(new QGraphicsScene(this));
  27. setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
  28. this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  29. this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  30. //设置视图属性
  31. //setRenderHint(QPainter::SmoothPixmapTransform);
  32. setRenderHint(QPainter::Antialiasing);
  33. setMouseTracking(true);
  34. setDragMode(RubberBandDrag);
  35. }
  36. ImageView::~ImageView()
  37. {
  38. }
  39. void ImageView::setPixmap(const QPixmap& newPixmap) {
  40. this->m_pixmap = newPixmap;
  41. scene()->clear();
  42. m_pixmapItem = scene()->addPixmap(m_pixmap);
  43. m_pixmapItem->setZValue(1);
  44. QPointF pixmapCenter(m_pixmap.width() / 2.0, m_pixmap.height() / 2.0);
  45. m_pixmapItem->setPos(-pixmapCenter);
  46. QRectF sceneRect(-pixmapCenter.x(), -pixmapCenter.y(), m_pixmap.width(), m_pixmap.height());
  47. scene()->setSceneRect(sceneRect);
  48. setSceneRect(scene()->itemsBoundingRect());
  49. this->resize(m_pixmap.width(), m_pixmap.height());
  50. m_imageOffset = QPoint(0, 0); // 重置图片偏移量为(0, 0)
  51. setCursor(Qt::ArrowCursor);
  52. update(); // 触发重绘
  53. }
  54. void ImageView::setCurPixmap(const QPixmap& newPixmap) {
  55. if (this->m_pixmap.isNull()) {
  56. this->m_pixmap = newPixmap;
  57. scene()->clear();
  58. m_pixmapItem = scene()->addPixmap(m_pixmap);
  59. m_pixmapItem->setZValue(1);
  60. QPointF pixmapCenter(m_pixmap.width() / 2.0, m_pixmap.height() / 2.0);
  61. m_pixmapItem->setPos(-pixmapCenter);
  62. QRectF sceneRect(-pixmapCenter.x(), -pixmapCenter.y(), m_pixmap.width(), m_pixmap.height());
  63. scene()->setSceneRect(sceneRect);
  64. setSceneRect(scene()->itemsBoundingRect());
  65. //this->resize(m_pixmap.width(), m_pixmap.height());
  66. m_imageOffset = QPoint(0, 0); // 重置图片偏移量为(0, 0)
  67. setCursor(Qt::ArrowCursor);
  68. update(); // 触发重绘
  69. }
  70. else {
  71. this->m_pixmap = newPixmap;
  72. m_pixmapItem->setPixmap(m_pixmap);
  73. }
  74. }
  75. void ImageView::addRuler()
  76. {
  77. m_bRulerState = true;
  78. }
  79. void ImageView::cancelRuler()
  80. {
  81. m_bRulerState = false;
  82. }
  83. void ImageView::paintEvent(QPaintEvent* event) {
  84. QGraphicsView::paintEvent(event);
  85. QPainter painter(viewport());
  86. painter.setRenderHint(QPainter::Antialiasing);
  87. drawCrosshair(painter);
  88. }
  89. void ImageView::mousePressEvent(QMouseEvent* event) {
  90. if (event->button() == Qt::LeftButton) {
  91. // 当光标底下没有 item 时,才能移动
  92. QPointF point = mapToScene(event->pos());
  93. if (scene()->itemAt(point, transform()) != nullptr
  94. && scene()->itemAt(point, transform())->type() == QGraphicsPixmapItem::Type) {
  95. setCursor(Qt::OpenHandCursor);
  96. m_bMouseTranslate = true;
  97. m_lastMousePos = event->pos();
  98. }
  99. }
  100. else if (event->button() == Qt::RightButton) {
  101. m_rightClickPressPos = event->pos();
  102. m_rightButtonPressed = true;
  103. if (m_bRulerState) {
  104. if (!m_isCreating) {
  105. // 第一次点击:开始创建
  106. m_isCreating = true;
  107. m_startPos = mapToScene(event->pos());
  108. m_pTempLine = scene()->addLine(QLineF(m_startPos, m_startPos),
  109. QPen(Qt::gray, 1, Qt::DashLine));
  110. m_pTempLine->setZValue(2);
  111. }
  112. else {
  113. // 第二次点击:完成创建
  114. m_isCreating = false;
  115. QPointF endPos = mapToScene(event->pos());
  116. scene()->removeItem(m_pTempLine);
  117. delete m_pTempLine;
  118. RulerLineItem* ruler = new RulerLineItem(QLineF(m_startPos, endPos));
  119. ruler->setRulerText(tr("test ruler"));
  120. ruler->setZValue(2);
  121. scene()->addItem(ruler);
  122. }
  123. }
  124. event->accept();
  125. }
  126. QGraphicsView::mousePressEvent(event);
  127. }
  128. void ImageView::mouseMoveEvent(QMouseEvent* event) {
  129. if (m_isCreating && m_pTempLine) {
  130. QPointF currentPos = mapToScene(event->pos());
  131. m_pTempLine->setLine(QLineF(m_startPos, currentPos));
  132. }
  133. if (m_bMouseTranslate) {
  134. // 计算鼠标当前位置与上次位置的差值
  135. QPointF delta = event->pos() - m_lastMousePos;
  136. // 平移视图
  137. horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x());
  138. verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y());
  139. m_lastMousePos = event->pos(); // 更新鼠标位置
  140. }
  141. else if ((event->buttons() & Qt::RightButton) && m_isDrawing && m_rightButtonPressed) {
  142. if (!m_curDrawing && (event->pos() - m_rightClickPressPos).manhattanLength() > 5) {
  143. m_curDrawing = true;
  144. // 根据初始位置开始绘制路径
  145. QPointF scenePos = mapToScene(m_rightClickPressPos);
  146. m_currentPath = QPainterPath(scenePos);
  147. m_currentPathItem = new QGraphicsPathItem();
  148. m_currentPathItem->setPen(QPen(Qt::red, 2));
  149. m_currentPathItem->setPath(m_currentPath);
  150. m_currentPathItem->setZValue(2);
  151. scene()->addItem(m_currentPathItem);
  152. m_drawnPaths.append(m_currentPathItem);
  153. }
  154. // 如果已经处于绘制状态,则继续添加点
  155. if (m_curDrawing && m_currentPathItem) {
  156. QPointF scenePos = mapToScene(event->pos());
  157. m_currentPath.lineTo(scenePos);
  158. m_currentPathItem->setPath(m_currentPath);
  159. }
  160. event->accept();
  161. return;
  162. }
  163. QGraphicsView::mouseMoveEvent(event);
  164. }
  165. void ImageView::mouseReleaseEvent(QMouseEvent* event) {
  166. if (event->button() == Qt::LeftButton) {
  167. setCursor(Qt::ArrowCursor); // 松开时恢复为箭头
  168. m_bMouseTranslate = false;
  169. }
  170. else if (event->button() == Qt::RightButton && m_rightButtonPressed) {
  171. if (!m_curDrawing) {
  172. if (!m_bRulerState) {
  173. // 右键点击(无拖动),弹出菜单
  174. QMenu menu(this);
  175. QAction* act1 = menu.addAction(tr("save picture"));
  176. QAction* act2 = menu.addAction(tr("clear"));
  177. connect(act1, &QAction::triggered, this, [this]() {
  178. saveImage();
  179. });
  180. connect(act2, &QAction::triggered, this, [this]() {
  181. clearDrawnLines();
  182. });
  183. menu.exec(event->globalPos());
  184. }
  185. }
  186. else {
  187. // 绘制结束
  188. m_currentPathItem = nullptr;
  189. m_curDrawing = false;
  190. }
  191. // 恢复状态
  192. m_rightButtonPressed = false;
  193. event->accept();
  194. return;
  195. }
  196. QGraphicsView::mouseReleaseEvent(event);
  197. }
  198. void ImageView::wheelEvent(QWheelEvent* event)
  199. {
  200. if (event->orientation() == Qt::Vertical) {
  201. event->ignore(); // 忽略竖直滚轮事件(即禁用滚动条滑动)
  202. return;
  203. }
  204. event->accept();
  205. }
  206. void ImageView::resizeEvent(QResizeEvent* event)
  207. {
  208. QGraphicsView::resizeEvent(event);
  209. viewport()->update(); // 窗口大小改变时重绘十字线
  210. }
  211. void ImageView::scrollContentsBy(int dx, int dy)
  212. {
  213. QGraphicsView::scrollContentsBy(dx, dy);
  214. viewport()->update(); // 滚动时更新十字线
  215. }
  216. void ImageView::drawCrosshair(QPainter& painter)
  217. {
  218. const QRect viewRect = viewport()->rect();
  219. int resolutionWidth = viewRect.width();
  220. int resolutionHeight = viewRect.height();
  221. painter.setPen(QPen(QColor(139, 105, 20, 255), 1));
  222. // 绘制垂直线
  223. painter.drawLine(resolutionWidth / 2, 0, resolutionWidth / 2, resolutionHeight);
  224. // 绘制水平线
  225. painter.drawLine(0, resolutionHeight / 2, resolutionWidth, resolutionHeight / 2);
  226. int centerX = resolutionWidth / 2;
  227. int centerY = resolutionHeight / 2;
  228. int rulerLength = viewRect.width(); // 量尺长度
  229. int tickSpacing = 5; // 刻度间距
  230. // 绘制水平中心线上的量尺
  231. int rulerStartXHorizontal = centerX;
  232. int rulerStartYHorizontal = centerY;
  233. for (int i = 0; i <= rulerLength / 2; i += tickSpacing) {
  234. int tickHeight = 0;
  235. if (i % (tickSpacing * 10) == 0) { // 长刻度
  236. tickHeight = 15;
  237. }
  238. else if (i % (tickSpacing * 5) == 0) { // 中等刻度
  239. tickHeight = 10;
  240. }
  241. else { // 短刻度
  242. tickHeight = 5;
  243. }
  244. painter.drawLine(rulerStartXHorizontal + i, rulerStartYHorizontal, rulerStartXHorizontal + i, rulerStartYHorizontal - tickHeight); // 绘制刻度线
  245. painter.drawLine(rulerStartXHorizontal - i, rulerStartYHorizontal, rulerStartXHorizontal - i, rulerStartYHorizontal - tickHeight); // 绘制刻度线
  246. }
  247. // 绘制垂直中心线上的量尺
  248. int rulerStartXVertical = centerX;
  249. int rulerStartYVertical = centerY;
  250. for (int i = 0; i <= rulerLength / 2; i += tickSpacing) {
  251. int tickWidth = 0;
  252. if (i % (tickSpacing * 10) == 0) { // 长刻度
  253. tickWidth = 15;
  254. }
  255. else if (i % (tickSpacing * 5) == 0) { // 中等刻度
  256. tickWidth = 10;
  257. }
  258. else { // 短刻度
  259. tickWidth = 5;
  260. }
  261. painter.drawLine(rulerStartXVertical, rulerStartYVertical - i, rulerStartXVertical - tickWidth, rulerStartYVertical - i);
  262. painter.drawLine(rulerStartXVertical, rulerStartYVertical + i, rulerStartXVertical - tickWidth, rulerStartYVertical + i);
  263. }
  264. }
  265. void ImageView::saveImage()
  266. {
  267. // 使用当前时间生成默认文件名
  268. QString defaultFileName = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss") + ".png";
  269. QString fileName = QFileDialog::getSaveFileName(
  270. this,
  271. tr("保存图片"),
  272. QDir::homePath() + "/" + defaultFileName, // 默认路径为用户目录,文件名为当前时间
  273. tr("PNG 文件 (*.png);;JPEG 文件 (*.jpg);;所有文件 (*)")
  274. );
  275. if (!fileName.isEmpty()) {
  276. QImage image(viewport()->size(), QImage::Format_ARGB32);
  277. image.fill(Qt::white);
  278. QPainter painter(&image);
  279. this->render(&painter);
  280. if (!image.save(fileName)) {
  281. QMessageBox::warning(this, tr("保存失败"), tr("无法保存图片到指定路径。"));
  282. }
  283. else {
  284. QMessageBox::information(this, tr("保存成功"), tr("图片已成功保存到:") + fileName);
  285. }
  286. painter.end();
  287. }
  288. }
  289. void ImageView::clearDrawnLines()
  290. {
  291. qDeleteAll(m_drawnPaths);
  292. m_drawnPaths.clear();
  293. foreach(QGraphicsItem * item, scene()->selectedItems()) {
  294. if (nullptr == item)
  295. continue;
  296. scene()->removeItem(item);
  297. }
  298. }