【问题标题】:Programmatic QGraphicsView scrolling not updating properly程序化 QGraphicsView 滚动未正确更新
【发布时间】:2012-07-16 17:23:31
【问题描述】:

我有一个从 QGraphicsView 派生的自定义类,它实现了一个 slot 调用 scrollHorizo​​ntal(int dx),里面的代码很简单

void CustomView::scrollHorizontal(int dx){
    scrollContentsBy(dx, 0);
}

我的问题是,像这样滚动有效,但不能正确更新场景,而是重复在视图边缘找到的任何像素,而不是重新调用项目的 paint() 方法。

之后我尝试调用update(),但没有任何反应。我尝试通过拖动启用滚动并且更新工作正常!但我需要以编程方式完成它,因为我有滚动条隐藏了 horizontalScrollBar()->setValue() 之类的东西,所以不要滚动视图。

我也试过了:

scrollContentsBy(dx, 0);
this->scene()->invalidate(sceneRect());
this->update();

更新:

QPointF center = mapToScene(viewport()->rect().center()); 
centerOn(center.x() - dx, center.y()); 
update(); 

正在工作,但现在我的顶视图滚动速度比底视图慢,这是一个新问题。它们与signals 和slots 链接,在底部视图中我将scrollContentsBy(int dx, int dy) 覆盖为emit horizontalScroll(dx);上面的slot在顶视图中捕捉到了。

任何想法为什么卷轴以不同的速度发生?滚动条可能与作为底部视图的一部分有效地使其成为“较小”窗口有关吗?

更新 2:

不同的滚动率似乎源于一些舍入,使用 mapToScene(viewport()->rect().center()); 给我一个基于整数的“中心”,当您滚动时,滚动速度越慢,此错误加起来越多,滚动速度越快,总数越少错误。

我有办法解决这个问题吗?我没有看到任何方法来获得浮点中心点。

更新 3:

所以我基本上解决了这个问题,结果证明需要 mapToScene(我在网上其他地方找到的代码)。

我通过存储 FP 计算的视口中心的 QPointF 来解决此问题,现在滚动两个视图时的错误量不明显。

最后一个问题是,当您向右滚动任意数量,然后调整窗口大小然后再次滚动时,视图不再排列。我认为这与计算中心点和居中发生时间的逻辑顺序有关。

现在我在 QGraphicsScene::ResizeEvent() 和其他地方使用以下代码 sn-p 来根据需要更新中心

QRectF viewPort(viewport()->rect());
QPointF rectCenter((viewPort.x() + viewPort.x() + viewPort.width())/2.0, (viewPort.y() + viewPort.y() + viewPort.height())/2.0);

viewCenter = rectCenter;

还有我的horizontalScroll(int dx)slot

void CustomView::horizontalScroll(int dx)
{
    viewCenter.setX(viewCenter.x() - dx);
    centerOn(viewCenter.x(), viewCenter.y());
    update();
}

如何解决在重新调整窗口大小时破坏两个视图对齐的问题?如果需要进一步澄清,请尽管问,如果需要,我可以尝试给出我所指的内容的骨架。

更新 4:

粗略的代码骨架

Class HeaderView:

class HeaderView View : public QGraphicsView
{
    Q_OBJECT
public:
    HeaderView(QWidget * parent = 0);
    HeaderView(QGraphicsScene * scene, QWidget * parent = 0);

private:
    QPointF viewCenter;

protected:
    void resizeEvent ( QResizeEvent * event );

public slots:
    void horizontalScroll(int);
    void addModel(qreal, qreal, const QString&);

};

HeaderView.cpp

void HeaderView::resizeEvent(QResizeEvent *event)
{
    QGraphicsView::resizeEvent(event);
    QRectF viewPort(viewport()->rect());
    QPointF rectCenter((viewPort.x() + viewPort.x() + viewPort.width())/2.0, (viewPort.y() + viewPort.y() + viewPort.height())/2.0);

    viewCenter = rectCenter;
}

void HeaderView::horizontalScroll(int dx)
{
    viewCenter.setX(viewCenter.x() - dx);
    centerOn(viewCenter.x(), viewCenter.y());
    update();
}

类事件视图:

class EventView : public QGraphicsView
{
Q_OBJECT
public:
    EventView(QWidget * parent = 0);
    EventView(QGraphicsScene * scene, QWidget * parent = 0);
    QRectF visibleRect();

protected:
     void scrollContentsBy ( int dx, int dy );

signals:
    void horizontalScroll(int);

};

EventView.cpp

void EventView::scrollContentsBy(int dx, int dy)
{
    QGraphicsView::scrollContentsBy(dx, dy);

    if(dx != 0){
        emit horizontalScroll(dx);
    }
}

类 MainWindow 中的某处:

