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) увеличивает его.
редактировать
(для вопроса 2) я не упоминал об этом, но я хочу, чтобы родительский виджет имел вертикальную полосу прокрутки.
Я ответил на свой собственный вопрос, но его многословный, а причина и аффект основаны. Правильный хорошо написанный ответ в стиле учебника для решения обеих точек получает награду: D
изменить 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:
родительские виджеты и макеты имеют поля, в дополнение к параметру интервала самого макета. По некоторым причинам и влиянию тестирования это apprent, что поля применяются как к внешней области родителя, так и к внутренней области.
так, например, если поле в 2 пикселя указано для родителя, вертикальная граница имеет <--2 pixel | 2 pixel -->
margin в дополнение к полям макета (в этом случае HBoxLayout). Если макет имеет 2 пикселя, а также область вокруг горизонтальной линии будет выглядеть так:
<-- 2 pixel | 2 pixel --> <-- 2 pixel (L) 2 pixel--> (W)
редактировать возможно, это больше похоже на следующее:| 2 pixel --> (L) 2 pixel --> <-- 2 pixel (W)
здесь |
является вертикальной линией родителя (L)
является вертикальной линией макета и (W)
- граница встроенного виджета в горизонтальной компоновке.
интервал макета является дополнительным параметром, который определяет, сколько пространства вставлено между виджеты макета в дополнение к любым полям макета.
приведенное выше описание может быть неточным (поэтому не стесняйтесь редактировать его там, где оно неточно), но установка полей родителя и макета на ноль, а также расстояние между макетами на ноль приводит к результату, который вам нужен.
для пункта 2:
я не думаю, что есть прямой способ решить эту проблему (вам, вероятно, придется прибегнуть к подключению на более низком уровне, который требует более глубокого понимания API). Я думаю, вы должны использовать QLabel
виджет вместо QTextEdit
виджет. Метки не имеют представления и, таким образом, расширяются по мере необходимости, по крайней мере, так они работают по умолчанию, пока родитель не ограничен в своем движении.
Итак, изменить QTextEdit
to Qlabel
и добавьте прокрутку к родителю, и все должно работать так, как вы хотите. У меня такое чувство, что вы выбрали QTextEdit
из-за этого фона. Исследовать пути в HTML работает в виджетах QT, и вы можете изменить фон с помощью HTML.
редактировать
этот виджет (извините за размер) создается следующим кодом на 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