Большинство виджетов Qt выглядит как родной виджет в Windows, но не как QToolBar.
Как сделать так, чтобы QToolBar выглядел как панель инструментов Windows?
Эта страница был опубликован в блоге Qt. Но он был разработан для Qt 4 и не работает с Qt 5, но, поскольку оригинальная лицензия допускает модификации, я адаптировал ее к Qt 5.
То, что я сделал, было просто преобразовать QWindowsVistaStyle
в QProxyStyle
,
Чтобы использовать эти стили, добавьте эти классы в свой проект и установите следующее:
добавлять QT += winextras
в файл вашего проекта.
И установить стиль для всего приложения:
#include "explorerstyle.h"...
QApplication a(argc, argv);
a.setStyle(new ExplorerStyle());
explorerstyle.h:
/****************************************************************************
**
** Copyright (c) 2007 Trolltech ASA <[email protected]>
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/
#ifndef EXPLORERSTYLE_H
#define EXPLORERSTYLE_H
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <QtWinExtras>
class ExplorerStyle : public QProxyStyle
{
public:
ExplorerStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget = 0) const;
void drawControl(ControlElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const;
void polish(QWidget *widget);
private:
mutable QRect m_currentTopRect; //current toolbar top area size
mutable QRect m_currentBottomRect; //current toolbar top area size
};
#endif //EXPLORERSTYLE_H
explorerstyle.cpp:
/****************************************************************************
**
** Copyright (c) 2007 Trolltech ASA <[email protected]>
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/
#include "explorerstyle.h"
#include <qt_windows.h>
#include <uxtheme.h>
#ifndef HTHEME
#define HTHEME void*
#endif
typedef HANDLE (WINAPI *PtrOpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
typedef HRESULT (WINAPI *PtrDrawThemeBackground)(HANDLE hTheme, HDC hdc, int iPartId, int iStateId,
const RECT *pRect, OPTIONAL const RECT *pClipRect);
typedef bool (WINAPI *PtrIsAppThemed)();
static PtrDrawThemeBackground pDrawThemeBackground = 0;
static PtrOpenThemeData pOpenThemeData = 0;
static PtrIsAppThemed pIsAppThemed = 0;
bool isAppThemed()
{
#ifdef Q_OS_WIN
return pIsAppThemed && pIsAppThemed();
#else
return false;
#endif
}
ExplorerStyle::ExplorerStyle()
: QProxyStyle()
{
#ifdef Q_OS_WIN
QLibrary themeLib(QLatin1String("uxtheme"));
themeLib.load();
if (themeLib.isLoaded()) { //resolve uxtheme functions
pIsAppThemed = (PtrIsAppThemed)themeLib.resolve("IsAppThemed");
pDrawThemeBackground = (PtrDrawThemeBackground)themeLib.resolve("DrawThemeBackground");
pOpenThemeData = (PtrOpenThemeData)themeLib.resolve("OpenThemeData");
}
#endif
}
void drawRebarBackground(const QRect &rect, QPainter *painter) {
if (rect.isEmpty())
return;
QString cacheKey = QLatin1String("q_rebar_") + QString::number(rect.size().width())
+ QLatin1Char('x') + QString::number(rect.size().height());
QPixmap pixmap;
if (!QPixmapCache::find(cacheKey, pixmap)) {
pixmap = QPixmap(rect.size());
const RECT wRect = {0, 0, pixmap.width(), pixmap.height()};
HBITMAP bitmap = QtWin::toHBITMAP(pixmap);
HDC hdc = CreateCompatibleDC(qt_win_display_dc());
HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, bitmap);
HTHEME theme = pOpenThemeData(0, L"REBAR");
pDrawThemeBackground(theme, hdc, 0, 0, &wRect, NULL);
pixmap = QtWin::fromHBITMAP(bitmap);
SelectObject(hdc, oldhdc);
DeleteObject(bitmap);
DeleteDC(hdc);
QPixmapCache::insert(cacheKey, pixmap);
}
painter->drawPixmap(rect.topLeft(), pixmap);
}
void ExplorerStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
QRect rect = option->rect;
switch (element) {
case PE_Widget:
if (isAppThemed()) {
if (QMainWindow *window = qobject_cast<QMainWindow*>(widget->window())) {
QRegion topreg;
QRegion bottomreg;
QMenuBar *menubar = window->findChild<QMenuBar*>();
//We draw the menubar as part of the top toolbar area
if (menubar) {
QRect rect(menubar->mapToParent(menubar->rect().topLeft()), menubar->rect().size());
topreg += rect;
}
//We need the bounding rect for all toolbars
QList<QToolBar*> toolbars = window->findChildren<QToolBar*>();
foreach (const QToolBar *tb, toolbars) {
if (!tb->isFloating()) {
QRect rect(tb->mapToParent(tb->rect().topLeft()), tb->rect().size());
if (window->toolBarArea(const_cast<QToolBar*>(tb)) == Qt::TopToolBarArea)
topreg += rect;
else if (window->toolBarArea(const_cast<QToolBar*>(tb)) == Qt::BottomToolBarArea)
bottomreg += rect;
}
}
//This is a hack to workaround missing toolbar updates since
//we now require updates that span across the whole toolbar area:
QRect topRect = topreg.boundingRect();
topRect.setWidth(window->width());
if (m_currentTopRect != topRect) {
m_currentTopRect = topRect;
window->update(topRect);
}
QRect bottomRect = bottomreg.boundingRect();
bottomRect.setWidth(window->width());
if (m_currentBottomRect != bottomRect) {
m_currentBottomRect = bottomRect;
window->update(bottomRect);
}
//Fill top toolbar area with gradient
drawRebarBackground(topRect, painter);
//Fill bottom toolbar area with gradient
drawRebarBackground(bottomRect, painter);
}
break;
} //fall through
default:
QProxyStyle::drawPrimitive(element, option, painter, widget);
break;
}
}
void ExplorerStyle::drawControl(ControlElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
QColor shadow = option->palette.dark().color();
shadow.setAlpha(120);
switch (element) {
case CE_DockWidgetTitle:
if (isAppThemed()) {
if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget*>(option)) {
painter->save();
QStyleOptionDockWidget adjustedOpt = *dwOpt;
QRect rect = option->rect.adjusted(0, 1, -1, -2);
adjustedOpt.palette.setBrush(QPalette::All, QPalette::Dark, Qt::transparent);
painter->save();
painter->setClipRect(rect);
drawRebarBackground(rect.adjusted(0, 0, 1, 1), painter);
painter->restore();
painter->setPen(shadow);
painter->drawRect(rect);
QProxyStyle::drawControl(element, &adjustedOpt, painter, widget);
painter->restore();
}
break;
} //fall through
case CE_MenuBarItem:
if (isAppThemed()) {
if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem*>(option)) {
QStyleOptionMenuItem adjustedItem = *mbi;
adjustedItem.palette.setBrush(QPalette::All, QPalette::Dark, shadow);
adjustedItem.palette.setBrush(QPalette::All, QPalette::Button, Qt::NoBrush);
QProxyStyle::drawControl(element, &adjustedItem, painter, widget);
}
break;
} //fall through
case CE_MenuBarEmptyArea:
if (isAppThemed()) {
if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem*>(option)) {
QStyleOptionMenuItem adjustedItem = *mbi;
adjustedItem.palette.setBrush(QPalette::All, QPalette::Dark, shadow);
adjustedItem.palette.setBrush(QPalette::All, QPalette::Button, Qt::NoBrush);
QProxyStyle::drawControl(element, &adjustedItem, painter, widget);
}
break;
} //fall through
case CE_ToolBar:
if (isAppThemed()) {
if (const QStyleOptionToolBar *toolbar = qstyleoption_cast<const QStyleOptionToolBar*>(option)) {
QStyleOptionToolBar adjustedToolBar = *toolbar;
adjustedToolBar.palette.setBrush(QPalette::All, QPalette::Dark, shadow);
QProxyStyle::drawControl(element, &adjustedToolBar, painter, widget);
}
break;
} //fall through
default:
return QProxyStyle::drawControl(element, option, painter, widget);
break;
}
}
void ExplorerStyle::polish(QWidget *widget)
{
if (QMainWindow *window = qobject_cast<QMainWindow*>(widget))
window->setAttribute(Qt::WA_StyledBackground, true);
return QProxyStyle::polish(widget);
}
И как это выглядит в Windows 7: