Medical Imaging Interaction Toolkit  2024.06.00
Medical Imaging Interaction Toolkit
Customizing the Main Window using Qt-Stylesheets

In a final step, we want to further customize the appearance of our mainWindow to give it an distinct non-native look and feel. We want to achieve this by pursuing the following aims:

  • Change the background and widget colors
  • Change the tab-widget and ToolButton style, also with respect to mouse-over-button (hovering) effects
  • Completing the non-native tab-widget like impression of the perspectives by gluing tab-bar and perspective's PageComposite together
  • DICOM Import functionality

For GUI customization, we will modify the Qt-Stylesheets files already used by blueberry applications. Within the Qt-Stylesheet-Files, all widgets can globally and locally be addressed inside the main window for style changes. We have to address the berry::IQtStyleManager to tell the BlueBerry workbench to use a specific Qt-Stylesheet. This is done inside the WorkbenchAdvisor in the CustomViewerWorkbenchAdvisor::Initialize() method:

void CustomViewerWorkbenchAdvisor::Initialize(berry::IWorkbenchConfigurer::Pointer configurer)
{
ctkPluginContext *pluginContext = org_mitk_example_gui_customviewer_Activator::GetPluginContext();
ctkServiceReference serviceReference = pluginContext->getServiceReference<berry::IQtStyleManager>();
// always granted by org.blueberry.ui.qt
Q_ASSERT(serviceReference);
berry::IQtStyleManager *styleManager = pluginContext->getService<berry::IQtStyleManager>(serviceReference);
Q_ASSERT(styleManager);
QString styleName = "CustomStyle";
styleManager->AddStyle(":/customstyle.qss", styleName);
styleManager->SetStyle(":/customstyle.qss");
// styleManager->AddStyle("/home/me/customstyle.qss", styleName);
// styleManager->SetStyle("/home/me/customstyle.qss");
}

The style manager is taken from the application's plugin context via service reference. Invoking the berry::IQtStyleManager::AddStyle() and berry::IQtStyleManager::SetStyle() methods, the workbench will now use the announced qss-File to style our Workbench Window. In a production system, the stylesheets are usually compiled into the plug-in or application using the Qt resource system. However, during development of the stylesheets it is often more convenient to reference them using a hard-coded path to the local file system (see live update functionality below).

Before we start customization we will first provide some customization convenience. We add an UpdateStyle()-slot to our CustomViewerWorkbenchWindowAdvisor where we explicitly reset the css-File to the style manager:

void CustomViewerWorkbenchWindowAdvisor::UpdateStyle()
{
ctkPluginContext *pluginContext = org_mitk_example_gui_customviewer_Activator::GetPluginContext();
ctkServiceReference serviceReference = pluginContext->getServiceReference<berry::IQtStyleManager>();
// granted by org.blueberry.ui.qt
Q_ASSERT(serviceReference);
berry::IQtStyleManager *styleManager = pluginContext->getService<berry::IQtStyleManager>(serviceReference);
Q_ASSERT(styleManager);
styleManager->SetStyle("/home/me/customstyle.qss");
}

By integrating an update style button to the Application's main window and connecting this button with the previously defined slot, we can now button-push-update the style on runtime. This will of course only work for stylesheets which are referenced from the local file system.

The unstyled Main Window


First we might want to change the background color style by setting the background color of the QWidget::CentralWidget to a linear gradient from light to dark blue:

QWidget#CentralWidget
{
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgb(43, 75, 116), stop:1 rgb(197, 245, 254));
}

Then, we give the page composite control widget a slight grey border (except for the upper border where no border should be visible) and the same background color as the activated tab widget:

QWidget#PageCompositeControlWidget
{
border-left: 1px solid #a0a0a0;
border-bottom: 1px solid #a0a0a0;
border-right: 1px solid #a0a0a0;
margin: 0px;
padding: 10px;
background: rgb(210, 221, 239);
}

The image below depicts the style changes.

Background-color changed Central and Composite Control Widgets


Concerning the tab-widget style, four states have to be customized: QtPerspectiveSwitcherTabBar::tab (the tab in general), QtPerspectiveSwitcherTabBar::tab:selected (when tab is selected), QtPerspectiveSwitcherTabBar::tab:selected:hover (when tab is selected and the mouse is hovering above), QtPerspectiveSwitcherTabBar::tab:!selected:hover (respectively).

All tabs are given round corners using border-top-left- and border-top-right-radius definitions. Additionally, all tabs is provided a gap to its neighbor defining a positive margin right. Selected tabs appear bigger by defining a negative upper margin, and they have no lower frame in the unselected state so a tab-widget appearance is provided. Finally, they have a brighter background color also used by the QWidget::ClientComposite. Hovering tabs are colored yellow and have a visible lower border:

QtPerspectiveSwitcherTabBar::tab
{
min-height: 24px;
border-top: 1px solid palette(mid);
border-left: 1px solid palette(mid);
border-bottom: 0px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
margin-top: -1px;
margin-right: 4px;
padding-left: 5px;
background: rgb(210, 221, 239);
}
QtPerspectiveSwitcherTabBar::tab:selected:hover {
border-bottom: 1px solid palette(mid);
background: yellow;
}
QtPerspectiveSwitcherTabBar::tab:!selected {
margin-top: 5px;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgb(156, 181, 220), stop:1 rgb(130, 160, 210));
}
QtPerspectiveSwitcherTabBar::tab:!selected:hover {
background: yellow;
}

Finally, we customize the Push- and Tool-Buttons in a similar way:

QToolButton#FileOpenButton
{
min-height: 20px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border: 1px solid gray;
padding-left: 5px;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgb(156, 181, 220), stop:1 rgb(130, 160, 210));
}
QToolButton#FileOpenButton:hover
{
background: yellow;
}
QPushButton#StyleUpdateButton
{
min-height: 25px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgb(210, 221, 239), stop:1 rgb(197, 245, 254));
}

The resulting style-customized main window is shown below (the style update button removed).

The final version of our Custom Viewer (viewer perspective).


The final version of our Custom Viewer (DICOM perspective).


Proceed to the previous page Adding functionality: Data Manager, Render Window, File Opening and DICOM Import.

berry::IQtStyleManager
Definition: berryIQtStyleManager.h:25
berry::QtWorkbenchAdvisor::Initialize
void Initialize(IWorkbenchConfigurer::Pointer configurer) override
berry::SmartPointer
Implements transparent reference counting.
Definition: berryICommandCategoryListener.h:21
berry::IQtStyleManager::SetStyle
virtual void SetStyle(const QString &fileName)=0
berry::IQtStyleManager::AddStyle
virtual void AddStyle(const QString &styleFileName, const QString &styleName=QString())=0