PDA

View Full Version : proportional widget resize



momesana
24th October 2009, 20:40
Hi,
I have a simple question regardin widget resizes. I want my widget that has a certain aspect ratio to shrink/grow without affecting that ratio. How do I do that? I thought about heightForWidth but I am not sure and it doesn't really work.

Thanks in advance
momesana

axeljaeger
25th October 2009, 00:53
heightForWidth is what you are looking for. What happens if you try it?

momesana
25th October 2009, 16:26
well,
nothing happens!
I probably have to activate set the hasWidthForHeight flag somewhere. All I know is that it doesn't work right now :-(.

axeljaeger
25th October 2009, 16:30
Yes you have to set hasHeightForWidth in the sizePolicy of your widget.

momesana
25th October 2009, 17:26
I did but it still doesn't work. Here is the code




#include <QApplication>
#include <QStylePainter>
#include <QStyleOption>
#include <QMouseEvent>
#include <QDebug>
#include <cmath>
#include <QWidget>
#include <QList>
#include <QRect>

class RgbBitMaskWidget : public QWidget
{
Q_OBJECT
public:
RgbBitMaskWidget(QWidget* parent = 0);
~RgbBitMaskWidget();
uchar red() const;
uchar green() const;
uchar blue() const;
virtual int heightForWidth(int) const;
virtual QSize sizeHint() const;
protected:
virtual void resizeEvent(QResizeEvent*);
virtual void paintEvent(QPaintEvent*);
virtual void mousePressEvent(QMouseEvent* );
signals:
void rgbBitMaskChanged(int, int, int) const;
private:
uchar mBits[3];
QList<QList<QRect> > mGeometryRects;

void recalculateRectGeometries();
};

RgbBitMaskWidget::RgbBitMaskWidget(QWidget* parent)
: QWidget(parent)
{
// initialize array
for (int i = 0; i < 3; ++i)
mBits[i] = 255;

// initialize list of arrays
for (int i = 0; i < 3; ++i) {
QList<QRect> l;
for (int j = 0; j < 8; ++j)
l << QRect();
mGeometryRects << l;
}

// set sizePolicy (important for heightForWidth)
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
sizePolicy.setHeightForWidth(true);
setSizePolicy(sizePolicy);

const int minWidth = 150;
setMinimumSize(minWidth, minWidth / (8 / 3.0));
}

RgbBitMaskWidget::~RgbBitMaskWidget()
{
}

void RgbBitMaskWidget::recalculateRectGeometries()
{
const int MARGIN = 2;
QRect r = contentsRect().adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);

int x = 0;
int y = 0;
int w = r.width() / 8;
int h = r.height() / 3;

for (int i = 0; i < mGeometryRects.size(); ++i) {
QList<QRect> rectList = mGeometryRects[i];
x = 0;
for (int j = 0; j < rectList.size(); ++j) {
mGeometryRects[i][j] = QRect(x, y, w, h);
x += w;
}
y += h;
}
}

void RgbBitMaskWidget::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
recalculateRectGeometries();
}

void RgbBitMaskWidget::mousePressEvent(QMouseEvent* event)
{
QPoint pos = event->pos();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 8; ++j) {
if (mGeometryRects[i][j].contains(pos)) {
uchar flag = std::pow(2, 7 - j);
if (flag == (mBits[i] & flag))
mBits[i] = mBits[i] & (~flag);
else
mBits[i] = mBits[i] | flag ;
}
}
}
QWidget::mousePressEvent(event);
update();
}

void RgbBitMaskWidget::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);

QStyleOption opt;
opt.init(this);
QStylePainter painter(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);

QList<QColor> colors;
colors << QColor(Qt::red) << QColor(Qt::green) << QColor(Qt::blue);
// paint rects
QPen pen(Qt::white);
pen.setWidth(3);
painter.setPen(pen);
for(int i = 0; i < 3; ++i) {
QList<QRect> l = mGeometryRects[i];
QColor c = colors[i];
for (int j = 0; j < 8; ++j) {
uchar flags = std::pow(2, 7 - j);
if ((mBits[i] & flags) == flags)
painter.setBrush(c);
else
painter.setBrush(c.lighter(185));

painter.drawRect(mGeometryRects[i][j]);
}
}
}

int RgbBitMaskWidget::heightForWidth(int) const
{
double ratio = 8 / 3;
return static_cast<int>(height() / ratio);
}

QSize RgbBitMaskWidget::sizeHint() const
{
int w = width();
return QSize(w, heightForWidth(w));
}

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
RgbBitMaskWidget rgb;
rgb.show();
return a.exec();
}

#include "main.moc"



Thanks in advance

