自定义Qt控件系列-实战(3)

wuchangjian2021-11-15 12:53:53编程学习

先不说发废话了,我们直接上图看效果

  • 支持文字描边(描边颜色,描边大小)

  • 支持文字颜色动态修改,即所见所得

  • 支持文字省略(省略号:左边,居中,右边)

  • 支持click,MouseEnter,MouseLeave信号

 我们还是老规矩创建个插件的项目,不过这次大家在创建的时候,有些选项需要注意下。

 就是在这里的时候需要注意继承的QLabel,其他的都不是重点了。

1.代码展示

接下来,我和大家一起看下代码的中实现。其实坐下来发现,掌握思路,实现起来并不是很难。

先看头文件的中说明。我在代码做些注释方便大家理解。

这里大家需要注意两点:

  • 我引入了#include <QtUiPlugin/QDesignerExportWidget>头文件

  • 这个class使用QDESIGNER_WIDGET_EXPORT宏定义导出

如果没有这个两点的话,会在QtCreator编译的时候会报错

#include <QtUiPlugin/QDesignerExportWidget>

class QDESIGNER_WIDGET_EXPORT QMyExtLabel : public QLabel
{
    Q_OBJECT
    // 省略号的属性
    Q_PROPERTY(bool autoElideText READ autoElideText WRITE SetAutoElideText)
    // 保留的源字符串
    Q_PROPERTY(QString rawText READ rawText WRITE SetRawText)
    // 省略号的位置(左边,居中,右边)
    Q_PROPERTY(Qt::TextElideMode textElideMode READ textElideMode WRITE SetTextElideMode)
    // 描边的边大小
    Q_PROPERTY(int borderSize READ borderSize WRITE SetBorderSize)
    // 是否支持描边
    Q_PROPERTY(bool textStroke READ textStroke WRITE SetTextStroke)
    // 描边的颜色
    Q_PROPERTY(QColor borderColor READ borderColor WRITE SetBorderColor)
    // 文字的颜色
    Q_PROPERTY(QColor textColor READ textColor WRITE SetTextColor)

public:
    QMyExtLabel(QWidget *parent = 0);

    bool autoElideText() const;
    void SetAutoElideText(bool autoElideText);

    QString rawText() const;
    void SetRawText(const QString &strRawText);

    Qt::TextElideMode textElideMode() const;
    void SetTextElideMode(Qt::TextElideMode textElideMode);

    int borderSize() const;
    void SetBorderSize(int borderSize);

    bool textStroke() const;
    void SetTextStroke(bool textStroke);

    QColor textColor() const;
    void SetTextColor(const QColor &textColor);

    QColor borderColor() const;
    void SetBorderColor(const QColor &borderColor);

protected:
    virtual void enterEvent(QEvent *ev);
    virtual void leaveEvent(QEvent *ev);
    virtual void mousePressEvent(QMouseEvent *ev);
    virtual void mouseReleaseEvent(QMouseEvent *ev);
    virtual void resizeEvent(QResizeEvent *ev);
    virtual void paintEvent(QPaintEvent * event);

signals:
    void clicked();
    void MouseEnter();
    void MouseLeave();

private:
    QString _ElideText();
    void _StrokeText(const QString &strText, Qt::Alignment align);
    void _PaintText();

private:
    bool m_textStroke    = false;
    bool m_bMousePressed = true;
    bool m_autoElideText = true;
    int m_borderSize     = 0;
    QColor m_borderColor = QColor(0,0,0);
    QColor m_textColor   = QColor(0,255,255);
    QString m_rawText    = tr("This is test Label Text");
    Qt::TextElideMode m_textElideMode = Qt::ElideMiddle;
};

cpp实现文件:

QMyExtLabel::QMyExtLabel(QWidget *parent) :
    QLabel(parent)
{
    this->setText(tr("QMyExtLabel"));
}

bool QMyExtLabel::autoElideText() const
{
    return m_autoElideText;
}

void QMyExtLabel::SetAutoElideText(bool autoElideText)
{
    m_autoElideText = autoElideText;
}

void QMyExtLabel::enterEvent(QEvent *ev)
{
    __super::enterEvent(ev);

    emit MouseEnter();
}

void QMyExtLabel::leaveEvent(QEvent *ev)
{
    __super::leaveEvent(ev);

    emit MouseLeave();
}

void QMyExtLabel::mousePressEvent(QMouseEvent *ev)
{
    __super::mousePressEvent(ev);

    m_bMousePressed = true;
}

