Qt Creator源码分析系列——UI界面:Theme类

该篇文章内容主要集中Qt Creator软件界面部分代码的分析。从分析插件中的libs\utils中的theme模块开始,项目文件在路径\qt-creator-master\qt-creator-master\src\libs\utils\theme\下。

Theme类是创建主题和设置主题的类,其定义了Color、ImageFile、Gradient、Flag和WidgetStyle五个枚举类型,它们的成员定义了主题的方方面面的标志。在Theme类中有指向ThemePrivate类的指针,ThemePrivate类则用于存储主题的方方面面的标志的相应的具体内容。比如,对于Flag枚举类型来说,其定义了存放bool类型的Qvector,用于存放Flag相关成员各自对应的值(true或false)。ThemePrivate类中还定义了着一些其他的变量,如id、displayName等。所有这些值都需要Theme类提供getter和setter函数。

ThemePrivate类

class QTCREATOR_UTILS_EXPORT ThemePrivate
{
public:
    ThemePrivate();
    QString id;
    QString fileName;
    QString displayName;
    QStringList preferredStyles;
    QString defaultTextEditorColorScheme;
    QVector<QPair<QColor, QString> > colors;
    QVector<QString> imageFiles;
    QVector<QGradientStops> gradients;
    QVector<bool> flags;
    QMap<QString, QColor> palette;
};

QTCREATOR_UTILS_EXPORT void setCreatorTheme(Theme *theme);
QTCREATOR_UTILS_EXPORT void setThemeApplicationPalette();
ThemePrivate::ThemePrivate()
{
    const QMetaObject &m = Theme::staticMetaObject;
    colors.resize        (m.enumerator(m.indexOfEnumerator("Color")).keyCount());
    imageFiles.resize    (m.enumerator(m.indexOfEnumerator("ImageFile")).keyCount());
    gradients.resize     (m.enumerator(m.indexOfEnumerator("Gradient")).keyCount());
    flags.resize         (m.enumerator(m.indexOfEnumerator("Flag")).keyCount());
}

这里的Theme::staticMetaObject指代下面的有关Qt对象的元信息,使用QMetaObject常引用来访问。
在这里插入图片描述
在这里插入图片描述
查找枚举器名称并返回其索引; 否则返回-1。
在这里插入图片描述
返回具有给定索引的枚举数的元数据。
在这里插入图片描述
返回键数。

这里的代码就是根据Color、ImageFile、Gradient、Flag五个枚举类型中成员的数量设置相应QVector的大小。

// 根据Theme::Color枚举类型成员在colors数组上存放的QColor和QString的QPair对
QVector<QPair<QColor, QString> > colors; -->
colors.resize        (m.enumerator(m.indexOfEnumerator("Color")).keyCount());
// 根据Theme::ImageFile枚举类型成员在imageFiles数组相应位置上存放相应图片名
QVector<QString> imageFiles; -->
imageFiles.resize    (m.enumerator(m.indexOfEnumerator("ImageFile")).keyCount());
QVector<QGradientStops> gradients; -->
gradients.resize     (m.enumerator(m.indexOfEnumerator("Gradient")).keyCount());
// 根据Theme::Flag枚举类型成员在flags数组相应位置上存放相应开关
QVector<bool> flags; -->
flags.resize         (m.enumerator(m.indexOfEnumerator("Flag")).keyCount());

在这里插入图片描述
在这里插入图片描述

QVector<QGradientStops> --->
QVector<QVector<QGradientStop>> -->
QVector<QVector<QPair<qreal, QColor>>>

Theme类

Theme类继承自QObject类,其中定义了Color、ImageFile、Gradient、Flag和WidgetStyle五个枚举类型。还有一个ThemePrivate指针。

class QTCREATOR_UTILS_EXPORT Theme : public QObject
{
    Q_OBJECT
    Q_ENUMS(Color)
    Q_ENUMS(ImageFile)
    Q_ENUMS(Gradient)
    Q_ENUMS(Flag)
    Q_ENUMS(WidgetStyle)
public:
    Theme(const QString &id, QObject *parent = nullptr);
    ~Theme() override;

