先不说发废话了,我们直接上图看效果
-
支持文字描边(描边颜色,描边大小)
-
支持文字颜色动态修改,即所见所得
-
支持文字省略(省略号:左边,居中,右边)
-
支持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编写自定义控件插件路过的坑及注意事项 - 飞扬青云 - 博客园