Difference between revisions of "Development/Tutorials/Introduction to Goya usage"

Jump to: navigation, search
m (Text replace - "</code>" to "</syntaxhighlight>")
 
(13 intermediate revisions by 5 users not shown)
Line 5: Line 5:
 
name=Introduction to the Goya Framework usage|
 
name=Introduction to the Goya Framework usage|
  
pre=[http://mindview.net/Books/TICPP/ThinkingInCPP2e.html C++], [http://www.trolltech.com/products/qt/ Qt], [http://doc.trolltech.com/latest/model-view-programming.html Model/View Qt Framework], [[Getting_Started/Build/KDE4|KDE4 development environment]]|
+
pre=[http://mindview.net/Books/TICPP/ThinkingInCPP2e.html C++], [http://www.trolltech.com/products/qt/ Qt], [http://doc.trolltech.com/latest/model-view-programming.html Model/View Qt Framework], [[Getting_Started/Build|KDE4 development environment]]|
 +
 
 +
next=[[Development/Tutorials/Introduction to Goya usage 2|A slightly more complex example]]
 +
|
 
}}
 
}}
 
==Abstract==
 
==Abstract==
Line 12: Line 15:
 
We could say Goya is a layer between the view and your delegate that draws widgets with the needed options and that seem to behave as if they were real widgets, but they are fake widgets after all.
 
We could say Goya is a layer between the view and your delegate that draws widgets with the needed options and that seem to behave as if they were real widgets, but they are fake widgets after all.
  
Goya is so nice mainly because it integrates pretty well with the Model/View design, and uses the Qt powerful signals and slots. Goya widgets will emit signals when something have happened to them, so you will be able to connect those signals to your app slots, and do fancy stuff without complex stuff.
+
Goya is so nice mainly because it integrates pretty well with the Model/View design, and uses the Qt powerful signals and slots. Goya widgets will emit signals when something has happened to them, so you will be able to connect those signals to your app slots, and do fancy stuff without complex stuff.
 
==A Simple Example==
 
==A Simple Example==
 
This example consists on a single window that will contain a list view. There will be pushbuttons only in the odd rows.
 
This example consists on a single window that will contain a list view. There will be pushbuttons only in the odd rows.
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
// Basic Goya includes
 
// Basic Goya includes
#include <goya/goya.h>
+
#include <goya/kwidgetitemdelegate.h>
#include <goya/pushbutton.h>
+
  
 
// Basic Qt includes
 
// Basic Qt includes
Line 35: Line 37:
 
#include <kicon.h>
 
#include <kicon.h>
  
// We define the model "MyModel" as a QStringListModel. In this very simple
+
// This is our delegate, it has to inherit KWidgetItemDelegate which inherits
// example, the class will only return strings, and the necessary widgets.
+
// QAbstractItemDelegate. The delegate needs on its constructor first
class MyModel
+
// parameter a view, this is different to a regular QAbstractItemDelegate
     : public QStringListModel
+
// because we need to install event filters in order to allow interaction
 +
// with the user.
 +
class MiDelegate
 +
     : public KWidgetItemDelegate
 
