Hi all,
I have been working on this issue for some time now, scouring the net, and reading on this forum, but haven't yet found an answer to my issue. I have a QGraphicsLinearLayout on my QGraphicsScene with a horizontal layout, and I added a number of widgets to it that are extended from QGraphicsProxyWidget. At some point during the program, something happens that causes one of the widgets, an indicator icon, either to show or hide. My expectation for this linear layout is that it should be able to adjust the cell widths according to the stretch factors given. It doesn't. Since I have the background that the layout is sitting over set to black, whenever the icon disappears, there is a black box in its place.
I have created a minimal version of what I am doing:
TestClasses.h
#ifndef TESTCLASSES_H
#define TESTCLASSES_H
#include <QtGui>
class QGraphicsWidget;
class InnerClass1;
class InnerClass2;
class OuterClass : public QGraphicsWidget
{
Q_OBJECT
public:
virtual ~OuterClass();
void showIcon(const bool show);
public slots:
void resetLayout();
protected:
private:
QGraphicsLinearLayout* m_layout;
InnerClass1* m_string1Widget;
InnerClass1* m_string2Widget;
InnerClass2* m_iconWidget;
};
class InnerClass1 : public QGraphicsProxyWidget
{
Q_OBJECT
public:
InnerClass1
(QGraphicsWidget
* parent
= 0,
const QString & string
= "");
~InnerClass1();
private:
};
class InnerClass2 : public QGraphicsProxyWidget
{
Q_OBJECT
public:
InnerClass2(QGraphicsWidget* parent = 0);
~InnerClass2();
void showIcon(const bool show);
signals:
void visibilityChanged();
protected:
private:
int m_width;
int m_timerId;
};
#endif // TESTCLASSES_H
#ifndef TESTCLASSES_H
#define TESTCLASSES_H
#include <QtGui>
class QGraphicsWidget;
class InnerClass1;
class InnerClass2;
class OuterClass : public QGraphicsWidget
{
Q_OBJECT
public:
OuterClass(QGraphicsItem* parent = 0);
virtual ~OuterClass();
void showIcon(const bool show);
public slots:
void resetLayout();
protected:
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget);
private:
QGraphicsLinearLayout* m_layout;
InnerClass1* m_string1Widget;
InnerClass1* m_string2Widget;
InnerClass2* m_iconWidget;
};
class InnerClass1 : public QGraphicsProxyWidget
{
Q_OBJECT
public:
InnerClass1(QGraphicsWidget* parent = 0, const QString & string = "");
~InnerClass1();
private:
QLabel *m_string;
};
class InnerClass2 : public QGraphicsProxyWidget
{
Q_OBJECT
public:
InnerClass2(QGraphicsWidget* parent = 0);
~InnerClass2();
void showIcon(const bool show);
signals:
void visibilityChanged();
protected:
void timerEvent(QTimerEvent * event);
private:
QLabel *m_icon;
int m_width;
int m_timerId;
};
#endif // TESTCLASSES_H
To copy to clipboard, switch view to plain text mode
TestClasses.cpp
#include "TestClasses.h"
#include <QGraphicsWidget>
/*****************************************************************************************
** OuterClass class definitions
*****************************************************************************************/
: QGraphicsWidget(parent)
{
m_layout = new QGraphicsLinearLayout();
m_layout->setContentsMargins(0,0,0,0);
m_layout->setSpacing(0);
setLayout(m_layout);
m_string1Widget = new InnerClass1(this, "First string");
m_string2Widget = new InnerClass1(this, "Second string");
m_iconWidget = new InnerClass2(this);
m_layout->addItem(m_string1Widget);
m_layout->setStretchFactor(m_string1Widget, 2);
m_layout->addItem(m_iconWidget);
m_layout->setStretchFactor(m_iconWidget, 1);
m_layout->addItem(m_string2Widget);
m_layout->setStretchFactor(m_string2Widget, 2);
connect(m_iconWidget, SIGNAL(visibilityChanged()), this, SLOT(resetLayout()));
}
OuterClass::~OuterClass() {
}
Q_UNUSED(option);
Q_UNUSED(widget);
painter->save();
painter
->setRenderHint
(QPainter::Antialiasing);
// First, fill rectangle with background color.
painter->fillRect(boundingRect(), Qt::black);
painter->restore();
}
void OuterClass::resetLayout()
{
// NOTE: adding these didn't help
//this->updateGeometry();
//m_layout->updateGeometry();
m_layout->invalidate();
m_layout->activate();
}
/*****************************************************************************************
** InnerClass1 class definitions
*****************************************************************************************/
InnerClass1
::InnerClass1(QGraphicsWidget
* parent,
const QString & string
) : QGraphicsProxyWidget(parent)
{
m_string->setText(string);
QStyle* style
= m_string
->style
();
style->visualAlignment(Qt::LayoutDirectionAuto, Qt::AlignCenter);
this->setWidget(m_string);
}
InnerClass1::~InnerClass1()
{
}
/*****************************************************************************************
** InnerClass2 class definitions
*****************************************************************************************/
static const QString ICON_SRC
= ":/circle.png";
InnerClass2::InnerClass2(QGraphicsWidget* parent)
: QGraphicsProxyWidget(parent)
{
m_icon->setPixmap(pixmap);
this->setWidget(m_icon);
m_width = m_icon->rect().width();
m_timerId = startTimer(1000);
}
InnerClass2::~InnerClass2()
{
}
{
if (event->timerId() == m_timerId)
showIcon(!m_icon->isVisible());
}
void InnerClass2::showIcon(bool show)
{
if (m_icon->isVisible() != show) {
m_icon->setVisible(show);
// adjust the icon geometry and tell the layout to reset itself
QRect rect
= m_icon
->rect
();
if (show)
rect.setWidth(m_width);
else
rect.setWidth(0);
// NOTE: adding this didn't help
//m_icon->setGeometry(rect);
this->setGeometry(rect);
emit visibilityChanged();
}
}
#include "TestClasses.h"
#include <QGraphicsWidget>
/*****************************************************************************************
** OuterClass class definitions
*****************************************************************************************/
OuterClass::OuterClass(QGraphicsItem* parent)
: QGraphicsWidget(parent)
{
m_layout = new QGraphicsLinearLayout();
m_layout->setContentsMargins(0,0,0,0);
m_layout->setSpacing(0);
setLayout(m_layout);
m_string1Widget = new InnerClass1(this, "First string");
m_string2Widget = new InnerClass1(this, "Second string");
m_iconWidget = new InnerClass2(this);
m_layout->addItem(m_string1Widget);
m_layout->setStretchFactor(m_string1Widget, 2);
m_layout->addItem(m_iconWidget);
m_layout->setStretchFactor(m_iconWidget, 1);
m_layout->addItem(m_string2Widget);
m_layout->setStretchFactor(m_string2Widget, 2);
connect(m_iconWidget, SIGNAL(visibilityChanged()), this, SLOT(resetLayout()));
}
OuterClass::~OuterClass() {
}
void OuterClass::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
Q_UNUSED(option);
Q_UNUSED(widget);
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
// First, fill rectangle with background color.
painter->fillRect(boundingRect(), Qt::black);
painter->restore();
}
void OuterClass::resetLayout()
{
// NOTE: adding these didn't help
//this->updateGeometry();
//m_layout->updateGeometry();
m_layout->invalidate();
m_layout->activate();
}
/*****************************************************************************************
** InnerClass1 class definitions
*****************************************************************************************/
InnerClass1::InnerClass1(QGraphicsWidget* parent, const QString & string)
: QGraphicsProxyWidget(parent)
{
m_string = new QLabel();
m_string->setText(string);
QStyle* style = m_string->style();
style->visualAlignment(Qt::LayoutDirectionAuto, Qt::AlignCenter);
this->setWidget(m_string);
}
InnerClass1::~InnerClass1()
{
}
/*****************************************************************************************
** InnerClass2 class definitions
*****************************************************************************************/
static const QString ICON_SRC = ":/circle.png";
InnerClass2::InnerClass2(QGraphicsWidget* parent)
: QGraphicsProxyWidget(parent)
{
QPixmap pixmap(ICON_SRC);
m_icon = new QLabel();
m_icon->setPixmap(pixmap);
this->setWidget(m_icon);
m_width = m_icon->rect().width();
m_timerId = startTimer(1000);
}
InnerClass2::~InnerClass2()
{
}
void InnerClass2::timerEvent(QTimerEvent * event)
{
if (event->timerId() == m_timerId)
showIcon(!m_icon->isVisible());
}
void InnerClass2::showIcon(bool show)
{
if (m_icon->isVisible() != show) {
m_icon->setVisible(show);
// adjust the icon geometry and tell the layout to reset itself
QRect rect = m_icon->rect();
if (show)
rect.setWidth(m_width);
else
rect.setWidth(0);
// NOTE: adding this didn't help
//m_icon->setGeometry(rect);
this->setGeometry(rect);
emit visibilityChanged();
}
}
To copy to clipboard, switch view to plain text mode
and I instantiate this from MainWindow.h:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "TestClasses.h"
#include <QGraphicsView>
MainWindow
::MainWindow(QWidget *parent
) : ui(new Ui::MainWindow)
{
ui->setupUi(this);
OuterClass *outer = new OuterClass();
m_scene->addItem(outer);
this->setCentralWidget(view);
}
MainWindow::~MainWindow()
{
delete ui;
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "TestClasses.h"
#include <QGraphicsView>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
OuterClass *outer = new OuterClass();
m_scene = new QGraphicsScene(outer->rect());
m_scene->addItem(outer);
QGraphicsView *view = new QGraphicsView(m_scene);
this->setCentralWidget(view);
}
MainWindow::~MainWindow()
{
delete ui;
}
To copy to clipboard, switch view to plain text mode
You could use any .png file, but I'm using the one from the Qt examples directory found at widgets/tooltips/images/circle.png.
In the OuterClass constructor, I create three widgets, two strings and one icon. I place then into the layout with the icon as the second in line. I give the two string widgets greater priority for stretching with a factor of 2 for each. I give the icon widget less with a factor of 1. Then I connect the signal from the icon widget to a slot belonging to OuterClass.
InnerClass1, the string class, sets the string into its QLabel. InnerClass2, the icon class, sets the pixmap and a timer for 1 second intervals. When the timer goes off, InnerClass2's timerEvent() calls showIcon() to toggle the icon visibility, and showIcon() emits the signal that was connected to by OuterClass. The OuterClass slot then calls invalidate() and activate() on the layout. I also tried adding a call to updateGeometry() for both the QLabel icon object and the icon widget itself.
From everything I've heard and read, this should cause the layout to reset itself, but if you grab my code and run it with some icon, you'll see that the text cells don't get allocated more space to cover over the icon's area, and then less space to make room for the icon again, but rather the black background is being shown. I even went to the extent of having InnerClass2::showIcon() reset the InnerClass2 rect to have the width of the icon when it is to be show, and 0 when it is not to be shown. I set the icon widget's geometry with this rect, and even tried setting the QLabel for icon as well with this rect. This didn't help.
Bookmarks