PySide Qt: автоматический вертикальный рост для виджета TextEdit и интервал между виджетами в вертикальной компоновке
Мне нужно решить две проблемы с моим виджетом выше.
- я хотел бы иметь возможность определить объем пространства, помещенного между виджетами post, показанными на изображении (они выглядят нормально, но я хочу знать, что это сделано).
- я хотел бы увеличить текстовые правки по вертикали на основе объема текста, который они содержат, без увеличения по горизонтали.
Для 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) увеличивает его.
Edit
(для вопроса 2) я не упоминал об этом, но я хочу, чтобы родительский виджет имел вертикальную полосу прокрутки.
Я ответил на свой собственный вопрос, но он многословен и основан на причине и аффекте. Правильный хорошо написанный ответ в стиле учебника для решения обеих проблем получает награду: DEdit 2
Используя мой собственный ответ ниже, я решил эту проблему. Я приму свой собственный ответ. сейчас.
2 ответа:
1) макеты
Другой ответ здесь очень неясен и, возможно, не касается того, как работают поля макета. Это на самом деле очень просто.
- макеты имеют поля содержимого
- виджеты имеют поля содержимого
Оба они определяют заполнение вокруг того, что они содержат. Значение поля 2 на макете означает 2 пикселя отступа со всех сторон. Если у вас есть родительско-дочерние виджеты и макеты, что всегда имеет место при создании пользовательского интерфейса, каждый из них объект может иметь определенные поля, которые вступают в силу индивидуально. То есть... Родительский макет, задающий поле 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)
I подкласс
Этот подход на самом деле не является низкоуровневым. Он использует обычно открытые сигналы и дочерние элементы виджета для получения уведомлений об изменениях состояния. Довольно часто можно использовать сигналы для расширения функциональности существующих виджетов.QTextEdit
->GrowingTextEdit
, и подключил сигнал, испускаемый его документом, к слотуsizeChange
, который проверяет высоту документа. Я также включил heightMin и атрибут heightMax, чтобы позволить вам указать, как большие или малые его разрешено авторасширения. Если вы попробуете это сделать, вы увидите, что по мере ввода в поле виджет начнет изменять свой размер, а также сжиматься при удалении строк. Вы также можете отключить полосы прокрутки, если хотите. В настоящее время каждое редактирование текста имеет свои собственные полосы, в дополнение к родительской области прокрутки. Кроме того, я думаю, что вы могли бы добавить небольшое значение pad кdocHeight
, чтобы оно расширяется ровно настолько, чтобы не показывать полосы прокрутки для содержимого.
Для Ответа На Вопрос 1:
Родительские виджеты и макеты имеют поля, в дополнение к параметру spacing самого макета. Из некоторых причинно-следственных тестов видно, что поля применяются как к внешней области родителя, так и к внутренней области.
Так, например, если родительскому элементу задано поле размером 2 пикселя, то вертикальная граница имеет поле
<--2 pixel | 2 pixel -->
в дополнение к полям макета (в данном случае HBoxLayout). Если макет имеет 2 пикселя поле, а также область вокруг горизонтальной линии будет выглядеть следующим образом:
<-- 2 pixel | 2 pixel --> <-- 2 pixel (L) 2 pixel--> (W)
Edit Возможно, это больше похоже на следующее:
| 2 pixel --> (L) 2 pixel --> <-- 2 pixel (W)
Где
|
- вертикальная линия родительского элемента(L)
- вертикальная линия макета, а(W)
- граница встроенного виджета в горизонтальном макете.Интервал макета-это дополнительный параметр, который определяет, сколько места вставляется между виджетами макета в дополнение к любому макету маржи.
Приведенное выше описание может быть неточным (поэтому не стесняйтесь редактировать его там, где оно неточно), но установка полей родителя и макета на ноль, а также интервалов между макетами на ноль дает результат, который вы ищете.
Для пункта 2:
Я не думаю, что существует прямой путь решения этой проблемы (вероятно, вам придется прибегнуть к подключению на более низком уровне, что требует более глубокого понимания API). Я думаю, вам следует использовать
QLabel
виджет вместо виджетаQTextEdit
. Метки не имеют представления и, таким образом, расширяются по мере необходимости, по крайней мере, так они работают по умолчанию, пока родитель не ограничен в своем движении.Итак, измените
QTextEdit
наQlabel
и добавьте прокрутку к родительскому виду, и все должно работать так, как вы хотите. У меня такое чувство, что вы выбралиQTextEdit
из-за его фона. Изучите, как HTML работает в виджетах QT, и вы сможете изменить фон с помощью HTML.Edit
Этот виджет (извините за размер) создается следующим кодом на 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