I want to create a little Filebrowser as described here, but by using PyQt5: Youtube-Video-Description
So far the Layout is working fine. Now I would like to implement the function that the files show up on the left QColumnView. Meaning the files of the clicked folder in the QTreeView can be seen on the right File-QColumnView. I don't get the point of how to create the right signal to set the pathindex for the QFileSystemModel of the QColumnView. Besides, it would be nicer if i could only show one (the name) column of the Folder-QTreeView.
Here is the code for the Browser:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QTreeView, QFileSystemModel, QApplication, QColumnView, QDockWidget, QMainWindow, QTextEdit
from PyQt5.QtCore import QDir, Qt
rootpath = QDir.currentPath()
class Browser(QMainWindow):
def __init__(self):
super(Browser, self).__init__()
self.createDockWindows()
self.textEdit = QTextEdit()
self.setCentralWidget(self.textEdit)
def createDockWindows(self):
dock = QDockWidget("Folders", self)
dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
#Code to Create FileView Colums and FolderTree
self.FileView = QtWidgets.QColumnView()
self.FileView.setGeometry(QtCore.QRect(240, 10, 291, 281))
self.FolderTree = QtWidgets.QTreeView()
self.FolderTree.setGeometry(QtCore.QRect(10, 10, 221, 281))
FolderTree = self.FolderTree
#FolderTree.hidecolumn(1),... ?? to show only name column
#include FolderTree to a Dock at the left side
dock.setWidget(FolderTree)
self.addDockWidget(Qt.LeftDockWidgetArea, dock)
#set the model and rootpath for filling the FolderTree from self.ui
dirmodel = QFileSystemModel()
#set filter to show only folders
dirmodel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)
dirmodel.setRootPath(rootpath)
#filemodel and filter for only files on right side
filemodel = QFileSystemModel()
filemodel.setFilter(QDir.NoDotAndDotDot | QDir.Files)
filemodel.setRootPath(rootpath)
FolderView = self.FolderTree
FolderView.setModel(dirmodel)
FolderView.setRootIndex(dirmodel.index(rootpath))
FileView = self.FileView
FileView.setModel(filemodel)
dock = QDockWidget("Files", self)
dock.setWidget(FileView)
self.addDockWidget(Qt.RightDockWidgetArea, dock)
#important lines for the connection, which does not work
self.FolderTree.clicked['QModelIndex'].connect(self.setpathonclick)
def setpathonclick(self):
currentpathindex = self.FolderTree.currentIndex()
self.FileView.setCurrentIndex(currentpathindex)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Browser()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
The last 12 lines are the important lines for the onclick connection of FolderTree and FileOverView.
You need to set the root index on the column-view:
filemodel = QFileSystemModel()
filemodel.setFilter(QDir.NoDotAndDotDot | QDir.Files)
filemodel.setRootPath(rootpath)
...
FileView = self.FileView
FileView.setModel(filemodel)
FileView.setRootIndex(filemodel.index(rootpath))
and then do more or less the same thing in the click handler:
...
self.FolderTree.clicked.connect(self.setpathonclick)
def setpathonclick(self, index):
rootpath = self.FolderTree.model().filePath(index)
filemodel = self.FileView.model()
filemodel.setRootPath(rootpath)
self.FileView.setRootIndex(filemodel.index(rootpath))
Related
I am new to PyQt.
I have a QLineEdit and a QTableView in my window.
My requirements:
Whenever I type something in QLineEdit, the table has to show filtered results according to what I typed.
I want to add a QPushButton at last column of QTableView.
I have successfully implemented these requirements individually. But I am not able to add these two requirements simultaniously.
Here's my code:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
class Application(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(0,0,700,200)
self.initUI()
def initUI(self):
self.mainLayout = QVBoxLayout()
self.searchBar = QLineEdit()
self.table = QTableView()
self.mainLayout.addWidget(self.searchBar)
self.mainLayout.addWidget(self.table)
self.modelOfTable = QStandardItemModel()
self.modelOfTable.setHorizontalHeaderLabels(['ID', 'Date', 'Description', 'Cause', 'Category', 'Button'])
self.table.setModel(self.modelOfTable)
self.modelOfTable.appendRow([QStandardItem(str(i)) for i in range(5)])
self.modelOfTable.appendRow([QStandardItem(str(i)) for i in range(4,9)])
self.modelOfTable.appendRow([QStandardItem(str(i)) for i in range(7,12)])
for i in range(3):
self.table.setIndexWidget(self.modelOfTable.index(i, 5), QPushButton("button"))
filter_proxy_model = QSortFilterProxyModel()
filter_proxy_model.setSourceModel(self.modelOfTable)
filter_proxy_model.setFilterKeyColumn(-1)
self.searchBar.textChanged.connect(filter_proxy_model.setFilterRegExp)
self.table.setModel(self.modelOfTable)
main_widget = QWidget()
main_widget.setLayout(self.mainLayout)
self.setCentralWidget(main_widget)
# Setting the window to be in maximised mode
#self.showMaximized()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Application()
ex.show()
sys.exit(app.exec_())
All the problem is in self.table.setModel line.
If I write self.table.setModel(self.modelOfTable) in that line, Pushbutton is placed in last column but filter is not working.
If I write self.table.setModel(self.modelOfTable) in that line, filter is working but there is no pushbutton in last column.
How can I add both two requirements at a time?
In my QMainWindow i have a button which opens a new QDialog in the bottom right monitorcorner with a successmessage when i click it.
Now, if i move the QMainWindow to another monitor (i have 3 monitor) and click the button the successmessage popup appears in the monitor where the QMainWindow was opened. What i want is that the popup message appears in the monitor where my QMainWindow actually is. So if i move the QMainWindow to Monitor 1 and click the button, the successpopup should opens in monitor 1. If the QMainWindow is in monitor 2, the successpopup should open in monitor 2 an same for monitor 3.
with
screenNumber = QDesktopWidget().screenNumber(self)
i can read the screennumber where the mainwindow is. and this works fine. Evertime i click the button i read out the screennumber. But i don't found a way, to set the screennumber to my notification.
Any ideas?
Edit:
maybe it helps if i show my notify class
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication, QDesktopWidget
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
## Some helping stuff
############################################################
parent_sSize = QDesktopWidget().screenGeometry(parent)
parent_screenNumber = QDesktopWidget().screenNumber(parent)
sSize = QDesktopWidget().screenGeometry()
screenNumber = QDesktopWidget().screenNumber()
print("notification ScreenNumber = " + str(screenNumber))
print(sSize.width())
print(sSize.height())
print("Parents ScreenNumber = " + str(parent_screenNumber))
print(parent_sSize.width())
print(parent_sSize.height())
self.Note_Exit.clicked.connect(self.close)
## ScreenSize from parent
############################################################
self.hidedPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()+200,
self.frameGeometry().width(),
self.frameGeometry().height())
self.showPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()-50,
self.frameGeometry().width(),
self.frameGeometry().height())
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.setGeometry(self.hidedPos)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(self.showPos)
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(self.hidedPos)
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
You cannot use the size of the widget during its construction, as at that moment it has a default size (640x480 for top level widgets, 100x30 for widgets created with a parent, including dialogs): the only reliable option is to use the sizeHint() or ensure that the layout has been properly activated with adjustSize().
Then, you don't need the screen to get the target position, as the parent geometry will suffice, but you do need it for the start position, otherwise the dialog will "pop up" at an arbitrary point below the window. Note that QDesktopWidget is considered obsolete, and you should use QScreen instead.
Finally, since you might want to reuse the notification, the start position should be set when the popup is actually being shown, not before. The same goes for the position when hiding (in case the notification could be moved).
class Notify(QDialog, Ui_Notification):
def __init__(self, parent):
super().__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.showAnim = QPropertyAnimation(self, b'geometry')
self.showAnim.setDuration(700)
self.showAnim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.hideAnim = QPropertyAnimation(self, b'geometry')
self.hideAnim.setDuration(700)
self.hideAnim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.hideTimer = QTimer(self, singleShot=True)
self.hideTimer.setInterval(4000)
self.hideTimer.timeout.connect(self.hideNote)
self.showAnim.finished.connect(self.hideTimer.start)
self.hideAnim.finished.connect(self.close)
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.adjustSize() # important!
endRect = self.rect()
center = self.parent().geometry().center()
endRect.moveCenter(center)
screen = QApplication.screenAt(center)
startRect = QRect(endRect)
startRect.moveTop(screen.geometry().bottom())
self.setGeometry(startRect)
self.showAnim.setStartValue(startRect)
self.showAnim.setEndValue(endRect)
self.showAnim.start()
self.show()
def hideNote(self):
rect = self.geometry()
self.hideAnim.setStartValue(rect)
screen = QApplication.screenAt(rect.center())
rect.moveTop(screen.geometry().bottom())
self.hideAnim.setEndValue(rect)
self.hideAnim.start()
if __name__ == "__main__":
notes = QApplication(sys.argv)
notes.setStyle('fusion')
w = QMainWindow()
b = QPushButton('click!')
w.setCentralWidget(b)
w.show()
notify = Notify(w)
b.clicked.connect(lambda: notify.setNote())
sys.exit(notes.exec())
Be aware that if you're going to create the popup every time, you should also set the WA_DeleteOnClose attribute in order to destroy it when closed, otherwise it will be kept in memory.
Note: QTimer.singleShot() is a static function, creating an instance of QTimer to use it is pointless, as that instance won't be used and a new QTimer would be created anyway.
Thank you.
In the meantime i found a solution which works for me.
Look a little dirty but works.
could you tell me, whats the difference between my code an yours?
Why should i use your code, except the fact that you are a better programmer ;-)
I set the WA_DeleteOnClose Attribute.
Good to know that. Thanks
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
clock = "clock"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
self.setWindowModality(QtCore.Qt.NonModal)
self.Note_Exit.clicked.connect(self.close)
self.parent_h = self.parent().geometry().height()
self.parent_w = self.parent().geometry().width()
self.parent_x = self.parent().geometry().x()
self.parent_y = self.parent().geometry().y()
self.dialog_w = self.width()
self.dialog_h = self.height()
self.setGeometry(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h)
## ScreenSize from parent
############################################################
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h-20, self.dialog_w, self.dialog_h))
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h))
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
How can I make it so the icon of a QListView's item resizes when i change the slider? It appears to resize the item but not it's icon.
I tried calling both of these, neither of them worked. I would ideally like to not call setGridSize since that causes the widget to ignore the setSpacing(5) which i intend on using.
self.uiListView.setGridSize(iconSize)
self.uiListView.setIconSize(iconSize)
import os, sys, re
from Qt import QtWidgets, QtGui, QtCore
from . import StyleUtils
values = ['MomBod','Colonel','Tater','Tot','Ginger','Donut','Sport','LaLa','Itchy','Bruiser','Cotton','Cumulus','Toodles','Salt','Ghoulie','Cat','Dirty','Harry','Buckeye','Flyby','Swiss','Miss','Buddy','Pecan','Sunny','Jet','Thor','Gingersnap','Cuddle','Pig','Turkey','Foxy','Mini','Me','Dolly','Stud','Music','Man','Barbie','Munchkin','Bubba','Hammer','Twizzler','Bebe']
class ViewerWidget(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.resize(500,500)
self.uiIconSize = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.uiIconSize.setRange(32,256)
self.uiIconSize.setValue(128)
self.uiIconSize.setMinimumWidth(100)
self.viewerModel = QtGui.QStandardItemModel()
self.viewerProxyModel = QtCore.QSortFilterProxyModel()
self.viewerProxyModel.setSourceModel(self.viewerModel)
self.uiListView = QtWidgets.QListView()
self.uiListView.setSpacing(5)
self.uiListView.setMovement(QtWidgets.QListView.Static)
self.uiListView.setViewMode(QtWidgets.QListView.IconMode)
self.uiListView.setLayoutMode(QtWidgets.QListView.Batched)
self.uiListView.setBatchSize(100)
self.uiListView.setFlow(QtWidgets.QListView.LeftToRight)
self.uiListView.setWrapping(True)
self.uiListView.setResizeMode(QtWidgets.QListView.Adjust)
self.uiListView.setDragEnabled(False)
self.uiListView.setUniformItemSizes(True)
self.uiListView.setIconSize(self.getIconSize())
self.uiListView.setSelectionMode(QtWidgets.QListView.ExtendedSelection)
self.uiListView.setModel(self.viewerProxyModel)
# main layout
self.layout = QtWidgets.QVBoxLayout()
self.layout.setContentsMargins(0,0,0,0)
self.layout.setSpacing(0)
self.layout.addWidget(self.uiListView)
self.layout.addWidget(self.uiIconSize)
self.setLayout(self.layout)
# Signals
self.uiIconSize.valueChanged.connect(self.setItemSize)
# Init
self.populateModel()
def getIconSize(self):
return QtCore.QSize(self.uiIconSize.value(), self.uiIconSize.value())
def setItemSize(self):
iconSize = self.getIconSize()
# self.uiListView.setGridSize(iconSize)
self.uiListView.setIconSize(iconSize)
def populateModel(self):
model = self.viewerModel
model.clear()
icon = QtGui.QIcon('C:/Users/jmartini/Desktop/image.png')
for x in values:
newItem = QtGui.QStandardItem(x)
newItem.setData(icon, role=QtCore.Qt.DecorationRole)
model.appendRow(newItem)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = ViewerWidget()
ex.show()
sys.exit(app.exec_())
I discovered this is a result of my icon's native size being 64x64. Qt will not resize the icon to be larger than it's original size. It will only resize the icon to be of a smaller size.
self.uiListView.setIconSize(QtCore.QSize(64,64))
I am trying to dynamically update a menu with new items when I add new items via the form into Qsettings. For example, if you open my code and click the button and then click "new" it will open a QLineEdit with a button. When the button is clicked the list data gets stored via Qsettings.
I'd like to be able to update the menu somehow to show the items without restarting. I tried some things like calling repaint and update in a few areas with no luck.
Here is my code, I slimmed it down the best that I could for the example.
import functools
import sys
from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget, QPushButton, QHBoxLayout, \
QVBoxLayout, QLineEdit,QApplication, QWidgetAction, QTextBrowser, QAction, QMenu
class MainWindow(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.layout = QHBoxLayout()
self.menu_action = QAction(QIcon("icon.png"),"New", self)
self.menu_btn = QPushButton()
self.menu = MyMenu("Menu", self.menu_btn)
self.add_menu = self.menu.addMenu(QIcon("icon.png"), "Menu")
self.add_menu.addAction(self.menu_action)
self.menu_btn.setMenu(self.menu)
self.textBox = QTextBrowser(self)
action = QWidgetAction(self.menu_btn)
action.setDefaultWidget(self.textBox)
self.menu_btn.menu().addAction(action)
settings = QtCore.QSettings('test_org', 'my_app')
self.new_items = settings.value('new_item', [])
print('%s' % self.new_items)
for item in self.new_items:
self.create_action = QAction(QIcon("icon.png"), item[0], self)
self.create_action.setData(item)
self.add_menu.addAction(self.create_action)
self.create_action.triggered.connect(functools.partial(self.menu_clicked, self.create_action))
self.layout.addWidget(self.menu_btn)
self.setLayout(self.layout)
self.menu_action.triggered.connect(self.open_window)
def open_window(self):
self.create_menu_item = Create_Menu_Item()
self.create_menu_item.show()
def menu_clicked(self, item):
itmData = item.data()
print(itmData)
class Create_Menu_Item(QWidget):
def __init__(self, parent=None):
super(Create_Menu_Item, self).__init__(parent)
self.resize(200, 195)
self.layout = QVBoxLayout()
self.form = QLineEdit()
self.btn = QPushButton()
self.layout.addWidget(self.form)
self.layout.addWidget(self.btn)
self.btn.clicked.connect(self.save_new_item)
self.setLayout(self.layout)
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
class MyMenu(QMenu):
def event(self,event):
if event.type() == QtCore.QEvent.Show:
self.move(self.parent().mapToGlobal(QtCore.QPoint(0,0))-QtCore.QPoint(0,self.height()))
return super(MyMenu,self).event(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
Anyone have any ideas? Thanks.
You can create a for loop to access the list.
Bare in mind it is a list of lists so a nested for loop is neccessary
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
# Add new menu items..
for x in self.new_item:
for y in x:
print(y)
The above will keep adding the WHOLE list of items every time you add a new item..
To just add the newest item, this is all you need (the last item added to the list)
w.add_menu.addAction(self.new_item[0][-1])
so
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
#ADD last item in the list
w.add_menu.addAction(self.new_item[0][-1])
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_())