Qt基础 | 自定义界面组件 | 提升法 | 为UI设计器设计自定义界面组件的Widget插件 | MSVC2019编译器中文乱码问题

news2024/11/25 16:37:15

文章目录

  • 一、自定义 Widget 组件
    • 1.自定义 Widget 子类
    • 2.自定义 Widget 组件的使用
  • 二、自定义 Qt Designer 插件
    • 1.创建 Qt Designer Widget 插件项目
    • 2.插件项目各文件的功能实现
    • 3.插件的编译与安装
    • 4.使用自定义插件
    • 5.使用 MSVC 编译器输出中文的问题

一、自定义 Widget 组件

  当 Qt 提供的界面组件不满足实际设计需求时,可以从 QWidget 继承自定义界面组件。有两种方法使用自定义界面组件:

  • 一种是提升法,将 Qt 提供的 UI 组件提升为自定义的类,提升法用于界面设计时不够直观,不能再界面上即可显示自定义组件的效果
  • 另一种是为 UI 设计器设计自定义界面组件的 Widget 插件,直接安装到 UI 设计器的组件面板里,这种方法在设计时就能看到组件的实际显示效果,只是在编译和运行时需要使用到插件的动态链接库(Windows平台上)。

1.自定义 Widget 子类

  Qt 的 UI 设计器提供了很多 GUI 设计的界面组件,可以满足常见的界面设计需求。但是某些时候需要设计特殊的界面组件,而在 UI 设计器的组件面板里根本没有合适的组件,这时就需要设计自定义的界面组件。

  所有界面组件的基类是 QWidget,要设计自定义的界面组件,可以从 QWidget 继承一个自定义的类,重定义其 paintEvent() 事件,利用 Qt 绘图功能绘制组件外观,并实现需要的其他功能。

  例如,要设计一个电池电量显示组件,用于电池使用或充电时显示其电量,由于 UI 设计器的组件面板中没有这样一个现成的组件,因此,就需要设计一个自定义的 Widget 组件。

qmybattery.h

#ifndef WBATTERY_H
#define WBATTERY_H

#include    <QWidget>
#include    <QColor>

class QmyBattery : public QWidget
{
    Q_OBJECT
//自定义属性
    Q_PROPERTY(int  powerLevel READ powerLevel WRITE setPowerLevel NOTIFY powerLevelChanged)

private:
    QColor  mColorBack=Qt::white;//背景颜色
    QColor  mColorBorder=Qt::black;//电池边框颜色
    QColor  mColorPower=Qt::green;//电量柱颜色
    QColor  mColorWarning=Qt::red;//电量短缺时的颜色

    int mPowerLevel=60;//电量0-100
    int mWarnLevel=20;//电量低警示阈值

protected:
    void    paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;

public:
    explicit QmyBattery(QWidget *parent = 0);

    void    setPowerLevel(int pow);//设置当前电量
    int     powerLevel();
    void    setWarnLevel(int warn);//设置电量低阈值
    int     warnLevel();
    QSize   sizeHint();//报告缺省大小

signals:
    void   powerLevelChanged(int );

public slots:
};

#endif // WBATTERY_H

私有变量:

  • 各种颜色定义
  • 当前电量值与电量低阈值

函数:

  • painterEvent():使用 QPianter 的绘图功能来绘制界面
  • powerLevel()setPowerLevel() :读取与设置当前电量值
  • warnLevel()setWarnLevel() :读取与设置电量低阈值
  • sizeHint():获得组件的缺省大小

信号:

  • powerLevelChanged():在当前电量值发生改变时,发射该信号。

qmybattery.cpp

  在绘图事件中使用了窗口坐标定义来绘图,而不用管实际的物理坐标范围的大小。当绘图设备大小变化时, 绘制的图形会自动变化大小。这样,就可以将绘图功能与绘图设备隔开来,使得绘图功能用于不同大小、不同类型的设备。即可实现当组件大小变化时,绘制的电池大小也会自动变化。

#include "qmybattery.h"

#include    <QPainter>