    enum Color {
        BackgroundColorAlternate,
        ...
        BackgroundColorDisabled,
        BadgeLabelBackgroundColorChecked,
        ...
        BadgeLabelTextColorUnchecked,
        CanceledSearchTextColor,
        ComboBoxArrowColor,
        ComboBoxArrowColorDisabled,
        ComboBoxTextColor,
        DetailsButtonBackgroundColorHover,
        DetailsWidgetBackgroundColor,
        DockWidgetResizeHandleColor,
        DoubleTabWidget1stSeparatorColor,
        ...
        DoubleTabWidget2ndTabInactiveTextColor,
        EditorPlaceholderColor,
        FancyToolBarSeparatorColor,
        ..
        FancyToolButtonSelectedColor,
        FutureProgressBackgroundColor,
        InfoBarBackground,
        InfoBarText,
        MenuBarEmptyAreaBackgroundColor,
        ...
        MenuItemTextColorNormal,
        MiniProjectTargetSelectorBackgroundColor, // TODO: Deprecate. -> Utils::StyleHelper().baseColor()
        ...
        MiniProjectTargetSelectorTextColor,
        OutputPaneButtonFlashColor,
        ...
        OutputPaneToggleButtonTextColorUnchecked,
        PanelStatusBarBackgroundColor,
        ...
        PanelTextColorLight,
        ProgressBarColorError,
        ...
        ProgressBarBackgroundColor,
        SplitterColor,
        TextColorDisabled,
        ...
        TextColorNormal,
        ToggleButtonBackgroundColor,
        ToolBarBackgroundColor,
        TreeViewArrowColorNormal,
        TreeViewArrowColorSelected,
        /* Palette for QPalette */
        PaletteWindow,
        ...
        /* Icons */
        IconsBaseColor,
        ...
        /* Code model Icons */
        IconsCodeModelKeywordColor,
        ...
        /* Code model text marks */
        CodeModel_Error_TextMarkColor,
        ...
        /* Output panes */
        OutputPanes_DebugTextColor,
        ...
        /* Debugger Log Window */
        Debugger_LogWindow_LogInput,
        ...
        /* Debugger Watch Item */
        Debugger_WatchItem_ValueNormal,
        ...
        /* Welcome Plugin */
        Welcome_TextColor,
        ...
        /* Timeline Library */
        Timeline_TextColor,
        ...
        /* VcsBase Plugin */
        VcsBase_FileStatusUnknown_TextColor,
        ...
        /* Bookmarks Plugin */
        Bookmarks_TextMarkColor,
        /* TextEditor Plugin */
        TextEditor_SearchResult_ScrollBarColor,
        TextEditor_CurrentLine_ScrollBarColor,
        /* Debugger Plugin */
        Debugger_Breakpoint_TextMarkColor,
        /* ProjectExplorer Plugin */
        ProjectExplorer_TaskError_TextMarkColor,
        ProjectExplorer_TaskWarn_TextMarkColor,
        /* QmlDesigner Plugin */
        QmlDesigner_BackgroundColor,
        ...
    };

    enum Gradient {
        DetailsWidgetHeaderGradient,
    };

    enum ImageFile {
        IconOverlayCSource,
        IconOverlayCppHeader,
        IconOverlayCppSource,
        IconOverlayPri,
        IconOverlayPrf,
        IconOverlayPro,
        StandardPixmapFileIcon,
        StandardPixmapDirIcon
    };

    enum Flag {
        DrawTargetSelectorBottom,
        DrawSearchResultWidgetFrame,
        DrawIndicatorBranch,
        DrawToolBarHighlights,
        DrawToolBarBorders,
        ComboBoxDrawTextShadow,
        DerivePaletteFromTheme,
        ApplyThemePaletteGlobally,
        FlatToolBars,
        FlatSideBarIcons,
        FlatProjectsMode,
        FlatMenuBar,
        ToolBarIconShadow,
        WindowColorAsBase,
        DarkUserInterface
    };

