Qt使用QGraphicsView实现滑动窗体效果

时间:2021-08-16 07:39:12

QGraphicsView用来显示一个滚动视图区的QGraphicsScene内容。QGraphicsScene提供了QGraphicsItem的容器功能。通常与QGraphicsView一起使用来描述可视化图形项目。

QGraphicsScene提供了一个视图的场景,通过在这样一个场景之上加入不同的QGraphicsItem来构建视图。而 QGraphicsView则提供了一个widget来显示QGraphicsScene的内容。所以要想成功构建一个视图,这三个元素缺一不可。

以下是一个QGraphicsView的例子,实现滑动的窗体效果,工具栏和图片均为场景中的Item。

  1. #include <QtCore>
  2. #include <QtGui>
  3. #include <QtSvg>
  4. /*程序中用到了svg格式的图片,所以需包含QtSvg*/
  5. #define PAGE_COUNT 5
  6. /*定义滑动窗体的窗体数*/

定义工具栏,NviBar继承自QGraphicsRectItem,用法与QGraphicsItem类似。

  1. class NaviBar : public QObject, public QGraphicsRectItem
  2. {
  3. Q_OBJECT
  4. public:
  5. NaviBar();
  6. void setPageOffset(qreal ofs);
  7. signals:
  8. void pageSelected(int page);
  9. protected:
  10. void mousePressEvent(QGraphicsSceneMouseEvent *event);
  11. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
  12. private:
  13. QList<QGraphicsSvgItem*> m_icons;
  14. QGraphicsRectItem *m_cursor;
  15. };