void QmyBattery::paintEvent(QPaintEvent *event)
{  //界面组件的绘制
    Q_UNUSED(event);

    QPainter    painter(this);
    QRect rect(0,0,width(),height()); //viewport矩形区
    painter.setViewport(rect);//设置Viewport
    painter.setWindow(0,0,120,50); // 设置窗口大小,逻辑坐标
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::TextAntialiasing);

    //绘制电池边框
    QPen    pen;//设置画笔
    pen.setWidth(2); //线宽
    pen.setColor(mColorBorder); //划线颜色
    pen.setStyle(Qt::SolidLine);//线的类型,实线、虚线等
    pen.setCapStyle(Qt::FlatCap);//线端点样式
    pen.setJoinStyle(Qt::BevelJoin);//线的连接点样式
    painter.setPen(pen);

    QBrush  brush;//设置画刷
    brush.setColor(mColorBack); //画刷颜色--白色
    brush.setStyle(Qt::SolidPattern); //画刷填充样式
    painter.setBrush(brush);

    //绘制电池边框
    rect.setRect(1,1,109,48);
    painter.drawRect(rect);

    //画电池正极头
    brush.setColor(mColorBorder); //画刷颜色--黑色
    painter.setBrush(brush);
    rect.setRect(110,15,10,20);
    painter.drawRect(rect);

    //画电池柱
    if (mPowerLevel>mWarnLevel)
    {  //正常颜色电量柱
        brush.setColor(mColorPower); //画刷颜色--绿色
        pen.setColor(mColorPower); //划线颜色
    }
    else
    { //电量低电量柱
        brush.setColor(mColorWarning); //画刷颜色--红色
        pen.setColor(mColorWarning); //划线颜色
    }
    painter.setBrush(brush);
    painter.setPen(pen);

    if (mPowerLevel>0)
    {
        rect.setRect(5,5,mPowerLevel,40);
        painter.drawRect(rect);//画电池柱
    }

    //绘制电量百分比文字
    QFontMetrics    textSize(this->font());
    QString powStr=QString::asprintf("%d%%",mPowerLevel);
    QRect textRect=textSize.boundingRect(powStr);//得到字符串的rect

    painter.setFont(this->font());
    pen.setColor(mColorBorder); //划线颜色
    painter.setPen(pen);

    painter.drawText(55-textRect.width()/2,
               23+textRect.height()/2,
               powStr);
}

QmyBattery::QmyBattery(QWidget *parent) : QWidget(parent)
{
//    setPalette(QPalette(mColorBack));
//    setAutoFillBackground(true);
//    this->resize(120,50);
}

void QmyBattery::setPowerLevel(int pow)
{ //设置当前电量值
    mPowerLevel=pow;
    emit powerLevelChanged(pow); //触发信号
    repaint();  //直接触发重绘
}

int QmyBattery::powerLevel()
{ //读取当前电量值
    return mPowerLevel;
}

void QmyBattery::setWarnLevel(int warn)
{//设置电量低阈值
    mWarnLevel=warn;
    repaint();
}

int QmyBattery::warnLevel()
{//读取电量低阈值
    return  mWarnLevel;
}

QSize QmyBattery::sizeHint()
{//报告缺省大小,调整比例
    int H=this->height();
    int W=H*12/5;
    QSize   size(W,H);
    return size;
}

2.自定义 Widget 组件的使用

  实现了 QmyBattery 类之后, 若是用代码创建 QmyBattery 类对象,其使用与一般的组件类是一样的;若是在 UI 设计器中使用 QmyBattery,需要采用提升法(promotion)。

  使用 UI 设计器设计主窗体时,在窗体上放置一个 QWidegt 类组件,然后鼠标右键调出其快捷菜单,单击 “Promote to” 菜单项 ,出现如下对话框:

image-20240724214306376

如下设置后,单击“提升”按钮,就可以将此 QWidget 组件提升为 QmyBattery类。

  虽然界面上放置的 QWidget 组件被提升为 QmyBattery 类,但是在这个组件 “Go to slot” 对话框里并没有 QmyBattery 类的 powerLevelChanged(int)信号, 无法采用可视化方法生成信号的槽函数。

image-20240724214716064

  设置一个滑动标尺组件,当滑动标尺滑动时,发出valueChanged(int)信号,在其关联槽函数里使用 setPowerLevel() 函数设置当前电量的值,并使用 repaint() 函数直接触发重绘事件。

void Widget::on_horizontalSlider_valueChanged(int value)
{
   ui->battery->setPowerLevel(value);
   QString  str=QStringLiteral("当前电量:")+QString::asprintf("%d %%",value);
   ui->LabInfo->setText(str);
}

二、自定义 Qt Designer 插件