    Q_INVOKABLE bool flag(Flag f) const;
    Q_INVOKABLE QColor color(Color role) const;
    QString imageFile(ImageFile imageFile, const QString &fallBack) const;
    QGradientStops gradient(Gradient role) const;
    QPalette palette() const;
    QStringList preferredStyles() const;
    QString defaultTextEditorColorScheme() const;

    QString id() const;
    QString filePath() const;
    QString displayName() const;
    void setDisplayName(const QString &displayName);
    void readSettings(QSettings &settings);
    static QPalette initialPalette();

protected:
    Theme(Theme *originTheme, QObject *parent = nullptr);
    ThemePrivate *d;

private:
    friend QTCREATOR_UTILS_EXPORT Theme *creatorTheme();
    friend QTCREATOR_UTILS_EXPORT Theme *proxyTheme();
    QPair<QColor, QString> readNamedColor(const QString &color) const;
};

QTCREATOR_UTILS_EXPORT Theme *creatorTheme();
QTCREATOR_UTILS_EXPORT Theme *proxyTheme();

构造函数将新建ThemePrivate变量,并将形参中的id赋给ThemePrivate变量的id成员变量。还有一个构造函数是将其他主题originTheme复制到新Theme变量中,也就是拷贝ThemePrivate的内容。

Theme::Theme(const QString &id, QObject *parent) : QObject(parent), d(new ThemePrivate)
{
    d->id = id;
}
Theme::Theme(Theme *originTheme, QObject *parent) : QObject(parent)
    , d(new ThemePrivate(*(originTheme->d)))
{
}

这里定义一个静态Theme指针,全局只有一个该指针。

static Theme *m_creatorTheme = nullptr;  //静态变量
Theme *creatorTheme()  //返回Theme指针
{
    return m_creatorTheme;
}
Theme *proxyTheme()  //返回Theme变量
{
    return new Theme(m_creatorTheme);
}
void setCreatorTheme(Theme *theme)
{
    if (m_creatorTheme == theme)  //如果当前m_creatorTheme指向的主题和形参指向相同变量,则返回,否则切换
        return;
    delete m_creatorTheme;
    m_creatorTheme = theme;
#ifdef Q_OS_MACOS
    // Match the native UI theme and palette with the creator
    // theme by forcing light aqua for light creator themes.
    // 使原生UI主题和调色板与创建者匹配
    // 通过将light aqua强制为灯光创作者主题来实现主题。
    if (theme && !theme->flag(Theme::DarkUserInterface))
        Internal::forceMacOSLightAquaApperance();
#endif
    setThemeApplicationPalette();
}
void setThemeApplicationPalette()
{
    if (m_creatorTheme && m_creatorTheme->flag(Theme::ApplyThemePaletteGlobally))
    // 如果m_creatorTheme指定了主题变量,且主题标记了ApplyThemePaletteGlobally标志,就设置全局调色板
        QApplication::setPalette(m_creatorTheme->palette()); 
}

ThemePrivate类相关成员的getter函数(id、fileName、displayName、preferredStyles、)

QString Theme::id() const
{
    return d->id;
}
QString Theme::filePath() const
{
    return d->fileName;
}

displayName的setter和getter函数:

void Theme::setDisplayName(const QString &name)
{
    d->displayName = name;
}
QString Theme::displayName() const
{
    return d->displayName;
}
QStringList Theme::preferredStyles() const
{
    return d->preferredStyles;
}
QString Theme::defaultTextEditorColorScheme() const
{
    return d->defaultTextEditorColorScheme;
}
QColor Theme::color(Theme::Color role) const
{
    // 根据Theme::Color枚举类型成员找到colors数组上存放的QColor
    return d->colors[role].first;
}
QString Theme::imageFile(Theme::ImageFile imageFile, const QString &fallBack) const
{
	// 根据Theme::ImageFile枚举类型成员找到imageFiles数组上存放的图片名
    const QString &file = d->imageFiles.at(imageFile);
    return file.isEmpty() ? fallBack : file;
}
QGradientStops Theme::gradient(Theme::Gradient role) const
{
    return d->gradients[role];
}
bool Theme::flag(Theme::Flag f) const
{
    return d->flags[f];
}

