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!
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_())
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_())
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!
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_())
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_())