Creating a styled Gradient Button Bar

From Qt Wiki
Jump to: navigation, search
Please be patient and hold your edits. I am working on this: Simow (talk) 22:16, 25 March 2015 (UTC)

Introduction

Sometimes when you are just bored by the default QTabWidget and don't want to pull QML dependencies into your project to create a fancy user interface this article might be for you. With the help of QStyle, QBrush, a left-to-right QListWidget we are creating a stylish tab bar that can switch through a QStackedLayout that looks like this (only an example, everything customizable):

Gradient-tab-bar-01.png

What you learn

This tutorial makes use of different features and techniques provided by Qt:

  • Resource System The icons you see in the screenshot are loaded via the Qt Resource System
  • QBrush For creating the gradient we make use of QLinearGradient that is assigned to a QBrush.
  • QPalette Qt has no direct way for setting colors to particular widgets, except using stylesheets, but as far as I know there is no support for gradients yet. So we need to make use of color roles and a customized QPalette
  • QListWidget We make use of the flow property to make the items flow horizontally.

Creating a new Project

To make our life easy and get results fast we use QtCreator along this tutorial. So lets create a new project by calling 'File' - 'New File or Project' and select 'Qt Widgets Application'. Follow the Wizard steps and we should end up with a project skeleton containing a form, header and source for the main window.

Preparing the Main Window

We start by modifying the mainwindow.ui form. Open the Forms folder and double click the .ui file. The form designer opens the empty main window. Since we don't need a tool bar, status bar and menu bar we get rid of them by right-click - 'Remove', either on the item directly or in the object inspector:

Gbb-object-inspector.png

Now that we have an empty form we add an item-based 'List Widget' (QListWidget) from the Widget Box and below that a normal widget (QWidget) that will later hold our stacked layout containing the tab pages. Let's give the list widget the name tabBar and the QWidget tabContainer. To make the widgets resize nicely when you resize the main window we select the main window and press the 'Lay Out Vertically' button of the form designer toolbar (or use the Ctrl+L shortcut).

This should give us the following result:

Gbb-form-with-widgets.png

Well, that doesn't look very nice. The list widget going to display the tab icons is way too high. This is because the widget property maximum height does not limit the height for the current layout situation. So we set it to a fixed height, let's say 50:

Gbb-form-with-widgets-sized.png

Nice. That's better.

Now we have a QListWidget as the tab bar. But wait, a list? Doesn't a list normally list the items from top to bottom? Yes. But this widget has the flow property we can set to LeftToRight:

Gbb-list-flow.png

Adding the Icon Resources

Now that we have an empty tab bar, let's add some items. But first we need to register a resource file that is going to hold the graphics files. If you want to follow the example from above you can download the icons from here:

Gbb-network.png Gbb-disc.png Gbb-floppy.png

Add a new resource file by choosing File - New File or Project. From that dialog select Qt from the template category list on the left and then Qt Resource File. Confirm by clicking on Choose.... Enter the name main.qrc and click Next, then on Finish to confirm the default settings for version management.

Now you should see the resource editor:

Gbb-resource-aditor.png

Now we need to add a prefix. A prefix can be seen as a virtual folder within a resource file. This technique can be used to group resource files or e.g. create different language sensitive icons. Bear in mind that you are not only limited to graphics. You could also add a license document to the resource file and load it in the about box.

Let's add the prefix called / what happens to be our root prefix. Click on the Add button then choose Add prefix from the popup menu. An automatically named entry /new/prefix1 is created. Remove the text portion so that only / remains in the text field below.

Now while the prefix / is selected you can add some files by clicking Add - Add Files. For the sake of simplicity I assume that the icons are located in the same directory as the rest of the project files. From the File picker you can also select multiple files.

Select the three icon PNG files and click 'Open'. This should result into:

Gbb-resource-tree.png

Adding Items to the Tab Bar

Not it's time to add some items to our tab bar. The project wizard created some cpp and header files we just need to modify.

In the mainwindow.cpp we find a constructor that creates the user interface (Ui::MainWindow) if you didn't change the default name. In the constructor the method setupUi is called what initializes the from the included ui_mainwindow.h header file which is in turn created by the uic (User Interface Compiler).

After the initialization we can access the list widget and add some items:

MainWindow::MainWindow(QWidget *parent) :

   QMainWindow(parent),
   ui(new Ui::MainWindow)

{

   ui->setupUi(this);
   QListWidgetItem *item1 = new QListWidgetItem(ui->listWidget);
   item1->setText("Floppy Disc");
   item1->setIcon( QIcon(":/floppy.png") );
   QListWidgetItem *item2 = new QListWidgetItem(ui->listWidget);
   item2->setText("Compact Disc");
   item2->setIcon( QIcon(":/disc.png") );
   QListWidgetItem *item3 = new QListWidgetItem(ui->listWidget);
   item3->setText("Network");
   item3->setIcon( QIcon(":/network.png") );

}

These lines are quite straight-forward:

  1. create a new QListWidgetItem and pass the list widget from the ui object as the parameter so that it gets added automatically
  2. set the text for the tab label
  3. set the icon from the resources we already added

Running our sample application with these modifications results into this:

Gbb-added-items.png

Well, we have items, we have icons and we can select but we are still missing the promised fanciness. The items are now painted using the default style (on my system the GTK-Qt-Style is used). And most important: Still no gradients. Seems like we need some more actors on the stage.

Enter QBrush and QLinearGradient

In order to create a linear gradient we need at least three bits of information:

  1. the coordinates to tell the painter where to start drawing the gradient
  2. start color the relative position and the start color
  3. end color the relative position and the end color

Put together we insert right after the line ui->setupUi(this);:

QLinearGradient buttonGradient(0,0,0,ui->listWidget->height());

The QLinearGradient constructor takes four parameters: x1, y1, x2, y2. With these coordinate pairs we can exactly define the interpolated area. In our case we want the background of the list widget being filled entirely by the gradient. Thus we pass as the first coordinate pair 0,0 (start at the upper left corner) and the second 0,ui->listWidget->height() stop at the lower left corner so that the gradient spans the entire height of the list widget.

buttonGradient.setColorAt(0,QColor(100,120,140)); buttonGradient.setColorAt(1,QColor(160,180,200));

These two lines define the start and stop color. The first parameter is the relative position where to set the color. It is a real value ranging from 0 to 1. Here we just define our two colors at 0 and at 1.