Search code examples
c++qtqt4qgraphicssceneqpixmap

QPixmap image file not appear on QGraphicsScene


By modifying Qt's Diagram Scene sample, I want my window to display an overlay object when a user clicks on a region that's described by GraphicalScene (original sample shows instead QPolygon). In the following code I'm using QPixmap. However nothing appears when the region is clicked. mousePressEvent passes reasonable positions where clicked. Appreciate your help.

diagramScene.cpp:

#include <iostream>
#include <QtGui>
#include <QPixmap>

#include "pkg/diagramscene.h"
#include "pkg/arrow.h"

DiagramScene::DiagramScene(QMenu *itemMenu, QObject *parent)
    : QGraphicsScene(parent)
{
    myItemMenu = itemMenu;
    myMode = MoveItem;
    myItemType = DiagramOverlayPixmapItem::Overlay;
}

void DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if (mouseEvent->button() != Qt::LeftButton) return;
    DiagramOverlayPixmapItem *item;
    switch (this->myMode) {
        case InsertItem: {
            const std::string tmpImgPathBase = "~/images/";
            std::string overlayObj = tmpImgPathBase + "overlayObj.png";
            QPixmap *img = new QPixmap(QString(overlayObj.c_str()));

            item = new DiagramOverlayPixmapItem(myItemType, myItemMenu, img);
            item->setPos(mouseEvent->scenePos());
            this->addPixmap(item->pixmap());  // QGraphicsScene::addPixmap.
            this->update();     // Expecting these parts would do the work..
        }
            break;
        default:
            ;
    }
    QGraphicsScene::mousePressEvent(mouseEvent);
}

diagramOverlayPixmapItem.cpp:

#include <iostream>
#include <QtGui>    
#include "pkg/arrow.h"
#include "pkg/diagramOverlayPixmapItem.h"

DiagramOverlayPixmapItem::DiagramOverlayPixmapItem(DiagramType diagramType, QMenu *contextMenu, QPixmap *img, QGraphicsItem *parent, QGraphicsScene *scene)
    : QGraphicsPixmapItem(*img, parent)
{
    myDiagramType = diagramType;
    myContextMenu = contextMenu;
    setFlag(QGraphicsItem::ItemIsMovable, true);
    setFlag(QGraphicsItem::ItemIsSelectable, true);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
}

void DiagramOverlayPixmapItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    scene()->clearSelection();
    setSelected(true);
    myContextMenu->exec(event->screenPos());
}

QVariant DiagramOverlayPixmapItem::itemChange(GraphicsItemChange change,
                                              const QVariant &value)
{
    if (change == QGraphicsItem::ItemPositionChange) {
        foreach (Arrow *arrow, arrows) {
            arrow->updatePosition();
        }
    }
    return value;
}

This thread is similar (though it's in python) but not giving me an idea.


Solution

  • "~" isn't a valid path. This is a shell expansion. Replace it with:

    QDir::homePath()
    

    which returns a QString of the current user's home directory. The documentation says:

    Under non-Windows operating systems the HOME environment variable is used if it exists [...]


    By the way, why are you using std::string? You should use QString in Qt applications.

    You could also use the QDir path building mechanism by saying:

    QDir tmpImgPathBase = QDir::home(); //home() returns a QDir, homePath() a QString
    tmoImgPathBase.cd("images"); //navigate to relative directory
    QString overlayObj = tmoImgPathBase.filePath("overlayObj.png"); //file in direct.
    QPixmap *img = new QPixmap(overlayObj);
    

    Note that you also should not overuse pointers in C++. The pixmap doesn't need to be a pointer (which you never delete here, causing memory leaks!):

    QPixmap img = QPixmap(overlayObj);
    item = new DiagramOverlayPixmapItem(myItemType, myItemMenu, img);
    

    and

    // I removed the asterisk at both the argument img and the
    // forwarding to the constructor of QGraphicsPixmapItem.
    DiagramOverlayPixmapItem::DiagramOverlayPixmapItem(DiagramType diagramType, QMenu *contextMenu, QPixmap img, QGraphicsItem *parent, QGraphicsScene *scene)
        : QGraphicsPixmapItem(img, parent)
    {
        ...
    }