{
 
{
 
     Q_OBJECT
 
     Q_OBJECT
 
 
public:
 
public:
     MyModel(QObject *parent = 0)
+
     MiDelegate(QAbstractItemView *itemView, QObject *parent = 0)
         : QStringListModel(parent)
+
         : KWidgetItemDelegate(itemView, parent)
 
     {
 
     {
        // We create a Goya pushbutton, this pushbutton will be shared by all
 
        // rows using it, so the memory impact for 1000 rows is the same as for
 
        // 1 row. Since all our rows will show the same information (that
 
        // meaning the pushbutton will show always "More information") we
 
        // initialize the values here, and all rows will reuse them. In a
 
        // slightly more complex example we can later see how to handle this
 
        // when rows want for instance a different text for the pushbutton, or
 
        // a different icon.
 
        button = new Goya::PushButton(0);
 
 
        button->setText("More Information");
 
        button->setIcon(KIcon("help-about"));
 
        button->setIconSize(QSize(16, 16));
 
 
        // Goya is able to "eat events". This means that the events that you
 
        // specify here won't be forwarded to the view. This is pretty helpful
 
        // because when you click on a button that is in a non-selected row
 
        // and the MouseButtonPress eat is enabled, the unselected row won't be
 
        // selected, because the button receives that event, and "eats" it.
 
        button->setEatEvents(QEvent::MouseButtonPress);
 
        button->setEatEvents(QEvent::MouseButtonRelease);
 
        button->setEatEvents(QEvent::MouseButtonDblClick);
 
 
        // We would like to connect to the clicked signal of the pushbutton.
 
        connect(button, SIGNAL(clicked(QModelIndex,const Goya::PushButton*)),
 
                this, SLOT(slotClicked(QModelIndex)));
 
 
     }
 
     }
  
     virtual ~MyModel()
+
     virtual ~MiDelegate()
 
     {
 
     {
        delete button;
 
 
     }
 
     }
  
     virtual QVariant data(const QModelIndex &index, int role) const
+
     QList<QWidget*> createItemWidgets() const
 
     {
 
     {
         // Goya when asking for widgets asks with role WidgetRole. We teach
+
         return QList<QWidget*>() << new QPushButton();
        // our model on what to do on this case. In this particular model, we
+
        // will return an empty widget list for odd rows, and a single widget
+
        // (our pushbutton) for even rows.
+
        // If the role that we were asked for is not the WidgetRole, we just
+
        // expect QStringListModel to do the right thing.
+
        if (role == Goya::WidgetRole)
+
        {
+
            if (index.row() % 2)
+
                return GOYA_EMPTY_WIDGET_LIST;
+
 
+
            return GOYA_WIDGET_LIST(button);
+
        }
+
 
+
        return QStringListModel::data(index, role);
+
 
     }
 
     }
  
private:
+
     void initializeItemWidgets(const QList<QWidget*> widgets,
     Goya::PushButton *button;
+
                              const QStyleOptionViewItem &option,
 
+
                              const QModelIndex &index) const
private Q_SLOTS:
+
    // This slot will be triggered when our pushbutton has been clicked. Note
+
    // that the signal has an index and even a Goya::PushButton* parameters.
+
    // In this case only with the index we are OK. On the messagebox we notify
+
    // the user which row button was clicked.
+
    void slotClicked(const QModelIndex &index)
+
 
     {
 
     {
         KMessageBox::information(0, "More information clicked on row " +
+
         QPushButton *button = static_cast<QPushButton*>(widgets.at(0));
                                QString::number(index.row() + 1),
+
        button->setText("More Information");
                                "Button clicked");
+
        button->setIcon(KIcon("help-about"));
    }
+
        button->setIconSize(QSize(16, 16));
};
+
  
// This is our delegate. It will perform custom painting, but this a very
+
        connect(button, SIGNAL(clicked(QModelIndex,const Goya::PushButton*)),
// important part with Goya integration. The most important thing here is that
+
                this, SLOT(slotClicked(QModelIndex)));
// this delegate inherits Goya::Canvas, what inherits QAbstractItemDelegate.
+
class MyDelegate
+
    : public Goya::Canvas
+
{
+
public:
+
    MyDelegate(QAbstractItemView *itemView, QObject *parent = 0)
+
        : Canvas(itemView, parent)
+
    {
+
    }
+
 
+
    virtual ~MyDelegate()
+
    {
+
    }
+
 
+
    // Goya asks for the position of widgets. In this method you should specify
+
    // where do you want widget to be placed. In a slightly more complex example
+
    // we will see later that you can also specify your position not only in
+
    // absolute terms, but relative to other Goya widgets.
+
    QPoint widgetPosition(Goya::Widget *widget, const QStyleOption *option,
+
                          const QModelIndex &index) const
+
    {
+
        return QPoint(option->fontMetrics.height(), option->fontMetrics.height());
+
 
     }
 
     }
  
Line 156: Line 90:
  
 
         painter->drawText(option.fontMetrics.height() + option.rect.left(),
 
         painter->drawText(option.fontMetrics.height() + option.rect.left(),
                            option.fontMetrics.height() * 3 + Canvas::sizeHint(option, index).height() + option.rect.top(),
+
                          option.fontMetrics.height() * 3 +  
                            QString("This is the index in row number ") + QString::number(index.row() + 1));
+
                          Canvas::sizeHint(option, index).height() +
 +
                          option.rect.top(),
 +
                          QString("This is the index in row number ") +  
 +
                          QString::number(index.row() + 1));
  
 
         painter->restore();
 
         painter->restore();
  
         Canvas::paint(painter, option, index);
+
         KWidgetItemDelegate::paintWidgets(painter, option, index);
 
     }
 
     }
  
     QSize sizeHint(const QStyleOptionViewItem &option,
+
     QSize sizeHint() const
                  const QModelIndex &index) const
