【问题标题】:QTreeView not spanning parent width or heightQTreeView 不跨越父宽度或高度
【发布时间】:2015-05-18 21:25:29
【问题描述】:

所以我是 QtGui 的新手,正在查找如何做事,我发现这个很简洁 example on QTreeView。当我自己让它工作时,我注意到它并没有像我预期的那样填满空间:

所以我一直在寻找答案,但在 Python 或 C++ 资源中都没有找到太多答案。我已经checking the documentation 很多次了,但仍然没有完全找到我要搜索的内容。

所以很明显有些东西没有正确的尺寸政策,但我很难弄清楚是什么。到目前为止,我已经淘汰了几个潜在的候选人:

  • 持有 QTreeView 实例的 QWidget 实例正确地跨越了它所在的布局(QWidget 跨越 QGroupBox 的宽度减去一点边距)。
  • 由于 QTreeView 的父小部件尺寸正确,我认为它对 QTreeView 来说更本地化,但是当我使用 setSizePolicy 时,我使用的所有策略似乎都无法解决问题。可能有多个我不知道的步骤?
  • QTreeView 继承的viewport(来自QAbstractScrollArea 比我预期的要小得多。使用新的空QWidget 调用QTreeView 的setViewport() 方法只会将非标题内容背景重绘为灰色而不是白色,我怀疑这很近,但不是我需要看的地方。
  • QTreeView 还有其他孩子(viewport 除外)我仍在调查中。
  • 我尝试过的大部分内容都在下面的代码中注释掉了。

这是我要重现的源代码:

import sys
from PySide.QtGui import *


class TreeTime(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.main_widget = QWidget()
        self.main_layout = QVBoxLayout()
        self.main_widget.setLayout(self.main_layout)
        self.setCentralWidget(self.main_widget)
        self.statusBar()

        self.make_tree()

        self.show()

    def make_tree(self):
        # init widgets
        self.tgb = QGroupBox("[Tree Group Box Title]")
        self.main_layout.addWidget(self.tgb)

        tgb_layout = QVBoxLayout()
        self.tgb.setLayout(tgb_layout)

        tgb_widget = QWidget()
        tgb_layout.addWidget(tgb_widget)

        debug_btn = QPushButton("DEBUG")
        tgb_layout.addWidget(debug_btn)

        view = QTreeView(parent=tgb_widget)
        # view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        view.setSelectionBehavior(QAbstractItemView.SelectRows)
        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(['col1', 'col2', 'col3'])
        view.setModel(model)
        view.setUniformRowHeights(True)

        # populate data
        for i in range(10):
            parent1 = QStandardItem('Family {}. Some long status text for sp'.format(i))
            for j in range(3):
                child1 = QStandardItem('Child {}'.format(i*3+j))
                child2 = QStandardItem('row: {}, col: {}'.format(i, j+1))
                child3 = QStandardItem('row: {}, col: {}'.format(i, j+2))
                parent1.appendRow([child1, child2, child3])
            model.appendRow(parent1)
            # span container columns
            view.setFirstColumnSpanned(i, view.rootIndex(), True)

        # expand third container
        index = model.indexFromItem(parent1)
        view.expand(index)

        # select last row
        selmod = view.selectionModel()
        index2 = model.indexFromItem(child3)
        selmod.select(index2, QItemSelectionModel.Select|QItemSelectionModel.Rows)

        def print_debug_info():
            print('')
            for child in view.children():
                print("child "+repr(child)) #not sure what all these are yet
            print('')
            print('self.main_widget.frameSize: '+repr(self.main_widget.frameSize()))
            print('view.parent().parent().frameSize(): '+repr(view.parent().parent().frameSize())) #group box
            # print('self.frameSize: '+repr(self.frameSize()))
            print('self.tgb.frameSize: '+repr(self.tgb.frameSize()))
            print('view.parent(): '+repr(view.parent()))
            print('view.parent().frameSize(): '+repr(view.parent().frameSize()))
            # print('view.parent().frameSize(): '+repr(view.parent().frameSize())+" (before)")
            # print('view.parent().adjustSize(): '+repr(view.parent().adjustSize()))
            # print('view.parent().frameSize(): '+repr(view.parent().frameSize())+" (after)")
            print('view.viewport(): '+repr(view.viewport()))
            print('view.viewport().frameSize(): '+repr(view.viewport().frameSize()))
            # print('view.parent().parent().parent().frameSize(): '+repr(view.parent().parent().parent().frameSize()))
            # print('calling setViewport: '+repr(view.setViewport(QWidget())))
            # view.adjustSize()

        debug_btn.clicked.connect(print_debug_info)

    def sayHello(self):
        self.statusBar().showMessage("Hello World!")
        import time; time.sleep(2)
        self.statusBar().showMessage("")

    def sayWords(self, words):
        self.statusBar().showMessage(words)


if __name__ == '__main__':
    app = QApplication([])
    tt = TreeTime()
    sys.exit(app.exec_())

我使用的是 Windows 8.1 机器和 Python 3.4.3,PySide 版本 1.2.2 - 任何帮助将不胜感激! (另外,如果我遗漏了任何重要细节,请告诉我)

更新(2015 年 5 月 19 日):我尝试将我的 DEBUG 按钮移到 QGroupBox 之外,结果是 QTreeView 被折叠成一个完全无法辨认的大小,所以你甚至无法分辨是什么该对象不再存在,因此即使我取消注释该行,它似乎也在最小化使用的空间:

view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

一位朋友建议这可能只是 Windows 的问题,而不是我的代码,但我没有任何支持。

2015 年 5 月 19 日更新:我已经实施了 @titusjan 提供的建议,但我有同样的问题/行为。

【问题讨论】:

    标签: python-3.x layout pyside qtreeview


    【解决方案1】:

    你需要去掉多余的tp_widget,将view添加到tgb_layout

    def make_tree(self):
        # init widgets
        self.tgb = QGroupBox("[Tree Group Box Title]")
        self.main_layout.addWidget(self.tgb)
    
        tgb_layout = QVBoxLayout()
        self.tgb.setLayout(tgb_layout)
    
        view = QTreeView()
        tgb_layout.addWidget(view)
    
        ...
    
        debug_btn = QPushButton("DEBUG")
        tgb_layout.addWidget(debug_btn)
    

    请注意,当您将小部件添加到布局时,它们将自动重新设置为布局的父级(只要有一个),因此实际上没有必要在构造函数中设置一个。

    还要注意:

        tgb_layout = QVBoxLayout(self.tgb)
    

    完全等价于:

        tgb_layout = QVBoxLayout()
        self.tgb.setLayout(tgb_layout)
    

    因为布局将始终重新设置为其设置的小部件的父级。

    【讨论】:

    • 啊哈!我明白了——我认为出于某种原因我必须将 QTreeView 添加到 QWidget,然后将该 QWidget 添加到视图中。我不知道我是怎么把它卡在脑海里的。非常感谢你帮助我解决这个问题!我现在开始工作了。
    【解决方案2】:

    您必须使用setLayout 方法将布局链接到小部件。所以改变...

    self.main_layout = QVBoxLayout(self.main_widget)
    

    进入

    self.main_layout = QVBoxLayout()
    self.main_widget.setLayout(self.main_layout)
    

    tgb_view 布局类似(为了清楚起见,我将其重命名为 tgb_layout)。

    最后你忘了给这个布局添加树视图,所以添加:

    tgb_view.addWidget(view)
    

    为方便起见,我把所有相关的修改代码放在下面。

    def initUI(self):
        self.main_widget = QWidget()
        self.main_layout = QVBoxLayout()
        self.main_widget.setLayout(self.main_layout)
        self.setCentralWidget(self.main_widget)
        self.statusBar()
        self.make_tree()
    
        self.show()
    
    def make_tree(self):
        # init widgets
        self.tgb = QGroupBox("[Tree Group Box Title]")
        self.main_layout.addWidget(self.tgb)
    
        tgb_view = QVBoxLayout()
        self.tgb.setLayout(tgb_view)
        tgb_widget = QWidget()
        tgb_view.addWidget(tgb_widget)
    
        debug_btn = QPushButton("DEBUG")
        tgb_view.addWidget(debug_btn)
    
        view = QTreeView(parent=tgb_widget)
        tgb_view.addWidget(view)
        ...
    

    尺寸政策的东西不是必需的,默认就可以了。

    【讨论】:

    • 有趣!我的印象是,在构造时传递给它的父小部件的布局将被分配为该小部件的布局。我已经实施了你的建议,@titusjan,但我的行为相同......我正在编辑我的原始帖子以反映代码中所做的更改。
    • @LastTigerEyes。你的印象完全正确。
    • @LastTigerEyes:那是因为你没有添加tgb_view.addWidget(view)这一行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    • 1970-01-01
    • 2019-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多