不知道你有没有遇到过这样的需求,将一个QComboBox的文字居中显示。我最近遇到了这样的需要,主要是要在表头中增加可以下拉的列表来进行过滤的功能,这也就要求我们必须将下拉列表的文字居中显示。

这种需求可能实现的方式会有好多种,但我一直坚信,能用原生的就用原生的,或者在原生的控件之上进行一些特例化的改动,让其满足我们的需求是最简单的方式,并且不会过多的影响样式表设置。

所以这儿我还是选择了QComboBox,而我们要做的事情就是怎样将他的文字居中显示。

下拉列表的居中我们都知道是比较好解决的事情,只要进行简单的设置就能满足。

dynamic_cast<QStandardItemModel*>(this->view()->model())->item(index)->setTextAlignment(Qt::AlignVCenter);

顶多,我们再加个循环就能搞定了。

void ComboBox::setTextAlignment(Qt::Alignment alignment) const
{auto* model = dynamic_cast<QStandardItemModel*>(this->view()->model());if (Q_NULLPTR == model){return;}for (int index = 0, size = model->rowCount(); index < size; ++index){if (Q_NULLPTR != model->item(index)){model->item(index)->setTextAlignment(alignment);}}
}

比较难的是怎么让没有下拉的时候它的文字居中显示。

我下面的所有例子都是建立在新建类 ComboBox 继承自 QComboBox 之上的,也就是这样。

class ComboBox : public QComboBox
{}

1、 借用其本身的QLineEdit

可能我们首先想到的会是这个方式。大家都知道,QLineEdit 是可以将文字设置为居中显示的。而QComboBox 中,其实是有一个子控件就是 QLineEdit 的。但是这个子控件被构造的时机是我们必须设置 QComboBox 为可编辑状态。

this->setEditable(true);
this->lineEdit()->setReadOnly(true);
this->lineEdit()->setAlignment(Qt::AlignCenter);

上面的这几行代码其实已经可以实现文字居中显示了。问题是:

  • 太丑了,这样设置之后的样式可能跟我们的预期会有点差距,但如果你只是自己玩玩,倒也不是不行。
  • 下拉列表的触发方式被改变了,这样就只能点击 QComboBox 后面的那个箭头触发下来列表的 popup 了,不管你是否设置这个QLineEdit是只读,而正常的结果是 QComboBox 的任何一个点都能触发。造成了操作上的不便。

当然,第二个问题是好解决的,因为我们在很多的地方可能都接触过事件的过滤,那我们就可以过滤触发在 QLineEdit 上的鼠标单点的事件来进行手动的 popup 。过滤的事件首先应该是鼠标事件,其次是鼠标的左键被 release 的状态,这样才能正常的模拟我们的鼠标单击。

bool ComboBox::eventFilter(QObject* obj, QEvent *event)
{if (event->type() == QEvent::MouseButtonRelease &&  dynamic_cast<QMouseEvent*>(event)->button() == Qt::LeftButton){showPopup();}return QObject::eventFilter(obj, event);
}
this->lineEdit()->installEventFilter(this);

就算进行了鼠标事件的过滤,模拟了鼠标单击,但我们还有一个问题,就是第一个的样式,这是我们用这种方式解决不了的。要解决这个问题,也就引出了我们下面的第二种方式。
看下实现的效果:

2、 借用外来的 QLineEdit

这种方式其实跟第一种是很像的,区别只是我们用了一个外来的 QLineEdit 代替了 QComboBox 本身存在的 QLineEdit。当然,这种方式下不用将QComboBox 设置为可编辑状态,因为我们不会用到他自身的 QLineEdit。

auto lineEdit = new QLineEdit();
lineEdit->setReadOnly(true);
lineEdit->installEventFilter(this);this->setQLineEdit(lineEdit);

这样的效果跟我们第一种的效果是完全不一样的。也基本上满足了我们的需求。如果只是浅尝辄止一下,那到这儿也就差不多了。

第二种的效果:

3、 重新绘制

为什么我说如果只是简单的进行一下测试,到第二种方法的时候就可以结束了,因为这种方式,会稍微有点难度,但难度也不大。

如果你经常会时不时地去瞄一眼Qt的源码,或许你就会发现很多你本来不知道,但非常好用的东西。比如下面这个QComboBoxpaintEvent 函数.