+
 
     {
 
     {
         Q_UNUSED(option);
+
         return QSize(600, 60);
        Q_UNUSED(index);
+
    }
  
         QSize size = Canvas::sizeHint(option, index);
+
private Q_SLOTS:
 +
    void slotClicked(const QModelIndex &index)
 +
    {
 +
         KMessageBox::information(0, "More information clicked on row " +
 +
                                QString::number(index.row() + 1),
 +
                                "Button clicked");
 +
    }
 +
};
  
        size.setWidth(size.width() + option.fontMetrics.height() * 4);
+
int main(int argc, char **argv)
        size.setHeight(size.height() + option.fontMetrics.height() * 4);
+
{
 +
    KAboutData aboutData("goyatest",
 +
                        0,
 +
                        ki18n("Goya Test "),
 +
                        "1.0",
 +
                        ki18n("A test for the Goya subsystem"),
 +
                        KAboutData::License_LGPL,
 +
                        ki18n("(c) Rafael Fernández López, 2007"),
 +
                        ki18n("A test for the Goya subsystem"),
 +
                        "http://www.ereslibre.es",
 +
                        "konqui@konqui.org");
  
         return size;
+
    KCmdLineArgs::init(argc, argv, &aboutData);
 +
    KApplication app;
 +
 
 +
    QWidget *widget = new QWidget();
 +
    QVBoxLayout *layout = new QVBoxLayout;
 +
 
 +
    widget->setLayout(layout);
 +
    widget->resize(800, 600);
 +
 
 +
    QListView *listView = new QListView();
 +
    listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
 +
    QStringListModel *model = new QStringListModel();
 +
    MiDelegate *delegate = new MiDelegate(listView);
 +
 
 +
    QListView *listView2 = new QListView();
 +
    listView2->setSelectionMode(QAbstractItemView::ExtendedSelection);
 +
    QStringListModel *model2 = new QStringListModel();
 +
    MiDelegate *delegate2 = new MiDelegate(listView2);
 +
 
 +
    model->insertColumn(0);
 +
    for (int i = 0; i < 1000; ++i)
 +
    {
 +
         model->insertRow(i);
 +
        model->setData(model->index(i, 0), QString::number(i));
 
     }
 
     }
};
+
 
</code>
+
    model2->insertColumn(0);
 +
    for (int i = 0; i < 10; ++i)
 +
    {
 +
        model2->insertRow(i);
 +
        model2->setData(model2->index(i, 0), QString::number(i));
 +
    }
 +
 
 +
    listView->setModel(model);
 +
    listView->setItemDelegate(delegate);
 +
    listView->setVerticalScrollMode(QListView::ScrollPerPixel);
 +
 
 +
    listView2->setModel(model2);
 +
    listView2->setItemDelegate(delegate2);
 +
    listView2->setVerticalScrollMode(QListView::ScrollPerPixel);
 +
 
 +
    layout->addWidget(new QPushButton("Above Button"));
 +
    layout->addWidget(listView);
 +
    layout->addWidget(listView2);
 +
    layout->addWidget(new QPushButton("Below Button"));
 +
 
 +
    widget->show();
 +
 
 +
    return app.exec();
 +
}
 +
 
 +
#include "main.moc"
 +
</syntaxhighlight>

Latest revision as of 21:51, 29 June 2011

Introduction to the Goya Framework usage
Tutorial Series   Goya Framework
Previous   C++, Qt, Model/View Qt Framework, KDE4 development environment
What's Next   A slightly more complex example
Further Reading   n/a

[edit] Abstract

We are developing some component of our application using Model/View (check prerequisites). At some point on our development, we discover that we actually want to add widgets to our delegate, but the Model/View framework does not provide a powerful and integrated way of doing so. Here is where Goya comes to help out for this task.

We could say Goya is a layer between the view and your delegate that draws widgets with the needed options and that seem to behave as if they were real widgets, but they are fake widgets after all.

Goya is so nice mainly because it integrates pretty well with the Model/View design, and uses the Qt powerful signals and slots. Goya widgets will emit signals when something has happened to them, so you will be able to connect those signals to your app slots, and do fancy stuff without complex stuff.

[edit] A Simple Example

This example consists on a single window that will contain a list view. There will be pushbuttons only in the odd rows.

// Basic Goya includes
#include <goya/kwidgetitemdelegate.h>
 
// Basic Qt includes
#include <QPainter>
#include <QBoxLayout>
#include <QListView>
#include <QStringListModel>
 
// Basic KDE includes
#include <kapplication.h>
#include <kaboutdata.h>
#include <kmessagebox.h>
#include <kcmdlineargs.h>
#include <klocalizedstring.h>
#include <kicon.h>
 
