Conclusion
- It is impossible to apply permanent changes to cells' height. It seems like
resizeRowsToContents() works only partially. Because after closing the attribute table, rows won't preserve their dimension
- It is possible to adjust column width both via PyQt and PyQGIS
Indeed, as was mentioned in a comment by @Matt, there is a setAttributeTableConfig() method of the QgsVectorLayer class:
This is a container for configuration of the attribute table.
The configuration is specific for one vector layer.
To get the width of a column one can try the attributeTableConfig() method.
Returns the attribute table configuration object.
This defines the appearance of the attribute table.
from qgis.utils import iface
layer = iface.activeLayer()
layer_attr_table_config = layer.attributeTableConfig()
columns = layer_attr_table_config.columns()
for column in columns:
if not column.hidden:
print(f"Column '{column.name}' : {column.width}")
Nevertheless, it will show the default width which is -1.
Column 'osm_id' : -1
Column 'lastchange' : -1
Column 'code' : -1
Column 'fclass' : -1
Column 'geomtype' : -1
Column 'name' : -1
Column 'type' : -1
Column 'height' : -1
Column 'levels' : -1
More details can be found in QgsAttributeTableConfig class.
To change the width of a single column
It utilizes the setColumnWidth() and setAttributeTableConfig() methods
from qgis.core import QgsProject
def setting_one_column_width(layer_name: str, column_name: str, new_width: int):
"""
Changes the width of a single column in the layer
:param layer_name: name of the layer
:param column_name: name of the target column
:param new_width: new column width in pixels
"""
layer = QgsProject.instance().mapLayersByName(layer_name)[0]
column_index = layer.fields().indexOf(column_name)
layer_attr_table_config = layer.attributeTableConfig()
layer_attr_table_config.setColumnWidth(column_index, new_width)
layer.setAttributeTableConfig(layer_attr_table_config)
return
setting_one_column_width('gis_osm_buildings', 'osm_id', 100)
To change the width of all columns
Based on @ThomasG77's answer. It uses the setColumns() and setAttributeTableConfig() methods
from qgis.core import QgsAttributeTableConfig, QgsProject
def setting_all_columns_widths(layer_name: str, new_width: int) -> None:
"""
Changes widths of all columns in the layer
:param layer_name: name of the layer
:param new_width: new column width in pixels
"""
layer = QgsProject.instance().mapLayersByName(layer_name)[0]
layer_attr_table_config = layer.attributeTableConfig()
columns_config = layer_attr_table_config.columns()
new_columns_config = []
new_layer_attr_table_config = QgsAttributeTableConfig()
for column in columns_config:
new_column = layer_attr_table_config.ColumnConfig()
new_column.hidden = column.hidden
new_column.name = column.name
new_column.type = column.type
new_column.width = new_width
new_columns_config.append(new_column)
new_layer_attr_table_config.setColumns(new_columns_config)
layer.setAttributeTableConfig(new_layer_attr_table_config)
return
setting_all_columns_widths('gis_osm_buildings', 100)
Keep in mind, that changes will be noticeable after closing and opening again the attribute table.
However, there are also several incompleteness in the above approaches:
- autosize functionality comes from PyQt
- it does not shrink rows, only columns
To autosize the width of all columns
Partially overlaps with @Joseph's and @MatthiasKuhn's answers. It applies the resizeColumnsToContents() method from the QTableView class.
from qgis.utils import iface
from qgis.core import QgsProject
from PyQt5.QtWidgets import QApplication, QTableView
def autosize_all_columns_widths(layer_name: str) -> None:
"""
Autosizes widths of all columns in the layer
:param layer_name: name of the layer
"""
layer = QgsProject.instance().mapLayersByName(layer_name)[0]
all_widgets = QApplication.instance().allWidgets()
attribute_table_widgets = [widget for widget in all_widgets if "AttributeTable" in widget.objectName()]
if len(attribute_table_widgets) == 0:
iface.showAttributeTable(layer)
all_widgets = QApplication.instance().allWidgets()
attribute_table_widgets = [widget for widget in all_widgets if "AttributeTable" in widget.objectName()]
for widget in attribute_table_widgets:
if not widget.isWindow():
if layer.name() in widget.objectName():
table_view = widget.findChildren(QTableView)[0]
table_view.resizeColumnsToContents()
# table_view.resizeRowsToContents()
widget.close()
return
autosize_all_columns_widths('gis_osm_buildings')
References:
setAttributeTableConfig()method ofQgsVectorLayer? Perhaps this is the way to go. Unfortunately, I don't have time to look into it properly right now. – Matt May 20 '22 at 12:32