>我有一个从QGraphicsView派生的自定义类,它实现了插槽调用scrollHorizontal(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();
正在工作,但现在我的顶视图滚动速度比底视图慢,这是一个新问题。它们与signal
s和slot
s相关联,在底部视图中,我scrollContentsBy(int dx, int dy)
覆盖到emit horizontalScroll(dx)
;在顶视图中被上述slot
捕获。
知道为什么卷轴以不同的速度发生吗?它是否与滚动条成为底部视图的一部分有关,有效地使其成为"较小"窗口?
更新 2:
不同的滚动速率似乎源于一些四舍五入,使用mapToScene(viewport()->rect().center());
给我一个基于整数的"中心",当你滚动时,滚动得越慢,这个错误加起来越多,你滚动得越快,总误差就越少。
有没有办法让我解决这个问题?我看不出有任何方法可以获得浮点中心点。
更新 3:
所以我已经解决了大部分问题,结果证明需要mapToScene(我在网络上其他地方找到的代码(。
我通过存储视口的FP计算中心的QPointF
来解决此问题,现在滚动两个视图时的错误量不明显。
最后一个问题是,当您向右滚动任何数量,然后调整窗口大小然后再次滚动时,视图不再对齐。我认为这与何时计算中心点和何时发生居中的逻辑顺序有关。
现在,我在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);
}
}
类主窗口中的 Somwhere :
connect(eventView, SIGNAL(horizontalScroll(int)), headerView, SLOT(horizontalScroll(int));
我在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
,这会将滚动条移动到适当的位置。
您不应该按照以下说明调用scrollContentsBy
:http://qt-project.org/doc/qt-4.8/qabstractscrollarea.html#scrollContentsBy
不知道你是否还能调用隐藏的滚动条来滚动它。如果没有,translate
是一种选择。
您是否尝试使用滚动条?隐藏它们并不会使它们不存在,文档说您应该使用 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!
}