Archive for the ‘Qt’ Category

Qt lectures

A while ago I wrote in one of my previous posts that many things had happened during last few months and I’d like to share some of them with you. So here is the first thing…

 

As you probably know I am a PhD candidate in Institute of Computer Science on Warsaw University of Technology. Part of my responsibilities involves having academic activities with students. Last semestre I managed to make myself part of the “Programming Interactive Applications” course that shows students the basics of technologies such as WinAPI, .NET, MFC, XLib and Qt. I was asked to conduct a six hour course on Qt, which entered the course just a semestre earlier. It was a very big thing for me – one might say that it was a vocation for becoming a “Qt Apostle” (I admit I borrowed that term from Scott Collins) so I treated it very seriously.

I think the lecture came out quite fine. The biggest problem was to decide what to tell about and what to omit. I talked quite much about paradigms like meta-types, signals and slots, layouts and virtual method based event handling. Because of that I had less time to talk about more advanced things like Arthur (I just managed to talk a bit about device independence and window-viewport transformations) or Interview (which is a pitty because you know how I like it…). But thanks to that I had more time to present the graphics view framework.

 Apart from the lectures I were to give students two exercises (not conducting them though). The first one was about creating a simple image viewer using available widgets and the second one was to prepare a kitchen timer widget and a Designer plugin for it. Students seemed to be interested in the projects so I guess the choice was correct. Starting with the semestre that starts in a week I’ll be conducting the exercises as well, so maybe I’ll have additional time to brainwash… eem… present some more Qt knowledge to students.

All in all people seemed interested in the topic which gives me much satisfaction. I should probably change or update the contents of the lectures a bit, so I’m waiting for your fresh ideas and comments. There is enough knowledge (as well as motivation and urg to pass that knowledge) to make a dedicated course, but unfortunately I don’t think an average PhD student can make that happen.

QRetargetScale

Of course I couldn’t resist myself from implementing the algorithm I have written about in the previous post.

Images below have been scaled to fit on the page. The second one was scaled down using the application.


QRetargetScale download

Qt book review

The Book of Qt4 coverSome time ago I’ve been asked if I wanted to write a review of one of the new books related to Qt. I agreed and soon after I had a copy of the book in my hands. Thanks go to Camille Herrera of No Starch Press for letting me do this. I’m certainly waiting for more!

 

The Book of Qt4 – The Art of Building Qt Applications review

 

If you do or don’t agree with my review, please leave your comment. Another review of the book is available here (the site seems to be currently down though).

Contest results

Oh, by the way – we have announced the results of the Qt Centre Programming Contest.

Container plugin

Just checked Qt 4.3rc1 for a containter extensions support. Still doesn’t work, even for their own containerextension example. Tough luck…

UIC problems with custom container widgets

 

Recently I’ve been spending much time developing “wwWidgets” – my set of custom widgets for Qt4. Among others, the set contains widgets that are multipage container widgets that have to be treated in a special way – by providing an extension to Designer that tells it how to add or remove new pages to the widget.

Unfortunately Designer seems to be having much trouble with that currently. I could even call it the biggest misdesign in Qt4 (at least the biggest I’m aware of). Container widgets need to be handled on two levels – first Designer has to save some information about the custom widget in the UI file and the UIC has to process the file and generate C++ code that does the widget layout. The problem is that Designer doesn’t provide enough information for UIC to generate code that adds pages to multipage container widgets. The “misdesign” is that currently UIC checks the class name of the container widget and if it is a subclass of QTabWidget, it calls addTab(child, label), if it is a subclass of QStackedWidget, it calls addWidget, but for all other widgets it ignores the multipage nature of the widget and just makes a parent-child relationship between the container and its pages. As one might expect it leads to unpredicted and unwanted behaviour.

I contacted Trolltech about it and they said they were working on it and it should already be solved in Qt4.3 beta. Unfortunately class and method names are still hardcoded into UIC. For the time being I suspended dealing with the problem as I don’t want to reinvent the wheel trying to come up with a fix if Trolls are already working on it (it means I’m giving them a chance to improve the design).

However this doesn’t mean I’m not thinking about possible solutions or temporary workarounds and I came up with three possible fixes.

Method 1

The first (and probably the best) idea is to somehow store the signatures of methods needed by the widget to manipulate its pages in the xml description of the custom widget added to each UI file using the widget. Then UIC could use that information to generate code that would call a proper method to add pages to widgets. The only question is, how to retrieve such data. According to me there are two possibilities. First involves the custom widget interface that accompaniates each widget plugin. There is a reserved method codeTemplate which was probably intended to do exactly the thing needed here – provide a template code to be used by UIC. The second possiblity is to use Q_CLASSINFO() macro to embed such information directly in the widget itself in a simmilar manner.

Method 2

