Normalerweise passen sich Widgets optisch an die verwendete Oberfläche an. Qt-Oberflächen können aber auch über in der Web-Programmierung übliche CSS-Stylesheets gestaltet werden. Dadurch ist es möglich, seiner Anwendung ein ganzes bestimmtes Aussehen zu verleihen.
Größtenteils kann der in der Web-Programmierung übliche Syntax verwendet werden. Qt bietet aber einige zusätzliche Funktionen, um die Gestaltung zu vereinfachen. An dieser Stelle wird aber nur eine grobe Übersicht über die Verwendung von CSS geboten, nähere Informationen befinden sich in einem eigenen CSS-Tutorial.
Die Gestaltung funktioniert über Änderung von Attributen für bestimmte Objekte. Über einen sogennanten Selektor
werden Objekte ausgewählt. CSS verwendet folgenden Syntax:
selector { property:value; property:value; ... }
Dabei können beliebig viele property:value
-Paare verwendet werden. Bei nur einem Paar kann der Semikolon weggelassen werden. Folgendes Beispiel färbt alle Objekte der Klasse QPushButton
rot:
QPushButton { color:red }
Als Selektor dient in diesem Fall die Klasse QPushButton
, dessen Attribut color
auf red
gesetzt wird.
Qt bietet jedoch viel flexiblere Selektoren als nur Klassennamen. Um die die Selektoren zu testen, verwenden wir folgendes Programm:
#include <QApplication> #include <QVBoxLayout> #include <QHBoxLayout> #include <QPushButton> #include <QLineEdit> #include <QCommandLinkButton> #include <QVariant> int main( int argc, char *argv[] ) { QApplication app( argc, argv ); QWidget *widget = new QWidget(); QPushButton *pButton1 = new QPushButton( "QPushButton 1" ), *pButton2 = new QPushButton( "QPushButton 2" ); QCommandLinkButton *cLinkButton = new QCommandLinkButton( "QCommandLinkButton" ); QLineEdit *lineEdit1 = new QLineEdit(), *lineEdit2 = new QLineEdit(); pButton1->setObjectName( "pButton1" ); pButton2->setFlat( true ); lineEdit2->setProperty( "mandatory", true ); //app.setStyleSheet( "" ); QVBoxLayout *vLayout = new QVBoxLayout(); QHBoxLayout *hLayout = new QHBoxLayout(); hLayout->addWidget( pButton1 ); hLayout->addWidget( pButton2 ); vLayout->addLayout( hLayout ); hLayout = new QHBoxLayout(); hLayout->addWidget( cLinkButton ); vLayout->addLayout( hLayout ); hLayout = new QHBoxLayout(); hLayout->addWidget( lineEdit1 ); hLayout->addWidget( lineEdit2 ); vLayout->addLayout( hLayout ); widget->setLayout( vLayout ); widget->show(); return app.exec(); }
An der auskommentierten Stelle wird jeweils das entsprechende Stylesheet übergeben. Ohne Stylesheet sieht das Widget unter KDE4 so aus:
Der Universalselektor * wählt alle Widgets aus.
Gibt man als Selektor einen Klassennamen an, wird die Klasse und dere Subklassen ausgewählt.
QPushButton { color:red }
Anzumerken ist hier, dass sowohl QPushButton
, als auch die Subklasse QCommandLinkButton
verändert wird, alle andern Widgets ihr Aussehen jedoch behalten.
Es können auch nur Widgets mit bestimmten Eigenschaften ausgewählt werden. Dabei können alle mit QVariant
kompatiblen Attribute verwendet werden. Die Bedingung wird dabei in eckigen Klammern nach dem Typ- bzw. Universalselektor geschrieben. Attribute können auch über die Methode QObject::setProperty()
gesetzt werden. Die Abfrage erfolgt auf gleichheit mit dem =
-Operator, bzw. mit ~=
, ob das Attribut den angegeben Text enthält. Der Text steht in Anführungszeichen und muss in C++ natürlich dementsprechend maskiert werden.
Widgets die über diesen Selektor ausgewählt wurden, werden aber nicht automatisch aktualisiert, nachdem sich ihr Wert ändert! Dieses Verhalten muss über Siganle/Slots und das neuerliche Setzen eines Stylesheets manuell erledigt werden.
QPushButton[flat="true"] { color:red } QLineEdit[mandatory="true"] { background:blue }
Hier werden nur der Button, auf den setFlat( true )
angewendet wurde, sowie die QLineEdit
-Instanz mit dem manuell gesetzten Attribut mandatory
ausgewählt.
Dieser Selektor funktioniert ähnlich wie der Typ-Selektor, jedoch werden abgeleitete Klassen nicht berücksichtigt. Vor dem Klassennamen wird der .
-Operator verwendet.
.QPushButton { color:red }
Wie beim Typ-Selektor werden die zwei QPushButton
-Instanzen rot, jedoch behält die abgeleitete Klasse QCommandLinkButton
ihr aussehen.
In HTML können Tags über eine ID identifziert werden. Qt-Stylesheets erkennen Objekte über ihren Objektnamen, der über QObject::setObjectName()
gesetzt wird. Dazu wird nach dem Klassennamen (es kann sowohl ein Typ- als auch ein Klassen-Selektor verwendet werden) der #
-Operator mit nachfolgendem Obejktnamen verwendet.
QPushButton#pButton1 { color:red }
Der Button mit dem Objektnamen pButton1
wird ausgewählt, sonst nichts.
Für die nächsten beiden Beispiele wird eine leicht erweiterte Version des Codes verwendet, bei dem die beiden QLineEdit
-Instanzen sich zusätzlich in einer QGroupBox
befinden und am Ende noch zusätzlich ein QLineEdit eingefügt wird.
#include <QApplication> #include <QVBoxLayout> #include <QHBoxLayout> #include <QPushButton> #include <QLineEdit> #include <QCommandLinkButton> #include <QVariant> #include <QGroupBox> int main( int argc, char *argv[] ) { QApplication app( argc, argv ); QWidget *widget = new QWidget(); QPushButton *pButton1 = new QPushButton( "QPushButton 1" ), *pButton2 = new QPushButton( "QPushButton 2" ); QCommandLinkButton *cLinkButton = new QCommandLinkButton( "QCommandLinkButton" ); QLineEdit *lineEdit1 = new QLineEdit(), *lineEdit2 = new QLineEdit(); QGroupBox *box = new QGroupBox(); pButton1->setObjectName( "pButton1" ); pButton2->setFlat( true ); QVBoxLayout *vLayout = new QVBoxLayout(); vLayout->addWidget( lineEdit1 ); vLayout->addWidget( lineEdit2 ); box->setLayout( vLayout ); lineEdit2->setProperty( "mandatory", true ); //app.setStyleSheet( "" ); vLayout = new QVBoxLayout(); QHBoxLayout *hLayout = new QHBoxLayout(); hLayout->addWidget( pButton1 ); hLayout->addWidget( pButton2 ); vLayout->addLayout( hLayout ); hLayout = new QHBoxLayout(); hLayout->addWidget( cLinkButton ); vLayout->addLayout( hLayout ); vLayout->addWidget( box ); vLayout->addWidget( new QLineEdit() ); widget->setLayout( vLayout ); widget->show(); return app.exec(); }
Wählt Widgets aus, die in der Objekt-Hierarchie unter einem bestimmten anderen stehen. Dabei wird zuerst das Objekt angegeben dessen Nachfahren behandelt werden sollen, dann eine Einschränkung der Nachfahren. In beiden Fällen können sowohl- als auch ein Klassen-Selektoren verwendet werden.
.QWidget QLineEdit { background:blue }
In diesem Fall bekommen alle QLineEdit
-Objekte die in der Hierarchie unter einem QWidget
(ohne Subklassen!) stehen, einen blauen Hintergrund.
Wie der Nachfahr-Selektor, jedoch sind nur direkte Nachfahren betroffen.