PySide6 QTableView integration into GUI
-
So I am trying to integrate a table into my PySide6 GUI. My goal is to have the table display data from a pandas dataframe, and show it on the GUI to the user. This GUI would also include other elements in it, such as some buttons and other text.
The problem I am currently running into is that when I add a table into my window, it takes up the whole screen. Here is an image of what I am describing:
I want it to look more like a small view of the table within the actual window, not taking up the whole window. There are other elements I want to be visible, and resizing the table to a smaller size doesn't really seem to do the trick.
Is this something that isn't possible? I'd like to think that I am not the only person who has ever wanted to do this. I feel like I am maybe missing something small.
Here is my code:
import sys from PySide6 import QtCore from PySide6.QtCore import Qt from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QTableView #from PySide6.QtSql import QSqlDatabase, QSqlDriver, QSqlQuery import pandas as pd from sqlalchemy import create_engine class TableModel(QtCore.QAbstractTableModel): def __init__(self, data): super(TableModel, self).__init__() self._data = data def data(self, index, role): if role == Qt.DisplayRole: value = self._data.iloc[index.row(), index.column()] return str(value) def rowCount(self, index): return self._data.shape[0] def columnCount(self, index): return self._data.shape[1] def headerData(self, section, orientation, role): # section is the index of the column/row. if role == Qt.DisplayRole: if orientation == Qt.Horizontal: return str(self._data.columns[section]) if orientation == Qt.Vertical: return str(self._data.index[section]) class DBEntry(QMainWindow): def __init__(self): super(DBEntry, self).__init__() # Adjusting dimensions of window and the title text size self.setWindowTitle('Database Entry') self.resize(640, 900) self.label = QLabel(self) self.label.setGeometry(120, 0, 400, 100) self.label.setText('Database') self.label.setAlignment(Qt.AlignCenter) self.label.setStyleSheet('font-size:40px') self.layout = QVBoxLayout() # Data created here and converted into DF engine = create_engine('postgresql://postgres:*******@localhost:5432/sampledb') df = pd.read_sql('formalloy', engine) #Table initiation with a call to TableModel class self.table = QTableView() self.model = TableModel(df) self.table.setModel(self.model) self.table.resize(200, 200) self.setCentralWidget(self.table) if __name__ == '__main__': app = QApplication(sys.argv) ex = DBEntry() ex.show() sys.exit(app.exec())
-
Hi,
Your issue is that you are setting the QTableView as central widget.
Use a "dummy" widget for the central widget and build your UI in it.
-
@SGaist Hello, thank you for your response.
Can you clarify what you mean by creating a dummy widget and building my UI into it?
As far as your comment about the central widget, is there an alternative for showing the table inside of the GUI outside of central widget? -
@ccortez
Look at the diagram in https://doc.qt.io/qt-5/qmainwindow.html#details. Set your central widget to aQWidget
. Put aQLayout
on that. Now sizing should be good. Add yourQTableView
onto the layout. Work from there. Should be better. -
@JonB Okay I think I somewhat figured it out. That was helpful.
Not sure if this is something you or @SGaist could help with but I am now running into this issue.
Here is a picture:I got something a little better going now but there is still the issue of the table taking up more space than it should. As you can see there are only 4 rows but the table is taking up a lot more space than that. I added another dummy column of data to extend out the columns, and it seems to react somewhat responsively to this. I'd like to achieve this with that long blank area of nothing in the table.
Using the .resize() doesn't do anything, so I am not really sure how to make it so that it isnt so long and taking up so much space.
Code;
import sys from PySide6.QtCore import Qt, QAbstractTableModel from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QTableView, QWidget, QPushButton import pandas as pd from sqlalchemy import create_engine class pandasModel(QAbstractTableModel): def __init__(self, data): QAbstractTableModel.__init__(self) self._data = data def rowCount(self, parent=None): return self._data.shape[0] def columnCount(self, parent=None): return self._data.shape[1] def data(self, index, role=Qt.DisplayRole): if index.isValid(): if role == Qt.DisplayRole: return str(self._data.iloc[index.row(), index.column()]) return None def headerData(self, col, orientation, role): if orientation == Qt.Horizontal and role == Qt.DisplayRole: return self._data.columns[col] return None class DBEntry(QMainWindow): def __init__(self): super(DBEntry, self).__init__() # Adjusting dimensions of window and the title text size self.setWindowTitle('Database Entry') self.resize(540, 480) label = QLabel() label.setGeometry(120, 0, 400, 100) label.setText('Database') label.setAlignment(Qt.AlignCenter) label.setStyleSheet('font-size:40px') engine = create_engine('postgresql://postgres:******@localhost:5432/sampledb') df = pd.read_sql('formalloy', engine) model = pandasModel(df) table = QTableView() table.setModel(model) #table.resize(100, 100) btn = QPushButton() btn.resize(250, 250) btn.setText('Database') btn.setStyleSheet('font-size:15px') self.layout = QVBoxLayout() self.layout.addWidget(label) self.layout.addWidget(table) self.layout.addWidget(btn) self.widget = QWidget() self.widget.setLayout(self.layout) self.setCentralWidget(self.widget) if __name__ == '__main__': app = QApplication(sys.argv) ex = DBEntry() ex.show() sys.exit(app.exec())
-
@ccortez
You can use spacer (QSpacerItem
) for keeping unwanted space blank.
or if you know exact row length you can set its height and width.Another way would be to calculate height for every resize according to total number of rows.
-
@ccortez said in PySide6 QTableView integration into GUI:
Using the .resize() doesn't do anything
Yes, because size of widgets in a layout is managed by the layout.
What is the problem with table consuming all available space? If it would not then you would simply have unused space, it would not look better in my opinion.