Sunday, June 27, 2010

State of UI Toolkits - Part 1

I'm sure that many people who've attempted to ever set up small-scale and cross-platform UI app will have encountered the inevitable problem of choosing a suitable UI Toolkit to use. And it's not like we don't have many choices either with popular systems such as:
  • QT
  • wxWidgets
  • GTK (and derivatives)
  • Java AWT/Swing
  • ...
to chose from, though there are many more that also work but which I have not listed here. But this is only the start of the troubles you'll face...



What quickly becomes obvious working with any of these toolkits is that you better choose carefully, as vendor lock-in is very very common in these parts, and that a wrong decision will be costly down the track when it becomes obvious that new UI components will need to be created to take part in your UI's, or that trying certain design patterns using that toolkit are going to be a right-jolly pain. (There are some people who'll probably argue that you shouldn't need to be doing that, but that's another discussion for another time).

Not all toolkits are created equally. While some basic functionality is basically present for all of them (buttons, checkboxes, optionboxes, labels, windows, tree and list widgets, layout managers - flow,border,grid) the ease with which these can be used to create your desired designs can vary quite a bit. What may be inherent in the design of one toolkit may not apply in another. Also, some may be basically not intended for hand-coding at all, requiring use of specialised GUI-builders that auto-generate code (one of the oft-recognised sources of vendor lock-in, especially with dependencies on specific GUI-builder versions as dependencies for the project).

Then there is the question of what language to use. Several considerations come into this: 1) the language the UI toolkit is written in, 2) the language the non-UI parts of your program are (going to be) written in, 3) whether there are suitable interfaces between these languages if different, 4) whether you intend to release the sources (closed initially then open later still counts as closed for the purposes of this discussion). It's necessary to recognise that there are really going to be some languages that you personally can't stand, and others that you really love. This is really quite a deciding factor at times, especially if this is for a personal 'hobby' project, which you'll want to find enjoyable not a annoying battle against the code...

Finally, these toolkits are quite large and bulky libraries, usually with many many modules (and sometimes many dependencies too). In fact, each of them basically comes with its own support (or 'standard') library, that they're probably really going to end up forcing you to using at some point for some or rather purpose (another source of vendor lock-in, not to mention additional dependencies which introduce distribution and concurrency problems).


Let's see how these factors play out in practice (as I've found)...

QT
This is quickly becoming quite a ubiquitous and semi "Industry Standard" across many sectors. Quite a few of the "heavyweights" in the 3D industry - Maya, 3DS Max, Houdini, and Lightwave CORE - now have user interfaces built using this toolkit. It is also used in a number of Open Source software, including music notation packages (MuseScore and a crappier/less mature one I've forgotten about), VLC Media Player, Pencil, and numerous KDE apps.

There are however many things to be wary about here:
  • It provides its own (rather substantial) standard library system which it uses in conjunction with its rather large UI toolkit modules
    • This is nice if you're using C++, don't like STL and don't feel like using BOOST, and too lazy/time strapped to build your own. I guess SEng types also
    • Most of the time though, you'll end up with heaps of dynamically-linked libs (i.e. *.dll's on Windows, and *.so on Linux) being distributed with your app as a result.
  • Uses "heavily modified" C++ 
    • C++ is already quite evil, so slapping another healthy dose of macros on top is even more questionable. Personally, I don't mind macros that much, as long as they do useful things that are obvious, and simplify otherwise repetitive and distracting "clutch + gear changing" machinery
    • There are bindings for other languages, most importantly Python, for which 2 flavors exist. (Which one these you use is really more of a case of license allegiances you have....)
  • Provides its own UI designer software with the package
    • Using it to develop apps using QT appears to be recommend by many users
    • Perfectly fine if you're doing basic stuff, and you're happy to have some automated tool cranking out code, with the lock-in risks that such approaches always have (breakage from version upgrades, one-way mapping from UI-design to code)
    • Acts as a reasonable IDE if you're not picky on editor features (for me, it lacks a few things I like to use...), and deals with compiling the "C+++" it uses