下面的函数就是读命名颜色的函数,返回QPair<QColor, QString>。

QPair<QColor, QString> Theme::readNamedColor(const QString &color) const
{
    if (d->palette.contains(color))  //如果调色板中有该颜色,直接返回
        return qMakePair(d->palette[color], color);
    if (color == QLatin1String("style"))  //如果是style则直接返回空QPair
        return qMakePair(QColor(), QString());

    const QColor col('#' + color);  //使用'#' + color查询
    if (!col.isValid()) {
        qWarning("Color \"%s\" is neither a named color nor a valid color", qPrintable(color));
        return qMakePair(Qt::black, QString());  //颜色不对
    }
    return qMakePair(col, QString());  //返回颜色对
}

// 获取Theme的调色板

QPalette Theme::palette() const
{
    QPalette pal = initialPalette();
    //如果不从Theme中提取调色板,就返回系统调色板
    if (!flag(DerivePaletteFromTheme))
        return pal;

    const static struct {
        Color themeColor;
        QPalette::ColorRole paletteColorRole;
        QPalette::ColorGroup paletteColorGroup;
        bool setColorRoleAsBrush;
    } mapping[] = {
        {PaletteWindow,                    QPalette::Window,           QPalette::All,      false},
        {PaletteWindowDisabled,            QPalette::Window,           QPalette::Disabled, false},
        {PaletteWindowText,                QPalette::WindowText,       QPalette::All,      true},
        {PaletteWindowTextDisabled,        QPalette::WindowText,       QPalette::Disabled, true},
        {PaletteBase,                      QPalette::Base,             QPalette::All,      false},
        {PaletteBaseDisabled,              QPalette::Base,             QPalette::Disabled, false},
        {PaletteAlternateBase,             QPalette::AlternateBase,    QPalette::All,      false},
        {PaletteAlternateBaseDisabled,     QPalette::AlternateBase,    QPalette::Disabled, false},
        {PaletteToolTipBase,               QPalette::ToolTipBase,      QPalette::All,      true},
        {PaletteToolTipBaseDisabled,       QPalette::ToolTipBase,      QPalette::Disabled, true},
        {PaletteToolTipText,               QPalette::ToolTipText,      QPalette::All,      false},
        {PaletteToolTipTextDisabled,       QPalette::ToolTipText,      QPalette::Disabled, false},
        {PaletteText,                      QPalette::Text,             QPalette::All,      true},
        {PaletteTextDisabled,              QPalette::Text,             QPalette::Disabled, true},
        {PaletteButton,                    QPalette::Button,           QPalette::All,      false},
        {PaletteButtonDisabled,            QPalette::Button,           QPalette::Disabled, false},
        {PaletteButtonText,                QPalette::ButtonText,       QPalette::All,      true},
        {PaletteButtonTextDisabled,        QPalette::ButtonText,       QPalette::Disabled, true},
        {PaletteBrightText,                QPalette::BrightText,       QPalette::All,      false},
        {PaletteBrightTextDisabled,        QPalette::BrightText,       QPalette::Disabled, false},
        {PaletteHighlight,                 QPalette::Highlight,        QPalette::All,      true},
        {PaletteHighlightDisabled,         QPalette::Highlight,        QPalette::Disabled, true},
        {PaletteHighlightedText,           QPalette::HighlightedText,  QPalette::All,      true},
        {PaletteHighlightedTextDisabled,   QPalette::HighlightedText,  QPalette::Disabled, true},
        {PaletteLink,                      QPalette::Link,             QPalette::All,      false},
        {PaletteLinkDisabled,              QPalette::Link,             QPalette::Disabled, false},
        {PaletteLinkVisited,               QPalette::LinkVisited,      QPalette::All,      false},
        {PaletteLinkVisitedDisabled,       QPalette::LinkVisited,      QPalette::Disabled, false},
        {PaletteLight,                     QPalette::Light,            QPalette::All,      false},
        {PaletteLightDisabled,             QPalette::Light,            QPalette::Disabled, false},
        {PaletteMidlight,                  QPalette::Midlight,         QPalette::All,      false},
        {PaletteMidlightDisabled,          QPalette::Midlight,         QPalette::Disabled, false},
        {PaletteDark,                      QPalette::Dark,             QPalette::All,      false},
        {PaletteDarkDisabled,              QPalette::Dark,             QPalette::Disabled, false},
        {PaletteMid,                       QPalette::Mid,              QPalette::All,      false},
        {PaletteMidDisabled,               QPalette::Mid,              QPalette::Disabled, false},
        {PaletteShadow,                    QPalette::Shadow,           QPalette::All,      false},
        {PaletteShadowDisabled,            QPalette::Shadow,           QPalette::Disabled, false}
    };

    for (auto entry: mapping) {
        const QColor themeColor = color(entry.themeColor);
        // Use original color if color is not defined in theme.
        // 如果在theme中定义了颜色,而original的调色盘中没有
        if (themeColor.isValid()) {
            if (entry.setColorRoleAsBrush)
                // TODO: Find out why sometimes setBrush is used
                pal.setBrush(entry.paletteColorGroup, entry.paletteColorRole, themeColor);
            else
                pal.setColor(entry.paletteColorGroup, entry.paletteColorRole, themeColor);
        }
    }

    return pal;
}

