Roger
Roger

Reputation: 67

How to PageUp/PageDown table with QTableWidget?

I am using QTableWidget i have set 100 rows and 2 columns, now i need to table scrolling with pageup and pagedown buttons.

i'm trying to browse the table with PageUp/PageDown buttons, but the buttons go to the home or go to end the table. I wonder if there is a way to scroll the list partially?

from PyQt5.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QApplication, QWidget, QTableWidget, QTableWidgetItem
import sys
from PyQt5.QtCore import Qt


class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.title = "PyQt5 Tables"
        self.top = 100
        self.left = 100
        self.width = 500
        self.height = 400

        self.qtd_rows = 100

        self.table_widget = QTableWidget()

        self.init_window()

    def init_window(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.top, self.left, self.width, self.height)
        self.creating_tables()
        self.show()

    def creating_tables(self):
        self.table_widget = QTableWidget()
        self.table_widget.setAutoScroll(True)
        self.table_widget.setRowCount(self.qtd_rows)
        self.table_widget.setColumnCount(2)

        self.table_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        vbox = QVBoxLayout()

        for text, slot in (("PageUp", self.btn_page_up), ("PageDown", self.btn_page_down)):
            button = QPushButton(text)
            vbox.addWidget(button)
            button.clicked.connect(slot)

        for i in range(0, self.qtd_rows):
            self.table_widget.setItem(i, 0, QTableWidgetItem("Name_" + str(i)))
            self.table_widget.setItem(i, 1, QTableWidgetItem("Email"))

        vBoxLayout = QVBoxLayout()
        vBoxLayout.addWidget(self.table_widget)

        hBox = QHBoxLayout()
        hBox.addLayout(vBoxLayout)
        hBox.addLayout(vbox)

        self.setLayout(hBox)

    def btn_page_up(self):
        self.table_widget.scrollToTop()

    def btn_page_down(self):
        self.table_widget.scrollToBottom()


App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

I expect browsing all table items using PageUp/PageDown buttons.

Upvotes: 3

Views: 1848

Answers (2)

musicamante
musicamante

Reputation: 48509

While the answer provided by @eyllanesc works fine, I'd like to suggest another approach.
Even when the scroll bars are hidden, they still exist and are constantly updated according to the item view contents and position, making it possible to use them to scroll, since their valueChanged signal is still connected to the item view itself.

def btn_page_up(self):
    scrollBar = self.table_widget.verticalScrollBar()
    scrollBar.setValue(scrollBar.value() - scrollBar.pageStep())

def btn_page_down(self):
    scrollBar = self.table_widget.verticalScrollBar()
    scrollBar.setValue(scrollBar.value() + scrollBar.pageStep())

As long as you are using ScrollPerItem mode for verticalScrollMode, you can even scroll by a specific amount of items also.
For example, if you want to scroll down by 10 items each time:

def btn_scroll_down(self):
    scrollBar = self.table_widget.verticalScrollBar()
    scrollBar.setValue(scrollBar.value() + scrollBar.singleStep() * 10)

The problem comes if you're using ScrollPerPixel, as items can have different sizes; so, if you want to use the page keys to scroll by items you'll need to find your own method (as there's no "perfect" one) to scroll according to the currently shown items and their sizes. If that's the case, you should implement it using the code provided by eyllanesc, while checking for item positioning (and ensuring if the possibly shown items are near to the end).

Upvotes: 4

eyllanesc
eyllanesc

Reputation: 244301

You could use the scrollToItem() method but there is a drawback: Not every grid has a QTableWidgetItem associated because you could not move to those grids. Instead it is better to use the scrollTo() method that QModelIndex uses, and in that case every grid has a QModelIndex associated.

On the other hand, obtaining the QModelIndex is pure geometry, for this the rect of the viewport() and the indexAt() method are used, then the row and column of the grid are obtained, in the end it is obtained to the next or previous QModelIndex using the model.

def btn_up(self):
    ix = self.table_widget.indexAt(self.table_widget.viewport().rect().topLeft())
    previous_ix = self.table_widget.model().index(ix.row() - 1, ix.column())
    self.table_widget.scrollTo(previous_ix)

def btn_down(self):
    ix = self.table_widget.indexAt(self.table_widget.viewport().rect().bottomLeft())
    next_ix = self.table_widget.model().index(ix.row() + 1, ix.column())
    self.table_widget.scrollTo(next_ix)

Upvotes: 2

Related Questions