Qt

Qt 3.3 Signals Without Magic

I had a small Qt 3.3 utility that refreshed a list after reading a directory. It worked until I renamed a slot, at which point clicking the button did precisely nothing. No crash, no compiler error, just a very calm refusal to cooperate.

My naive fix was to add qDebug() calls everywhere except the place that mattered. The button emitted its signal and the refresh function worked when called directly. After too much staring, I finally checked the return value from connect() and ran the program with Qt warnings visible.

bool connected = connect(refreshButton, SIGNAL(clicked()),
                         this, SLOT(reloadDirectory()));
Q_ASSERT(connected);

The slot declaration and the string in SLOT() no longer agreed. Qt’s meta-object compiler records the signal and slot information that ordinary C++ does not provide. The connection is therefore checked at runtime, not by the compiler. Once I remembered that mechanism, the silence stopped being mysterious.

The generated meta-object code also explains why a class using signals or slots needs the Q_OBJECT macro and must pass through moc. Forgetting that step can produce linker errors rather than a friendly explanation. With the normal Qt build tools, the extra generation is automatic; with a handmade makefile, it is another dependency that must be stated correctly.

I tested disconnection and destruction as well. Qt removes connections involving a destroyed object, which is safer than retaining callbacks into dead C++ instances. That convenience still depends on the receiver actually being a QObject with a well-defined lifetime.

I now keep signals and slots in the appropriate class section, inspect the generated warnings, and assert important connections during development. I also avoid clever overloads unless they buy something substantial. The old string syntax is useful, but it can turn a typo into a tiny mime performance.

Small executable tests help here too: create the sender and receiver, emit once, and verify the resulting state before involving the whole window.

Qt 3.3 remains pleasant C++ because it removes a great deal of event plumbing. It does not remove the need to understand that plumbing. Framework convenience is best treated as compressed machinery: use it freely, but know where to open the panel when it stops.

A Model Pattern for Qt 3 List Views

I have a Qt 3 dialog that displays several hundred server records in a QListView. The first implementation stored the actual application state in QListViewItem subclasses. It worked until another window needed the same records and sorting the view began to feel suspiciously like rearranging the database.

Qt 3 does not provide the general item model API one might wish for here. QListView owns a tree of items, and those items naturally contain display text. That does not require making them the authoritative business objects.

My simpler pattern is to keep records in an ordinary domain collection and make each list item an adapter containing only a stable identifier. Display columns are copied from the record when the view is populated or refreshed.

class ServerItem : public QListViewItem
{
public:
    ServerItem(QListView *view, int id)
        : QListViewItem(view), serverId(id) {}

    int id() const { return serverId; }

private:
    int serverId;
};

When selection changes, the controller reads the item’s ID and looks up the record. Editing updates the record first, then refreshes the item text. Deleting the view item never deletes the underlying record unless the user explicitly requested that operation.

This separation fixes several observed problems. Sorting changes presentation order without changing application order. Two views can show the same record differently. Reloading the widget cannot silently discard unsaved state hidden in a child item. Unit-like tests can exercise record operations without constructing widgets or starting an X connection.

Signals and slots keep the pieces reasonably loose. The dialog connects selection and activation signals to slots that translate a QListViewItem * into a record ID. The record-owning object emits a signal after a successful change, and the view refreshes the affected row.

There is a caveat: copying all text into items can be expensive for very large datasets. For hundreds or a few thousand rows it is straightforward and fast enough. If the data is enormous, a custom widget or a specialised table that fetches visible values may be warranted. I would measure before building that machinery.

Stable IDs are important. Storing a pointer into a collection is tempting, but reallocating a vector or reloading records can invalidate it. An integer or other durable key makes the lookup explicit and failures easier to detect.

I do not call this a framework. It is three rules: own data outside widgets, put identities in items, and route changes through one owner. Qt’s item widgets remain useful presentation objects without becoming a tiny, badly documented database. Most dialogs need no grander architecture; they merely need the courage not to store reality in column zero.

Flicker-Free Custom Painting in Qt 3

I wrote a small Qt 3 widget that draws a graph, and it flickered whenever another window crossed it. The first version painted the background and graph directly onto the widget. The user could occasionally see the exciting interval between those operations.

The obvious cure is to draw a complete frame off-screen and copy it in one operation.

void Graph::paintEvent(QPaintEvent *event)
{
    QPixmap frame(size());
    frame.fill(colorGroup().base());

    QPainter p(&frame);
    drawGrid(&p);
    drawValues(&p);
    p.end();

    bitBlt(this, event->rect().topLeft(), &frame, event->rect());
}