From my own experiences using apps written using it, watch out for:
  • Sluggish performance/impaired usability of some of the filebrowsers in apps using it
    • I'm not entirely sure whether this problem is that widespread, but the file-browsers used in MuseScore under Windows (version 0.95) are notoriously bad in terms of loading up and responding to user input. Moving between folders there seems to require a long refresh period during which the UI is not responsive and no folders or paths are shown. Hopefully this is just a case of one app accessing or creating its own poorly-behaved filebrowser hack. In any case, to know what to avoid, check out the source code there and avoid whatever it does in your own apps :)
  • Occasional clunkiness of certain UI operations, in particular moving toolbars/regions around in some of the apps using QT that I've tested
From my (compartively limited) experiences on the other side of the fence:
  • I had a bit of trouble trying to set up certain novelty interfaces that I wanted to try create there. I was doing this under one of the PyQT bindings (whose documentation was a bit lacking IMO), and as of last check, I've been either unable to get my widgets to appear and/or have been getting immediate crashes. However, probably choosing a less ambitious or more conventional design would have worked fine. 
  • There is a distinct lack of much reference material available anywhere on how to do many things programmically, with more focus usually on just using the UI designer only
Another factor working in its favor is that general performance and quality of the widgets is good (from user perspective). There are quite a lot of standard and decent widgets available which is to be expected, and they generally appear in the standard OS theming/styling. 


wxWidgets
This toolkit is a bit more of a lesser player that is increasingly being used less and less. Among the apps that used to use it was VLC Media Player, which has now jumped ship to QT, and improved the overall polish it had. 

Pros and Cons in General:
  • It has Python bindings but is once again another C++ toolkit, though it is more of a "garden variety" type.
  • The widgets are supposed to mostly use 'native' ones for each OS instead of mimicking the appearance and behaviour per OS. 
    • While this mostly works ok, there are some glitchy instances where this doesn't work so well.
    • VLC suffered from some "blankout" refresh problems on some controls, and also had annoying control gain rates in some cases when it still used the old wxWidgets UI. I'm not entirely sure how much of this was to be blamed on the wxWidgets toolkit itself, and how much on the implementation in VLC (also how VLC used ffmpeg... ahem)
    • Sometimes there are some performance problems here too, which make it feel less polished than true native controls would
  • Non-native novelty widgets also exist, but are usually implemented per language binding rather than being part of the overall toolkit. 
    • These are in general much less polished than the rest of the toolkit, and many do have various bugs of sorts
    • At least with the Python bindings these widgets do not seem to be actively maintained or developed anymore for at least a few years now. Requests for help/clarification on matters regarding this controls mostly fell on dead ears.
  • Unlike QT, there isn't really a UI designer, but there are heaps of examples instead which makes up for that in spades
    • Many of these examples are helpful for using each of the controls and understanding their various functionalities
I have to say here that I have quite a bit more experience using wxWidgets than I do with QT, and maybe some of the following statements are/are't true about QT too:
  • Frustratingly, wxWidgets does not really appear to be well designed for any MVC (or derivative) GUI setups. 
    • None of the examples are even suggestive of how to go about using them in such an architecture. In fact, most of the examples end up using the states of UI controls to store data, and also state changes need to be explicitly managed in event-handling callbacks bound to controls.
    • A more detailed discussion on this may be better suited to another post later...
  • wxWidgets makes it much easier to achieve certain things than QT
    • certain layout managers in QT seemed to want to only give me padded regions instead of non-padded ones
    • creating new types of widgets in wxWidgets is quite logical + straightforward, but in QT a sort of new object system needs to be learnt (slots, windows/widgets, etc.)
Overall, this toolkit is reasonable to work with, though the end results lack a bit of polish that QT has.


GTK
This is another heavyweight toolkit, and one which powers "the other half" of Linux apps (i.e. all the gnome ones and a few more such as GIMP, Inkscape). For a change, this is written in good ol' C, with bindings to other languages too if desired.