1.创建 Qt Designer Widget 插件项目

  Qt 提供了两种设计插件的 API,可以用于扩展 Qt 的功能。

  • 高级 API 用于设计插件以扩展 Qt 的功能,例如定制数据库驱动、图像格式、文本编码、定制样式等,Qt Creator 里大量采用了插件,单击 Qt Creator 的主菜单栏的 “Help” —> “About Plugins” 菜单项,会显示 Qt Creator 里已经安装的各种插件。
  • 低级 API 用于创建插件以扩展自己编写应用程序的功能,最常见的就是将自定义 Widget 组件安装到 UI 设计器里,用于窗口界面设计。

  本小节采用创建 Qt Designer 插件的方式来创建这个类,并将其安装到 UI 设计器的组件面板里。

创建步骤

  • 单击 Qt Creator 的 “File” —> “New File or Project” 菜单,在出现的对话框里选择 “Other Project” 分组的 “Qt Custom Designer Widget” 项目,出现一个向导对话框

    image-20240725131803693

  • 设置插件项目的名称和保存路径,

    image-20240725131943724

  • 选择项目编译器,可以选择多个编译器,在编译时,再选择具体的编译器。

    注意:使用 Qt 创建的 Widget 插件,若要在 Qt Creator 的 UI 设计器里正常显示,编译插件的编译器版本必须和编译 Qt Creator 的版本一致

    image-20240725132213513

  • 设置自定义 QWidget 类的名称,只需在左侧的 Widget classes 列表里设置类名,右侧就会自动设置缺省的文件名,这里添加一个类 QwBattery。还可以选择一个图标文件作为自定义组件在 UI 设计器组件面板里的显示图标。

    image-20240725135419953

    在 “说明” 页还可以设置 Group、Tooltip 和 What’s this等信息,Group 是自定义组件在组件面板里的分组名称,这里设置为 “My Widget”

    image-20240725133109186

  • 接下来,显示和设置插件名称、资源文件名称。这里插件名称设置为 qwbatteryplugin,资源文件名称为 icons.qrc,一般用缺省的即可。

    image-20240725133315016

  • 完成设置,生成项目。项目文件组织结构如下:

    image-20240725135459899

    • QwBatteryPlugin.pro:是插件项目的项目文件,用于实现插件接口
    • qwbatteryplugin.h 和 qwbatteryplugin.cpp 是插件的头文件和实现文件
    • icons.qrc 是插件项目的资源文件,存储了图标
    • qwbattery.pri 是包含在 QwBatteryPlugin.pro 项目中的一个项目文件,用于自定义组件类
    • qwbattery.h 和 qwbattery.cpp 是自定义类 QwBattery 的头文件和实现文件。

2.插件项目各文件的功能实现

QwBatteryPlugin.pro

CONFIG      += plugin debug_and_release
TARGET      = $$qtLibraryTarget(qwbatteryplugin)
TEMPLATE    = lib

HEADERS     = qwbatteryplugin.h
SOURCES     = qwbatteryplugin.cpp
RESOURCES   = icons.qrc
LIBS        += -L. 

greaterThan(QT_MAJOR_VERSION, 4) {
    QT += designer
} else {
    CONFIG += designer
}

target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS    += target

include(qwbattery.pri)
  • CONFIG 是用于 qmake 编译设置的,这里配置为CONFIG += plugin debug_and_release
    • plugin 表示项目要作为插件,编译后只会产生 lib 和 dll(或.so)文件,
    • debug_and_release 表示项目可以用 debug 和 release 模式编译
  • TEMPLATE 定义项目的类型,这里配置为TEMPLATE = lib
    • lib 表示项目是一个库
    • 一般的应用程序模版类型是 app

qwbatteryplugin.h:对插件类 QwBatteryPlugin 的定义

#ifndef QWBATTERYPLUGIN_H
#define QWBATTERYPLUGIN_H

#include <QDesignerCustomWidgetInterface>

class QwBatteryPlugin : public QObject, public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_INTERFACES(QDesignerCustomWidgetInterface)
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")

public:
    explicit QwBatteryPlugin(QObject *parent = nullptr);
	//有关插件信息或功能的函数,很多内容会根据创建插件向导里设置的内容自动生成
    bool isContainer() const override;
    bool isInitialized() const override;
    QIcon icon() const override;
    QString domXml() const override;
    QString group() const override;
    QString includeFile() const override;
    QString name() const override;
    QString toolTip() const override;
    QString whatsThis() const override;
    QWidget *createWidget(QWidget *parent) override;
    void initialize(QDesignerFormEditorInterface *core) override;

private:
    bool m_initialized = false;
};

#endif // QWBATTERYPLUGIN_H