axeljaeger
25th October 2009, 17:33
I think you should not reimplement sizeHint then. But anyway maybe heightForWidth is not supported for toplevel-widgets. Reason: How should the widget be resized when the user clicks "maximize" and the display has an aspect ratio != your heightForWidth?

momesana
25th October 2009, 18:05
I just added it to a QWidget that itself is the centralWidget of a QMainWindow. But it still loses the aspect ratio when it is resized. Btw, the widget itself is supposed to be placed into a QDockWidget later. So how can I make it work so that it keeps its aspect ratio and only grows proportionally? Any Ideas?

Thanks in advance
momesana



#include <QtGui>
#include <cmath>

class RgbBitMaskWidget : public QWidget
{
Q_OBJECT
public:
RgbBitMaskWidget(QWidget* parent = 0);
~RgbBitMaskWidget();
uchar red() const;
uchar green() const;
uchar blue() const;
virtual int heightForWidth(int) const;
virtual QSize sizeHint() const;
protected:
virtual void resizeEvent(QResizeEvent*);
virtual void paintEvent(QPaintEvent*);
virtual void mousePressEvent(QMouseEvent* );
signals:
void rgbBitMaskChanged(int, int, int) const;
private:
uchar mBits[3];
QList<QList<QRect> > mGeometryRects;

void recalculateRectGeometries();
};

RgbBitMaskWidget::RgbBitMaskWidget(QWidget* parent)
: QWidget(parent)
{
// initialize array
for (int i = 0; i < 3; ++i)
mBits[i] = 255;

// initialize list of arrays
for (int i = 0; i < 3; ++i) {
QList<QRect> l;
for (int j = 0; j < 8; ++j)
l << QRect();
mGeometryRects << l;
}

// set sizePolicy (important for heightForWidth)
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
sizePolicy.setHeightForWidth(true);
setSizePolicy(sizePolicy);

const int minWidth = 150;
setMinimumSize(minWidth, minWidth / (8 / 3.0));
}

RgbBitMaskWidget::~RgbBitMaskWidget()
{
}

void RgbBitMaskWidget::recalculateRectGeometries()
{
const int MARGIN = 2;
QRect r = contentsRect().adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);

int x = 0;
int y = 0;
int w = static_cast<int>(r.width() / 8.0);
int h = static_cast<int>(r.height() / 3.0);

for (int i = 0; i < mGeometryRects.size(); ++i) {
QList<QRect> rectList = mGeometryRects[i];
x = 0;
for (int j = 0; j < rectList.size(); ++j) {
mGeometryRects[i][j] = QRect(x, y, w, h);
x += w;
}
y += h;
}
}

void RgbBitMaskWidget::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
recalculateRectGeometries();
}

void RgbBitMaskWidget::mousePressEvent(QMouseEvent* event)
{
QPoint pos = event->pos();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 8; ++j) {
if (mGeometryRects[i][j].contains(pos)) {
uchar flag = std::pow(2, 7 - j);
if (flag == (mBits[i] & flag))
mBits[i] = mBits[i] & (~flag);
else
mBits[i] = mBits[i] | flag ;
}
}
}
QWidget::mousePressEvent(event);
update();
}

void RgbBitMaskWidget::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);

QStyleOption opt;
opt.init(this);
QStylePainter painter(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);

QList<QColor> colors;
colors << QColor(Qt::red) << QColor(Qt::green) << QColor(Qt::blue);
// paint rects
QPen pen(Qt::white);
pen.setWidth(3);
painter.setPen(pen);
for(int i = 0; i < 3; ++i) {
QList<QRect> l = mGeometryRects[i];
QColor c = colors[i];
for (int j = 0; j < 8; ++j) {
uchar flags = std::pow(2, 7 - j);
if ((mBits[i] & flags) == flags)
painter.setBrush(c);
else
painter.setBrush(c.lighter(185));

painter.drawRect(mGeometryRects[i][j]);
}
}
}

int RgbBitMaskWidget::heightForWidth(int width) const
{
return static_cast<int>(width / (8 / 3.0));
}

QSize RgbBitMaskWidget::sizeHint() const
{
int w = width();
return QSize(w, heightForWidth(w));
}

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// central widget
QWidget* cw = new QWidget;
QVBoxLayout* lo = new QVBoxLayout;
cw->setLayout(lo);

RgbBitMaskWidget* rgb = new RgbBitMaskWidget();
cw->layout()->addWidget(rgb);

QMainWindow* mw = new QMainWindow;
mw->setCentralWidget(cw);
mw->show();
return a.exec();
}

#include "main.moc"

Onanymous
15th December 2010, 04:22
Sorry to pick up the old thread, but have you found a solution?
I failed to solve it within spacers, layouts and heightForWidth, setHeightForWidth etc. functions.
Basically the question is how to force a widget to keep proportions under resizing its parent?