Sunday 16 May 2010

Using platform rendering for widgets in a graphics scene

We've all written our own small toolkits, and the like in the past, and today I revisited my glory days: I made a button.

Actually, it was a bit more involved.

Some of you might have heard of a nifty thing called a QGraphicsScene (and friends), a fairly useful tool to allow for complex rendering/manipulating of 2D objects, animations, all the rest of the bling. It's been used for a lot of things over time, and recently I've been getting to know it in my copious "free time" over this weekend.

I decided to see how difficult it would be to create my own button inside a QGraphicsScene (yes, I know QGraphicsProxyWidget exists, but it is fairly slow, so using it isn't the best for many situations), so while I was at it, I decided to make it blend in with the rest of the widgets on my desktop too.

This is more a proof of concept than anything, but in case anyone else ever wants to write their own widgets and render them in a QGraphicsScene, here's a bit of a pointer in the right direction. ;)

#include <QApplication>
#include <QGraphicsWidget>
#include <QPainter>
#include <QStyleOptionGraphicsItem>

class AButton : public QGraphicsWidget
{
public:
    AButton()
        : QGraphicsWidget(),
        m_isPressed(false)
    {
    }
    QRectF boundingRect() const
    {
        // TODO: fetch QRectF from text() + icon() and cache
        return QRectF(0, 0, 40, 40);
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
    {
        QStyleOptionButton opt;
        // TODO: QStyleOption::initFrom overload for QStyleOptionGraphicsItem would be nice
        //opt.initFrom(this);

        opt.state = (m_isPressed ? QStyle::State_Sunken : QStyle::State_Raised) | QStyle::State_Enabled;
        opt.text = text();
        opt.icon = icon();
        opt.rect = option->rect;
        opt.palette = option->palette;

        QApplication::style()->drawControl(QStyle::CE_PushButton, &opt, painter);
    }

    QString text() const
    {
        return "hi";
    }

    QPixmap icon() const
    {
        return QPixmap();
    }

    void mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        m_isPressed = true;
        update();
    }

    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    {
        m_isPressed = false;
        update();
    }

private:
    bool m_isPressed;
};

#include <QApplication>
#include <QGraphicsView>

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

    // set up scene
    QGraphicsScene scene;
    AButton button;
    scene.addItem(&button);

    // add a view
    QGraphicsView view(&scene);
    view.setRenderHint(QPainter::Antialiasing);
    view.resize(200, 100);
    view.setBackgroundBrush(QApplication::palette().background());
    view.show();

    return a.exec();
}

Labels: , , , , ,