QwBatteryPlugin 类实现了 QDesignerCustomWidgetInterface 接口,这是专门为 Qt Designer 设计自定义 Widget 组件的接口。

宏声明:

  • 使用了 Q_INTERFACES 宏声明了实现的接口,
  • 使用了 Q_PLUGIN_METADATA 宏声明了元数据名称,这些都无需改动。

公有函数:

  • 有关插件信息或功能的函数,很多内容会根据创建插件向导里设置的内容自动生成
  • createWidget() 函数创建一个 QwBattery 类的示例,在 UI 设计器里作为设计实例;
  • name() 函数返回组件的类名称
  • group() 函数设置组件安装在面板的分组名称
  • icon() 函数设置组件的图标
  • isContainer() 函数设置组件是否作为容器,false表示不作为容器,不能在这个组件上放置其他组件
  • domXml() 函数用 XML 设置组件的一些属性,缺省的只设置了类型和实例名

qwbatteryplugin.cpp

#include "qwbattery.h"
#include "qwbatteryplugin.h"

#include <QtPlugin>

QwBatteryPlugin::QwBatteryPlugin(QObject *parent)
    : QObject(parent)
{
    m_initialized = false;
}

void QwBatteryPlugin::initialize(QDesignerFormEditorInterface * /* core */)
{
    if (m_initialized)
        return;

    m_initialized = true;
}

bool QwBatteryPlugin::isInitialized() const
{//是否初始化
    return m_initialized;
}

QWidget *QwBatteryPlugin::createWidget(QWidget *parent)
{//返回自定义Widget组件的实例
    return new QwBattery(parent);
}

QString QwBatteryPlugin::name() const
{//自定义Widget组件类的名称
    return QLatin1String("QwBattery");
}

QString QwBatteryPlugin::group() const
{//在组件面板中所属分组名称
    return QLatin1String("MyWidget");
}

QIcon QwBatteryPlugin::icon() const
{//图标文件名
    return QIcon(QLatin1String(":/44.ico"));
}

QString QwBatteryPlugin::toolTip() const
{//toolTip信息
    return QLatin1String("Battery charger indicator");
}

QString QwBatteryPlugin::whatsThis() const
{//whatsThis 信息
    return QLatin1String("A battery charger indicator");
}

bool QwBatteryPlugin::isContainer() const
{ //是否作为容器, false表示该组件上不允许再放其他组件
    return false;
}

QString QwBatteryPlugin::domXml() const
{//XML文件描述信息
    return QLatin1String("<widget class=\"QwBattery\" name=\"qwBattery\">\n</widget>\n");
}

QString QwBatteryPlugin::includeFile() const
{//包含文件名
    return QLatin1String("qwbattery.h");
}
#if QT_VERSION < 0x050000
Q_EXPORT_PLUGIN2(qwbatteryplugin, QwBatteryPlugin)
#endif // QT_VERSION < 0x050000

qwbattery.h

#ifndef WBATTERY_H
#define WBATTERY_H

#include <QtUiPlugin/QDesignerExportWidget>
//#include <QDesignerExportWidget>

#include    <QWidget>
#include    <QColor>

class QDESIGNER_WIDGET_EXPORT QwBattery : public QWidget
{
    Q_OBJECT
//自定义属性
    Q_PROPERTY(int  powerLevel READ powerLevel WRITE setPowerLevel NOTIFY powerLevelChanged DESIGNABLE true)

private:
    QColor  mColorBack=Qt::white;//背景颜色
    QColor  mColorBorder=Qt::black;//电池边框颜色
    QColor  mColorPower=Qt::green;//电量柱颜色
    QColor  mColorWarning=Qt::red;//电量短缺时的颜色

    int mPowerLevel=60;//电量0-100
    int mWarnLevel=20;//电量低警示阈值

protected:
    void    paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;

public:
    explicit QwBattery(QWidget *parent = 0);

    void    setPowerLevel(int pow);//设置当前电量
    int     powerLevel();
    void    setWarnLevel(int warn);//设置电量低阈值
    int     warnLevel();
    QSize   sizeHint();//报告缺省大小

signals:
    void   powerLevelChanged(int );

public slots:
};

#endif // WBATTERY_H
  • QDESIGNER_WIDGET_EXPORT 宏用于将自定义组件类从插件导出给 Qt Designer 使用,必须在类名称前使用此宏
  • Q_PROPERTY 宏用于定义属性,这里定义了 int 型的属性 powerLevel。READ 宏声明了属性的读取函数是 powerLevel();WRlTE 宏声明了设置属性值的函数是 setPowerLevel();NOTIFY 宏声明了其值变化时发射的信号是 powerLevelChanged(); DESIGNABLE 宏定义属性在 Ul 设计器是否可见,缺省为 true。

