9

在此处输入图像描述

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

  1. 我希望能够定义图像中显示的帖子小部件之间的空间量(它们看起来很好,但我想知道它已经完成了)。
  2. 我想根据它们包含的文本量垂直增长文本编辑而不水平增长。

对于 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

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

在此处输入图像描述

4

2 回答 2

13

1) 布局

此处的另一个答案非常不清楚,并且可能与布局边距的工作方式有关。它实际上非常简单。

  1. 布局有内容边距
  2. 小部件具有内容边距

这两个都定义了围绕它们包含的内容的填充。布局上的边距设置为 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)

布局图像示例

可以看到顶层边距每边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->进行了子类GrowingTextEdit化,并将从其文档发出的信号连接到一个sizeChange检查文档高度的插槽。我还包括了一个 heightMin 和 heightMax 属性,让您可以指定它允许自动增长的大小。如果您尝试一下,您会看到当您在框中键入时,小部件将开始自行调整大小,并且在您删除行时也会缩小。如果需要,您也可以关闭滚动条。现在,除了父滚动区域之外,每个文本编辑都有自己的栏。另外,我认为您可以向 中添加一个小的 pad 值,docHeight以便它扩展得刚好足以不显示内容的滚动条。

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

自动增长小部件示例图片

于 2012-08-01T17:29:57.203 回答
1

解决问题 1:

除了布局本身的间距参数外,父控件和布局都有边距。从某些原因和影响测试 显然,边距既适用于父区域的外部区域,也适用于内部区域。

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

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

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

其中|父级(L)的竖线是Layout的竖线,(W)是水平布局中嵌入widget的边框。

布局的间距是一个附加参数,它控制在布局的小部件之间插入多少空间以及任何布局边距。

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

对于第 2 点:

我认为没有直接的方法来解决这个问题(您可能不得不求助于较低级别的挂钩,这需要对 API 有更深入的了解)。我认为您应该使用QLabel小部件而不是QTextEdit小部件。标签没有视图,因此可以根据需要扩展,至少默认情况下它们是这样工作的,只要父对象的移动不受限制。

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

编辑

在此处输入图像描述

这个小部件(请原谅大小)是由带有 PyQT 的 OS X 上的以下代码创建的:

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_()

左侧小部件中的标签显示了已完成的间隔和边距调整,我已将 aQLabel用于发布文本。请注意,我已调整标签使其看起来更像默认标签QTextEdit

于 2012-07-31T22:18:36.750 回答