// This is our delegate, it has to inherit KWidgetItemDelegate which inherits
// QAbstractItemDelegate. The delegate needs on its constructor first
// parameter a view, this is different to a regular QAbstractItemDelegate
// because we need to install event filters in order to allow interaction
// with the user.
class MiDelegate
    : public KWidgetItemDelegate
{
    Q_OBJECT
public:
    MiDelegate(QAbstractItemView *itemView, QObject *parent = 0)
        : KWidgetItemDelegate(itemView, parent)
    {
    }
 
    virtual ~MiDelegate()
    {
    }
 
    QList<QWidget*> createItemWidgets() const
    {
        return QList<QWidget*>() << new QPushButton();
    }
 
    void initializeItemWidgets(const QList<QWidget*> widgets,
                               const QStyleOptionViewItem &option,
                               const QModelIndex &index) const
    {
        QPushButton *button = static_cast<QPushButton*>(widgets.at(0));
        button->setText("More Information");
        button->setIcon(KIcon("help-about"));
        button->setIconSize(QSize(16, 16));
 
        connect(button, SIGNAL(clicked(QModelIndex,const Goya::PushButton*)),
                this, SLOT(slotClicked(QModelIndex)));
    }
 
    void paint(QPainter *painter, const QStyleOptionViewItem &option,
               const QModelIndex &index) const
    {
        if (option.state & QStyle::State_Selected)
        {
            painter->fillRect(option.rect, option.palette.highlight());
        }
 
        painter->save();
 
        if (option.state & QStyle::State_Selected)
        {
            painter->setPen(QPen(option.palette.highlightedText().color()));
        }
 
        painter->drawText(option.fontMetrics.height() + option.rect.left(),
                          option.fontMetrics.height() * 3 + 
                          Canvas::sizeHint(option, index).height() +
                          option.rect.top(),
                          QString("This is the index in row number ") + 
                          QString::number(index.row() + 1));
 
        painter->restore();
 
        KWidgetItemDelegate::paintWidgets(painter, option, index);
    }
 
    QSize sizeHint() const
    {
        return QSize(600, 60);
    }
 
private Q_SLOTS:
    void slotClicked(const QModelIndex &index)
    {
        KMessageBox::information(0, "More information clicked on row " + 
                                 QString::number(index.row() + 1),
                                 "Button clicked");
    }
};
 
int main(int argc, char **argv)
{
    KAboutData aboutData("goyatest",
                         0,
                         ki18n("Goya Test "),
                         "1.0",
                         ki18n("A test for the Goya subsystem"),
                         KAboutData::License_LGPL,
                         ki18n("(c) Rafael Fernández López, 2007"),
                         ki18n("A test for the Goya subsystem"),
                         "http://www.ereslibre.es",
                         "konqui@konqui.org");
 
    KCmdLineArgs::init(argc, argv, &aboutData);
    KApplication app;
 
    QWidget *widget = new QWidget();
    QVBoxLayout *layout = new QVBoxLayout;
 
    widget->setLayout(layout);
    widget->resize(800, 600);
 
    QListView *listView = new QListView();
    listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    QStringListModel *model = new QStringListModel();
    MiDelegate *delegate = new MiDelegate(listView);
 
    QListView *listView2 = new QListView();
    listView2->setSelectionMode(QAbstractItemView::ExtendedSelection);
    QStringListModel *model2 = new QStringListModel();
    MiDelegate *delegate2 = new MiDelegate(listView2);
 
    model->insertColumn(0);
    for (int i = 0; i < 1000; ++i)
    {
        model->insertRow(i);
        model->setData(model->index(i, 0), QString::number(i));
    }
 
    model2->insertColumn(0);
    for (int i = 0; i < 10; ++i)
    {
        model2->insertRow(i);
        model2->setData(model2->index(i, 0), QString::number(i));
    }
 
    listView->setModel(model);
    listView->setItemDelegate(delegate);
    listView->setVerticalScrollMode(QListView::ScrollPerPixel);
 
    listView2->setModel(model2);
    listView2->setItemDelegate(delegate2);
    listView2->setVerticalScrollMode(QListView::ScrollPerPixel);
 
    layout->addWidget(new QPushButton("Above Button"));
    layout->addWidget(listView);
    layout->addWidget(listView2);
    layout->addWidget(new QPushButton("Below Button"));
 
    widget->show();
 
    return app.exec();
}
 
#include "main.moc"

This page was last modified on 29 June 2011, at 21:51. This page has been accessed 13,446 times. Content is available under Creative Commons License SA 3.0 as well as the GNU Free Documentation License 1.2.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal