I am really new to pyqt and this question maybe silly. Any help, I would really appreciate. I have this code I get from this page where it codes in filtering a qtablewidget. This code works perfectly fine to my desired filtering output. However I have a table and it has lot of rows, I want the menu bar used in filtering to be scrollable instead of displaying all unique contents in the row. I want to have fixed size height of the menubar.
This is the code:
import csv
import sys
from PyQt5 import QtCore
from PyQt5 import QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent=parent)
self.verticalLayout = QtWidgets.QVBoxLayout(self)
self.table = QtWidgets.QTableWidget(self)
self.table.setColumnCount(0)
self.table.setRowCount(0)
self.verticalLayout.addWidget(self.table)
self.loadAll()
self.horizontalHeader = self.table.horizontalHeader()
self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
self.keywords = dict([(i, []) for i in range(self.table.columnCount())])
self.checkBoxs = []
self.col = None
def slotSelect(self, state):
for checkbox in self.checkBoxs:
checkbox.setChecked(QtCore.Qt.Checked == state)
def on_view_horizontalHeader_sectionClicked(self, index):
self.menu = QtWidgets.QMenu()
self.col = index
data_unique = []
self.checkBoxs = []
checkBox = QtWidgets.QCheckBox("Select all", self.menu)
checkableAction = QtWidgets.QWidgetAction(self.menu)
checkableAction.setDefaultWidget(checkBox)
self.menu.addAction(checkableAction)
checkBox.setChecked(True)
checkBox.stateChanged.connect(self.slotSelect)
for i in range(self.table.rowCount()):
if not self.table.isRowHidden(i):
item = self.table.item(i, index)
if item.text() not in data_unique:
data_unique.append(item.text())
checkBox = QtWidgets.QCheckBox(item.text(), self.menu)
checkBox.setChecked(True)
checkableAction = QtWidgets.QWidgetAction(self.menu)
checkableAction.setDefaultWidget(checkBox)
self.menu.addAction(checkableAction)
self.checkBoxs.append(checkBox)
btn = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
QtCore.Qt.Horizontal, self.menu)
btn.accepted.connect(self.menuClose)
btn.rejected.connect(self.menu.close)
checkableAction = QtWidgets.QWidgetAction(self.menu)
checkableAction.setDefaultWidget(btn)
self.menu.addAction(checkableAction)
headerPos = self.table.mapToGlobal(self.horizontalHeader.pos())
posY = headerPos.y() + self.horizontalHeader.height()
posX = headerPos.x() + self.horizontalHeader.sectionPosition(index)
self.menu.exec_(QtCore.QPoint(posX, posY))
def menuClose(self):
self.keywords[self.col] = []
for element in self.checkBoxs:
if element.isChecked():
self.keywords[self.col].append(element.text())
self.filterdata()
self.menu.close()
def loadAll(self):
with open("pokemon_data.csv", "r") as inpfil:
reader = csv.reader(inpfil, delimiter=',')
csheader = next(reader)
ncol = len(csheader)
data = list(reader)
row_count = len(data)
self.table.setRowCount(row_count)
self.table.setColumnCount(ncol)
self.table.setHorizontalHeaderLabels(('%s' % ', '.join(map(str, csheader))).split(","))
for ii in range(0, row_count):
mainins = data[ii]
for var in range(0, ncol):
self.table.setItem(ii, var, QtWidgets.QTableWidgetItem(mainins[var]))
def clearFilter(self):
for i in range(self.table.rowCount()):
self.table.setRowHidden(i, False)
def filterdata(self):
columnsShow = dict([(i, True) for i in range(self.table.rowCount())])
for i in range(self.table.rowCount()):
for j in range(self.table.columnCount()):
item = self.table.item(i, j)
if self.keywords[j]:
if item.text() not in self.keywords[j]:
columnsShow[i] = False
for key, value in columnsShow.items():
self.table.setRowHidden(key, not value)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
This is currently what it looks like:

When i try to filter by clicking the header, all my desktop window filled up because I have so much rows in my table as shown in the image below.
i just need a better size of the menubar.
I tried searching related queries to this but I just couldn't find that I can integrate it to this code. Please be gentle with your response as Im really new to this. Thank you so much!

The easiest solution is to use an undocumented stylesheet property (as proposed in the unaccepted answer of this post).
Alternatively (if, for any reason, that behavior doesn't work as expected or its support is removed in the future) you can create a QProxyStyle subclass, implement its
styleHintand returnTrueif the given hint isSH_Menu_Scrollable.If you want to keep that behavior only for that menu, you can apply the proxy style to the menu instead of doing it for the whole application:
By the way, you are using a menu, not a menubar. A menubar is the widget normally placed on the top of a window, containing different items, each one of it being (possibly) a menu.
UPDATE
Since the items are a lot, using a QMenu is not a good solution for various reasons. A better approach would be to use a QWidget that contains a QListWidget and the button box. To keep the behavior similar to that of a menu (it should close if a click happens outside it), you can add the
Popupwindow flag.