Linux Tech Blog

Handling GraphicsView events – Part. 2

by fred on Dec.09, 2009, under GraphicsView, Qt, Widgets

In my previous post, I’ve shown you how to handle events (specifically mouse events) inside GraphicsView.

Lets expand this idea and create a customized widget on Graphics View. The simplest widget of them all is the Push Button (actually the simplest widget is the Label, but then, I wouldn’t have much to write on this post :) ).

The Button widget has the following characteristics:

  1. Display 2 images depending on its state (normal & pressed);
  2. Detects mouse clicks (including moving the mouse while clicked);

On to the coding part…

There’s only one attribute for storing the Button’s state: m_isPressed. Depending on the value of m_isPressed, the paint() method will either draw one of two QPixmap objects, m_normal or m_pressed.

Here’s the paint() method for the Button class:

void Button::paint(QPainter *painter,
                   const QStyleOptionGraphicsItem *option,
                   QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
 
    if (m_isPressed)
        painter->drawPixmap(0, 0, m_pressed);
    else
        painter->drawPixmap(0, 0, m_normal);
}

The change between the normal and pressed image happens through the mouse handling methods. Here’s the mousePressEvent() method:

void Button::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        if (contains(event->pos()))
            m_isPressed = true;
 
        update();
    }
}

If the user clicks within the image area, m_isPressed is set. Therefore, the pressed image is displayed.

Now the mouseMoveEvent() method:

void Button::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        if (contains(event->pos())) {
            m_isPressed = true;
        } else {
            m_isPressed = false;
        }
 
        update();
    }
}

It the user moves the mouse (while clicking) to outside the image area, m_isPressed is changed.

And finally, the mouseReleaseEvent() method:

void Button::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        m_isPressed = false;
 
        update();
 
        if (contains(event->pos())) {
            emit clicked();
        }
    }
}

The m_isPressed attribute is unset and the clicked() signal is emitted (if the mouse stays within the image area).
Here’s the customized Button in action:

The source code for this example is at my gitorious repository, under the button dir:

http://gitorious.org/tech-blog/sources/trees/master/button

Because the image is a rounded one, there are some parts “outside” of the Button that also receive mouse events. This happens because we still need to determine the “clickable” area through the shape() method. But that’s something for another post. :)

Till next time.


6 Comments for this entry

  • Chris BrunerNo Gravatar

    Thanks for your tutorials, they have really shortened my learning curve. Keep up the good work.

    As a suggestion, I’d like to know how to drag a graphics item around the scene with the mouse.

  • Amit BahreeNo Gravatar

    Hi, when I try and compile the sample I get an error on the Class declaration on Line 28 in the header file of your code.

    The errors I get are: /usr/include/qt4/QtGui/qgraphicsitem.h ‘QGraphicsItem::QGraphicsItem(const QGraphicsItem&)’ is private

    and

    /usr/include/qt4/QtCore/qobject.h ‘QObject::QObject(const QObject&)’ is private

    And the line of code is:
    class MyButton : public QObject, public QGraphicsItem
    {
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)

    Any idea what is wrong?

    Thanks,
    Amit.

  • fredNo Gravatar

    Bahree, I tried to replicate this error on my machine
    with several versions of Qt (4.5.2, 4.6.0, 4.6.1, 4.6.2 and even 4.7) but
    they all seen to work. No errors.

    You could try inheriting from the QGraphicsObject class.
    It’s almost the same as the dual inheritance from the QObject and QGraphicsItem classes. For that to work, you’ll also need
    to remove the “Q_INTERFACES(QGraphicsItem)” line.
    But this class is only available from Qt 4.6 up.

    Is there a more detailed log of the error message?

  • ptyxsNo Gravatar

    Same problem as for Amit Bahree.
    At compile time with Qt 4.5.3 (under Mandriva Linux Powerpack 2010.0).

    Error message is :

    button.h:31: Error: Undefined interface

    Line button.h:31 is :

    Q_INTERFACES(QGraphicsItem)

  • Aditya BhattNo Gravatar

    Hi Frederico,

    Thanks for this!
    I just used it in my project “libkface” in KDE svn.
    I’ve added your name to the copyright.

    Just FYI :)

  • fredNo Gravatar

    You’re welcome, Aditya.

Leave a Reply

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit our friends!

A few highly recommended friends...

Archives

All entries, chronologically...