// 获取系统调色板

QPalette Theme::initialPalette()
{
    static QPalette palette = QApplication::palette();
    return palette;
}

关键函数readSettings

readSettings函数中绝大多数代码是对QSettings操作。那么先看看QSettings提供的功能。
QSettings类提供与平台无关的持久性应用程序设置。用户通常希望应用程序在整个会话中记住其设置(窗口大小和位置,选项等)。此信息通常存储在Windows上的系统注册表中,以及macOS和iOS上的属性列表文件中。在Unix系统上,在没有标准的情况下,许多应用程序(包括KDE应用程序)都使用INI文本文件。QSettings是围绕这些技术的抽象,使您能够以可移植的方式保存和恢复应用程序设置。 它还支持自定义存储格式。QSettings的API基于QVariant,使您可以省力地保存大多数基于值的类型,例如QString,QRect和QImage。如果您需要的只是一个基于非持久性内存的结构,请考虑改用QMap <QString,QVariant>。
创建QSettings对象时,必须传递公司或组织的名称以及应用程序的名称。 例如,如果您的产品称为Star Runner,而您的公司称为MySoft,则可以按以下方式构造QSettings对象:QSettings settings("MySoft", "Star Runner");
QSettings对象可以在堆栈或堆上创建(即使用new)。 构造和销毁QSettings对象非常快。如果您从应用程序中的许多地方使用QSettings,则可能要使用QCoreApplication :: setOrganizationName()和QCoreApplication :: setApplicationName()来指定组织名称和应用程序名称,然后使用默认的QSettings构造函数:

QCoreApplication::setOrganizationName("MySoft");
QCoreApplication::setOrganizationDomain("mysoft.com");
QCoreApplication::setApplicationName("Star Runner");
 ...
QSettings settings;

(在此,我们还指定了组织的Internet域。设置了Internet域后,它会在macOS和iOS上使用,而不是在组织名称上使用,因为macOS和iOS应用程序通常会使用Internet域来标识自己。如果未设置任何域, 假域名来自组织名称。有关详细信息,请参见下面的“特定于平台的说明”。)
QSettings存储设置。每个设置都由一个QString和一个QVariant组成,该QString指定设置的名称(键),该QVariant存储与该键关联的数据。要编写设置,请使用setValue()。 例如:settings.setValue("editor/wrapMargin", 68);
如果已经存在具有相同键的设置,则现有值将被新值覆盖。 为了提高效率,更改可能不会立即保存到永久存储中。 (您始终可以调用sync()提交更改。)
您可以使用value()返回设置的值:int margin = settings.value("editor/wrapMargin").toInt();
如果没有具有指定名称的设置,则QSettings返回一个空QVariant(可以将其转换为整数0)。 您可以通过将第二个参数传递给value()来指定另一个默认值:int margin = settings.value("editor/wrapMargin", 80).toInt();
要测试给定密钥是否存在,请调用contains()。 要删除与键关联的设置,请调用remove()。 要获取所有键的列表,请调用allKeys()。 要删除所有键,请调用clear()。
由于QVariant是Qt Core模块的一部分,因此它无法提供对Qt GUI的一部分的数据类型(例如QColor,QImage和QPixmap)的转换功能。 换句话说,在QVariant中没有toColor(),toImage()或toPixmap()函数。
相反,您可以使用QVariant :: value()或qVariantValue()模板函数。 例如:

