Issue
I need to Solve two problems With my widget above.
- I'd like to be able to define the amount of space put between the post widgets shown in the image (they look fine as is, but I wanna know it's done).
- I'd like to grow the text edits vertically based on the amount of text they contain without growing horizontally.
For 1 the code that populates the widgets is as follows :
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) doesn't bring things any closer, however SetSpacing(100) does increase it.
edit
(for Question 2) I haven't mentioned this, but I want the parent widget to have a vertical scrollbar.
I have answered my own question, but its wordy, and cause and affect based. A proper well written tutorial style answer to address both points gets the bounty :D
edit 2
Using my own answer below I have solved the problem. I'll be accepting my own answer now.
Solution
1) Layouts
The other answer on here is very unclear and possibly off about how layout margins work. Its actually very straightforward.
- Layouts have content margins
- Widgets have content margins
Both of these define a padding around what they contain. A margin setting of 2 on a layout means 2 pixels of padding on all sides. If you have parent-child widgets and layouts, which is always the case when you compose your UI, each object can specific margins which take effect individually. That is... a parent layout specifying a margin of 2, with a child layout specifying a margin of 2, will effectively have 4 pixels of margin being displayed (obviously with some frame drawing in between if the widget has a frame.
A simple layout example illustrates this:
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)
You can see that the top level margin is 10 on each side, and the child layout is 20 on each side. Nothing really complicated in terms of math.
Margin can also be specified on a per-side basis:
# left: 20, top: 0, right: 20, bottom: 0
layout.setContentsMargins(20,0,20,0)
There is also the option of setting spacing on a layout. Spacing is the pixel amount that is placed between each child of the layout. Setting it to 0 means they are right up against each other. Spacing is a feature of the layout, while margin is a feature of the entire object. A layout can have margin around it, and also spacing between its children. And, the children of the widget can have their own margins which are part of their individual displays.
layout.setSpacing(10) # 10 pixels between each layout item
2) Auto-Resizing QTextEdit
Now for the second part of your question. There are a few ways to create a auto-resizing QTextEdit I am sure. But one way to approach it is to watch for content changes in the document, and then adjust the widget based on the document height:
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 subclassed QTextEdit
-> GrowingTextEdit
, and connected the signal emitted from its document to a slot sizeChange
that checks the document height. I also included a heightMin and heightMax attribute to let you specify how large or small its allowed to autogrow. If you try this out, you will see that as you type into the box, the widget will start to resize itself, and also shrink back when you remove lines. You can also turn off the scrollbars if you want. Right now each text edit has its own bars, in addition to the parent scroll area. Also, I think you could add a small pad value to the docHeight
so that it expands just enough to not show scrollbars for the content.
This approach is not really low level. It uses the commonly exposed signals and child members of the widget for you to receive notifications of state changes. Its pretty common to make use of the signals for extending functionality of existing widgets.
Answered By - jdi
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.