How to determine the correct size of a QTableWidget?
The thread How to set a precise size of QTableWidget to prevent from having scroll bars? (Qt-interest Archive, June 2007) between Lingfa Yang and Susan Macchia seems to resolve my question. I will post more details shortly, if my testing works.
Update #1: My test now generates the nice-looking window:
The complete test code for this, with Test.h unchanged, is:
#include "Test.h"
static QSize myGetQTableWidgetSize(QTableWidget *t) {
int w = t->verticalHeader()->width() + 4; // +4 seems to be needed
for (int i = 0; i < t->columnCount(); i++)
w += t->columnWidth(i); // seems to include gridline (on my machine)
int h = t->horizontalHeader()->height() + 4;
for (int i = 0; i < t->rowCount(); i++)
h += t->rowHeight(i);
return QSize(w, h);
}
static void myRedoGeometry(QWidget *w) {
const bool vis = w->isVisible();
const QPoint pos = w->pos();
w->hide();
w->show();
w->setVisible(vis);
if (vis && !pos.isNull())
w->move(pos);
}
Test::Test() : QMainWindow() {
QVBoxLayout *vbox = new QVBoxLayout;
QPushButton *btn = new QPushButton("Hello World etc etc etc etc etc");
QTableWidget *tbl = new QTableWidget(2, 2);
vbox->addWidget(btn);
vbox->addWidget(tbl);
setCentralWidget(new QWidget);
centralWidget()->setLayout(vbox);
layout()->setSizeConstraint(QLayout::SetMinimumSize); // or SetFixedSize
tbl->setVerticalHeaderItem(1, new QTableWidgetItem("two")); // change size
myRedoGeometry(this);
tbl->setMaximumSize(myGetQTableWidgetSize(tbl));
tbl->setMinimumSize(tbl->maximumSize()); // optional
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Test test;
test.show();
app.exec();
}
Some notes:
The above thread's inclusion of
verticalScrollBar()->width()
seems to be wrong. And, in my testing, this was always either a default value of 100, or the value 15, if the scrollbar had been displayed.Applying the
show(); hide();
sequence just to the QTableWidget was not sufficient to force Qt to recalculate the geometry, in this test. I needed to apply it to the whole window.Any suggestions for improvements would be welome. (I'll wait a bit before accepting my own answer, in case there are better solutions.)
Update #2:
The Qt-interest thread may be wrong (or, at least, it disagrees with my version of Qt running my machine) regarding details on how to calculate the size: the +1 for each gridline is unnecessary, but an overall +4 is needed.
I'm still working through
layout()->invalidate()
vs. e.g. QT: How to preview sizes of widgets in layout BEFORE a show().
Update #3:
This is my final version--but I'm not very happy with it. Any improvements would be very welcome.
Things like
adjustSize()
andlayout()->invalidate()
andQt::WA_DontShowOnScreen
don't seem to help.The blog Shrinking Qt widgets to minimum needed size is interesting, but using
setSizeConstraint()
is just as good.The
setSizeConstraint()
andmove()
methods are needed for subsequent changes to the table, not shown here.There was an odd thing in my testing, done on CentOS 5 with Qt 4.6.3 and 4.7.4. For the
hide(); show();
sequence, the window position is saved/restored. But about 25% of the time (the patterning was irregular) the restored position would be 24 pixels higher on the screen, presumably the height of the window title. And about 10% of the time the value returned bypos()
would be null. The Qt site says for X11 it needsnifty heuristics and clever code
for this, but something seems to be broken somewhere.
Calculating the exact needed height for a QTableWidget
You can get tableWidget's height with "tableWidget->viewport()->height()" .
Regarding the vertical scrollbar, you can use this functions.
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff)
Then, the vertical scrollbar will be permanently hidden.
Adjust the size (width/height) of a custom QTableWidget
void QHeaderView::setSectionResizeMode(int logicalIndex, QHeaderView::ResizeMode mode)
Sets the constraints on how the section specified by logicalIndex in the header can be resized to those described by the given mode. The logical index should exist at the time this function is called.
from PyQt5 import QtGui, QtCore, QtWidgets
import numpy as np
#-- Table Model
class MyTableModel(QtCore.QAbstractTableModel):
def __init__(self, data, parent=None, *args):
super(MyTableModel, self).__init__(parent)
# table data
self.table_data = data
self.rows_nr, self.columns_nr = data.shape
# vertical & horizontal header labels
self.hheaders = ["Head-{}".format(i) for i in range(self.columns_nr)]
self.vheaders = ["Row-{}".format(i) for i in range(self.rows_nr)]
# nr of rows
def rowCount(self, parent):
return self.rows_nr
# nr of columns
def columnCount(self, parent):
return self.columns_nr
# row and column headers
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return self.hheaders[section]
#END if
#ELSE:
return QtCore.QVariant()
# display table contents
def data(self, index, role=QtCore.Qt.DisplayRole):
r_ = index.row()
c_ = index.column()
if role == QtCore.Qt.DisplayRole:
return "{}".format(data[r_, c_])
#ELSE:
return QtCore.QVariant()
# set data
def setData(self, index, value, role):
r_ = index.row()
c_ = index.column()
# editable fields
if role == QtCore.Qt.EditRole:
# interprete values
self.table_data[r_,c_] = str(value)
return True
# view/edit flags
def flags(self, index):
r_ = index.row()
c_ = index.column()
return QtCore.Qt.ItemIsEnabled
class MyTableWidget(QtWidgets.QWidget):
def __init__(self, data, *args):
super(MyTableWidget, self).__init__(*args)
#-- table model
tablemodel = MyTableModel(data=data, parent=self)
#-- table view
tableview = QtWidgets.QTableView()
tableview.setModel(tablemodel)
tableview.verticalHeader().hide() # hide vertical/row headers
#-- +++
tableview.setAlternatingRowColors(True)
tableview.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
tableview.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
tableview.horizontalHeader().setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
tableview.horizontalHeader().setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
# size policy
tableview.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
#tableview.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) # ---
tableview.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)# +++
#-- layouts
#--- buttons
button_hlayout = QtWidgets.QHBoxLayout()
button_hlayout.addWidget(QtWidgets.QPushButton("Button 1"))
button_hlayout.addWidget(QtWidgets.QPushButton("Button 2"))
button_hlayout.addWidget(QtWidgets.QPushButton("Button 3"))
#--- table
table_layout = QtWidgets.QVBoxLayout()
table_layout.addLayout(button_hlayout)
table_layout.addWidget(tableview)
self.setLayout(table_layout)
#----------------------------------------
#-- produce sample data
data = np.empty(shape=(3,4), dtype=np.object)
for r in range(3):
for c in range(4):
data[r,c] = str(list(range((r+1) * (c+1))))
app = QtWidgets.QApplication([""])
w = MyTableWidget(data=data)
w.show()
app.exec_()
In the code above, tableview.horizontalHeader().SetSectionResizeMode(QtWidgets.QHeaderView.Stretch)
applies the Stretch mode to all columns, and the remaining 3 operators set the corresponding columns to the ResizeToContents
mode.
The resizing behaviour of the widget window is determined by setSizePolicy
method. In this case, the policy can be also tableview.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
, which allows the user to enlarge or shrink the widget window.
How to set QTableWidget height under 70
Set the minimum height of the QTableWidget
to 10. By default it has some kind of an internal minimum height and it behaves like you described.
tableWidget->setMinimumHeight(10);
or just set it in QtCreator UI editor property.
How to I set the Size Hint for A QTableWidget in Python
sizeAdjustPolicy : SizeAdjustPolicy
This property holds the policy describing how the size of the scroll area changes when the size of the viewport changes.
Try it:
import sys
import pandas as pd
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class MyWin(QMainWindow):
def __init__(self, df):
super().__init__()
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
layout = QGridLayout(centralWidget)
self.tableWidget = self.build_table(df)
self.tableWidget.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) # <---
self.tableWidget.setAlternatingRowColors(True)
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
layout.addWidget(self.tableWidget)
layout.addWidget(QPushButton("Button"))
def build_table(self, df):
table = QTableWidget()
table.setColumnCount(len(df.columns))
table.setRowCount(len(df.index))
table.setHorizontalHeaderLabels(df.columns)
for row_num, row in enumerate(df.index):
for col_num, col in enumerate(df.columns):
item = QTableWidgetItem(str(df.loc[row,col]))
table.setItem(row_num, col_num, item) # +++
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
table.resizeColumnsToContents()
table.resizeRowsToContents()
table.verticalHeader().setVisible(False)
# self.table.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) # ---
return table # +++
df = pd.DataFrame(
{'a': ['1','2','3','4','Mary','Jim','John'], 'b': ['3','4','1','2',100, 200, 300], 'c': ['1','2','3','4','a','b','c'],
'd': ['1','2','3','4','Mary','Jim','John'], 'e': ['1','2','3','4',100, 200, 300], 'f': ['1','2','3','4','a','b','c'],
'g': ['1','2','3','4','Mary','Jim','John'], 'h': ['1','2','3','4',100, 200, 300], 'j': ['1','2','3','4','a','b','c'],
'k': ['1','2','3','4','Mary','Jim','John'], 'l': ['1','2','3','4',100, 200, 300], 'm': ['1','2','3','4','a','b','c'],
})
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWin(df)
w.show()
sys.exit(app.exec_())
Related Topics
Automatic Copy Files to Output During Application Building
Purpose of Explicit Default Constructors
Using Pair as Key in a Map (C++/Stl)
Std::Make_Tuple Doesn't Make References
Why Vector Access Operators Are Not Specified as Noexcept
Assignment Operator with Reference Members
Cmake Simple Config File Example
How to Convert a String of Hex Values to a String
Eigen How to Concatenate Matrix Along a Specific Dimension
Macro to Replace C++ Operator New
When Do We Need to Have a Default Constructor
How to Use Clang++ with -Std=C++11 -Weverything -Werror
Is It Valid for a Lambda To, Essentially, Close Over Itself