connect(eventView, SIGNAL(horizontalScroll(int)), headerView, SLOT(horizontalScroll(int));

【问题讨论】:

  • 我真的很想看一下重现此代码的最小示例。
  • 我也认为最好的办法是创建一个最小的示例代码。只有这两种观点有联系。你能做这个吗?这会有很大帮助。也许您会在这样做的同时找到解决方案,这种情况经常发生。 ;)

标签: c++ qt user-interface graphics scroll


【解决方案1】:

我曾在 Qt 4.6.3 - 4.7.2 中使用过 QGraphicsView,并且不得不证明您可以通过以下方式使用各自的 QScrollBar

//graphics view initialization
QGraphicsView *graphicsView = new QGraphicsView(parent);
QGraphicsScene *scene = new QGraphicsScene(0,0,widthOfScene,heightOfScene,parent);
graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
graphicsView->setScene(scene);

//in another method
QScrollBar* yPos=graphicsView->verticalScrollBar();
yPos->setValue((int) newValue);

它们是否隐藏并不重要。只要您的图形场景大于图形视图,他们仍会回复setValue(int)

QGraphicsView 也会响应ensureVisible,它将滚动条移动到适当的位置。

【讨论】:

  • 原来我试图 scollBar.scroll() 错误地是滚动条继承的公共 QWidget 函数。最终,我最终通过发射/捕获 this->horizo​​ntalScrollBar()->value() 和 setValue() 来同步窗口
  • 很好的答案!这为我节省了大量时间。
【解决方案2】:

你不应该像这里解释的那样打电话给scrollContentsByhttp://qt-project.org/doc/qt-4.8/qabstractscrollarea.html#scrollContentsBy

不知道还能不能调用隐藏的滚动条来滚动。如果没有,translate 是一个选项。

【讨论】:

  • 调用 translate(dx, 0) 对场景没有任何作用。
  • 好吧。它应该工作。但是然后尝试 centerOn 一个场景点。您需要自己计算点数。
  • void CustomView::horizo​​ntalScroll(int dx) { QPointF center = mapToScene(viewport()->rect().center()); centerOn(center.x() + dx, center.y());更新(); } 也不起作用
  • QPointF center = mapToScene(viewport()->rect().center()); centerOn(center.x() - dx, center.y());更新();正在工作,但现在我的顶视图滚动速度比底视图慢,这是一个新问题。
  • 如果目标是跟踪一组视图和场景到另一组,并且两个场景具有相同的大小,我会考虑复制视图转换。每当驱动视图发生变化时,将驱动视图设置为具有相同的变换。
【解决方案3】:

您是否尝试过使用滚动条?隐藏它们并不会使它们不存在,the documentation says 您应该使用QScrollBar::setValue 滚动到给定位置。

另一种选择是将QGraphicsView::centerOn(QPointF) 与当前中心点结合使用——正如你也尝试过的那样——但直接在你的方法中计算中心点(不要预先计算和存储中心点),通过使用QGraphicsView::mapToScene(int,int):

void CustomView::horizontalScroll(int dx)
{
    QPointF viewCenter = mapToScene(width() / 2, height() / 2);
    viewCenter += QPointF(dx, 0); // Why did you subtract instead of add dx?
    centerOn(viewCenter); // BTW, you don't need to do .x(), .y()
    // You can remove update(); as this is already called in centerOn().
}

请注意,如果您有如您所说的“scrollContentsBy(int dx, int dy) 覆盖为emit horizontalScroll(dx)”,您还必须调用超类方法以便视图可以自行滚动:

void CustomView::scrollContentsBy(int dx, int dy)
{
    emit horizontalScrolled(dx); // (You should call it different than the slot!)
    QGraphicsView::scrollContentsBy(dx, dy); // <-- This is what I mean!
}

【讨论】:

  • 我确实已经调用了超类方法,并且当 QScrollBar 隐藏时它们不会初始化,因此 QScrollBar::setValue 不会导致任何行为。减去 dx 是因为当添加 dx 时,卷轴朝相反的方向移动。我的视图原点是左上角的 (0,0),正数导致视图中的位置较低。
  • 我尝试了你的 Horizo​​ntalScroll() 方法,它向下滚动我的视图....然后水平滚动到发射视图滚动的相反方向。更改为 viewCenter += QPointF(-1 * dx, 0);将其设置在正确的方向,但仍会导致视图向下滚动(我怀疑是 mapToScene() 导致它)。
  • 尝试以下操作:删除点添加行,看看调用horizontalScroll(anything) 时会发生什么(或看看调用horizontalScroll(0) 时会发生什么)。问题可能是:width() / 2, height() / 2 是整数除法,如果大小为奇数,则向下舍入。将大小设置为偶数并重试,就像测试一样。您也可以尝试(width() + 1) / 2 以向上取整而不是向下取整。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 2012-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多