void QComboBox::paintEvent(QPaintEvent *)
{QStylePainter painter(this);painter.setPen(palette().color(QPalette::Text));// draw the combobox frame, focusrect and selected etc.QStyleOptionComboBox opt;initStyleOption(&opt);painter.drawComplexControl(QStyle::CC_ComboBox, opt);// draw the icon and textpainter.drawControl(QStyle::CE_ComboBoxLabel, opt);}

看看这简单的几行代码,外加必要的注释,基本上已经让你将这个函数吃透了。

最后一行代码。

// draw the icon and text
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);

他的作用是绘制 icon 和 text。这特么不就是我们需要的吗?也就是说,我们只需要修改这一行代码,就能满足我们绘制需求了。所以就有了下面的这个重写函数。

void ComboBox::paintEvent(QPaintEvent* e)
{QStylePainter painter(this);painter.setPen(palette().color(QPalette::Text));QStyleOptionComboBox opt;initStyleOption(&opt);painter.drawComplexControl(QStyle::CC_ComboBox, opt);...
}

这个函数上面的部分我们保持不变,并且还需要保持一种方式就是当QComboBox可编辑的时候需要跟以前一样。而我们通过对 QStyleOptionComboBox 类的详细了解发现,这个类里面是有一个 editable 成员变量的。

class Q_WIDGETS_EXPORT QStyleOptionComboBox : public QStyleOptionComplex
{public:enum StyleOptionType { Type = SO_ComboBox };enum StyleOptionVersion { Version = 1 };bool editable;QRect popupRect;bool frame;QString currentText;QIcon currentIcon;QSize iconSize;QStyleOptionComboBox();QStyleOptionComboBox(const QStyleOptionComboBox &other) : QStyleOptionComplex(Version, Type) { *this = other; }protected:QStyleOptionComboBox(int version);
};

偷下懒,如果 QComboBox 是可编辑状态,就还是按照原先的那种方式绘制去吧。

if(opt.editable)painter.drawControl(QStyle::CE_ComboBoxLabel, opt);

如果不是可编辑状态:

首先按照QComboBox的大小,获取到文字显示的矩形框,这个矩形框获取的过程中是不包含QComboBox最后面的那个下来箭头的。

QRect editRect = this->style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this);

然后绘制一个ButtonLabel,我们都知道,QPushbutton默认是文字居中显示的,所以不用设置其他的。最后进行绘制。

QStyleOptionButton buttonOpt;
buttonOpt.initFrom(this);
buttonOpt.rect = editRect;
buttonOpt.text = opt.currentText;
buttonOpt.icon = opt.currentIcon;
buttonOpt.iconSize = opt.iconSize;
painter.drawControl(QStyle::CE_PushButtonLabel, buttonOpt);

上面是我们用了同一个绘制 QStylePainter 的对象 painter 实现了绘制过程,但让,还有另外一种绘制方式,就是利用 QStyle 。

painter.end();QPainter pt(this);
QStyleOptionButton buttonOpt;
buttonOpt.initFrom(this);
QRect editRect = this->style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this);
buttonOpt.rect = editRect;
buttonOpt.text = opt.currentText;buttonOpt.icon = opt.currentIcon;buttonOpt.iconSize = opt.iconSize;
this->style()->drawControl(QStyle::CE_PushButtonLabel, &buttonOpt, &pt, this);

这种方式现实的效果:

完整的函数是这样的:

void ComboBox::paintEvent(QPaintEvent* e)
{QStylePainter painter(this);painter.setPen(palette().color(QPalette::Text));QStyleOptionComboBox opt;initStyleOption(&opt);painter.drawComplexControl(QStyle::CC_ComboBox, opt);if(opt.editable){painter.drawControl(QStyle::CE_ComboBoxLabel, opt);return;}QRect editRect = this->style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this);QStyleOptionButton buttonOpt;buttonOpt.initFrom(this);buttonOpt.rect = editRect;buttonOpt.text = opt.currentText;buttonOpt.icon = opt.currentIcon;buttonOpt.iconSize = opt.iconSize;#if 1painter.drawControl(QStyle::CE_PushButtonLabel, buttonOpt);
#elsepainter.end();QPainter pt(this);this->style()->drawControl(QStyle::CE_PushButtonLabel, &buttonOpt, &pt, this);
#endif
}

很多时候,我们总会选择一些比较方便,能够轻松解决的方式进行处理,会忽略一些比较耗能的过程,而那些路径比较长的实现方式,大多时候是我们能够学到东西的最好路径。就像选择 QStylePainter 的绘制,会比前两种方式更能让我们了解一个控件或者类的内部。

