PDA

View Full Version : Parts of rendered QGraphicsTextItem text is destroyed by other scene items



ghb
7th May 2012, 08:20
I'm experiencing a strange problem in my application. I'm using a QGraphicsView along with a QGraphicsScene to display items. Some of the items have special tooltips which appear when the mouse hovers on top of them.

7699

The tooltips inherit QGraphicsTextItem in order to provide a border, margin, and custom background. Also, some of the items, which are children to the item with the current tooltip, also display a tooltip of their own when hovered.

7700

And now to the problem: When the second tooltip is removed (by moving the mouse out of the child item), the text of the first tooltip is cropped.

7701

This doesn't always happen but very often when the tooltips are displayed and then removed. Moreover, the same things sometimes happens even when there is no second tooltip over it. First I suspected this had something to do with the antialiasing, but deactivating it didn't remove the symptoms. I've provided a minimal working example below to isolate the problem.


#include <QApplication>
#include <QGraphicsItem>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsSceneHoverEvent>
#include <QGraphicsTextItem>
#include <QGraphicsView>
#include <QMainWindow>
#include <QPainter>
#include <QPointF>
#include <QRectF>
#include <QSizeF>
#include <QString>
#include <QStyleOptionGraphicsItem>

class ToolTipItem : public QGraphicsTextItem {
public:
ToolTipItem(const QString& text)
: QGraphicsTextItem(text, 0)
{
setAcceptHoverEvents(true);
}

virtual ~ToolTipItem(void) {}

virtual QRectF boundingRect(void) const {
QRectF rect(QPointF(0, 0), getSize());
qreal d = BORDER_WIDTH / 2;
rect.adjust(-d, -d, d, d);
return rect;
}

virtual void paint(
QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget)
{
// Draw surrounding box
painter->setPen(QPen(BORDER_COLOR, BORDER_WIDTH));
painter->setBrush(QBrush(BACKGROUND_COLOR));
QRectF rect(QPointF(0, 0), getSize());
painter->drawRect(rect);

// Draw text content
painter->translate(QPointF(MARGIN, MARGIN));
QGraphicsTextItem::paint(painter, option, widget);
}

virtual QPainterPath shape(void) const {
QPainterPath path;
path.addRect(boundingRect());
return path;
}

QSizeF getSize(void) const {
QRectF rect(QGraphicsTextItem::boundingRect());
rect.adjust(0, 0, 2*MARGIN, 2*MARGIN);
return rect.size();
}

void placeNextTo(QGraphicsItem* item) {
QPointF item_point_in_scene =
item->mapToScene(item->boundingRect().topLeft());
qreal x_pos = item_point_in_scene.x() - boundingRect().size().width()
+ 1.5 * BORDER_WIDTH;
qreal y_pos = item_point_in_scene.y() + BORDER_WIDTH / 2;
QPointF tooltip_point_in_scene(x_pos, y_pos);
setPos(tooltip_point_in_scene);
}

protected:
static const QColor BACKGROUND_COLOR;
static const qreal MARGIN;
static const qreal BORDER_WIDTH;
static const QColor BORDER_COLOR;
};

const QColor ToolTipItem::BACKGROUND_COLOR(Qt::white);
const qreal ToolTipItem::MARGIN = 5;
const qreal ToolTipItem::BORDER_WIDTH = 1;
const QColor ToolTipItem::BORDER_COLOR(Qt::black);

class MyItem : public QGraphicsRectItem {
public:
MyItem(qreal x, qreal y, qreal width, qreal height,
QGraphicsItem* parent = 0)
: QGraphicsRectItem(x, y, width, height, parent),
tooltip_(NULL)
{
setAcceptHoverEvents(true);
}

virtual ~MyItem(void) {}


protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event) {
event->accept();
if (!tooltip_) {
tooltip_ = new ToolTipItem("bla bla bla\nfadsf asdf\nfdasdfas");
tooltip_->placeNextTo(this);
scene()->addItem(tooltip_);
}
tooltip_->show();
}

virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) {
event->accept();
if (tooltip_) tooltip_->hide();
}

private:
ToolTipItem* tooltip_;
};



int main(int argc, char** argv) {
QApplication app(argc, argv);

QGraphicsScene* scene = new QGraphicsScene;
MyItem* item1 = new MyItem(0, 0, 50, 50);
MyItem* item2 = new MyItem(20, 10, 10, 10, item1);
MyItem* item3 = new MyItem(20, 20, 10, 10, item2);
scene->addItem(item1);

QGraphicsView* view = new QGraphicsView(scene);
view->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(view);
window.show();

return app.exec();
}

ghb
10th May 2012, 08:41
No one has any idea on what's going on...?

norobro
10th May 2012, 22:50
Not sure, but it looks like some artifact left over from the translate. Try this instead:
// Draw text content
//painter->translate(QPointF(MARGIN, MARGIN));
document()->setDocumentMargins(MARGIN);
QGraphicsTextItem::paint(painter, option, widget);

ghb
11th May 2012, 09:43
Interesting. Removing the translate() call actually fixes the problem!

However, in my case, setDocumentMargin() does nothing, or at least the call has no effect. What can I do to add some margin between the border and the content without resorting to translate()?

Added after 49 minutes:

Wrapping the HTML text with a <div style="margin: MARGINpx"> ... </div> at least adds some margin to the sides, but for some reason it has no effect on the margin of the top or bottom. Strange... Well, it'll have to do; at least it looks better than before, and I no longer have those weird artefacts. Thanks for your help!

wysota
11th May 2012, 11:42
You can only paint within your own boundingRect(). If you paint outside it (like when using translate()), you will be getting artifacts.

norobro
11th May 2012, 21:34
However, in my case, setDocumentMargin() does nothing, or at least the call has no effect. Strange. Works here using your example.

The docs say the default margin is 4 and you only use 5. Have you tried a larger value?

ghb
13th May 2012, 21:18
I believe I used a value of 10.