The second method is somewhat simpler – let’s just assume the method to add new page has to follow some well known naming scheme or that the container widget has to implement some interface which serves the purpose of letting UIC use well known (hardcoded) method names to manipulate widget pages.

Method 3

The last method is merely a workaround that can be applied with existing Qt versions without the need to patch any Qt code. Qt objects receive a special event (QChildEvent) that informs that a child was added or removed from the object. It could be used to intercept the pages inserted with the faulty behaviour of UIC so that the widget itself could incorporate the child as its page. Of course it means it wouldn’t be possible to add child widgets to the widget “the traditional way” as all widget children would be treated as pages.

Comments on Qt Centre programming contest

Today I posted a note to QtCentre regarding upcoming closing of the contest registration period and I’d like to write a few words of comment and thoughts regarding the contest.

First of all I am surprised by the total lack of entries in the “Mobile Application”. Given the fact that you can win a magnificent device (belive me, I played with it last year) worth probably about $1000 (Trolltech sells it for $700 but it’s less than the Greenphone market value) that can actually run your application (assuming you don’t already have such a device) I expected a flood of entries in this category (I’d take part in the competition myself if I could).

Second of all right after the contest has been announced there has been a little wave of comments suggesting some kind of con or enourmously strict rules of the contest (for example look here). I will only say that such aqusations are unfair. You can read my detailed opinion directly on Dot.

Third of all I’m surprised only three entries have been submitted to the “Development Tool” category. Knowing that at least three IDE projects exist for Qt4 (and not all entries in the category are IDE applications) and there are surely more initiatives related to development (wizards, documentation tools, parsers, frontends, etc.) it is weird that none of them entered the competition.

Fourth of all while organizing the competition we managed to extend our contacts in Qt world. At last I don’t feel like walking blindly in Qt world, so this is an obvious benefit of the whole initiative for me. Hopefully one day Qt community may benefit from that.

There are still almost two weeks remaining for people to register their apps so hopefully all my worries will prove wrong, but for now all makes me wonder why the situation looks like this. I don’t think it’s because of poor prizes as, you must admit, these are great and honestly I don’t know if sponsors will be willing to donate such great prizes next year (if we decide to organize it) if they’re not satisfied with the interest in the event this year.

The bottom line is – if you have written a Qt4 application that doesn’t violate rules of engagement (it’s open source and portable), enter the competition. You don’t lose anything and you can gain quite much.

DomElementContainer

I often write code that iterates over an XML document and performs actions on elements with some specifig tag. Usually I do it using code like the following:

for(QDomElement elem = parent.firstChildElement("tag");
                !elem.isNull();
                elem = elem.nextSiblingElement("tag")){
    doSomething(elem);
}

This is fine, but I thought it’d be nicer to do it using the foreach() loop offered by Qt. Out of the box Qt doesn’t allow to use foreach with xml documents, so I decided to do something about it :)

After 15 minutes the class was ready:

#include 
#include 
#include 

class DomElementContainer {
public:
  class const_iterator {
    friend class DomElementContainer;
  public:
      const_iterator(){}
      const_iterator &operator++(){
        m_e = m_e.nextSiblingElement(m_t);
        return *this;
      }
      const QDomElement & operator*(){
        return m_e;
      }
      bool operator==(const const_iterator &other) const {
        return (m_e==other.m_e && m_t==other.m_t);
      }
      bool operator!=(const const_iterator &other) const {
        return (m_e!=other.m_e || m_t!=other.m_t);
      }
  private:
      const_iterator(const QDomElement &e, const QString &t){
        m_e = e;
        m_t = t;
      }
      QDomElement m_e;
      QString m_t;
  };

  DomElementContainer(const QDomElement &e, const QString &tag=QString::null){
    m_tag = tag;
    m_elem = e;
  }
  DomElementContainer(const QDomDocument &d, const QString &tag=QString::null){
    m_tag = tag;
    m_elem = d.documentElement();
  }
  const_iterator begin() const{
    return const_iterator(m_elem.firstChildElement(m_tag), m_tag);
  }
  const_iterator end() const {
    return const_iterator(QDomElement(), m_tag);
  }
private:
  QDomElement m_elem;
  QString m_tag;
};

Now it’s possible to do the following:

#include "domelementcontainer.h"

const char *xml = "content 1content 2 "
                  "wrongcontent"
                  "content 3";

int main(){
    QDomDocument doc;
    doc.setContent(QString(xml));
    DomElementContainer c(doc, "tag");
    foreach(QDomElement e, c)
      qDebug("%s", qPrintable(e.text()));
    return 0;
}

Download available here.

QtCentre anniversary and contest

Anniversary

Today is the first anniversary of QtCentre – exactly one year ago on a cold winter morning QtCentre was announced to public. It was created as a result of transfer and ongoing negligence of the new owner of QtForum. As the situation over year didn’t change – the site is still dying and is trashed with spam, I see that we’ve made the right decision.

