PySide Qt:TextEdit Widget的自动垂直增长,以及垂直布局中小部件之间的间距

时间:2012-07-26 20:27:59

标签: python qt qt4 pyqt pyside

enter image description here

我需要通过上面的小部件解决两个问题。

  1. 我希望能够定义图像中显示的帖子小部件之间的空间量(它们看起来很好,但我想知道它已经完成)。
  2. 我希望根据文字的数量垂直增加文字修改,而不会水平增长。
  3. 对于1,填充小部件的代码如下:

    self._body_frame = QWidget()
    self._body_frame.setMinimumWidth(750)
    self._body_layout = QVBoxLayout()
    self._body_layout.setSpacing(0)
    self._post_widgets = []
    for i in range(self._posts_per_page):
        pw = PostWidget()
        self._post_widgets.append(pw)
        self._body_layout.addWidget(pw)
    
        self._body_frame.setLayout(self._body_layout)
    

    SetSpacing(0)不会使事情更接近,但SetSpacing(100)确实会增加它。

    修改

    (对于问题2)我没有提到这一点,但我希望父窗口小部件有一个垂直滚动条。

    我已经回答了我自己的问题,但它的罗嗦,原因和影响基础。一个恰当的精心编写的教程样式答案来解决这两点得到了赏金:D

    编辑2

    使用我自己的答案,我已经解决了这个问题。我现在会接受我自己的答案。

    enter image description here

2 个答案:

答案 0 :(得分:11)

1)布局

这里的另一个答案非常不清楚,可能还有关于布局边距如何工作的答案。它实际上非常简单。

  1. 布局具有内容边距
  2. 窗口小部件具有内容边距
  3. 这两个都定义了它们包含的填充。布局上的边距设置为2意味着所有边上的填充2个像素。如果您具有父子窗口小部件和布局(构建UI时总是如此),则每个对象都可以单独生成特定边距。这是...指定边距为2的父布局,子布局指定边距为2,将有效地显示4个像素的边距(显然,如果窗口小部件具有框架,则在其间插入一些框架。

    一个简单的布局示例说明了这一点:

    w = QtGui.QWidget()
    w.resize(600,400)
    
    layout = QtGui.QVBoxLayout(w)
    layout.setMargin(10)
    frame = QtGui.QFrame()
    frame.setFrameShape(frame.Box)
    layout.addWidget(frame)
    
    layout2 = QtGui.QVBoxLayout(frame)
    layout2.setMargin(20)
    frame2 = QtGui.QFrame()
    frame2.setFrameShape(frame2.Box)
    layout2.addWidget(frame2)
    

    Layout Image Example

    您可以看到每侧的顶级边距为10,每侧的子布局为20。在数学方面没有什么真正复杂的。

    也可以基于每一方面指定保证金:

    # left: 20, top: 0, right: 20, bottom: 0
    layout.setContentsMargins(20,0,20,0)
    

    还可以选择在布局上设置间距。间距是布局的每个子项之间放置的像素数量。将其设置为0意味着它们正好相互对立。间距是布局的一个特征,而边距是整个对象的一个​​特征。布局可以在其周围具有边距,并且还可以在其子节点之间具有间距。而且,小部件的子节点可以有自己的边距,这是他们各自显示的一部分。

    layout.setSpacing(10) # 10 pixels between each layout item
    

    2)自动调整QTextEdit

    现在问题的第二部分。我确定有几种方法可以创建自动调整大小的QTextEdit。但接近它的一种方法是观察文档中的内容更改,然后根据文档高度调整窗口小部件:

    class Window(QtGui.QDialog):
    
        def __init__(self):
            super(Window, self).__init__()
            self.resize(600,400)
    
            self.mainLayout = QtGui.QVBoxLayout(self)
            self.mainLayout.setMargin(10)
    
            self.scroll = QtGui.QScrollArea()
            self.scroll.setWidgetResizable(True)
            self.scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
            self.mainLayout.addWidget(self.scroll)
    
            scrollContents = QtGui.QWidget()
            self.scroll.setWidget(scrollContents)
    
            self.textLayout = QtGui.QVBoxLayout(scrollContents)
            self.textLayout.setMargin(10)
    
            for _ in xrange(5):
                text = GrowingTextEdit()
                text.setMinimumHeight(50)
                self.textLayout.addWidget(text)
    
    
    class GrowingTextEdit(QtGui.QTextEdit):
    
        def __init__(self, *args, **kwargs):
            super(GrowingTextEdit, self).__init__(*args, **kwargs)  
            self.document().contentsChanged.connect(self.sizeChange)
    
            self.heightMin = 0
            self.heightMax = 65000
    
        def sizeChange(self):
            docHeight = self.document().size().height()
            if self.heightMin <= docHeight <= self.heightMax:
                self.setMinimumHeight(docHeight)
    

    我已经分组QTextEdit - &gt; GrowingTextEdit,并将其文档中发出的信号连接到检查文档高度的插槽sizeChange。我还包含了一个heightMin和heightMax属性,可以指定允许自动增长的大小。如果您尝试这样做,您将看到当您在框中键入时,窗口小部件将开始自行调整大小,并在删除行时缩小。您也可以根据需要关闭滚动条。除了父滚动区域之外,现在每个文本编辑都有自己的条形。此外,我认为您可以向docHeight添加一个小的填充值,以便它扩展到足以不显示内容的滚动条。

    这种方法并不是很低级别。它使用常用的公开信号和小部件的子成员来接收状态更改的通知。将信号用于扩展现有小部件的功能非常常见。

    Auto-Growing widget example picture