void QMyExtLabel::mouseReleaseEvent(QMouseEvent *ev)
{
    __super::mouseReleaseEvent(ev);

    if (m_bMousePressed)
    {
        m_bMousePressed = false;
        emit clicked();
    }
}

void QMyExtLabel::resizeEvent(QResizeEvent *ev)
{
    __super::resizeEvent(ev);

    if (m_autoElideText) {
        QString strText = _ElideText();
        setText(strText);
    }
    else {
        setText(m_rawText);
    }
}

void QMyExtLabel::paintEvent(QPaintEvent * event)
{
    if (m_textStroke)
    {
        _StrokeText(text(), alignment());
    }
    else
    {
       _PaintText();
    }
}

QString QMyExtLabel::_ElideText()
{
    // 去掉margin的距离
    QMargins mergin = this->contentsMargins();

    QFont font = this->font();
    QFontMetrics fm(font);
    QString strElideText = fm.elidedText(m_rawText, m_textElideMode, this->width() - mergin.right() - mergin.left());

    return strElideText;
}

void QMyExtLabel::_StrokeText(const QString &strText, Qt::Alignment align)
{
    // 这块代码需要大家仔细的琢磨下,思路还是很常见的。
    QMargins margins = this->contentsMargins();
    QRect rcSize = this->rect();
    rcSize.adjust(margins.left(), margins.top(), -margins.right(), -margins.bottom());

    QFont font = this->font();
    QFontMetrics metrics(font);
    int len = metrics.width(strText);

    int px = rcSize.left();
    if (align & Qt::AlignmentFlag::AlignHCenter)
    {
      px = (len - rcSize.width()) / 2 + margins.left();
    }
    else if (align & Qt::AlignmentFlag::AlignRight)
    {
      int width = rcSize.width();
      px = width - len + margins.left();
    }
    if (px < 0)
    {
      px = -px;
    }

    int py = (rcSize.height() - metrics.height()) / 2 + metrics.ascent() + margins.top();
    if (align & Qt::AlignmentFlag::AlignTop)
    {
      py = metrics.ascent() + margins.top();
    }
    else if (align & Qt::AlignmentFlag::AlignBottom)
    {
      py = rcSize.height() - metrics.height() + metrics.ascent() + margins.top();
    }
    if (py < 0)
    {
      py = -py;
    }

    QPen pen;
    pen.setColor(m_borderColor);
    pen.setWidth(m_borderSize);

    QPainterPath path;
    path.addText(px, py, font, strText);

    QPainter painter(this);
    painter.save();
    painter.setRenderHints(QPainter::Antialiasing);
    painter.strokePath(path, pen);
    painter.drawPath(path);
    painter.fillPath(path, QBrush(m_textColor));
    painter.restore();
}

void QMyExtLabel::_PaintText()
{
    QPen pen;
    pen.setColor(m_textColor);

    QPainter painter(this);
    painter.save();
    painter.setPen(pen);
    painter.setFont(this->font());
    painter.drawText(this->rect(), this->text(), this->alignment());
    painter.restore();
}

QString QMyExtLabel::rawText() const
{
    return m_rawText;
}

void QMyExtLabel::SetRawText(const QString &strRawText)
{
    m_rawText = strRawText;
    setText(m_rawText);

    update();
}

Qt::TextElideMode QMyExtLabel::textElideMode() const
{
    return m_textElideMode;
}

void QMyExtLabel::SetTextElideMode(Qt::TextElideMode textElideMode)
{
    m_textElideMode = textElideMode;

    if (m_autoElideText) {
        QString strText = _ElideText();
        setText(strText);
    }
    else {
        setText(m_rawText);
    }
    update();
}

int QMyExtLabel::borderSize() const
{
    return m_borderSize;
}

void QMyExtLabel::SetBorderSize(int borderSize)
{
    m_borderSize = borderSize;
    update();
}

bool QMyExtLabel::textStroke() const
{
    return m_textStroke;
}

void QMyExtLabel::SetTextStroke(bool textStroke)
{
    m_textStroke  = textStroke;

    update();
}

QColor QMyExtLabel::textColor() const
{
    return m_textColor;
}

void QMyExtLabel::SetTextColor(const QColor &textColor)
{
    m_textColor = textColor;

    update();
}

QColor QMyExtLabel::borderColor() const
{
    return m_borderColor;
}

