PyQt – Linking multiple QTableView objects through scrollbars

Question:

I have searched online but have been unable to find a solution this problem. I have three (although this can be any number) QTableView objects that are all longer than the size they are displaying (they are also equal length). For all 3 I have a scroll bar automatically generated. I would like clicking on any one of these to move the other QTableView objects by the same amount.

Unfortunately I was unable to find a solution for this online. The closest I got was this (https://forum.qt.io/topic/25139/solved-synchronizing-two-qtableview-s-scrollbars/3) although this did not help my situation.

Any help on this question would be much appreciated! Thanks!

Asked By: jim mako

||

Answers:

Here’s a MCVE of three QTableView widgets with their vertical scrollbars linked. We connect the move_other_scrollbars() custom method to the QAbstractSlider.valueChanged signal of each scrollbar, using lambdas to pass the appropriate information: the idx of the scrollbars and the scrollbar that’s been moved by the user). In turn, move_other_scrollbars() finds all the other scrollbars and updates their position with QAbstractSlider.setValue(idx).

from PyQt5.QtCore import (Qt, QStringListModel)
from PyQt5.QtWidgets import (QApplication, QWidget, QTableView, QHBoxLayout)


class MainWindow(QWidget):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.table_view_1 = QTableView()
        self.table_view_2 = QTableView()
        self.table_view_3 = QTableView()
        items = ['apples', 'bananas', 'cookies', 'drinks', 'eggs', 'flour', 'gatorade']
        items_2 = ['alligator', 'bear', 'cat', 'deer', 'elephant', 'flamingo', 'goose']
        items_3 = ['Arsenic', 'Boron', 'Carbon', 'Dysprosium', 'Europium', 'Flourine', 'Gold']
        self.model = QStringListModel(items)
        self.model_2 = QStringListModel(items_2)
        self.model_3 = QStringListModel(items_3)

        self.table_view_1.setModel(self.model)
        self.table_view_2.setModel(self.model)
        self.table_view_3.setModel(self.model_3)
        self.layout = QHBoxLayout()

        self.list_of_tables = [self.table_view_1,self.table_view_2, self.table_view_3]

        def move_other_scrollbars(idx,bar):
            scrollbars = {tbl.verticalScrollBar() for tbl in self.list_of_tables}
            scrollbars.remove(bar)
            for bar in scrollbars:
                bar.setValue(idx)

        for tbl in self.list_of_tables:
            scrollbar = tbl.verticalScrollBar()
            scrollbar.valueChanged.connect(lambda idx,bar=scrollbar: move_other_scrollbars(idx, bar))
            self.layout.addWidget(tbl)

        self.setLayout(self.layout)

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
Answered By: Crispin

QTableView have two ScrollBar : verticalScrollBar ,horizontalScrollBar.
you can get this object with verticalScrollBar () ,horizontalScrollBar(), the scroll bar object have valueChanged single this signal is emit when the scroll bar change position.
this code is a simple solution.

from PyQt5.QtCore import QStringListModel
from PyQt5.QtWidgets import QApplication, QMainWindow , QTableView, QVBoxLayout,QWidget

class window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.tab1 = QTableView(self)
        self.tab2 = QTableView(self)
        

        model1=QStringListModel([str(val) for val in range(0,100)])
        model2=QStringListModel([str(val) for val in range(100,200)])
        
        self.tab1.setModel(model1)
        self.tab2.setModel(model2)
        
        self.lyout = QVBoxLayout(self)
        
        self.lyout.addWidget(self.tab1)
        self.lyout.addWidget(self.tab2)
        
        
        wid = QWidget(self)
        self.setCentralWidget(wid)
        wid.setLayout(self.lyout)
        
        # connect the scroll bar signal to our slot
        self.tab1.verticalScrollBar().valueChanged.connect(self.__chnge_position)
        self.tab2.verticalScrollBar().valueChanged.connect(self.__chnge_position)
        
    def __chnge_position(self,index):
        # slot to change the scroll bar position of all tables
        self.tab1.verticalScrollBar().setValue(index)
        self.tab2.verticalScrollBar().setValue(index)
        
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    win = window()
    win.show()
    sys.exit(app.exec_())
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.