After a year of activity QtCentre is already half the size of QtForum in postcount and about the same size in usercount (the usercount on QtForum is invalid due to a merge with the user database from kde-forum.org about 18 months ago). Apart from the forum itself we have published a wiki, which already has about a hundred articles (many of them are class stubs, so you’re welcome to fill them in), many thanks go to JPN for active contibution to the wiki.

Contest

For the last few months I have been less active on the forum, but now without a reason. Apart from other things which were occupying my attention, I was taking part in preparations for the QtCentre Programming Contest. I’m happy to follow the announcements on QtCentre and other sites and inform, that the contest has started today! You can find all the information about it on its website. Feel invited to enter the competition and win very nice prizes. The contest will be judged by representatives from all organising parties – the top-notch Qt programmers and engineers.

Hopefully I’ll have more time now to focus on my PhD studies :)

Remote models

The Christmas break came and I have finally found some free time to finish some little projects and experiments I started some time ago and I decided to publish preliminary (yet working) results of one of them.

The problem

Qt4 supports the model-view paradigm through the Interview framework, but unfortunately it doesn’t handle models which store data on some remote host. “Hey, of course it can operate on models with remote datasets – just take a look at the SQL models available!” – one might say and basically this is true. But this is just a partial truth – have you tried using those models (for example QSqlTableModel) on a large dataset, let’s say… with thousand records holding some image and textual data? The problem with SQL models is that when the model initialises (when select() is called) it retrieves all the data from the SQL DBMS and blocks the GUI until all of the data is ready. This is not a big problem with local databases – 1k records of 50kB of data each gives 50MB of data that needs to be transfered – over a Fast Ethernet (100Mbps) network it’ll take not more than a few seconds, but try doing the same using a 1Mb network link… After 6 minutes your model will be ready and your application could continue.

Possible solutions

The problem would be easy to overcome if one of two things were true – either QSqlQuery would work asynchronously or QSqlTableModel would begin with an empty model, execute the query in the background and fill the model after the data is ready. The result of both of these solutions would be simmilar – the data would be added to the model dynamically as it is retrieved from the distant server.
Unfortunately QSql*Model classes don’t support such behaviours. In general the same problem applies to all data sources that are blocking.
The proper solution to the problem is to use a thread or set of threads that fetch the data in the background and insert it into the model using signals and slots. Because of queued connections across threads, updating the model is thread safe and it doesn’t block the GUI thread.

As a proof of concept I implemented a subclass of QAbstractTableModel that uses a thread and a simple updater object to transmit data between the application and a distant data storage. The concept uses signals and custom events to do the job and developers only need to implement the updater object and call proper methods in the model.

How does it work?

Here is an example implementation of a remote model:

class MyModel : public RemoteTableModel {
public:
  MyModel() : RemoteTableModel(){
    setUpdaterFactory(new MyUpdaterFactory()); // terrible hack here
    start(); // start filling the model
  }
  int columnCount ( const QModelIndex & parent = QModelIndex() ) const{
    if(parent.isValid()) return 0;
    return 2; // two column flat model
  }
  int rowCount( const QModelIndex &parent = QModelIndex() ) const {
    if(parent.isValid()) return 0;
    return m_rows.count();
  }
  QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const{
    if(!index.isValid() || role!=Qt::DisplayRole) return QVariant();
    int row = index.row();
    if(row>=m_rows.count()) return QVariant();
    if(index.column()==1){
      return m_rows.at(row).title;
    } else {
      return m_rows.at(row).tid;
    }
  }
protected:
  void addRow(const QVariant &data){
    // add a row retrieved from a remote data source
    beginInsertRows(QModelIndex(), m_rows.size(), m_rows.size());
    QVariantList vlist = data.toList();
    m_rows << st(vlist.at(0).toString(), vlist.at(1).toInt());
    endInsertRows();
  }
private:
  /**
   *  Internal data structure
   */
  struct st {
    st(QString t, int i){ title = t; tid = i; }
    QString title; // column 1 data
    int tid;       // column 0 data
  };
  QList m_rows; // data container
};

One also needs to implement an updater object that will do the actual fetching and storing. You can see an example in the tar bundle attached at the end of this post. Basically what it does is to fetch a list of threads in QtCentre’s Qt Programming forum using QtCentre’s archive features over the HTTP protocol. QHttp works asynchronously so I could implement that particular example directly without using threads too, but it’s just an example – I use it successfully to fetch and store data in a SQL database, but I don’t have a public database to use in an example, so the HTTP example has to suffice for now.

Next thing that needs to be done is to split the data transfer functionality from the model interface so that it could be used for hierarchical models or even some other things as well and to clean the implementation a little
(now I’m using an ugly hack to prevent creating a QObject in the context of a wrong thread).

Example code