Wednesday, May 02, 2012

A Concise Introduction to using CSS with Qt Classes and Custom-Made Classes

Qt is a really nice, efficient framework. It's a real pleasure to be able to style objects with CSS-like declarations. However, I had a hard time to make my own Qt widgets interact faithfully with my CSS declarations.

I think the main reason is because the most relevant part of Qt's documentation is a bit scattered in it's structure and is not easily linked when you browse through it.
This post is a quick introduction and summary of what you should know to work efficiently with Qt's stylsheets.

Note!: This post is about Qt version 4.8. It should also be valid, more or less, for older or newer versions of Qt.

Note! #2: This post is not a tutorial. it is intended as a collection of pointers to the most relevant part of Qt's documentation.

The Very Basics


First of all, if you are not very familiar with CSS stylesheets, or if you think you forgot how selectors work in some cases, you should have a look at Qt's Style Sheet Syntax.

Secondly, if you want some information on the way the Box Model works, and what content/padding/border/margin means, go to the Customizing Qt Widgets Using Style Sheets page.

Don't miss the explanations on sub-controls at the end of the page: they are very specific for Qt widgets.

The Reference Document


You would be wise to print or bookmark the Qt Style Sheets Reference. Whenever you need to know what can be done with Qt Style Sheets, and how to do it, you will find the answers within the reference.

If you need some examples for a specific kind of widget, take a look at Qt Qtyle Sheets Examples.

 

What to do with your Own Widgets?


Sometimes, in your own project, you need to derive from a QWidget. If you do so, you need to pay special attention to what is said in the Qt Style Sheets Reference about QWidget, especially if you still wish to use Qt Style sheets to customize the look and feel of your own classes:

If you subclass from QWidget, you need to provide a paintEvent for your custom QWidget as below:
 void CustomWidget::paintEvent(QPaintEvent *)
 {
     QStyleOption opt;
     opt.init(this);
     QPainter p(this);
     style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
 }

The above code is a no-operation if there is no stylesheet set.
Warning: Make sure you define the Q_OBJECT macro for your custom widget.

Updating CSS: don't recompile! Reload Style Sheets...


When you are in the process of fine-tuning your Style Sheets and when you constantly need to check the result of these small modifications, it is not always practical to constantly recompile your project. 

I usually define a global (application-wide) shortcut that dynamically reloads the main Qt Style Sheet from a specific location on the hard drive (and not from the resources pseudo-file system because these resources can only be modified by recompiling the project...).

This process can save a lot of time!

For those interested by this way of working, here is a quick'n dirty way of doing it. It is based on the idea of accessing a file on the hard drive and not via the Qt Resource System. Otherwise a compilation would be needed and this is what we are trying to avoid!

Here's how you can trap a certain Key Event of YourWidget (let's say it is the $ key...):

void YourWidget::keyPressEvent(QKeyEvent *event) {
[...]
        case Qt::Key_Dollar:
        {
            // We access the file and load it
            QFile css_file("/path/to/your/css/file/gui.css");
            css_file.open(QFile::ReadOnly);
            QTextStream css_stream(&css_file);
            QString css_string(css_stream.readAll());
            css_file.close();

            // We apply the CSS file
            setStyleSheet(css_string);
            setStyle(QApplication::style());
            break;
        }

}

Good Luck!

[Posted by PhS]