PDA

View Full Version : Scroll QTableView beyond last column/row



ftnirp
28th August 2013, 20:33
Greetings,

I have a simple QTableView connected to an QAbstractTableModel. For the purposes of my question, let’s assume that these are the most basic you can have in order to get a table with data in it.

Default behavior is that you can scroll the table so that the last column/row becomes visible, but no further. I would like to be able to scroll the table past the last row/column, i.e. I want to be able to continue to click right on the horizontal scroll bar even though I have reached the last column, thereby making the last column continue to shift left in the table revealing “empty space” in the TableView.

I have been unsuccessful in trying to find a way and hoped that someone here had a way to do this or a suggestion as to how.

Thank you.

Santosh Reddy
28th August 2013, 21:09
Try this
1. Turn off scroll bars of QTableView
2. Put QTableView in another QScrollArea
3. Set minimum size of QTableView so that it fits all rows and columns

ftnirp
3rd September 2013, 13:27
Thanks for your suggestion. I managed to find different solution so I am posting it in case anyone else is wondering how to do this. In the table view I connect to the actionTriggered signal of the scrollbars (please note, I use PyQt. The variable "self" is the same as "this" in C++):


self.verticalScrollBar().actionTriggered.connect(s elf.vertScrollActionTriggered)
self.setVerticalScrollMode(QtGui.QAbstractItemView .ScrollPerPixel)

self.horizontalScrollBar().actionTriggered.connect (self.horizScrollActionTriggered)
self.setHorizontalScrollMode(QtGui.QAbstractItemVi ew.ScrollPerPixel)
I will explain the scroll mode shortly. The action triggered methods:


def vertScrollActionTriggered(self, action):
vertBar=self.verticalScrollBar()
if action==QtGui.QAbstractSlider.SliderSingleStepAdd: #if the user pressed the arrow
if vertBar.value()==vertBar.maximum(): #if we are at the maximum
#set a new maximum to go one more step past the original maximum, this lets us "go past" the last row/column
vertBar.setMaximum(vertBar.maximum()+vertBar.singl eStep())

vertBar.setValue(vertBar.maximum())

I look for only when a single step is being added as this is when a user presses the arrow of the scroll bar. If the scroll bar is at the maximum, then I add a single step to the maximum and increase the scroll bar to that new maximum. This makes it so that if the user wants to scroll past the last row, they can click the arrow to increase the range of the scroll bar and "go past" the last row. This is the same for horizontal.

You have to set the scroll mode to per pixel. Otherwise, if it is per item (which is default), when the user gets to the maximum point on the scroll bar, the table will "snap back" to the last row/column. This is because in the base QTableView code, in the scrollContentsBy method if the mode is per item, and the scroll bar value is the maximum value, it calls setOffsetToLastSection of the header instead of setting the offset to the value of the scroll bar, causing the "snapping" effect when the scroll bar gets to the maximum value, it can been seen in the following C++ code of the QTableView:


if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
int oldOffset = d->horizontalHeader->offset();
if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum()) <--------- this line!
d->horizontalHeader->setOffsetToLastSection();
else
d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value());
int newOffset = d->horizontalHeader->offset();
dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
} else {
d->horizontalHeader->setOffset(horizontalScrollBar()->value());
}
Hope this helps anyone else.