PDA

View Full Version : ResizeEvent/Resize out of control



C167
22nd June 2008, 00:05
Hi, another problem :-)
I have a class ImageLabel that receives a QByteArray and converts it into an image. To be able to control resizing, i re-implemented the resizeEvent of the widget. I use it in two positions of the code, both time its in some H/VBox layouts. One time, it works as expected: It loads an image and resizes it as it should if the window gets resized.

On the other position it runs crazy. Instead of scaling the image once to the maximum size, it resizes to infinity! It slowly resizes, and finallyresizes the whole window. I have absolutly no idea why this happens. First, some code:imageLabel.h
class ImageLabel : public QWidget
{
Q_OBJECT
public:
ImageLabel ( QWidget *parent = 0 );
signals:
void renderingFinished ();
public slots:
void setImage ( const int&, const QByteArray& );
protected:
void resizeEvent ( QResizeEvent* );
private:
void resize ( QSize );
QHBoxLayout *layout;
QLabel *imageLabel;
QPixmap image;
QSize imageSize;
};ImageLabel.cpp
ImageLabel::ImageLabel ( QWidget *parent )
: QWidget ( parent )
{
layout = new QHBoxLayout ( this );
imageLabel = new QLabel ( this );
layout->addWidget ( imageLabel );
}

void ImageLabel::setImage ( const int &handle, const QByteArray &data )
{
Q_UNUSED ( handle );
QImage img = QImage::fromData ( data );
// imageLabel->setPixmap ( QPixmap() );
if ( !img.isNull() )
{
image = QPixmap::fromImage ( img );
imageLabel->setPixmap ( image );
resize ( size() );
}
else
{
imageLabel->setText("No Image");
}
}

void ImageLabel::resizeEvent ( QResizeEvent *event )
{
qDebug() << "resize event: " << event->size();
imageSize = event->size();
resize ( event->size() );
}