QSettings settings("MySoft", "Star Runner");
QColor color = settings.value("DataPump/bgcolor").value<QColor>();

对于QVariant支持的所有数据类型,包括与GUI相关的类型,将自动进行逆转换(例如,从QColor到QVariant):

QSettings settings("MySoft", "Star Runner");
QColor color = palette().background().color();
settings.setValue("DataPump/bgcolor", color);

可以使用QSettings存储使用qRegisterMetaType()和qRegisterMetaTypeStreamOperators()注册的自定义类型。
设置键可以包含任何Unicode字符。 Windows注册表和INI文件使用不区分大小写的键,而macOS和iOS上的CFPreferences API使用区分大小写的键。 为避免可移植性问题,请遵循以下简单规则:

  1. 始终使用相同的大小写引用相同的键。 例如,如果在代码的某个位置将键称为“
    text fonts”,则不要在其他地方将其称为“
    Text Fonts”。
  2. 除情况外,请避免使用相同的键名。 例如,如果您有一个名为“ MainWindow”的键,请不要尝试将另一个键另存为“ mainwindow”。
  3. 在节或键名中不要使用斜杠(“ /”和“ \”); 反斜杠字符用于分隔子键(请参见下文)。 在Windows上,QSettings将“ \”转换为“ /”,从而使它们相同。
    您可以使用’/'字符作为分隔符来形成分层键,类似于Unix文件路径。 例如:
settings.setValue("mainwindow/size", win->size());
settings.setValue("mainwindow/fullScreen", win->isFullScreen());
settings.setValue("outputpanel/visible", panel->isVisible());

如果要保存或还原具有相同前缀的许多设置,则可以使用beginGroup()指定前缀,并在末尾调用endGroup()。 这再次是相同的示例,但是这次使用组机制:

settings.beginGroup("mainwindow");
settings.setValue("size", win->size());
settings.setValue("fullScreen", win->isFullScreen());
settings.endGroup();

settings.beginGroup("outputpanel");
settings.setValue("visible", panel->isVisible());
settings.endGroup();

如果使用beginGroup设置了一个组,则大多数函数的行为都会改变。 可以递归设置组。除组外,QSettings还支持“数组array”概念。 有关详细信息,请参见beginReadArray()和beginWriteArray()。

假设您创建了一个QSettings对象,其组织名称为MySoft,应用程序名称为Star Runner。 当您查找一个值时,将按该顺序最多搜索四个位置:Star Runner应用程序的用户特定位置、MySoft所有应用程序的用户特定位置、Star Runner应用程序在系统范围内的位置、MySoft在所有应用程序的系统范围内的位置。
(有关Qt支持的不同平台上这些位置的信息,请参阅下面的特定于平台的说明。)
如果在第一个位置找不到key,则在第二个位置继续搜索,依此类推。 这使您可以存储系统范围或组织范围的设置,并可以基于每个用户或每个应用程序覆盖它们。 要关闭此机制,请调用setFallbacksEnabled(false)。
尽管可以从所有四个位置读取key,但是只能访问第一个文件(应用程序的用户特定位置)进行写入。 要写入任何其他文件,请省略应用程序名称和/或指定QSettings :: SystemScope(与默认设置QSettings :: UserScope相对)。

