I have a custom class derived from QGraphicsView that implements a slot call scrollHorizontal(int dx), inside the code is simply
void CustomView::scrollHorizontal(int dx){
scrollContentsBy(dx, 0);
}
My problem is, scrolling like this works but doesn't update the scene properly, instead any pixels found on the edge of the view are repeated instead of having a fresh call to the item's paint()
method.
I've attempted calling update()
after, but nothing happens. I tried enabling scrolling by dragging and updates work fine! But I need it done programmatically, and since I have the scroll bars hidden things like horizontalScrollBar()->setValue()
do not scroll the view.
I also tried :
scrollContentsBy(dx, 0);
this->scene()->invalidate(sceneRect());
this->update();
update:
QPointF center = mapToScene(viewport()->rect().center());
centerOn(center.x() - dx, center.y());
update();
is working, but now my top view is scrolling slower than my bottom view, which is a new problem. They are linked with signal
s and slot
s, in the bottom view i have scrollContentsBy(int dx, int dy)
overrided to emit horizontalScroll(dx)
; which is caught by the above slot
in the top view.
Any ideas why the scrolls happen at different rates? Might it have something to do with the scroll bars being a part of the bottom view effectively making it a "smaller" window?
update 2:
The different scroll rates seems to stem from some rounding happening to give me an integer based "center" using mapToScene(viewport()->rect().center());
, as you scroll and the slower you scroll the more this error adds up, the faster you scroll the less total error.
Is there a way for me to get around this? I don't see any way to get a floating point center point.
update 3:
So I have this mostly solved, turns out the mapToScene was needed(code I found elsewhere on the web).
I fixed this by storing QPointF
of FP calculated center of the viewport, now the amount of error when scrolling the two views is unnoticeable.
The final issue is, the views no longer line up when you scroll ANY amount to the right, and then resize the window then scroll again. I assume this has something to do with the logical ordering of when the center point is calculated and when the centering happens.
Right now I use the following code snippet in QGraphicsScene::ResizeEvent()
and elsewhere that updates the center as needed
QRectF viewPort(viewport()->rect());
QPointF rectCenter((viewPort.x() + viewPort.x() + viewPort.width())/2.0, (viewPort.y() + viewPort.y() + viewPort.height())/2.0);
viewCenter = rectCenter;
and my horizontalScroll(int dx)
slot
void CustomView::horizontalScroll(int dx)
{
viewCenter.setX(viewCenter.x() - dx);
centerOn(viewCenter.x(), viewCenter.y());
update();
}
How can I fix the issue when re-sizing the window breaking the alignment of the two views? If any more clarification is needed please just ask, I can try to give skeletons of what I'm referring to if need be.
Update 4:
Rough code Skeleton
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:
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);
}
}
Somwhere in Class MainWindow:
connect(eventView, SIGNAL(horizontalScroll(int)), headerView, SLOT(horizontalScroll(int));
I've worked with QGraphicsView
in Qt 4.6.3 - 4.7.2 and have to argue that you can use the respective QScrollBar
in the following way:
//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);
It does not matter if they are hidden or not. They will still respond to setValue(int)
as long as you have a graphics scene that is larger than the graphics view.
The QGraphicsView
will also respond to ensureVisible
, which moves the scrollbars to the appropriate location.
You are not supposed to call scrollContentsBy
as explained here: http://qt-project.org/doc/qt-4.8/qabstractscrollarea.html#scrollContentsBy
I don't know if you can still call the hidden scrollbar to scroll it. If not, translate
is an option.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With