Qt: установите ширину TableView на ширину содержимого

у меня есть окно, которое содержит QTableView, который столбцы настраиваются на содержание и фиксированной ширины. The QTableView вложен в QWidget это, в свою очередь, вложено в QScrollArea это, в свою очередь, вложено в вкладки QMdiArea что это centralWidget of a QMainWindow.

когда QScrollArea показал,QTableView имеет дополнительное пространство справа от последнего столбца, который я хочу удалить :

Screenshot of TableView

я хочу QTableView чтобы соответствовать точной ширине столбцов (т. е. без дополнительного пространства после самого правого столбца).

я пытался использовать tableView.setFixedWidth(desired_width) но тогда единственный способ, которым он мог работать, - это перебрать все столбцы, получить их ширину, суммировать их вместе и добавить verticalHeader ширина и ширина полосы прокрутки и передать его как desired_width.

это работает, но это кажется очень сложным для такой явный требование: я думаю, что многие разработчики программ хотят, чтобы ширина их таблиц соответствовала ширине столбцов, и это заставляет меня задуматься, что, возможно, есть метод, который делает это автоматически без дополнительных вычислений, и что я не знаю.

Итак, мой вопрос : есть ли более простой способ достичь того же результата ?

вот мой код для ссылки :

код t_main модуль, ответственный за создание QMainWindow :

import sys
import t_wdw
from PySide import QtGui

class Main_Window(QtGui.QMainWindow):
    def __init__(self):
        super(Main_Window,self).__init__()
        self.initUI()


    def initUI(self):
        self.statusBar()
        # Defines QActions for menu
        self.new_window=QtGui.QAction("&Window alpha",self)
        self.new_window.triggered.connect(self.open_window)
        # Creates the menu
        self.menu_bar=self.menuBar()
        self.menu1=self.menu_bar.addMenu('&Menu 1')
        self.menu1.addAction(self.new_window)
        # Creates a QMdiArea to manage all windows.
        self.wmanager=QtGui.QMdiArea()
        self.wmanager.setViewMode(QtGui.QMdiArea.TabbedView)
        self.setCentralWidget(self.wmanager)
        self.showMaximized()

    # Opens the new window that holds the QTableView
    def open_window(self):
        t_wdw.launch_window()
        t_wdw.window_alpha=self.wmanager.addSubWindow(t_wdw.window)
        t_wdw.window_alpha.show()

def main():
    app=QtGui.QApplication(sys.argv)
    main_wdw=Main_Window()
    sys.exit(app.exec_())

if __name__=="__main__":
    main()

код t_wdw модуль, который отвечает за создание SubWindow С QTableView.

from PySide import QtGui
from PySide import QtCore

def launch_window():
    global window
    # Creates a new window
    window=QtGui.QScrollArea()
    window1=QtGui.QWidget()
    row=0
    data=[["VH"+str(row+i),1,2,3] for i in range(20)]
    headers=["HH1","HH2","HH3"]
    # Creates a table view with columns resized to fit the content.
    model=my_table(data,headers)
    tableView=QtGui.QTableView()
    tableView.setModel(model)
    tableView.resizeColumnsToContents()
    # Fixes the width of columns and the height of rows.
    tableView.horizontalHeader().setResizeMode(QtGui.QHeaderView.Fixed)
    tableView.verticalHeader().setResizeMode(QtGui.QHeaderView.Fixed)

    """
    Here is the solution I resorted to to fix the tableView width 
    equal to its content and that I want to make simpler
    """
    vhwidth=tableView.verticalHeader().width()
    desired_width=QtGui.QStyle.PM_ScrollBarExtent*2+vhwidth+1
    for i in range(len(headers)):
        desired_width+=tableView.columnWidth(i)
    tableView.setFixedWidth(desired_width)

    """
    Sets the layouts and widgets using a QHBoxLayout because
    I want the QTableView to be centered on the window
    and more widgets and layouts are to be added later.
    """

    window1.main_layout=QtGui.QHBoxLayout()
    window1.main_layout.addStretch(0)
    window1.main_layout.addWidget(tableView)
    window1.main_layout.addStretch(0)
    window.setLayout(window1.main_layout)
    window.setWidget(window1)

class my_table(QtCore.QAbstractTableModel):

    def __init__(self,data,headers,parent=None):
        QtCore.QAbstractTableModel.__init__(self,parent)
        self.__data=data
        self.__headers=headers

    def rowCount(self,parent):
        return len(self.__data)

    def columnCount(self,parent):
        return len(self.__headers)

    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column+1]

    def headerData(self,section,orientation,role):
        if role == QtCore.Qt.DisplayRole:
            if orientation == QtCore.Qt.Horizontal:
                return self.__headers[section]
            if orientation == QtCore.Qt.Vertical:
                return self.__data[section][0]

дополнительный вопрос для тех, кто читает код: зачем мне нужно умножать PM_ScrollBarExtent 2, чтобы получить правильный результат ?

P. S: Я использую PySide 1.2.1, но ответы на PyQt или C++ в порядке.

3 ответов


есть несколько вещей о вашей калькуляции ширины, которые являются неправильными.

во-первых, вы пытаетесь использовать QtGui.QStyle.PM_ScrollBarExtent чтобы получить ширину вертикальной полосы прокрутки - но это константа, а не собственность. Вместо этого вам нужно использовать класса qstyle.pixelMetric:

tableView.style().pixelMetric(QtGui.QStyle.PM_ScrollBarExtent)

во-вторых, вы не учитываете ширину рамки tableview, которая может быть рассчитана следующим образом:

tableView.frameWidth() * 2

сложение этих значений вместе с размерами заголовки, окончательный расчет должен быть:

vwidth = tableView.verticalHeader().width()
hwidth = tableView.horizontalHeader().length()
swidth = tableView.style().pixelMetric(QtGui.QStyle.PM_ScrollBarExtent)
fwidth = tableView.frameWidth() * 2

tableView.setFixedWidth(vwidth + hwidth + swidth + fwidth)

Это должно оставить точно пространство, необходимое для вертикальной полосы прокрутки.

PS:

поскольку вы устанавливаете фиксированную ширину для tableview, вы также можете избавиться от горизонтальной полосы прокрутки, которая является избыточной:

tableView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

В C++ можно сделать что-то вроде этого:

tableview->resizeColumnsToContents();

QHeaderView* header = tableview->horizontalHeader();
header->setStretchLastSection(true);
tablewview->setHorizontalHeader(header);

начиная с Qt 5.2 вы можете использовать следующее:

view->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);

или

view->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);