I send the whole code of my small application (it needs ZeroTier-One installed to be run).
QMainWindow
centralWidget
contains essentially a QTableView
(inside a QGroupBox
).
My aim is to resize the whole QMainWindow
to fit contents snugly.
This code seems to work correctly vertically (almost correctly: I didn't find a way to shrink table beyond a certain limit), but horizontally cuts table roughly in half.
This is what I get:
... and this is what I would like to have:
(getting rid of blank space at the bottom would be even better, but I suspect this would be another, possibly unrelated, question)
I already perused several answers including: Resize window to fit content and Resize QMainWindow to minimal size after content of layout changes
What am I missing?
import json
import os
import sys
import typing
from PyQt6.QtCore import Qt, QAbstractTableModel, pyqtSlot, QModelIndex, QSettings, QTimer
from PyQt6.QtWidgets import QApplication, QMainWindow, QInputDialog, QHeaderView
from PyQt6.uic import loadUi
from urllib3 import PoolManager
class NetworksModel(QAbstractTableModel):
class Column:
def __init__(self, tag, header):
self.tag = tag
self.header = header
def data(self, item, role):
if role == Qt.ItemDataRole.DisplayRole:
return str(item[self.tag])
class CBColumn(Column):
def data(self, item, role):
if role == Qt.ItemDataRole.CheckStateRole:
return Qt.CheckState.Checked if item[self.tag] else Qt.CheckState
class LiColumn(Column):
def data(self, item, role):
if role == Qt.ItemDataRole.DisplayRole:
return '\n'.join(item[self.tag])
columns = [
Column('name', 'Name'),
Column('id', 'NwID'),
Column('status', 'Status'),
Column('type', 'Type'),
LiColumn('assignedAddresses', 'Addresses'),
CBColumn('allowDNS', 'DNS')
]
def __init__(self):
super().__init__()
self._data = []
def data(self, index: QModelIndex, role: int = ...) -> typing.Any:
r = index.row()
c = index.column()
if r < len(self._data):
e: dict = self._data[r]
return self.columns[c].data(e, role)
def rowCount(self, parent: QModelIndex = ...) -> int:
return len(self._data)
def columnCount(self, parent: QModelIndex = ...) -> int:
return len(self.columns)
def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any:
if role == Qt.ItemDataRole.DisplayRole:
if orientation == Qt.Orientation.Horizontal:
return self.columns[section].header
def set(self, data):
self.beginResetModel()
self._data = data
self.endResetModel()
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
f = super().flags(index)
# c = index.column()
# i = self.columns[c]
# if i['formatter'] == bool:
# f |= Qt.ItemFlag.ItemIsUserCheckable
return f
class MainWindow(QMainWindow):
def __init__(self, settings):
super().__init__()
loadUi("mainwindow.ui", self)
self.settings: QSettings = settings
self.authtoken = self.settings.value('local/authtoken', None)
self.pm = PoolManager()
self.model = NetworksModel()
self.networks.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
self.networks.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
self.networks.setModel(self.model)
self.refresh_timer = QTimer()
self.refresh_timer.timeout.connect(self.on_actionrefresh_triggered)
if self.authtoken:
self.refresh_timer.start(5*1000)
self.on_actionrefresh_triggered()
# self.main_layout.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
@pyqtSlot()
def on_actionauthtoken_triggered(self):
authtoken, ok = QInputDialog.getText(self, 'enter authtoken', '24 alphanumerics')
if ok:
self.authtoken = authtoken
# TODO: enable refreshing
self.settings.setValue('local/authtoken', authtoken)
self.settings.sync()
self.on_actionrefresh_triggered()
self.refresh_timer.start(5*1000)
@pyqtSlot()
def on_actionrefresh_triggered(self):
if self.authtoken:
r = self.pm.request('GET', 'http://localhost:9993/network', headers={'X-ZT1-AUTH': self.authtoken})
if r.status == 200:
j = r.data
li = json.loads(j)
self.model.set(li)
self.trigger_resize()
else:
print(f'on_actionrefresh_triggered() request ERROR: {r.status}')
self.refresh_timer.stop()
else:
print('on_actionrefresh_triggered() ERROR: missing authtoken')
self.refresh_timer.stop()
def trigger_resize(self):
def _resize_me():
self.adjustSize()
# self.resize(self.minimumSizeHint())
QTimer.singleShot(10, _resize_me)
if __name__ == '__main__':
os.environ['DISPLAY'] = "localhost:10.0"
app = QApplication(sys.argv)
window = MainWindow(QSettings('Condarelli', 'ZT1'))
window.show()
# Start the event loop.
exit(app.exec())
and mainwindow.ui
:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="main_layout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Networks:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTableView" name="networks">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionauthtoken"/>
<addaction name="actionrefresh"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionauthtoken">
<property name="text">
<string>authtoken</string>
</property>
<property name="toolTip">
<string>set authtoken</string>
</property>
</action>
<action name="actionrefresh">
<property name="text">
<string>refresh</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>