【问题标题】:Qt : Fit width of TableView to width of contentQt:使 TableView 的宽度适合内容的宽度
【发布时间】:2014-01-14 20:24:21
【问题描述】:

我有一个包含QTableView 的窗口,其中列已调整为内容并且宽度固定QTableView 嵌套在 QWidget 中,而 QScrollArea 又嵌套在 QMdiArea 中,QMdiAreacentralWidgetQMainWindow .

当显示QScrollArea 时,QTableView 在我要删除的最后一列右侧有额外的空间:

我希望QTableView 适合列的确切宽度(即最右边的列之后没有多余的空间)。

我尝试使用tableView.setFixedWidth(desired_width),但唯一可行的方法是遍历所有列并获取它们的宽度并将它们相加并添加verticalHeader 宽度和滚动条宽度并传递它作为desired_width

它确实以这种方式工作,但对于如此明显的要求似乎非常复杂:我认为很多程序开发人员希望他们的表格宽度适合列的宽度,这让我想知道也许有一种无需额外计算即可自动执行此操作且我不知道的方法。

所以我的问题是:有没有更简单的方法可以达到同样的效果?

这是我的参考代码:

负责创建QMainWindowt_main 模块的代码:

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 模块的代码,负责使用QTableView 创建SubWindow

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++ 中的答案很好。

【问题讨论】:

  • 您可以使用tableView.visualRect(model.index(0, model.columnCount() - 1)).right() 之类的东西,而不是遍历所有列。
  • 谢谢,但似乎不起作用,visualRect 返回 (0,0,0,0)。
  • 我设法使用tableView.horizontalHeader().length() 来避免迭代,但我仍然需要用tableView.verticalHeader().width()PM_ScrollBarExtent*2 来总结它。

标签: qt pyside qtableview


【解决方案1】:

从 Qt 5.2 开始,您可以使用以下内容:

view->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);

view->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);

【讨论】:

  • 这些对我没有任何影响。
【解决方案2】:

在 C++ 中,你可以这样做:

tableview->resizeColumnsToContents();

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

【讨论】:

  • 感谢您的回答,但 setStretchLastSection 只是拉伸最后一列以填充 tableView 中的剩余空间,而我正在尝试做相反的事情,即缩小 tableView 到列的宽度。
【解决方案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)

【讨论】:

  • 感谢您的回答,我最终使用了 tableView.horizontalHeader().length()tableView.verticalHeader().width(),正如我在 cmets 中所说的,我忘了说,但我将 QtGui.QStyle.PM_ScrollBarExtent 替换为 tableView.verticalScrollBar().sizeHint().width()。现在我不确定哪个更正确,sizeHint() 还是你的方法?但我总是添加 1 个像素以获得适当的结果,我现在猜想,多亏了你的回答,这个像素占了 tableView.frameWidth() * 2 。很遗憾没有更简单的方法。再次感谢您。
  • @ekhumoro 这真的很有帮助。奇怪的是,我仍然需要添加 6 个像素才能完全匹配。我认为这可能是由于列之间的行添加了像素,但无论显示的列数如何,它都是 6 个像素。现在我只是将其添加为软糖因素,但不希望...
  • @neuronet。没有看到实际代码很难说。请开始一个新问题,并包含一个演示该问题的最小工作示例。您可能还应该说出您在哪个平台上。
  • @ekhumoro:刚刚发布:stackoverflow.com/questions/26960006/…
猜你喜欢
  • 2017-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
  • 2014-05-19
  • 1970-01-01
  • 2017-12-03
相关资源
最近更新 更多