qwbattery.cpp

#include "qwbattery.h"

#include    <QPainter>

void QwBattery::paintEvent(QPaintEvent *event)
{  //界面组件的绘制
    Q_UNUSED(event);

    QPainter    painter(this);
    QRect rect(0,0,width(),height()); //viewport矩形区
    painter.setViewport(rect);//设置Viewport
    painter.setWindow(0,0,120,50); // 设置窗口大小,逻辑坐标
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::TextAntialiasing);

//绘制电池边框
    QPen    pen;//设置画笔
    pen.setWidth(2); //线宽
    pen.setColor(mColorBorder); //划线颜色
    pen.setStyle(Qt::SolidLine);//线的类型,实线、虚线等
    pen.setCapStyle(Qt::FlatCap);//线端点样式
    pen.setJoinStyle(Qt::BevelJoin);//线的连接点样式
    painter.setPen(pen);

    QBrush  brush;//设置画刷
    brush.setColor(mColorBack); //画刷颜色
    brush.setStyle(Qt::SolidPattern); //画刷填充样式
    painter.setBrush(brush);

    rect.setRect(1,1,109,48);
    painter.drawRect(rect);//绘制电池边框

    brush.setColor(mColorBorder); //画刷颜色
    painter.setBrush(brush);
    rect.setRect(110,15,10,20);
    painter.drawRect(rect); //画电池正极头

//画电池柱
    if (mPowerLevel>mWarnLevel)
    {  //正常颜色电量柱
        brush.setColor(mColorPower); //画刷颜色
        pen.setColor(mColorPower); //划线颜色
    }
    else
    { //电量低电量柱
        brush.setColor(mColorWarning); //画刷颜色
        pen.setColor(mColorWarning); //划线颜色
    }
    painter.setBrush(brush);
    painter.setPen(pen);

    if (mPowerLevel>0)
    {
        rect.setRect(5,5,mPowerLevel,40);
        painter.drawRect(rect);//画电池柱
    }

//绘制电量百分比文字
    QFontMetrics    textSize(this->font());
    QString powStr=QString::asprintf("%d%%",mPowerLevel);
    QRect textRect=textSize.boundingRect(powStr);//得到字符串的rect

    painter.setFont(this->font());
    pen.setColor(mColorBorder); //划线颜色
    painter.setPen(pen);

    painter.drawText(55-textRect.width()/2,
               23+textRect.height()/2,
               powStr);
}

QwBattery::QwBattery(QWidget *parent) : QWidget(parent)
{
//    setPalette(QPalette(mColorBack));
//    setAutoFillBackground(true);
//    this->resize(120,50);
}

void QwBattery::setPowerLevel(int pow)
{ //设置当前电量值
    mPowerLevel=pow;
    emit powerLevelChanged(pow); //触发信号
    repaint();
}

int QwBattery::powerLevel()
{ //读取当前电量值
    return mPowerLevel;
}

void QwBattery::setWarnLevel(int warn)
{//设置电量低阈值
    mWarnLevel=warn;
    repaint();
}

int QwBattery::warnLevel()
{//读取电量低阈值
    return  mWarnLevel;
}

QSize QwBattery::sizeHint()
{//报告缺省大小,调整比例
    int H=this->height();
    int W=H*12/5;
    QSize   size(W,H);
    return size;
}

3.插件的编译与安装

  使用 MSVC 编译器,将插件项目在 release 模式下编译,编译后生成 qwbatteryplugin.dll 和 qwbatteryplugin.lib 两个文件(一个是动态链接库文件,一个静态链接库文件)。

image-20240725162310640

将 qwbatteryplugin.dll 文件复制到 Qt Creator 的插件目录和 Qt 插件目录下,如:

D:\Qt\5.15.2\msvc2019\plugins\designer
D:\Qt\Tools\QtCreator\bin\plugins\designer

  重启 Qt Creator,使用 UI 设计器设计窗口时,在左侧的组件面板里会看到增加了一个 “MyWidget” 分组,里面有一个组件 QwBattery。如果没有看到,则通过 “工具” --> “界面编辑器” --> “About Qt Designer Plugins" 查看插件加载失败的原因。

image-20240725181319414

  将从 QWidget 继承的子类 QwBattery 作为插件安装到 Ul 设计器中,则在设计器间就可以从属性编辑器里看到这个 powerLevel 属性并进行设置。

编译和安装 Widget 插件必须注意以下事项

  • 要让插件在 Qt creator 的 UI 设计器里正常显示,编译插件项目的编译器必须与编译 Qt Creator 的编译器一致,否则,即使将编译后生成的 DLL 文件复制到 Qt 的目录下, Qt Creator 的 UI 设计器的组件面板里也不会出现自定义的组件。
  • 用 debug 和 release 模式编译的插件也分别只适用于 debug 和 release 模式编译的应用程序。在 debug 模式下编译的插件项目生成的 Lib 和 DLL文件会在文件名最后自动增加一个字母 “d”。

4.使用自定义插件

  在 Qt Creator 的 UI 设计器的组件面板里能正常显示自定义的 QwBattery 组件后,就可以在窗体设计时使用 QwBattery 组件了。创建一个基于 QWidget 的类 BatteryUser。设计窗体时,从组件面板上拖放一个 QwBattery 到窗体上。可以在属性编辑器里找到 QwBattery 组件的 powerLevel 属性以及可以找到其自定义的信号 powerLevelChanged(int),并可以为此信号设计槽函数。

  要正常编译项目 BatteryUser,还需做以下设置:

  • 在项目的源文件目录下创建 include 子目录(名称随个人喜好设置),将QwBattery 类定义的头文件 qwbattery.h 、插件的 debug 和 release 两种模式编译生成的库文件 qwbatteryplugin.lib 以及 qwbatteryplugind.lib 复制到此目录下 ,项目在编译链接需要使用此头文件和库文件

  • 添加外部库,使用已经编译好的库文件

    image-20240725170927876

    Qt Creator 会自动修改项目文件 BatteryUser.pro 的内容,在其中添加了以下几行

    win32:CONFIG(release, debug|release): LIBS += -L$$PWD/include/ -lqwbatteryplugin
    else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/include/ -lqwbatteryplugind
    
    INCLUDEPATH += $$PWD/include
    DEPENDPATH += $$PWD/include
    
    • LIBS 用于设置添加的库文件,会判断当前项目是以 debug 还是 release 模式编译,自动加入库文件
    • INCLUDEPATH 和 DEPENDPATH 用于设置头文件目录和项目依赖项目录,都指向项目路径下的 include 目录。

    这样设置后,项目就可以在 release 和 debug 模式下编译了。

    注意

    要运行应用程序,还需要将插件的 DLL 文件复制到编译后的 release 或 debug 版本的可执行文件目录下,在本例中就是 qwbatteryplugin.dll 以及 qwbatteryplugind.dll 文件,因为应用程序运行需要相应的 DLL 文件, 在应用程序发布时,也需要将 DLL 文件随同应用程序发布。

      自定义 Widget 插件的功能使得我们可以扩展 Qt Creator 的组件种类,设计自己需要的组件。也有许多 Widget 插件可供直接使用,减少自己编程的 工作量,例如:QWT 就是一套非常好的开源 Widget 插件。

5.使用 MSVC 编译器输出中文的问题

  在 Qt Creator 中使用 MSVC 编译器编译项目时,若处理不当容易出现中文字符乱码问题。这是因为 Qt Creator 保存的文件使用的是 UTF-8 编码,MSVC 编译器虽然可以正常编译带 BOM 的UTF-8编码的源文件,但是生成的可执行文件的编码是 windows 本地字符集 ,比如 GB2312。在生成的可执行文件中,中文字符是以GB2312编码的,而程序执行到这句代码时,这个中文字符串却是以UTF-8解码的,故而出现乱码的情况。

解决方法

  • 一种方法是使用 ==QStringLiteral()==宏封装字符串

    QStringLiteral(str) 宏在编译时将一个字符串 str 生成字符串数据,并且存储在编译后文件的只读数据段中,程序运行时使用到此字符串时,只需读出此字符串数据即可。

    程序中需要使用 QStringLiteral() 宏对每个中文字符串进行封装,并且不能再使用 tr() 函数用于翻译字符串

  • 另一种方法是强制 MSVC 编译器生成的可执行文件使用 UTF-8 编码(只在 MSVC2015 编译器中生效)

    需要在每个使用到中文字符串的头和源程序文件的前部加入如下的语句:

    #if _MSC_VER >= 1600     //MSVC2015>1899,    MSVC_VER= 14.0
    #pragma execution_character_set("utf-8")
    #endif
    

    MSVC2010 以后的编译器可以使用此方案,这是强制编译后的执行文件采用 UTF-8 编码。这样,即使不再使用 QStringLiteral() 宏,程序运行时也不会再出现汉字乱码问题。而且,也可以使用 tr() 函数用于翻译字符串。

    这个方案在 MSVC2015 编译器中起作用,我在 MSVC2019 编译器测试时,直接由”中文乱码问题“变得“编译不过了”。但是可以使用如下方案

  • 定义编译 C++ 源代码时使用的额外编译器标志,来保证整个项目在编译和运行时都能正确处理 UTF-8 编码的字符。

    win32{
        QMAKE_CXXFLAGS += /source-charset:utf-8 /execution-charset:utf-8
    }
    
    • QMAKE_CXXFLAGS 宏:用于定义编译C++源代码时使用的额外编译器标志。
    • /source-charset:utf-8:这个标志告诉编译器,源代码文件的字符编码是UTF-8。
    • /execution-charset:utf-8:这个标志告诉编译器,程序在运行时使用的字符编码也是UTF-8。

    在 MSVC2019 编译器中,亲测可以使用,其他版本未测试!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1952555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【React】详解受控表单绑定

文章目录 一、受控组件的基本概念1. 什么是受控组件&#xff1f;2. 受控组件的优势3. 基本示例导入和初始化定义函数组件处理输入变化处理表单提交渲染表单导出组件 二、受控组件的进阶用法1. 多个输入框的处理使用多个状态变量使用一个对象管理状态 2. 处理选择框&#xff08;…

leetcode-104. 二叉树的最大深度

题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;root [1,n…

24款美规奔驰GLS450更换中规高配主机系统,提升车辆功能和使用体验

平行进口奔驰GLS450 语音小助手要说英语 十分的麻烦 而且也没有导航&#xff0c;原厂记录仪也减少了 很不方便 那要怎么解决呢 往下看 其实很简单&#xff0c;我们只需要更换一台中规的新主机就可以实现以下功能&#xff1a; ①中国地图 ②语音小助手&#xff08;你好&#…

C++编译jsoncpp库

下载https://github.com/hailong0715/jsoncpp/tree/master windows编译工程 jsoncpp-master\makefiles\vs71 1.msvcprtd.lib(MSVCP140D.dll) : error LNK2005 解决办法&#xff1a; (1).工程(Project)->属性(Properties)->配置属性(Configuration Properties)->c/c-…

OZON打开哈萨克斯坦市场,OZON测试开通哈萨克斯坦市场中国产品

在全球化日益深入的今天&#xff0c;跨境电商成为了连接不同国家和地区消费者的重要桥梁。2024年7月26日&#xff0c;Ozon Global宣布了一项重大扩展计划&#xff0c;正式将中国卖家的销售版图拓展至哈萨克斯坦市场&#xff0c;为中国企业打开了新的增长机遇之门。 OZON哈萨克斯…

2024AGI面试官 常问的问题以及答案(附最新的AI大模型算法面试大厂必考100题 )

前言 在这个人工智能飞速发展的时代&#xff0c;AI大模型已经成为各行各业创新与变革的重要驱动力。从自动驾驶、医疗诊断到金融分析&#xff0c;AI大模型的应用场景日益广泛&#xff0c;为我们的生活带来了前所未有的便捷。作为一名程序员&#xff0c;了解并掌握AI大模型的相…

移植QT项目出现无法找到 v143 的生成工具(平台工具集 =“v143”)。若要使用 v143 生成工具进行生成,请安装 v143 生成工具。

由于使用的是visual studio2019&#xff0c;在扩展里没找到msvc v143的工具集&#xff0c;这时候可能需要升级下版本&#xff0c;比如换用visual studio2022 或者在三个地方更改所使用的工具集&#xff0c;一般来讲只要v143编译能通过的v142编译也能通过&#xff0c;所以换用v…

ctfshow-web入门-php特性(web147-web150_plus)

目录 1、web147 2、web148 3、web149 4、web150 5、web150_plus 1、web147 ^&#xff1a;匹配字符串的开头。 $&#xff1a;匹配字符串的结尾&#xff0c;确保整个字符串符合规则。 [a-z0-9_]&#xff1a;表示允许小写字母、数字和下划线。 *&#xff1a;匹配零个或多个前面…

c++入门----类与对象(中)

OK呀&#xff0c;家人们承接上文&#xff0c;当大家看过鄙人的上一篇博客后&#xff0c;我相信大家对我们的c已经有一点印象了。那么我们现在趁热打铁再深入的学习c入门的一些知识。 类的默认成员函数 首先我们学习的是我们的默认函数。不知道大家刚读这个名词是什么反应。默认…

一下午连续故障两次,谁把我们接口堵死了?!

唉。。。 大家好&#xff0c;我是程序员鱼皮。又来跟着鱼皮学习线上事故的处理经验了喔&#xff01; 事故现场 周一下午&#xff0c;我们的 编程导航网站 连续出现了两次故障&#xff0c;每次持续半小时左右&#xff0c;现象是用户无法正常加载网站&#xff0c;一直转圈圈。 …

2020 CSP第一题:数字拆分

2020 CSP第一题&#xff1a;数字拆分 示例1 输入 6 输出 4 2 题意&#xff1a; 实质就是将一个偶数转化为二进制数&#xff0c;然后分别用十进制逆序输出每一项 数据约束&#xff1a; n最大在10的七次方左右&#xff0c;int类型够了&#xff0c;十进制转化为二进制后&#x…

重生之“我打数据结构,真的假的?”--3.栈和队列

1.栈和队列的基本概念 1.1 栈 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则…

鸿蒙开发——axios封装请求、拦截器

描述&#xff1a;接口用的是PHP&#xff0c;框架TP5 源码地址 链接&#xff1a;https://pan.quark.cn/s/a610610ca406 提取码&#xff1a;rbYX 请求登录 HttpUtil HttpApi 使用方法

开源模型应用落地-LangChain实用小技巧-ChatPromptTemplate的partial方法(一)

一、前言 在当今的自然语言处理领域&#xff0c;LangChain 框架因其强大的功能和灵活性而备受关注。掌握一些实用的小技巧&#xff0c;能够让您在使用 LangChain 框架时更加得心应手&#xff0c;从而更高效地开发出优质的自然语言处理应用。 二、术语 2.1.LangChain 是一个全方…

TCP/IP协议(全的一b)应用层,数据链层,传输层,网络层,以及面试题

目录 TCP/IP协议介绍 协议是什么,有什么作用? 网络协议为什么要分层 TCP/IP五层网络协议每层的作用 应⽤层 DNS的作用及原理 DNS工作流程 数据链路层 以太⽹帧格式 MAC地址的作用 ARP协议的作⽤ ARP协议的工作流程 MTU以及MTU对 IP / UD / TCP 协议的影响 传输层…

MySQL(持续更新中)

第01章_数据库概述 1. 数据库与数据库管理系统 1.1 数据库相关概念 DB&#xff1a;数据库&#xff08;Database&#xff09;即存储数据的“仓库”&#xff0c;其本质是一个文件系统。它保存了一系列有组织的数据DBMS&#xff1a;数据库管理系统&#xff08;Database Manageme…

2024年【广东省安全员B证第四批(项目负责人)】考试报名及广东省安全员B证第四批(项目负责人)模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 广东省安全员B证第四批&#xff08;项目负责人&#xff09;考试报名根据新广东省安全员B证第四批&#xff08;项目负责人&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将广东省安全员B证第四批&#x…

AFast and Accurate Dependency Parser using Neural Networks论文笔记

基本信息 作者D Chendoi发表时间2014期刊EMNLP网址https://emnlp2014.org/papers/pdf/EMNLP2014082.pdf 研究背景 1. What’s known 既往研究已证实 传统的dp方法依存句法分析特征向量稀疏&#xff0c;特征向量泛化能力差&#xff0c;特征计算消耗大&#xff0c;并且是人工构…

UE5 with plugins AirSim in Windows ROS in WSL2-Ubuntu 20.04配置过程记录

一、概述 因为需要使用到Windows系统下的UE5和插件AirSIm进行研究&#xff0c;所以在Windows环境下进行配置。但又因为需要使用到ros进行操作&#xff0c;所以&#xff0c;在通过对诸多资源进行考察过后&#xff0c;因为UE5plugins AirSim已经配置成功。只需要考虑跟ROS的通信以…

构建查询洞察 UI

本文字数&#xff1a;2631&#xff1b;估计阅读时间&#xff1a;7 分钟 作者&#xff1a;Bucky Schwarz 本文在公众号【ClickHouseInc】首发 我们最近发布了 Query Insights 的初步实现&#xff0c;为 ClickHouse Cloud 用户提供了一种便捷的方法来查看和解释查询日志。该功能对…