A few things to be wary about:
  • AFAIK, this started life as part of the GIMP project, and was later branched off to become a GNU-Linux staple (please don't flame about loose terminology usage... I'm not a lawyer or like working in that way :P). 
    • As such, it and all its dependencies are part of many Linux distributions quite comfortably most of the time if you don't start having dependency problems between various apps using different lib versions in which case you might have a few hairy moments.
      • I'm not sure on the specifics of how distribution usually works for smaller apps, though from experience, it is usually more of "here's the code... do what you want/need to get it working for you".
    • The flipside is that it is difficult to get these dependencies set up and playing nice on other (*ahem* propriety *ahem*) platforms, platforms which many coders there do have strong ideological stances about, is challenging at times. 
      • Not to mention there being quite a few of them that are quite interlinked, and the fact that usually to get things working/compiling, you'll the need to have nearly the whole family tree
      • Distributing binaries will require either the runtime environment or redistributing heaps of .dlls with the app. And from there, we can get into heaps of interesting and frustrating support problems with dll-dependency-hell and related problems, which are kindof discouraging for the average user
  • As mentioned in the previous point, is the rather tight-coupling with the gobject/glib system (which provides OO in C), which ends up resulting in quite a few dependencies to deal with
  • Occasionally flaky performance of widgets and graphical displays everywhere
    • This is most pronounced on Windows, when screen resizing can lead to blackouts and refresh problems. Blankouts/refresh problems also occur when using various widgets normally too. Also, some widgets end up looking a bit worse for wear (corners on buttons) sometimes
    • Under Linux, I've seen the occasional glitch/sluggishness too, but it's fairly ok. 
    • In defense of GTK, graphical glitches were also typical of earlier versions of Windows and/or those running on overloaded or stretched systems. Kindof makes you wonder if GTK is waiting for more powerful systems to really prosper ;)
  • (Some verbosity in terms of the API, and maybe not that many widgets available)
    • I'm probably really underqualified to make too much comments here. This is just based on examining some UI code that ended up coming out of wxGlade to be used for Geany. 
    • Perhaps it's really not that bad in practice, but I haven't really used it enough in practice to know (the first three points I mention really rule it out as an option for me so far)

Java Swing/AWT
(I never really thought I'd say many nice words about Java or any "jThing", but comparing some of the options out there, it's actually not too bad. In particular, when compared to the evil that is C++, some of Java's own shortcomings pale in comparison.)


On with some points about this:
  • Mostly, this does a fairly credible job on the API design front, especially for supporting (and even enforcing) MVC type designs. Hat's off to the Java guys to doing something decent for a change.
    • I particularly like the design of the tree widget, which can be extended much more easily than the wxWidgets ones I've encountered
    • Granted, the anonymous-inner-classes syntax is really perplexing to anyone who hasn't seen it before, and also looks like a bit of a kludge, but in retrospect, it works well enough...
  • A major point of contention with this toolkit is that by default, it uses a completely different and foreign theming/styling to native OS widgets. 
    • The 2D bold-Helvetica toting smurf-parade that are most Java-UI's may have some elements of appeal (at least it's consistent cross platform), though sometimes they really look rather ugly
    • Fortunately, it is possible to get some rather-flaky native OS emulation. Once again, not perfect, as with most other toolkits, especially suffering from some flickering.
  • Older versions of Java had truly terrible performance that would rule it out for any purpose full stop IMO. Current versions are more acceptable on modern hardware.
    • Loading times are particularly bad on older machines + older Java versions. Not totally clean these days either, but generally fine within some constraints. Was typically 1-2 seconds loading time at least, as the JVM would have to recompile some binaries from the bytecode, and sometimes randomly longer. These unpredictable and sometimes long load times were (and are still are) a factor that plagues this.
    • Larger apps may have serious problems with responsiveness and overall startup times. There is particularly a tendency to need splash screens there, with app startup times usually around 30s on a good day.
    • Refresh problems and/or threading problems were common in older versions, but are often negligible in newer versions apart from a few critical things such as filebrowsers.
  • We're talking about JAVA here!
    • Java is cross platform, and will work on any machine with a Java VM installed once you compile your sources once and distribute to those machines. But still, these aren't quite standalone executables...
    • There are quite a number of irritating quirks of Java which make programming in it an exercise in satisfying an anal-retentive compiler while having your teeth pulled out for procedure, all the while without any sugar for compensation. Then again, compared to the nastiness of C++ templates (Java ones are also ugly, but don't barf screeds of useless crap upon tiny typos), madness of initialiser lists, and IMO worthless reference variables, it's a far less headache-inducing world.
    • Fortunately, it's still possible to actually code chunks of your app in C and only link it up to be called via a Java frontend. Most people are probably not aware of this, but it can be done (and I have done it).



(Continued in Part 2)

No comments:

Post a Comment