PDA

View Full Version : Layout problem



MorrisLiang
13th September 2010, 05:58
Screenshot:
5176

The m_layout has been inited like this:


m_layout = new QVBoxLayout();
m_layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
m_layout->setAlignment(Qt::AlignLeft);
m_layout->setContentsMargins(3,0,0,0);


What my code does:
1. Parse the data from the server.
2. Remove the last widget if it has reach maximum count. (By calling QLayout::removeWidget(QWidget*)).
3. Create a new widget, or reuse the removed one. Update it with the data. Resize it to proper size. Both minimumSizeHint() and sizeHint() will return this proper size.
4. Insert the widget back to the layout.

How can I do these:
1. The m_parentWidget should always resize to fit the children. When I add new children. It expands, when I remove one, it shrinks.
2. The children widgets should always resize to its proper size. As you can see from the image, the children doesn't resize properly.
3. The code I describe above would run several times at once. How can I make sure that the layout calculate/move/resize my widgets only once after I finished removing/inserting the widgets?

Lykurg
13th September 2010, 07:42
I would do a custom calc function which calculates the dimension of m_parentWidget. Then set this size. (Or see if setSizeConstraint(QLayout::SetFixedSize) does the tick for you.)
For the children, react on any size event of the parent and call a function like customResize(int newWidth);
Just call the parent resize function at the end of all your actions. And a vertical resize of the parent is not so time consuming. So it won't matter so much.

wysota
13th September 2010, 13:17
According to me proper implementations of sizeHint() together with setting a layout constraint should do the trick without the need for any custom calculations.

MorrisLiang
14th September 2010, 01:54
I would do a custom calc function which calculates the dimension of m_parentWidget. Then set this size. (Or see if setSizeConstraint(QLayout::SetFixedSize) does the tick for you.)
For the children, react on any size event of the parent and call a function like customResize(int newWidth);
Just call the parent resize function at the end of all your actions. And a vertical resize of the parent is not so time consuming. So it won't matter so much.

If I do this, then the using layout is meaningless.


According to me proper implementations of sizeHint() together with setting a layout constraint should do the trick without the need for any custom calculations.
That's what I thought, I have already implement the sizeHint(), it returns the proper size. But the problem is that the layout seems to ignore it. So, some of my widget has been cut.

Lykurg
14th September 2010, 06:21
If I do this, then the using layout is meaningless.Yes, but it still arranges the items for you.
How does your sizeHint function look like (also of the child widgets)?

MorrisLiang
14th September 2010, 09:00
// Header File
#ifndef MINIBLOGENTRYWIDGET_H
#define MINIBLOGENTRYWIDGET_H

#include <QWidget>
class QFrame;
class QTextBrowser;
class QTextDocument;
namespace Douban
{
class MiniBlogEntryWidget : public QWidget
{
Q_OBJECT
public:
MiniBlogEntryWidget(MiniBlogEntry*);
~MiniBlogEntryWidget(){}

QSize sizeHint() const {return m_sizeHint;}
QSize minimumSizeHint() const {return m_sizeHint;}
void updateContent();
void updateRelatedImg();
private:
MiniBlogEntry* m_entry;

QFrame* m_bgFrame;
QTextBrowser* m_contentText;
QTextDocument* m_contentDoc;
QSize m_sizeHint;
};
}
#endif // MINIBLOGENTRYWIDGET_H


// Source File
MiniBlogEntryWidget::MiniBlogEntryWidget(MiniBlogE ntry* e):
QWidget(0),
m_entry(e)
{
setObjectName("MiniBlogEntry");
m_bgFrame = new QFrame(this);
m_bgFrame->setObjectName("bgFrame");

m_contentText = new QTextBrowser(this);
m_contentText->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) ;
m_contentText->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOf f);
connect(m_contentText,SIGNAL(anchorClicked(QUrl)), this,SLOT(onLinkClicked(QUrl)));

ensurePolished();

setMaximumWidth(minimumWidth());

m_contentDoc = new QTextDocument();
m_contentText->setDocument(m_contentDoc);
m_contentDoc->setTextWidth(m_contentText->width());

m_sizeHint.setWidth(minimumWidth());
}

void MiniBlogEntryWidget::updateContent()
{
show();

//... //omit some other unimportant code.

// Set the related image and the content text
QString html = Entry_HTML_TEMPLATE_IMAGE;
m_contentDoc->addResource(QTextDocument::ImageResource,
QUrl("relatedImage.jpg"),
QVariant(m_entry->relatedImg()));

m_contentDoc->setHtml(html.arg(m_entry->content()));
m_contentText->resize(m_contentText->width(),
m_contentDoc->size().height());

int h = m_contentText->y() + m_contentText->height();
if(h < minimumHeight())
h = minimumHeight();
m_sizeHint.setHeight(h);

m_bgFrame->resize(m_sizeHint);
resize(m_sizeHint);
}

void MiniBlogEntryWidget::updateRelatedImg()
{
QString html = Entry_HTML_TEMPLATE_IMAGE;
m_contentDoc->addResource(QTextDocument::ImageResource,
QUrl("relatedImage.jpg"),
m_entry->relatedImg());

m_contentDoc->setHtml(html->arg(m_entry->content()));
m_contentText->resize(m_contentText->width(),
m_contentDoc->size().height());

int h = m_contentText->y() + m_contentText->height();
if(h < minimumHeight())
h = minimumHeight();

if(m_sizeHint.height() < h)
{
m_sizeHint.setHeight(h);

m_bgFrame->resize(m_sizeHint);
resize(m_sizeHint);
updateGeometry();
}
}


As I mentioned in the first post, I parse the data from the server, then update the data by calling "updateContent()". I resized the widget in "updateContent()" function. Then insert the widget into the layout.

Sometimes, it will be a while before the image is downloaded. After the image is downloaded (at this time, the widget has been added into the layout) , I calc the size again.
If the height of the widget is smaller than it needs, resize the widget.

wysota
14th September 2010, 10:41
If you change sizeHint, you have to inform Qt about it by calling QWidget::updateGeometry().

MorrisLiang
14th September 2010, 15:47
If you change sizeHint, you have to inform Qt about it by calling QWidget::updateGeometry().

I try, it doesn't work. I call updateContent() to change the sizehint before I insert the widget to the layout

wysota
14th September 2010, 15:53
I try, it doesn't work. I call updateContent() to change the sizehint before I insert the widget to the layout

Did I say anything about "updateContent()"? If you ever call resize(sizeHint()) then it almost always means you are doing something wrong.