QStylePainter 提供了很多的封装的控件绘制方法,为我们提供了便利。也不会影响其他的基础功能。

QComboBox文字居中的几种实现方式相关推荐

  1. css分割线 文字居中的7种实现方式

    最近开始研究前端,会不定期更新一些小块代码,写下自己的学习笔记,也希望能和大家一起进步! 1.单个标签实现分隔线: <html> <head lang="en"& ...

  2. css:居中的几种布局方式

    居中布局的方式 初始状态 <!DOCTYPE html> <html lang="en"> <head><style>.outer ...

  3. css3实现文字闪烁效果的三种展示方式

    转载自:http://www.fly63.com/article/detial/616 文字闪烁效果一: 通过改变透明度来实现文字的渐变闪烁,效果如下: 文字带渐变效果的闪烁: <div cla ...

  4. 文字居中、CSS中实现盒子水平垂直居中的方法

    1. 文字居中: 第一种方式: 当用text-align:center时,达到的是水平居中的效果,那再用vertical-align:middle:其实是实现不了垂直居中的,此时就需要用到displa ...

  5. html文章整体居中,HTML如何让文字居中?附两种方式

    我们在编写一个网页时,经常需要将文字居中.那么这篇文章小编教你HTML如何让文字居中. 方法一. 居中标签中可以直接添加align="center"样式,使文字居中.具体代码如下: ...

  6. 图文对齐居中的几种方式

    总结图文居中的几种方式 1.方法一 css #target{ width: 150px; border:1px purple solid; line-height: 40px; text-indent ...

  7. WPS和Word段落文字5种对齐方式的功能、区别和用法详细解析

    在WPS文字和Word文档中,段落中的文字对齐方式共有五种,分别是:左对齐.居中.右对齐.两端对齐.分散对齐. 这五种对齐方式分别实现了什么对齐效果?他们的区别是什么?在什么时候使用哪种对齐方式呢?能 ...

  8. CSS元素上下左右居中的几种方式

    CSS元素上下左右居中的几种方式 假设以以下父子元素实现上下左右居中为例: <div class='father'><div class='son'></div> ...

  9. 通过CSS实现 文字渐变色 的两种方式

    说明 这次的重点就在于两个属性,  background 属性  mask 属性  这两个属性分别是两种实现方式的关键. 解释 方式一 效果图 代码 <!DOCTYPE html> < ...

最新文章

  1. Windows下Nginx的安装及开机启动
  2. Android 获取SD卡路径和判断SD卡是否存在.
  3. 将matlab的.m文件打包为独立可执行程序.exe —— 基于Matlab R2015b
  4. vagrant 本地添加box 支持带版本号
  5. C++ const修饰符和指针
  6. jquery easyui datagrid mvc server端分页排序筛选的实现
  7. 关于 SAP Commerce Cloud 启动时报 Address already in use - bind 的错误消息
  8. 全国计算机等级考试题库二级C操作题100套(第25套)
  9. ddrelease64 黑苹果_High Sierra 黑苹果构建 微星X99A GAMING PRO CARBON+i7 6800k+GTX1070
  10. java 扫描类_Java扫描指定包中所有类
  11. tf.truncated_normal_initializer 从截断的正态分布中输出随机值。
  12. Android实际开发中的bug总结与解决方法(一)
  13. 父元素没有高度,子元素高度失效
  14. pip太慢豆瓣下载地址
  15. 同一个网络下怎样在两台机器之间传输文件
  16. javascript 函数传参
  17. 《Using OpenRefine》翻译~15
  18. 数学分析教程(科大)——6.3笔记+习题
  19. js【点击 div 2s 后颜色变成『粉色」】
  20. 6.详解第二代蜂窝移动通信系统的典型代表——GSM和通用分组无线业务(GPRS)

热门文章

  1. linux的文件隐藏属性
  2. 入职第一天--随便说几句话
  3. 天龙八部3服务器延迟,残酷45分钟 《天龙八部3》云服务器经验战役
  4. 另类破解xp密码办法
  5. 关于高可用,我们关注得好像有点窄
  6. (七)Django 在线平台(详情页配置)
  7. 拼多多竞业协议亮相,太狠了!拼多多员工离职后居然被全互联网封杀!
  8. 1,Java语言基础-Java语言概述和必要计算机知识
  9. 定义一元二次方程求根函数
  10. 魅族黄章深夜发文:雷军做小米不是因为我“不舍股份”