答案 1 :(得分:1)

解决问题1:

除了布局本身的间距参数外,父窗口小部件和布局都有边距。从某些原因和影响测试边缘应用于父母的外部区域和内部区域。

因此,例如,如果为父级指定了2像素边距,则除了布局的边距(在本例中为HBoxLayout)之外,垂直边框还具有<--2 pixel | 2 pixel -->边距。如果布局具有2像素边距,则水平线周围的区域将如下所示:

<-- 2 pixel | 2 pixel --> <-- 2 pixel (L) 2 pixel--> (W)

编辑也许更像是这样:| 2 pixel --> (L) 2 pixel --> <-- 2 pixel (W)

其中|是父(L)的垂直线是布局的垂直线,而(W)是水平布局中嵌入小部件的边框。

布局的间距是一个额外的参数,它控制除了任何布局边距之外在布局的小部件之间插入多少空间。

上面的描述可能不准确(因此可以在不准确的地方编辑它),但是将父级和布局的边距设置为零以及将布局间距设置为零会产生您所追求的结果。

对于第2点:

我认为没有一种直接的方法可以解决这个问题(您可能不得不求助于更低层次,这需要更深入地了解API)。我认为你应该使用QLabel Widget而不是QTextEdit小部件。标签没有视图,因此根据需要进行扩展,至少是默认情况下它们如何工作,只要父级不受其运动约束。

因此,将QTextEdit更改为Qlabel并向父级添加滚动视图,一切都应该可以正常工作。我有一种感觉,你选择QTextEdit因为它的背景。研究HTML在QT小部件中的工作方式,您可以通过HTML改变背景。

修改

enter image description here

这个小部件(借口大小)是由OS X上的以下代码用PyQT创建的:

import sys
from PyQt4 import Qt

class PostMeta(Qt.QWidget):
    posted_at_base_text = "<b> Posted At:</b>"
    posted_by_base_text = "<b> Posted By:</b>"

    def __init__(self):
        Qt.QWidget.__init__(self)
        self._posted_by_label = Qt.QLabel()
        self._posted_at_label = Qt.QLabel()
        layout = Qt.QVBoxLayout()
        layout.setMargin(0)
        layout.setSpacing(5)
        layout.addWidget(self._posted_by_label)
        layout.addWidget(self._posted_at_label)
        layout.addStretch()
        self.setLayout(layout)
        self._posted_by_label.setText(PostMeta.posted_by_base_text)
        self._posted_at_label.setText(PostMeta.posted_at_base_text)


class FramePost(Qt.QFrame):
    def __init__(self):
        Qt.QFrame.__init__(self)
        layout = Qt.QHBoxLayout()
        layout.setMargin(10)
        self.te = Qt.QLabel()
        self.te.setStyleSheet("QLabel { background : rgb(245,245,245) }")
        self.te.setFrameStyle( Qt.QFrame.Panel |  Qt.QFrame.Sunken)
        self.te.setLineWidth(1)
        self._post_meta = PostMeta()
        layout.addWidget(self._post_meta)
        vline = Qt.QFrame()
        vline.setFrameShape(Qt.QFrame.VLine)
        layout.addWidget(vline)
        layout.addWidget(self.te)
        self.te.setText(
            """            line one
            line two
            line three
            line four
            line five
            line six
            line seven
            line eight
            line nine
            line ten
            line eleven
            line twelve
            line thirteen""")
        self.setLayout(layout)

        self.setFrameStyle(Qt.QFrame.Box)
        self.setLineWidth(2)

app = Qt.QApplication(sys.argv)
w = Qt.QWidget()
layout = Qt.QHBoxLayout()
fp = FramePost()
layout.addWidget(fp)
w.setLayout(layout)
w.show()
app.exec_()

左侧小部件中的标签显示间隔和边距调整已完成,我使用QLabel作为帖子文本。请注意,我已将标签调整为更像默认QTextEdit