void ImageLabel::resize ( QSize size )
{
if ( !image.isNull() )
{
imageLabel->setPixmap ( image.scaled ( size.width()-8, size.height()-8, Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
}
}The only differences between the two position is that one receives the QByteArray through a QueuedConnection and the other (the crazy one) through a normal method call. My code to create the label is for the working part:
imageLabel = new ImageLabel ( this );
imageLabel->setObjectName ( QString::fromUtf8 ( "imageLabel" ) );
imageLabel->setSizePolicy ( QSizePolicy::Ignored, QSizePolicy::Ignored );
imageLabel->setBackgroundRole ( QPalette::Base );
imageLabel->setStyleSheet ( "border-width: 1px; border-style: solid; border-color: black;" );
vBox->addWidget ( imageLabel );and for the crazy one:
screen = new ImageLabel ( this );
screen->setObjectName ( QString::fromUtf8 ( "screen" ) );
screen->setSizePolicy ( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
screen->setBackgroundRole ( QPalette::Base );
screen->setStyleSheet ( "border-width: 1px; border-style: solid; border-color: black;" );

//load Image
void BinaryViewer::showImages ( )
{
QSqlQuery query ( QSqlDatabase::database() );
query.prepare ( QString ( "SELECT img0 FROM bin_programs WHERE id = :id" ) );
query.bindValue ( ":id", id );
query.exec();
query.next();
QByteArray array = query.value ( 0 ).toByteArray();
screen->setImage ( 0, array );
}
I played around with the size policys, but with Ignored, i get no object at all (does not allocate space in the gui etc.)
This problem first occured on windows, and after some changes (which i try to recover from the svn currently) it also happens on linux! I'm now in big troubles, cause it destroys my timetable and the program should be finished by monday morning :-(

Any hints?
C167

wysota
22nd June 2008, 09:04
There is a method in QWidget called resize() and it is not virtual, thus your version of resize() probably never gets called and you get an infinite loop of resize-resizeEvent calls. Have you tried simply setting scaledContents of QLabel to true and using a plain label instead?

C167
22nd June 2008, 09:49
scaledContents is what i wanted to avoid, cause it destroys the proportions of the image. I renamed the method to resizeImage, but still no change.

wysota
22nd June 2008, 10:20
You can start from this:


class ScalableImage : public QWidget {
public:
ScalableImage(..) ... { ... m_wdiff = 0; m_hdiff = 0; }
void setPixmap(const QPixmap &px){
m_px = px;
recalculate();
updateGeometry();
update();
}
QSize sizeHint() const { return m_px.isNull() ? QSize(100,100) : m_px.size(); }
protected:
void resizeEvent(QResizeEvent *ev){
if(m_px.isNull()) return;
recalculate();
update();
}
void paintEvent(QPaintEvent *pe){
if(m_px.isNull()) return;
QPainter painter(this);
painter.drawPixmap(m_wdiff/2, m_hdiff/2, m_scaled);
}
void recalculate(){
m_scaled = m_px.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_wdiff = width()-m_scaled.width();
m_hdiff = height()-m_scaled.height();
}
private:
QPixmap m_px, m_scaled;
int m_wdiff, m_hdiff;
};

C167
22nd June 2008, 13:07
Oh, wow, QPainter for painting instead of that QLabel! And now the images are centered instead of left aligned! Thank you very much
I still haven't figured out why it resized, but okay, code is in svn, i won't loose any information :)
Thanks
C167

C167
22nd June 2008, 16:13
oh, i've run in a little problem: the images seem to only show up after resizing the whole window. i tried to manually resize it (same code like in paintEvent) but that doesn't work

wysota
22nd June 2008, 20:56
Yes, of course, my bad. If you call setPixmap() before show() is called, recalculate() will calculate the new pixmap based on incorrect width and height of the widget (although it's a bit strange as the showEvent should trigger a resizeEvent). You can reimplement showEvent() and call recalculate() and update() there and everything should be fine. The widget will repaint itself twice, but that's a minor problem as one of the runs will return immediately. If you want to fix it, you should for example assign m_px to m_scaled in setPixmap and set the margins to 0 instead of calling recalculate(). If the size hint of the widget is kept, the image will be fine.

C167
23rd June 2008, 01:42
At the moment, i have no idea what update does ;) Qt tells me:
Widget painting can only begin as a result of a paintEventThats cause i just used the same code in update as for paintEvent

wysota
23rd June 2008, 08:32
You don't implement update, you call it and Qt schedules a paintEvent. You were to implement showEvent() and call recalculate() and update() there.


void xxx:showEvent(QShowEvent *e){
recalculate();
update();
QWidget::showEvent(e);
}

C167
23rd June 2008, 13:10
i'm sorry, i just found functions that expected some parameters, is missed the normal QWidget::update() :-)
In one place where i have two instanced in a tab widget as individual tabs, there is now the problem that after the images load, the widgets resize to nearly the full size of the image rather than to the size of the widget. But except that, it works. Thank you :-)

wysota
23rd June 2008, 13:45
You probably forgot to apply some of the layouts.

C167
23rd June 2008, 16:35
not directly layouts ;) I felt the power of QSizePolicy:
not the tab widget itself, but the objects that show the images need a policy:
screen1->setSizePolicy ( QSizePolicy::Ignored, QSizePolicy::Ignored );
screen2->setSizePolicy ( QSizePolicy::Ignored, QSizePolicy::Ignored );hehe, again, thank you very much. As everything works well (and now, the images show up immediatly in the tabWidget instead of needing 7 seconds to load without sizePolicys), i'm very happy that the program is finally finished (my biggest program ever).

wysota
23rd June 2008, 21:42
No, certainly Ignored is not needed. If you think you need it, you must have done something Bad. I've been programming Qt for more than 4 years and I never needed to set the size policy to ignored :)

C167
25th June 2008, 09:27
Hm... then i may be on the wrong path in general when making GUIs.
If you have some time, could you please have a look at what i did to make the gui? The files are here:
Base to the vcs (http://git.valouch.info/?p=cdlauncher.git;a=tree;f=src;h=e643f305d6e75229a 1370ae95ac3c4772b7e9a6c;hb=HEAD).
The GUI-Files are BinaryViewer.cpp (http://git.valouch.info/?p=cdlauncher.git;a=blob;f=src/BinaryViewer.cpp;h=f2d1e4b5945145fd6dfce37db7ec8d7 a7a3bbe6b;hb=HEAD), BinaryViewer.h (http://git.valouch.info/?p=cdlauncher.git;a=blob;f=src/BinaryViewer.h;h=03f6a2abc7b25fe1a694bf0b98b0db65d cad0685;hb=HEAD), ImageViewer.cpp (http://git.valouch.info/?p=cdlauncher.git;a=blob;f=src/ImageViewer.cpp;h=72af2e7e8ffaf22d08503bba80636cd1 64a9768e;hb=HEAD), ImageViewer.h (http://git.valouch.info/?p=cdlauncher.git;a=blob;f=src/ImageViewer.h;h=a67612f1709935be42fc257e9c683913aa 0106c8;hb=HEAD). There are some others, but they have no real GUI but provide a simple Stack that shows the actual GUIs.
Thanks, C167