QSettings obj1("MySoft", "Star Runner");
QSettings obj2("MySoft");
QSettings obj3(QSettings::SystemScope, "MySoft", "Star Runner");
QSettings obj4(QSettings::SystemScope, "MySoft");

下表总结了哪些QSettings对象访问哪个位置。 “ X”表示该位置是与QSettings对象关联的主要位置,并且用于读取和写入。 “ o”表示该位置在读取时用作备用。
在这里插入图片描述
这种机制的优点在于,它可以在Qt支持的所有平台上运行,并且仍然为您提供了很大的灵活性,而无需您指定任何文件名或注册表路径。
如果要在所有平台上使用INI文件而不是本机API,则可以将QSettings :: IniFormat作为第一个参数传递给QSettings构造函数,然后是范围,组织名称和应用程序名称:

  QSettings settings(QSettings::IniFormat, QSettings::UserScope, "MySoft", "Star Runner");

QSettings通常用于存储GUI应用程序的状态。 下面的示例说明如何使用QSettings保存和还原应用程序主窗口的几何。

void MainWindow::writeSettings()
  {
      QSettings settings("Moose Soft", "Clipper");
      settings.beginGroup("MainWindow");
      settings.setValue("size", size());
      settings.setValue("pos", pos());
      settings.endGroup();
  }

  void MainWindow::readSettings()
  {
      QSettings settings("Moose Soft", "Clipper");
      settings.beginGroup("MainWindow");
      resize(settings.value("size", QSize(400, 400)).toSize());
      move(settings.value("pos", QPoint(200, 200)).toPoint());
      settings.endGroup();
  }

有关为什么最好调用QWidget :: resize()和QWidget :: move()而不是QWidget :: setGeometry()来恢复窗口几何的讨论,请参见窗口几何。必须从主窗口的构造函数和close事件处理程序中调用readSettings()和writeSettings()函数,如下所示:

MainWindow::MainWindow()
{
      ...
    readSettings();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
    if (userReallyWantsToQuit()) {
        writeSettings();
        event->accept();
    } else {
        event->ignore();
    }
}

同时从多个线程或进程访问设置
QSettings是可重入的。这意味着您可以同时在不同的线程中使用不同的QSettings对象。即使QSettings对象引用磁盘上的相同文件(或系统注册表中的相同条目),该保证仍然有效。如果通过一个QSettings对象修改了设置,则该更改将立即在任何在同一位置运行且处于同一进程中的其他QSettings对象中可见。
可以安全地从不同的进程(可以是同时运行的应用程序的不同实例,也可以是不同的应用程序的不同实例)中使用QSettings来读写相同的系统位置。 它使用咨询文件锁定和智能合并算法(advisory file locking and a smart merging algorithm)来确保数据完整性。请注意,sync()导入其他进程所做的更改(除了从此QSettings中写入更改之外)。

QSettings会将应用程序的设置最多存储在四个位置,具体取决于设置是用户特定的还是系统范围的,以及设置是特定于应用程序的还是组织范围的。 为了简单起见,我们假设组织名为MySoft,应用程序称为Star Runner。
在Unix系统上,如果文件格式为NativeFormat,则默认使用以下文件:
在这里插入图片描述
在macOS版本10.2和10.3上,默认情况下使用以下文件:
在这里插入图片描述
在Windows上,NativeFormat设置存储在以下注册表路径中:
在这里插入图片描述
如果文件格式为NativeFormat,则在应用程序的主目录中为“ Settings / MySoft / Star Runner.conf”。
如果文件格式为IniFormat,则在Unix,macOS和iOS上使用以下文件:
在这里插入图片描述
在Windows上,使用以下文件:
在这里插入图片描述
以FOLDERID_为前缀的标识符是特殊项目ID列表,将传递给Win32 API函数SHGetKnownFolderPath()以获得相应的路径。
FOLDERID_RoamingAppData通常指向C:\ Users \ User Name \ AppData \ Roaming,也由环境变量%APPDATA%显示。
FOLDERID_ProgramData通常指向C:\ ProgramData。
如果文件格式为IniFormat,则在应用程序的主目录中为“ Settings / MySoft / Star Runner.ini”。
.ini和.conf文件的路径可以使用setPath()进行更改。 在Unix,macOS和iOS上,用户可以通过设置XDG_CONFIG_HOME环境变量来覆盖它们。 有关详细信息,请参见setPath()。

