6

我有一个从 QGraphicsView 派生的自定义类,它实现了一个插槽调用 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 和s 链接,在我已覆盖slot的底部视图中;在顶视图中被上面捕捉到。scrollContentsBy(int dx, int dy)emit horizontalScroll(dx)slot

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

更新2:

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

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

更新 3:

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

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

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

现在我在QGraphicsScene::ResizeEvent()和其他地方使用以下代码片段,根据需要更新中心

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&);

};

页眉视图.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);

};

事件视图.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));
4

3 回答 3

10

我曾QGraphicsView在 Qt 4.6.3 - 4.7.2 中使用过,并且不得不争辩说您可以通过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它将滚动条移动到适当的位置。

于 2012-07-20T17:02:13.420 回答
3

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

不知道你是否还能调用隐藏的滚动条来滚动它。如果没有, translate是一种选择。

于 2012-07-17T18:22:41.600 回答
2

您是否尝试使用滚动条?隐藏它们并不会使它们不存在,并且文档说您应该使用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!
}
于 2012-07-19T21:41:06.367 回答