PDA

View Full Version : QGraphicsWidgets erased slowly



Manuka
17th April 2019, 11:12
Hi,

I'm working on a QGraphicsScene application in Qt 5,12. In my scene, I have static and dynamic elements. I have two lists of texts on the two side of my screen, as sources and targets. In between them, I have dynamic circle elements which make a trajectory between the source and the target based on the time.

My text item is a QGraphicsWidget in order to be able to stock them in a layout. I overrode the paint function of the QGraphicsWidget in which I call QGraphicsWidget::paint and I also draw a text using QPainter::drawText.

My circle item inherits from QGraphicsEllipseItem and it has two pointers to its source and destination.

By using a QTimer I update the position of my dynamic items so that they are moving from the source to the target.

My problem is that slowly my texts become erased as the circles pass. Please look at the attached screenshot.

I found a workaround to solve this problem by calling update on all of my text item when the timer times out.

Another solution I found is to subclass QgraphicsLayoutItem instead of subclassing the QGraphicsWidget.

Could you please someone explain me why in the first case my texts become erased?

Thanks

Manuka
18th April 2019, 14:21
I have noticed that also when I resize my widow my texts are corrected, due to the update event.

I've tried to change the ZValue of my elements because I thought that my texts are not visible due to a circle which masks them but even setting the ZValue does not solve the problem.

Manuka
23rd April 2019, 10:22
Does somebody has an idea , I still could not figure it out?

ChrisW67
25th April 2019, 01:21
Without seeing your actual code, or a small, self-contained example that shows the problem it is hard to say. Not sure why you are using a custom painter for the text

Manuka
25th April 2019, 12:19
Thank you for your response.

I cannot post my code because it is too large but I wrote a small self-contained example to indicate the problem.

Actually I'm using custom painter for the text because QGraphicsTextItem cannot be inserted in a layout. Hence, first I decided to subclass QGraphicsWidget and override its paint function. With this solution I encountered the problem I've mentioned above. Here is the code:



class GraphicsTextItem : public QGraphicsWidget
{
public:
QString m_Name;
QColor m_Color;

GraphicsTextItem(QGraphicsItem * parent = nullptr, const QString& name = QString())
: QGraphicsWidget(parent)
, m_Name(name)
, m_Color(50 + (std::rand() % (255 - 50 + 1)), 50 + (std::rand() % (255 - 50 + 1)), 50 + (std::rand() % (255 - 50 + 1)))
{
setMaximumHeight(12);
setMinimumHeight(12);
}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
{
QFont font("Times", 10);
painter->setFont(font);
painter->setPen(m_Color);
painter->drawText(0, 0, m_Name);
}
};

class GraphicsTextItem;
class GraphicsCircleItem : public QGraphicsEllipseItem
{
private:
const GraphicsTextItem* m_Source;
bool m_SourceGood;

public:
GraphicsCircleItem(const GraphicsTextItem* source)
: QGraphicsEllipseItem()
, m_Source(source)
, m_SourceGood(false)
{
setBrush(QBrush(m_Source->m_Color));
setPen(QPen(m_Source->m_Color));
setRect(0, 0, 20, 20);
}

bool isSourcePositionValid() const { return m_Source->pos().x() != 0.0 || m_Source->pos().y() != 0.0; }

void moveAndShow()
{
if(isSourcePositionValid() && m_SourceGood == false)
{
m_SourceGood = true;
setPos(m_Source->scenePos());
show();
return;
}
else
{
if(!m_SourceGood)
hide();
}

if(m_SourceGood)
{
moveBy(1,6);
}
}
};

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;

QGraphicsWidget* layout_widget = new QGraphicsWidget();
QGraphicsLinearLayout* layout = new QGraphicsLinearLayout(Qt::Vertical);
layout_widget->setLayout(layout);

QGraphicsScene* scene = new QGraphicsScene(&w);
scene->setItemIndexMethod(QGraphicsScene::NoIndex);
scene->setBackgroundBrush(Qt::black);
scene->addItem(layout_widget);

QGraphicsView* scene_view = new QGraphicsView(&w);
scene_view->setScene(scene);
scene_view->setSceneRect(0, 0, 1024, 768);

std::vector<GraphicsTextItem*> source_list;
std::vector<GraphicsCircleItem*> message_list;
for(int i = 0; i < 1000; i++)
{
std::string source = std::string("SourceName_") + std::to_string(i);
GraphicsTextItem* source_item = new GraphicsTextItem(nullptr, QString(source.c_str()));
layout->addItem(source_item);
source_list.push_back(source_item);

GraphicsCircleItem* message_item = new GraphicsCircleItem(source_item);
scene->addItem(message_item);
message_list.push_back(message_item);
}

QTimer timer;
timer.callOnTimeout([&]()
{
static uint64_t counter = 0;
if(counter == 500)
{
for(auto& item : message_list)
{
scene->removeItem(item);
delete item;
}
message_list.clear();

for(auto& item : source_list)
{
GraphicsCircleItem* message_item = new GraphicsCircleItem(item);
scene->addItem(message_item);
message_list.push_back(message_item);
}

counter = 0;
}

for(auto& item : message_list)
{
item->moveAndShow();
}
counter++;

});
timer.start(10);

w.setCentralWidget(scene_view);
w.show();

return a.exec();
}



I attach also a photo about the issue with the sample code. As I wrote before I have not encountered this problem if I subclass QGraphicsLayoutItem instead of QGraphicsWidget.

13091

I hope the sample code helps.

Manuka
9th June 2019, 23:19
Anybody could please advise?