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
Qt Code:
  1. #ifndef TESTCLASSES_H
  2. #define TESTCLASSES_H
  3.  
  4. #include <QtGui>
  5.  
  6. class QGraphicsWidget;
  7. class InnerClass1;
  8. class InnerClass2;
  9.  
  10. class OuterClass : public QGraphicsWidget
  11. {
  12. Q_OBJECT
  13.  
  14. public:
  15. OuterClass(QGraphicsItem* parent = 0);
  16. virtual ~OuterClass();
  17.  
  18. void showIcon(const bool show);
  19.  
  20. public slots:
  21. void resetLayout();
  22.  
  23. protected:
  24. void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget);
  25.  
  26. private:
  27. QGraphicsLinearLayout* m_layout;
  28. InnerClass1* m_string1Widget;
  29. InnerClass1* m_string2Widget;
  30. InnerClass2* m_iconWidget;
  31. };
  32.  
  33. class InnerClass1 : public QGraphicsProxyWidget
  34. {
  35. Q_OBJECT
  36.  
  37. public:
  38. InnerClass1(QGraphicsWidget* parent = 0, const QString & string = "");
  39. ~InnerClass1();
  40.  
  41. private:
  42. QLabel *m_string;
  43.  
  44. };
  45.  
  46. class InnerClass2 : public QGraphicsProxyWidget
  47. {
  48. Q_OBJECT
  49.  
  50. public:
  51. InnerClass2(QGraphicsWidget* parent = 0);
  52. ~InnerClass2();
  53.  
  54. void showIcon(const bool show);
  55.  
  56. signals:
  57. void visibilityChanged();
  58.  
  59. protected:
  60. void timerEvent(QTimerEvent * event);
  61.  
  62. private:
  63. QLabel *m_icon;
  64. int m_width;
  65. int m_timerId;
  66.  
  67. };
  68.  
  69. #endif // TESTCLASSES_H
To copy to clipboard, switch view to plain text mode 

TestClasses.cpp
Qt Code:
  1. #include "TestClasses.h"
  2. #include <QGraphicsWidget>
  3.  
  4.  
  5. /*****************************************************************************************
  6.  ** OuterClass class definitions
  7.  *****************************************************************************************/
  8.  
  9. OuterClass::OuterClass(QGraphicsItem* parent)
  10. : QGraphicsWidget(parent)
  11. {
  12. m_layout = new QGraphicsLinearLayout();
  13. m_layout->setContentsMargins(0,0,0,0);
  14. m_layout->setSpacing(0);
  15. setLayout(m_layout);
  16.  
  17. m_string1Widget = new InnerClass1(this, "First string");
  18. m_string2Widget = new InnerClass1(this, "Second string");
  19. m_iconWidget = new InnerClass2(this);
  20.  
  21. m_layout->addItem(m_string1Widget);
  22. m_layout->setStretchFactor(m_string1Widget, 2);
  23.  
  24. m_layout->addItem(m_iconWidget);
  25. m_layout->setStretchFactor(m_iconWidget, 1);
  26.  
  27. m_layout->addItem(m_string2Widget);
  28. m_layout->setStretchFactor(m_string2Widget, 2);
  29.  
  30. connect(m_iconWidget, SIGNAL(visibilityChanged()), this, SLOT(resetLayout()));
  31. }
  32.  
  33. OuterClass::~OuterClass() {
  34.  
  35. }
  36.  
  37. void OuterClass::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
  38. Q_UNUSED(option);
  39. Q_UNUSED(widget);
  40.  
  41. painter->save();
  42. painter->setRenderHint(QPainter::Antialiasing);
  43. // First, fill rectangle with background color.
  44. painter->fillRect(boundingRect(), Qt::black);
  45. painter->restore();
  46. }
  47.  
  48. void OuterClass::resetLayout()
  49. {
  50. // NOTE: adding these didn't help
  51. //this->updateGeometry();
  52. //m_layout->updateGeometry();
  53. m_layout->invalidate();
  54. m_layout->activate();
  55. }
  56.  
  57.  
  58. /*****************************************************************************************
  59.  ** InnerClass1 class definitions
  60.  *****************************************************************************************/
  61.  
  62. InnerClass1::InnerClass1(QGraphicsWidget* parent, const QString & string)
  63. : QGraphicsProxyWidget(parent)
  64. {
  65. m_string = new QLabel();
  66. m_string->setText(string);
  67. QStyle* style = m_string->style();
  68. style->visualAlignment(Qt::LayoutDirectionAuto, Qt::AlignCenter);
  69. this->setWidget(m_string);
  70. }
  71.  
  72. InnerClass1::~InnerClass1()
  73. {
  74. }
  75.  
  76.  
  77. /*****************************************************************************************
  78.  ** InnerClass2 class definitions
  79.  *****************************************************************************************/
  80.  
  81. static const QString ICON_SRC = ":/circle.png";
  82.  
  83. InnerClass2::InnerClass2(QGraphicsWidget* parent)
  84. : QGraphicsProxyWidget(parent)
  85. {
  86. QPixmap pixmap(ICON_SRC);
  87. m_icon = new QLabel();
  88. m_icon->setPixmap(pixmap);
  89. this->setWidget(m_icon);
  90. m_width = m_icon->rect().width();
  91. m_timerId = startTimer(1000);
  92. }
  93.  
  94. InnerClass2::~InnerClass2()
  95. {
  96. }
  97.  
  98. void InnerClass2::timerEvent(QTimerEvent * event)
  99. {
  100. if (event->timerId() == m_timerId)
  101. showIcon(!m_icon->isVisible());
  102. }
  103.  
  104. void InnerClass2::showIcon(bool show)
  105. {
  106. if (m_icon->isVisible() != show) {
  107. m_icon->setVisible(show);
  108. // adjust the icon geometry and tell the layout to reset itself
  109. QRect rect = m_icon->rect();
  110. if (show)
  111. rect.setWidth(m_width);
  112. else
  113. rect.setWidth(0);
  114. // NOTE: adding this didn't help
  115. //m_icon->setGeometry(rect);
  116. this->setGeometry(rect);
  117. emit visibilityChanged();
  118. }
  119. }
To copy to clipboard, switch view to plain text mode 

and I instantiate this from MainWindow.h:
Qt Code:
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include "TestClasses.h"
  4. #include <QGraphicsView>
  5.  
  6. MainWindow::MainWindow(QWidget *parent) :
  7. QMainWindow(parent),
  8. ui(new Ui::MainWindow)
  9. {
  10. ui->setupUi(this);
  11. OuterClass *outer = new OuterClass();
  12. m_scene = new QGraphicsScene(outer->rect());
  13. m_scene->addItem(outer);
  14.  
  15. QGraphicsView *view = new QGraphicsView(m_scene);
  16. this->setCentralWidget(view);
  17. }
  18.  
  19. MainWindow::~MainWindow()
  20. {
  21. delete ui;
  22. }
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.