void QMyExtLabel::SetBorderColor(const QColor &borderColor)
{
    m_borderColor = borderColor;
    update();
}

编译完成之后,我们需要把生成的dll文件拷贝到两个目录,这里我写个脚本处理。

放到QtCreator目录中是为了,在QtCreator中也可以打开designer,这样就也可以编辑插件。

写了个bat批处理,帮助我们copy文件

xcopy .\build-QMyExtLabel-Desktop_Qt_5_5_0_MSVC2013_32bit-Release\release\*.dll "C:\Qt\Qt5.5.0\5.5\msvc2013\plugins\designer\" /Y
xcopy .\build-QMyExtLabel-Desktop_Qt_5_5_0_MSVC2013_32bit-Release\release\*.lib "C:\Qt\Qt5.5.0\5.5\msvc2013\plugins\designer\" /Y
xcopy .\build-QMyExtLabel-Desktop_Qt_5_5_0_MSVC2013_32bit-Release\release\*.dll "C:\Qt\Qt5.5.0\Tools\QtCreator\bin\plugins\designer" /Y
pause

2.如何在项目中使用

  • 使用QtCreator新建一个项目,把生成的lib和头文件都拿过来

  • 在新建的项目里面新建一个lib目录,include目录。分别将lib和.h文件放到两个目录中

  • 在新建的项目中.pro文件中添加lib和.h文件

LIBS += $$PWD/lib/qmyextlabelplugin.lib
INCLUDEPATH += $$PWD/include
  • 使用QtCreator拖拽一个QMyExtLabel控件放到widget窗体上。

  • 最后在运行的时候,需要我们把插件的dll和exe运行同一级目录下。

 运行的效果如下:

 代码地址:GitHub - MingYueRuYa/QtDemoStydy: 学习Qt,一些自绘制的Demo,仅供大家学习。

最后我也从网上找了一段自定义插件遇到的一些坑

Qt自定义插件注意事项:

1:每个Qt库bin目录的designer可执行文件都是和该库同一个编译器编译的,可用,如果想要集成到Qt Creator中,则需要注意版本,一般在windows上的Qt Creator版本是MSVC的,则需要对应的Qt库也是MSVC编译的,库版本和编译器版本必须保持一致才能是顺利集成到Qt Creator的重要前提。

2:自定义控件的名称不能小写,否则拖过去的控件自动生成的默认名称和类名一样,会编译通不过。这个问题坑了我很久,造成自动生成的UI代码保存,一直没有怀疑,后面才发现自动生成的代码类名和实例名称一样,冲突导致的。

3:自定义控件类头文件引入,Qt5.7以下版本为#include <QtDesigner/QDesignerExportWidget> 以上版本为#include <QtUiPlugin/QDesignerExportWidget>

4:类名前必须加入 QDESIGNER_WIDGET_EXPORT 宏。否则集成到Qt Creator 中编译会报错。不加的话可以在设计器中加载,但是编译会报错。

5:如果将生成好的dll文件放到Qt库目录下的 plugins\designer 下,可以在 designer 中看到。放到Qt Creator下的 bin\plugins\designer 则可以集成到Qt Creator中。

6:将自定义控件的头文件、dll文件、lib(mingw编译器为.a)文件复制出来,放到include(可自己随便命名,我这里习惯用include)目录,将include目录放到项目的源码文件下,在使用了自定义控件的项目的pro文件中,增加两行

INCLUDEPATH += $$PWD/include

LIBS += $$PWD/include/***.lib(mingw编译器为.a)

这样可以正常编译,但是编译完成后不能运行,还需要将 对应自定义控件的dll文件复制到可执行文件同一目录即可,至此大功告成。

7:官网提供的Qt Creator版本基本上是MSVC版本,如果需要在mingw的Qt库对应的Qt Creator中集成自定义控件,需要自己用对应的Qt库编译Qt Creator源码。

原文地址:Qt编写自定义控件插件路过的坑及注意事项 - 飞扬青云 - 博客园

相关文章

第一次到天津

昨天下午第一次来到天津。 天津是一个历史积淀厚重的城市。 天津名字的...

C语言运算符优先级

优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组...

没有bug队——加贝——Python 练习实例 17,18

17.题目: 输入一行字符,分别统计出其中英文字母、空格、...

JAVA(2021-11-2)leetcode每日一题----删除链表中的节点

力扣https://leetcode-cn.com/problems/delete-...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。