The pixmap receives the background and every graph element before the screen changes, so the widget never displays a half-painted frame. For a frequently updated widget, I keep a cached pixmap and rebuild it only when the size, palette, or data changes.

Calling update() schedules a paint event and allows Qt to combine several dirty regions. Calling repaint() paints immediately. I use update() unless the application genuinely requires synchronous drawing; repeated immediate paints are an efficient way to make smooth animation less smooth.

Another option is the WNoAutoErase widget flag, which prevents Qt from erasing the background before paintEvent(). It can remove one source of flicker, but then the paint code must cover every exposed pixel. Missing one produces attractive garbage from whichever window was there before.

Double buffering costs memory proportional to the widget area, and redrawing an elaborate pixmap for every tiny exposure wastes time. Respect the event’s rectangle and cache expensive static parts.

The result is not clever: compose, then copy. That is precisely why I like it. Rendering bugs are much easier to diagnose when the screen sees only finished frames.

KDE 3.2 in Daily Use

KDE 3.2 was released this week, and I have moved my normal account from 3.1 to the new version. The upgrade was painless on this machine, but I still copied .kde first. Confidence is a fine emotion; it is not a backup strategy.

The feature I notice most is Kontact. Having KMail, KOrganizer, the address book, and related tools in one window sounds cosmetic until one uses it all day. The components remain useful separately, but the shared shell reduces window hunting and makes the PIM suite feel like one piece of software rather than neighbours who happen to share a fence.

Konqueror feels more polished as both browser and file manager. KHTML handles more of the troublesome pages I encounter, although “works in Safari” still does not guarantee “works in Konqueror.” They share ancestry and code, not every platform integration or every patch. Web developers should test both instead of converting the relationship into a new browser-detection shortcut.

I also like the many small improvements more than any single headline. Configuration pages are easier to navigate, applications agree more often about behaviour, and the visual result is cleaner. KDE already had enough knobs to operate a modest submarine. The useful work now is choosing good defaults and making the common paths obvious.

My post-upgrade check is deliberately mundane:

send and receive mail
open old calendar entries
print from two applications
test file associations
visit SSL sites
check keyboard shortcuts
log out and back in

That last step catches session restoration and startup problems that a quick tour misses. I also removed third-party panel applets before upgrading and added them back one at a time. Plugins compiled against an older set of libraries are not where I want to begin debugging the desktop itself.

Performance is difficult to judge scientifically from a chair, but the desktop remains responsive and startup is reasonable. The larger applications naturally consume memory; integration does not repeal arithmetic. On a modest machine I would choose which Kontact components to load rather than assuming the complete suite is free.

KDE 3.2 is a substantial release, but it succeeds because the desktop feels more connected, not because the version contains a longer feature list. I can do the same work with fewer interruptions. That is not glamorous, and it is exactly what I want from a desktop.

Trying the KDE 3.2 Beta

I have been running the KDE 3.2 beta on a spare account because I wanted to see whether the next release changes daily work or merely rearranges the furniture. KDE 3.1 is already a comfortable desktop, so additions now have to earn their place.

The most visible newcomer is Kontact, which presents mail, calendar, contacts, and related information in one shell. The important word is “presents.” It is integrating existing KDE PIM components rather than replacing every application with one enormous program. KMail still behaves like KMail, but I can move between mail and appointments without managing a row of separate top-level windows.

Konqueror and KHTML also continue to improve. Pages that used to expose small layout failures are behaving better, and Safari’s use of KHTML has clearly raised both attention and expectations. I would not claim identical rendering: the engines have already diverged in places, platform code differs, and a site can always find a novel way to be broken. Still, more real-world testing is showing.

The obvious test procedure is not to click around for ten minutes and declare victory. I copied my normal profile, used it for several days, and watched the console output. I tested IMAP folders, printing, file previews, keyboard shortcuts, and the few unpleasant web applications I cannot avoid. Pretty menus are easy; preserving mail and settings is the examination.

Anyone trying a beta should keep a separate home directory or at least a backup of .kde. Configuration files can be upgraded, plugins built for another KDE release may not load, and returning to 3.1 after writing new settings is not guaranteed to be graceful. A beta is an offer to find bugs, not an unusually exciting package update.

My impression so far is that 3.2 is becoming more coherent rather than merely larger. That distinction matters. KDE has no shortage of features. What it needs is for related features to fit together, for defaults to be sensible, and for common paths to require less ceremony.

Kontact is a good example of the right sort of integration: reuse the specialised applications and give them a shared front door. If the remaining beta period concentrates on reliability, 3.2 should be a worthwhile upgrade. If it concentrates on adding twelve more buttons, I reserve the right to hide the toolbars and sulk.