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();
}
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();
}