函数实现

  1. #define ICON_SIZE 50
  2. #define ICON_PAD 4
  3. NaviBar::NaviBar()
  4. : QGraphicsRectItem()
  5. {
  6. setRect(0, 0, 5 * ICON_SIZE, ICON_SIZE);
  7. setPen(Qt::NoPen);
  8. QStringList names;
  9. names << "map" << "web" << "home" << "weather" << "contacts";
  10. for (int i = 0; i < names.count(); ++i) {
  11. QString fname = names[i];
  12. fname.prepend(":/icons/");
  13. fname.append("-page.svg");
  14. QGraphicsSvgItem *icon = new QGraphicsSvgItem(fname);
  15. icon->setParentItem(this);
  16. const int dim = ICON_SIZE - ICON_PAD * 2;
  17. qreal sw = dim / icon->boundingRect().width();
  18. qreal sh = dim / icon->boundingRect().height();
  19. icon->setTransform(QTransform().scale(sw, sh));
  20. icon->setZValue(2);
  21. m_icons << icon;
  22. }
  23. m_cursor = new QGraphicsRectItem;
  24. m_cursor->setParentItem(this);
  25. m_cursor->setRect(0, 0, ICON_SIZE, ICON_SIZE);
  26. m_cursor->setZValue(1);
  27. m_cursor->setPen(Qt::NoPen);
  28. m_cursor->setBrush(QColor(Qt::white));
  29. m_cursor->setOpacity(0.6);
  30. }
  31. void NaviBar::setPageOffset(qreal ofs)
  32. {
  33. m_cursor->setPos(ofs * ICON_SIZE, 0);
  34. for (int i = 0; i < m_icons.count(); ++i) {
  35. int y = (i == static_cast<int>(ofs + 0.5)) ? ICON_PAD : ICON_PAD * 2;
  36. m_icons[i]->setPos(i * ICON_SIZE + ICON_PAD, y);
  37. m_icons[i]->setOpacity(1);
  38. }
  39. }
  40. void NaviBar::mousePressEvent(QGraphicsSceneMouseEvent *event)
  41. {
  42. emit pageSelected(static_cast<int>(event->pos().x() / ICON_SIZE));
  43. }
  44. void NaviBar::paint(QPainter * painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  45. {
  46. painter->setBrush(Qt::white);
  47. painter->setOpacity(0.2);
  48. painter->drawRect(option->rect.adjusted(-20, ICON_PAD, 20, 0));
  49. }

定义视图

  1. class ParallaxHome: public QGraphicsView
  2. {
  3. Q_OBJECT
  4. public:
  5. QGraphicsScene m_scene;
  6. NaviBar *m_naviBar;
  7. QGraphicsPixmapItem *m_wallpaper;
  8. QTimeLine m_pageAnimator;
  9. qreal m_pageOffset;
  10. QList<QGraphicsPixmapItem*> m_items;
  11. QList<QPointF> m_positions;
  12. public:
  13. ParallaxHome(QWidget *parent = 0)
  14. : QGraphicsView(parent)
  15. , m_pageOffset(-2) {
  16. setupScene();
  17. setScene(&m_scene);
  18. setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  19. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  20. setFrameShape(QFrame::NoFrame);
  21. setWindowTitle("Parallax Home");
  22. connect(&m_pageAnimator, SIGNAL(frameChanged(int)), SLOT(shiftPage(int)));
  23. m_pageAnimator.setDuration(500);
  24. m_pageAnimator.setFrameRange(0, 100);
  25. m_pageAnimator.setCurveShape(QTimeLine::EaseInCurve);
  26. pageChanged(static_cast<int>(m_pageOffset));
  27. }
  28. signals:
  29. void pageChanged(int page);
  30. public slots:
  31. void slideRight() {
  32. if (m_pageAnimator.state() != QTimeLine::NotRunning)
  33. return;
  34. int edge = -(m_pageOffset - 1);
  35. if (edge < PAGE_COUNT)
  36. slideBy(-1);
  37. }
  38. void slideLeft() {
  39. if (m_pageAnimator.state() != QTimeLine::NotRunning)
  40. return;
  41. if (m_pageOffset < 0)
  42. slideBy(1);
  43. }
  44. void slideBy(int dx) {
  45. int start = m_pageOffset * 1000;
  46. int end = (m_pageOffset + dx) * 1000;
  47. m_pageAnimator.setFrameRange(start, end);
  48. m_pageAnimator.start();
  49. }
  50. void choosePage(int page) {
  51. if (m_pageAnimator.state() != QTimeLine::NotRunning)
  52. return;
  53. if (static_cast<int>(-m_pageOffset) == page)
  54. return;
  55. slideBy(-page - m_pageOffset);
  56. }
  57. private slots:
  58. void shiftPage(int frame) {
  59. int ww = width();
  60. int hh = height() - m_naviBar->rect().height();
  61. int oldPage = static_cast<int>(-m_pageOffset);
  62. m_pageOffset = static_cast<qreal>(frame) / qreal(1000);
  63. int newPage = static_cast<int>(-m_pageOffset);
  64. m_naviBar->setPageOffset(-m_pageOffset);
  65. if (oldPage != newPage)
  66. emit pageChanged(newPage);
  67. int ofs = m_pageOffset * ww;
  68. for (int i = 0; i < m_items.count(); ++i) {
  69. QPointF pos = m_positions[i];
  70. QPointF xy(pos.x() * ww, pos.y() * hh);
  71. m_items[i]->setPos(xy + QPointF(ofs, 0));
  72. }
  73. int center = m_wallpaper->pixmap().width() / 2;
  74. const int parallax = 3;
  75. int base = center - (ww / 2) - (PAGE_COUNT >> 1) * (ww / parallax);
  76. int wofs = base - m_pageOffset * ww / parallax;
  77. m_wallpaper->setPos(-wofs, 0);
  78. }
  79. protected:
  80. void resizeEvent(QResizeEvent *event) {
  81. Q_UNUSED(event);
  82. layoutScene();
  83. }
  84. void keyPressEvent(QKeyEvent *event) {
  85. if (event->key() == Qt::Key_Right)
  86. slideRight();
  87. if (event->key() == Qt::Key_Left)
  88. slideLeft();
  89. event->accept();
  90. }
  91. private:
  92. void layoutScene() {
  93. int ww = width();
  94. int hh = height();
  95. m_scene.setSceneRect(0, 0, PAGE_COUNT * ww - 1, hh - 1);
  96. centerOn(ww / 2, hh / 2);
  97. int nw = m_naviBar->rect().width();
  98. int nh = m_naviBar->rect().height();
  99. m_naviBar->setPos((ww - nw) / 2, hh - nh);
  100. shiftPage(m_pageOffset * 1000);
  101. }
  102. void setupScene() {
  103. qsrand(QTime::currentTime().second());
  104. QStringList names;
  105. names << "brownies" << "cookies" << "mussels" << "pizza" << "sushi";
  106. names << "chocolate" << "fish" << "pasta" << "puding" << "trouts";
  107. for (int i = 0; i < PAGE_COUNT * 2; ++i) {
  108. QString fname = names[i];
  109. fname.prepend(":/images/");
  110. fname.append(".jpg");
  111. QPixmap pixmap(fname);
  112. pixmap = pixmap.scaledToWidth(200);
  113. QGraphicsPixmapItem *item = m_scene.addPixmap(pixmap);
  114. m_items << item;
  115. qreal x = (i >> 1) + (qrand() % 30) / 100.0;
  116. qreal y = (i & 1) / 2.0  + (qrand() % 20) / 100.0;
  117. m_positions << QPointF(x, y);
  118. item->setZValue(1);
  119. }
  120. m_naviBar = new NaviBar;
  121. m_scene.addItem(m_naviBar);
  122. m_naviBar->setZValue(2);
  123. connect(m_naviBar, SIGNAL(pageSelected(int)), SLOT(choosePage(int)));
  124. m_wallpaper = m_scene.addPixmap(QPixmap(":/icons/surfacing.png"));
  125. m_wallpaper->setZValue(0);
  126. m_scene.setItemIndexMethod(QGraphicsScene::NoIndex);
  127. }
  128. };

main函数

  1. #include "parallaxhome.moc"
  2. int main(int argc, char *argv[])
  3. {
  4. QApplication app(argc, argv);
  5. ParallaxHome w;
  6. w.resize(360, 640);
  7. w.show();
  8. return app.exec();
  9. }

效果图

原文:http://blog.csdn.net/huihui1988/article/details/5725955