qtsmartgraphics  2.1.1
A simple library that improves the user experience when displaying images by Qt's QLabel and QGraphicsView.
qsmartgraphicsview.cpp
Go to the documentation of this file.
1 #include "qsmartgraphicsview.h"
2 #include <QStyleOptionGraphicsItem>
3 #include <QMenu>
4 #include <QPixmap>
5 #include <QFileDialog>
6 #include <QGraphicsSceneMouseEvent>
7 #include <QtConcurrent/QtConcurrentMap>
8 #include <QTime>
9 #include <QDebug>
10 #include <QReadWriteLock>
11 extern QReadWriteLock lock;
12 
14  QGraphicsView(parent)
15 {
16  qRegisterMetaType<std::vector<QPixmap>>("std::vector<QPixmap>");
17  this->setTransformationAnchor(QGraphicsView::NoAnchor);
18  this->setMouseTracking(true);
19  clipboard = QApplication::clipboard();
20  saveAction = new QAction("Save Image", this);
21  copyToClipBoardAction = new QAction("Copy to Clipboard", this);
22  connect(saveAction, SIGNAL(triggered()), this, SLOT(on_saveAction_triggered()));
23  connect(copyToClipBoardAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboardAction_triggered()));
24 
25 #ifndef NO_SIDEMENU
26  hideSideBar = new QAction("Hide Side Bar", this);
27  hideSideBar->setCheckable(true);
28  copySelectedRegion = new QAction("Copy Selected Region", this);
29  connect(hideSideBar, SIGNAL(triggered()), this, SLOT(on_hideSideBar_triggered()));
30  connect(copySelectedRegion, SIGNAL(triggered()), this, SLOT(on_copySelectedRegionAction_triggered()));
31 #endif
32  img_num = 0;
33  scene = new QGraphicsScene;
34 
35 #ifndef NO_SIDEMENU
36  //New side button bar. Not finished.
37  sbtn = new QSideButtonBar(2, this);
38  sbtn->renameButtonID("Normal", 0);
39  sbtn->renameButtonID("Select", 1);
40 #ifdef QT_SVG_LIB
41  QIcon normalsvg(":/d/dark/eye.svg");
42  QIcon selectsvg(":/d/dark/alignment-align.svg");
43  if(normalsvg.isNull() || selectsvg.isNull())
44  {
45  sbtn->renameButtonText("N", 0);
46  sbtn->renameButtonText("S", 1);
47  }
48  else
49  {
50  sbtn->setButtonIcon("Normal", normalsvg);
51  sbtn->setButtonIcon("Select", selectsvg);
52  }
53 
54 #else
55  sbtn->renameButtonText("N", 0);
56  sbtn->renameButtonText("S", 1);
57 #endif
58  connect(sbtn->returnButtonByName("Normal"), SIGNAL(clicked()), this, SLOT(on_normal_triggered()));
59  connect(sbtn->returnButtonByName("Select"), SIGNAL(clicked()), this, SLOT(on_selectRegion_triggered()));
60  sbtn->returnButtonByName("Normal")->setChecked(true);
61  QButtonGroup* group = new QButtonGroup(this);
62  group->addButton(sbtn->returnButtonByName("Normal"));
63  group->addButton(sbtn->returnButtonByName("Select"));
64  group->setExclusive(true);
65  mEffect = new QGraphicsOpacityEffect(sbtn);
66  mEffect->setOpacity(1.0);
67  sbtn->setGraphicsEffect(mEffect);
68  scene->addWidget(sbtn);
69 #endif
70  this->setScene(scene);
71 #ifdef QT_OPENGL_LIB
72  this->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers | QGL::DirectRendering)));
73 #endif
74  this->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
75 }
76 
78 {
79  scene->clear();
80  delete scene;
81 }
82 
83 void QSmartGraphicsView::initialize(const int _img_num, const int width, const int height, int changeRow)
84 {
85  const int CHANGE = changeRow > _img_num ? _img_num : changeRow;
86  img_num = _img_num;
87  const size_t CAP_NUM = img_num;
88  //Clear
89  scene->clear();
90  pix_item_vec.clear();
91  //--
92  // Add Pixmap Items
93  for(size_t i = 0; i < CAP_NUM; ++i){
94  QGraphicsPixmapItem *pix_item = scene->addPixmap(QPixmap(width, height));
95  pix_item_vec.push_back(pix_item);
96  }
97 
98  int hori_spacing = 0, verti_spacing = 0; //30 default
99  pix_item_vec[0]->setPos(0, 0);
100  QPointF p = pix_item_vec[0]->pos();
101  for(size_t i = 1; i < CAP_NUM; i++)
102  {
103  hori_spacing = (i % CHANGE) == 0 ? 0 : 30;
104  verti_spacing = (i < CHANGE) ? 0 : 30;
105 
106  pix_item_vec[i]->setPos(p.x() + width * (i % CHANGE) + hori_spacing * (i % CHANGE), p.y() + (int)(i / CHANGE) * height + verti_spacing);
107  }
108  this->fitInView(0, 0, width * CHANGE, height * CHANGE + verti_spacing * (CAP_NUM / CHANGE), Qt::KeepAspectRatio);
109  _initial = true;
110 }
111 
112 #ifdef HAVE_OPENCV
113 void QSmartGraphicsView::setImage(const cv::Mat &img)
114 {
115  lock.lockForRead();
116  QImage img_temp = QImage((uchar*)img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
117  lock.unlock();
118 //memcpy slows down the performance. Don't know why. :(
119 // QImage img_temp(img.cols, img.rows, QImage::Format_RGB888);
120 // lock.lockForRead();
121 // for(int y = 0; y < img.rows; ++y){
122 // memcpy(img_temp.scanLine(y), img.data + y * img.cols * 3, img.cols * 3);
123 // }
124 // lock.unlock();
125  pix_item_vec[0]->setPixmap(QPixmap::fromImage(img_temp.rgbSwapped()));
126 }
127 
128 void QSmartGraphicsView::setImage(const std::vector<cv::Mat> &imgs)
129 {
130  lock.lockForRead();
131  for(size_t i = 0; i < imgs.size(); ++i){
132  QImage img_temp(imgs[i].cols, imgs[i].rows, QImage::Format_RGB888);
133  for(int y = 0; y < imgs[i].rows; ++y){
134  memcpy(img_temp.scanLine(y), imgs[i].data + y * imgs[i].cols * 3, imgs[i].cols * 3);
135  }
136  pix_item_vec[i]->setPixmap(QPixmap::fromImage(img_temp.rgbSwapped()));
137  }
138  lock.unlock();
139  QList<QGraphicsItem *> item_list = this->items(this->rect());
140  for(int i = 0; i < item_list.size()/2; ++i){
141  item_list.at(i)->update();
142  }
143 }
144 #endif
145 
147 {
148  pix_item_vec[0]->setPixmap(QPixmap::fromImage(qimg));
149 }
150 
152 {
153  QList<QGraphicsItem *> item_list = this->items(this->rect());
154  for(int i = 0; i < item_list.size(); ++i){
155  QGraphicsPixmapItem *item = dynamic_cast<QGraphicsPixmapItem*>(item_list[i]);
156  if(item)
157  item->update();
158  }
159 }
160 
161 void QSmartGraphicsView::setImagefromQImage(const std::vector<QImage> &qimgs)
162 {
163  lock.lockForRead();
164  for(size_t i = 0; i < qimgs.size(); ++i)
165  pix_item_vec[i]->setPixmap(QPixmap::fromImage(qimgs[i]));
166  lock.unlock();
167  QList<QGraphicsItem *> item_list = this->items(this->rect());
168  for(int i = 0; i < item_list.size()/2; ++i){
169  item_list.at(i)->update();
170  }
171 }
172 
173 void QSmartGraphicsView::wheelEvent(QWheelEvent *event)
174 {
175  if(event->delta() == 0)
176  return;
177  QList<QGraphicsItem*> list = this->items();
178  if(list.size() <= 0)
179  return;
180 
181  QPointF pt = this->mapToScene(event->pos());
182  double factor;
183  if(event->delta() > 0)
184  factor = 1.1;
185  else if(event->delta() < 0)
186  factor = 0.9;
187  else
188  factor = 1;
189 #ifndef NO_SIDEMENU
190  if(rubberBand)
191  {
192  rubberBand->hide();
193  }
194 #endif
195  this->scale(factor, factor);
196  this->centerOn(pt);
197 }
198 
199 void QSmartGraphicsView::mouseMoveEvent(QMouseEvent *event)
200 {
201 #ifndef NO_SIDEMENU
202  if((mouse_status == 0) && event->buttons() == Qt::LeftButton){
203 #endif
204  this->translate(( -mou_x + event->x())/1.0, ( -mou_y + event->y())/1.0);
205  this->setCursor(Qt::ClosedHandCursor);
206  //QMessageBox::information(0, QString::number(mou_x - event->x()), QString::number(mou_y - event->y()));
207  this->setCursor(Qt::OpenHandCursor);
208 #ifndef NO_SIDEMENU
209  }
210  else if((mouse_status == 1) && (event->modifiers() & Qt::ControlModifier) && event->buttons() == Qt::LeftButton){
211  this->translate(( -mou_x + event->x())/1.0, ( -mou_y + event->y())/1.0);
212  this->setCursor(Qt::ClosedHandCursor);
213  //QMessageBox::information(0, QString::number(mou_x - event->x()), QString::number(mou_y - event->y()));
214  this->setCursor(Qt::OpenHandCursor);
215  }
216  else if((mouse_status == 1) && event->buttons() == Qt::LeftButton)
217  {
218  if(!is_item)
219  {
220  QGraphicsPixmapItem *item = dynamic_cast<QGraphicsPixmapItem *>(this->itemAt(event->pos()));
221  if(!item)
222  return;
223  select_item_start = this->mapFromScene(item->mapToScene(0, 0));
224  select_item_bound = this->mapFromScene(item->mapToScene(item->boundingRect().width(),item->boundingRect().height()));
225  int&& pos_x = (event->pos().x()) > select_item_bound.x() ? select_item_bound.x() : (event->pos().x() < select_item_start.x() ? select_item_start.x() : event->pos().x());
226  int&& pos_y = (event->pos().y()) > select_item_bound.y() ? select_item_bound.y() : (event->pos().y() < select_item_start.y() ? select_item_start.y() : event->pos().y());
227  select_start = QPoint(pos_x, pos_y);
228  rubberBand->setGeometry(QRect(select_start.toPoint(), QSize()));
229  rubberBand->show();
230  is_item = true;
231  return;
232  }
233 
234  int&& pos_x = (event->pos().x()) > select_item_bound.x() ? select_item_bound.x() : (event->pos().x() < select_item_start.x() ? select_item_start.x() : event->pos().x());
235  int&& pos_y = (event->pos().y()) > select_item_bound.y() ? select_item_bound.y() : (event->pos().y() < select_item_start.y() ? select_item_start.y() : event->pos().y());
236  rubberBand->setGeometry(QRect(select_start.toPoint(), QPoint(pos_x, pos_y)).normalized());
237  }
238 #endif
239 
240 
241  mou_x = event->x();
242  mou_y = event->y();
243 }
244 
245 void QSmartGraphicsView::mousePressEvent(QMouseEvent *event)
246 {
247  mou_x = event->x();
248  mou_y = event->y();
249  if(
250 #ifndef NO_SIDEMENU
251  (mouse_status == 0) &&
252 #endif
253  (event->button() == Qt::LeftButton))
254  this->setCursor(Qt::ClosedHandCursor);
255 #ifndef NO_SIDEMENU
256  else if(_initial && (mouse_status == 1) && event->buttons() == Qt::LeftButton)
257  {
258  if (!rubberBand)
259  rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
260  this->setDragMode(QGraphicsView::RubberBandDrag);
261 
262  QGraphicsPixmapItem *item = dynamic_cast<QGraphicsPixmapItem *>(this->itemAt(event->pos()));
263  if(!item)
264  {
265  rubberBand->hide();
266  return;
267  }
268 
269  select_item_start = this->mapFromScene(item->mapToScene(0, 0));
270  select_item_bound = this->mapFromScene(item->mapToScene(item->boundingRect().width(),item->boundingRect().height()));
271  int&& pos_x = (event->pos().x()) > select_item_bound.x() ? select_item_bound.x() : (event->pos().x() < select_item_start.x() ? select_item_start.x() : event->pos().x());
272  int&& pos_y = (event->pos().y()) > select_item_bound.y() ? select_item_bound.y() : (event->pos().y() < select_item_start.y() ? select_item_start.y() : event->pos().y());
273  select_start = QPoint(pos_x, pos_y);
274  rubberBand->setGeometry(QRect(select_start.toPoint(), QSize()));
275  rubberBand->show();
276  is_item = true;
277  }
278 #endif
279  else if(event->button() == Qt::MidButton)
280  {
281 #ifndef NO_SIDEMENU
282  if(rubberBand)
283  {
284  rubberBand->hide();
285  }
286 #endif
287  this->fitInView(0, 0, this->sceneRect().width(), this->sceneRect().height(), Qt::KeepAspectRatio);
288  }
289  emit sendMousePress();
290 }
291 
293 {
294  QGraphicsPixmapItem *item = dynamic_cast<QGraphicsPixmapItem *>(this->itemAt(event->pos()));
295  if(!item)
296  return;
297  QPointF local_pt = item->mapFromScene(this->mapToScene(event->pos()));
298  qDebug () << local_pt;
299  if(this->pix_item_vec.size() == 1)
300  emit sendItemMouXY(local_pt.x(), local_pt.y());
301 }
302 
304 {
305  this->setCursor(Qt::ArrowCursor);
306  if(event->button() == Qt::RightButton){
307  QMenu m(this);
308  m.addAction(saveAction);
309  m.addAction(copyToClipBoardAction);
310 #ifndef NO_SIDEMENU
311  if(mouse_status == 1)
312  {
313  m.addAction(copySelectedRegion);
314  }
315  m.addSeparator();
316  m.addAction(hideSideBar);
317 #endif
318  mou_press = event->pos();
319  m.exec(event->globalPos());
320  }
321 #ifndef NO_SIDEMENU
322  else if(event->button() == Qt::LeftButton && this->dragMode() == QGraphicsView::RubberBandDrag)
323  {
324  is_item = false;
325  if(event->pos() == select_start)
326  rubberBand->hide();
327 
328  this->setDragMode(QGraphicsView::NoDrag);
329  }
330 #endif
331 }
332 
333 #ifndef NO_SIDEMENU
334 void QSmartGraphicsView::keyPressEvent(QKeyEvent *event)
335 {
336  if(event->key() == Qt::Key_H)
337  {
338  hideSideBar->trigger();
339  }
340 }
341 #endif
342 
343 void QSmartGraphicsView::on_saveAction_triggered()
344 {
345  bool isError = false;
346  if(img_num == 0) {return;}
347  QFileDialog d;
348  if(img_num > 1)
349  d.setConfirmOverwrite(false);
350  QFileInfo file_name(d.getSaveFileName(0, "Img",0,"PNG (*.png);;BMP (*.bmp);;JPG (*.jpg)"));
351  if(file_name.fileName().isNull()) {
352  return;
353  }
354  if(img_num > 1)
355  for(int i = 0; i < img_num; ++i)
356  {
357  if(!pix_item_vec[i]->pixmap().isNull())
358  {
359  int num_index = 0;
360  if(file_name.exists())
361  ++num_index;
362  while(QFile::exists(file_name.absolutePath() + "/" + file_name.completeBaseName() + "_" + QString::number(i + num_index)+"."+file_name.suffix()))
363  ++num_index;
364  if(i == 0 && num_index == 0)
365  pix_item_vec[i]->pixmap().save(file_name.absoluteFilePath());
366  else
367  pix_item_vec[i]->pixmap().save(file_name.absolutePath() + "/" + file_name.completeBaseName() +"_"+QString::number(i + num_index)+"."+file_name.suffix());
368  }
369  else{isError = true;}
370  }
371  else
372  {
373  if(!pix_item_vec[0]->pixmap().isNull()){pix_item_vec[0]->pixmap().save(file_name.absoluteFilePath());}
374  else{isError = true;}
375  }
376  if(isError){QMessageBox::information(0, 0, "Can Not Save Image!!");}
377 }
378 
379 void QSmartGraphicsView::on_copyToClipboardAction_triggered()
380 {
381  bool isError = false;
382  if(img_num == 0) {return;}
383 
384  clipboard->clear();
385 
386  QGraphicsPixmapItem *item = dynamic_cast<QGraphicsPixmapItem *>(this->itemAt(mou_press));
387 
388  if(!item){isError = true;}
389  else if(!item->pixmap().isNull()){clipboard->setPixmap(item->pixmap());}
390  else{isError = true;}
391 
392  if(isError){QMessageBox::information(0, 0, "Can Not Save Image!!");}
393 }
394 
395 #ifndef NO_SIDEMENU
396 void QSmartGraphicsView::on_normal_triggered()
397 {
398  if(mouse_status == 0)
399  {
400  return;
401  }
402  mouse_status = 0;
403 }
404 
405 void QSmartGraphicsView::on_selectRegion_triggered()
406 {
407  if(mouse_status == 1)
408  {
409  return;
410  }
411  mouse_status = 1;
412 }
413 
414 
415 void QSmartGraphicsView::on_hideSideBar_triggered()
416 {
417  fadeOut();
418 }
419 
420 void QSmartGraphicsView::on_copySelectedRegionAction_triggered()
421 {
422  if(!rubberBand)
423  return;
424  if(rubberBand->isHidden())
425  return;
426 
427  QGraphicsPixmapItem *item = dynamic_cast<QGraphicsPixmapItem *>(this->itemAt(rubberBand->pos()));
428  if(!item)
429  return;
430 
431  QPointF point = item->mapFromScene(this->mapToScene(rubberBand->pos()));
432  QPointF point2 = item->mapFromScene(this->mapToScene(rubberBand->pos().x() + rubberBand->rect().width(), rubberBand->pos().y() + rubberBand->rect().height()));
433 
434  QImage cpy_img = item->pixmap().copy(QRect(point.toPoint(), point2.toPoint() - QPoint(1, 1))).toImage();
435  emit sendSelectedRegion(cpy_img);
436 }
437 
438 void QSmartGraphicsView::fadeOut()
439 {
440  QPropertyAnimation* animation = new QPropertyAnimation(mEffect,"opacity");
441  animation->setDuration(500);
442  if(sbtn->isVisible())
443  {
444  animation->setStartValue(1.0);
445  animation->setEndValue(0.0);
446  connect(animation,SIGNAL(finished()),this,SLOT(onAnimationFinished()));
447  }
448  else
449  {
450  sbtn->setVisible(true);
451  animation->setStartValue(0.0);
452  animation->setEndValue(1.0);
453  }
454  animation->start(QAbstractAnimation::DeleteWhenStopped);
455 }
456 
457 void QSmartGraphicsView::onAnimationFinished()
458 {
459  sbtn->setVisible(false);
460 }
461 #endif
void sendMousePress()
Sends signal if the mouse is pressed.
void mouseReleaseEvent(QMouseEvent *event)
void keyPressEvent(QKeyEvent *event)
void mouseDoubleClickEvent(QMouseEvent *event)
QReadWriteLock lock
void sendSelectedRegion(const QImage &img)
Send selected region selected by the rubberBand.
void renameButtonText(QString text, int btn_num)
void setImagefromQImage(const QImage &qimg)
Set a single image (QImage) to QSmartGraphicsView.
void sendItemMouXY(const double x, const double y)
Sends the mouse coordinate of the image when clicked the image.
void mousePressEvent(QMouseEvent *event)
void renameButtonID(QString ID, int btn_num)
void initialize(const int _img_num, const int width, const int height, int changeRow=4)
Must initial before setting any image to QSmartGraphicsView.
void mouseMoveEvent(QMouseEvent *event)
void setButtonIcon(QString name, const QIcon &icon)
QPushButton * returnButtonByName(QString name)
void wheelEvent(QWheelEvent *event)
QSmartGraphicsView(QWidget *parent=0)