void Theme::readSettings(QSettings &settings)
{
	const QMetaObject &m = *metaObject();
	// 从QSettings中读取fileName、displayname、preferredStyles、DefaultTextEditorColorScheme
		// fileName -> fileName
		// ThemeName -> displayname 
		// PreferredStyles -> preferredStyles
		// DefaultTextEditorColorScheme -> DefaultTextEditorColorScheme
    	d->fileName = settings.fileName();  
        d->displayName = settings.value(QLatin1String("ThemeName"), QLatin1String("unnamed")).toString();
        d->preferredStyles = settings.value(QLatin1String("PreferredStyles")).toStringList();
        // 从QList中去除null string
        d->preferredStyles.removeAll(QString());
        d->defaultTextEditorColorScheme = settings.value(QLatin1String("DefaultTextEditorColorScheme")).toString();

	// 从QSettings中读取palette
	    // <Palette/****, QColor>
        settings.beginGroup(QLatin1String("Palette"));
        foreach (const QString &key, settings.allKeys())
            d->palette[key] = readNamedColor(settings.value(key).toString()).first;
        settings.endGroup();
        
    {
        settings.beginGroup(QLatin1String("Colors"));
        QMetaEnum e = m.enumerator(m.indexOfEnumerator("Color"));
        for (int i = 0, total = e.keyCount(); i < total; ++i) {
            const QString key = QLatin1String(e.key(i));
            if (!settings.contains(key)) {
                if (i < PaletteWindow || i > PaletteShadowDisabled)
                    qWarning("Theme \"%s\" misses color setting for key \"%s\".",
                             qPrintable(d->fileName), qPrintable(key));
                continue;
            }
            d->colors[i] = readNamedColor(settings.value(key).toString());
        }
        settings.endGroup();
    }
    {
        settings.beginGroup(QLatin1String("ImageFiles"));
        QMetaEnum e = m.enumerator(m.indexOfEnumerator("ImageFile"));
        for (int i = 0, total = e.keyCount(); i < total; ++i) {
            const QString key = QLatin1String(e.key(i));
            d->imageFiles[i] = settings.value(key).toString();
        }
        settings.endGroup();
    }
    {
        settings.beginGroup(QLatin1String("Gradients"));
        QMetaEnum e = m.enumerator(m.indexOfEnumerator("Gradient"));
        for (int i = 0, total = e.keyCount(); i < total; ++i) {
            const QString key = QLatin1String(e.key(i));
            QGradientStops stops;
            int size = settings.beginReadArray(key);
            for (int j = 0; j < size; ++j) {
                settings.setArrayIndex(j);
                QTC_ASSERT(settings.contains(QLatin1String("pos")), return);
                const double pos = settings.value(QLatin1String("pos")).toDouble();
                QTC_ASSERT(settings.contains(QLatin1String("color")), return);
                const QColor c('#' + settings.value(QLatin1String("color")).toString());
                stops.append(qMakePair(pos, c));
            }
            settings.endArray();
            d->gradients[i] = stops;
        }
        settings.endGroup();
    }
    {
        settings.beginGroup(QLatin1String("Flags"));
        QMetaEnum e = m.enumerator(m.indexOfEnumerator("Flag"));
        for (int i = 0, total = e.keyCount(); i < total; ++i) {
            const QString key = QLatin1String(e.key(i));
            QTC_ASSERT(settings.contains(key), return);;
            d->flags[i] = settings.value(key).toBool();
        }
        settings.endGroup();
    }
}

在这里插入图片描述
返回存储使用此QSettings对象写入的设置的路径。在Windows上,如果格式为QSettings :: NativeFormat,则返回值是系统注册表路径,而不是文件路径。

发布了134 篇原创文章 · 获赞 141 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/asmartkiller/article/details/104366723