0.前言

Qt提供了一个QComboBox下拉框组件,但是对于一些自定义样式的需求实现起来并不方便,很多东西还得去倒腾源码,还不如直接用基础的组件自己来实现一个下拉框。不过,自己组合的组件对样式表的支持不是很好,而且水平不够通用性差,所以我只在一些定制化程度高的需求才使用这种方式。

1.实现思路与问题

首先是下拉框的文本框和按钮,我使用QLineEdit+QPushButton;然后弹出框我分为两部分,一是弹出框Widget容器,二是弹出框中的内容为了后续的自定义抽象了一个简单的基类,使用的时候继承基类实现自己的弹出框样式即可。剩下的就是模拟一些QComboBox的接口和效果了。

遇到的问题一,弹出框QWidget子类设置为Popup后,没法设置背景半透明。后来发现可以给要展示的Widget的parent或者更上层的parent设置透明属性,这样展示的Widget就可以半透明了。

//背景透明FramelessWindowHint+WA_TranslucentBackground
//这样才能给上面的组件设置透明色
setWindowFlags(Qt::Popup|Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);

遇到的问题二, 弹出后点击标题栏拖动弹框不会消失。开始我以为是焦点的问题,但是设置后也没效果。后来发现因为我弹出动画高度是从0开始,设置成从1开始就没问题了。

resize(width,1);
animation->setStartValue(QSize(width,1));

待实现的需求一:样式表的设置如何反应到布局中,增加自定义属性在QSS种设置值么。

待实现的需求二:弹出框的方向目前直接往下的,应该判断下位置来决定向上还是向下。

2.实现代码

完整代码链接(RBasicComboBox类):https://github.com/gongjianbo/RectangleComponent

部分实现(因为有好几个组成部分,所以只贴了主体类):

#ifndef RBASICCOMBOBOX_H
#define RBASICCOMBOBOX_H#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>
#include <QTimer>#include "RBasicComboPopup.h"/*** @brief 使用QLineEdit+QPushButton+弹出框组合的下拉框* @author 龚建波* @date 2020-7-6* @history* [2020-7-7]* 重构弹出框部分,增加可扩展性* 基础组件:Box+Popup,继承Container实现接口后设置给Popup*/
class RBasicComboBox : public QWidget
{Q_OBJECT
public:explicit RBasicComboBox(QWidget *parent = nullptr);~RBasicComboBox();//当前行int getCurrentIndex() const;void setCurrentIndex(int index);//当前文本QString getCurrentText() const;void setCurrentText(const QString text);//数据项QList<QString> getItems() const;void setItems(const QList<QString> &items);//弹出框RBasicComboPopup *getPopup() const;protected://过滤组件事件bool eventFilter(QObject *watched, QEvent *event) override;private://初始化组件设置void initComponent();//popup-containervoid initContainer();//默认样式设置void initStyleSheet();//编辑后查询对应行并设置modelvoid checkTextRow();signals:void currentIndexChanged(int index);void currentTextChanged(const QString text);private://可以使用前置声明,然后把new放到初始化列表去//文本框QLineEdit *boxEdit=new QLineEdit(this);//按钮QPushButton *boxButton=new QPushButton(this);//布局QHBoxLayout *boxLayout=new QHBoxLayout(this);//弹框RBasicComboPopup *boxPop=new RBasicComboPopup(this);//定时器QTimer *editTimer=new QTimer(this);
};#endif // RBASICCOMBOBOX_H
#include "RBasicComboBox.h"#include <QDesktopWidget>
#include <QKeyEvent>
#include <QFocusEvent>
#include <QMouseEvent>#include <QDebug>RBasicComboBox::RBasicComboBox(QWidget *parent): QWidget(parent)
{setAttribute(Qt::WA_StyledBackground); //支持样式表setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed);initComponent();initStyleSheet();
}RBasicComboBox::~RBasicComboBox()
{boxPop->hidePopup();
}int RBasicComboBox::getCurrentIndex() const
{if(boxPop->getContainer()){return boxPop->getContainer()->getCurrentIndex();}return -1;
}void RBasicComboBox::setCurrentIndex(int index)
{if(boxPop->getContainer()){boxPop->getContainer()->setCurrentIndex(index);}
}QString RBasicComboBox::getCurrentText() const
{return boxEdit->text();
}void RBasicComboBox::setCurrentText(const QString text)
{editTimer->stop();boxEdit->setText(text);
}QList<QString> RBasicComboBox::getItems() const
{if(boxPop->getContainer()){return boxPop->getContainer()->getItems();}return QList<QString>();
}void RBasicComboBox::setItems(const QList<QString> &items)
{if(boxPop->getContainer()){boxPop->getContainer()->setItems(items);}
}RBasicComboPopup *RBasicComboBox::getPopup() const
{return boxPop;
}bool RBasicComboBox::eventFilter(QObject *watched, QEvent *event)
{if(watched==boxEdit){//过滤编辑框事件switch (event->type()) {case QEvent::KeyRelease:{if(boxPop->getContainer()){//这里只考虑了edit可编辑的情况QKeyEvent *key_event=static_cast<QKeyEvent*>(event);if(key_event->key()==Qt::Key_Up){setCurrentText(boxPop->getContainer()->getPrevText());}else if(key_event->key()==Qt::Key_Down){setCurrentText(boxPop->getContainer()->getNextText());}}}break;case QEvent::FocusAboutToChange:case QEvent::FocusIn:{//获得焦点时全选QFocusEvent *focus_event=static_cast<QFocusEvent*>(event);if(focus_event->gotFocus()){QTimer::singleShot(20,boxEdit,&QLineEdit::selectAll);}}break;default:break;}}else if(watched==boxButton){//过频按钮事件}else if(watched==boxPop){//过滤弹框事件if(event->type()==QEvent::Show){boxButton->setChecked(true);}else if(event->type()==QEvent::Hide){boxButton->setChecked(false);}}return false;
}void RBasicComboBox::initComponent()
{//按钮设置boxButton->setObjectName("button");boxButton->setFixedWidth(20);boxButton->setCheckable(true); //用选中来表示弹框弹出boxButton->setFocusPolicy(Qt::NoFocus);boxButton->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);boxButton->installEventFilter(this);//编辑框设置boxEdit->setObjectName("edit");boxEdit->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);boxEdit->installEventFilter(this);//index和text两个属性可以看成独立的connect(boxEdit,&QLineEdit::textChanged,this,&RBasicComboBox::currentTextChanged);//编辑时,延迟一会儿进行查询-currentindexconnect(boxEdit,&QLineEdit::textEdited,[this]{editTimer->start(300);});//编辑结束,进行查询-currentindexconnect(boxEdit,&QLineEdit::editingFinished,this,&RBasicComboBox::checkTextRow);editTimer->setSingleShot(true);connect(editTimer,&QTimer::timeout,this,&RBasicComboBox::checkTextRow);//弹框容器设置boxPop->attachTarget(this);boxPop->installEventFilter(this);initContainer();connect(boxPop,&RBasicComboPopup::containerChanged,this,&RBasicComboBox::initContainer);//布局boxLayout->setMargin(1);boxLayout->setSpacing(1);boxLayout->addWidget(boxEdit);boxLayout->addWidget(boxButton);//点击按钮,弹出//这里有个问题,已经弹出时,点击别的地方会隐藏,//然后我事件过滤又把按钮设置成了非选中,所以点击按钮只会触发弹出connect(boxButton,&QPushButton::toggled,[this](bool checked){if(checked){boxPop->showPopup();}else{boxPop->hidePopup();}});
}void RBasicComboBox::initContainer()
{if(!boxPop->getContainer())return;connect(boxPop->getContainer(),&RBasicComboContainer::currentIndexChanged,this,&RBasicComboBox::currentIndexChanged);connect(boxPop->getContainer(),&RBasicComboContainer::updateData,[this]{setCurrentText(boxPop->getContainer()->getCurrentText());});
}void RBasicComboBox::initStyleSheet()
{setStyleSheet(R"(RBasicComboBox{color:black;background: rgb(160,160,160);}RBasicComboBox:disable{color:rgb(160,160,160);background: rgb(160,160,160);}RBasicComboBox:hover{background: rgb(0,120,215);}RBasicComboBox #edit{border:0;margin:0;padding:0px 3px;color:black;background:white;}RBasicComboBox #button{border:5px solid white;padding:0;margin:0;min-width:12px;max-width:12px;background-color: rgb(200,200,200);}RBasicComboBox #button:hover,RBasicComboBox #button:checked{background-color: rgb(180,215,243);}RBasicComboContainer{background: transparent;border:1px solid rgb(0,120,215);}RBasicComboView{background:white;border:0;font:13px "宋体";}RBasicComboView::item{height:20px;color:black;background:white;}RBasicComboView::item:selected,RBasicComboView::item:hover{color:white;background:rgb(0,120,215);})");
}void RBasicComboBox::checkTextRow()
{//如果model中有匹配的文本,就修改view的currentIndexif(boxPop->getContainer()){if(boxPop->getContainer()->checkTextRow(boxEdit->text())>=0){setCurrentText(boxPop->getContainer()->getCurrentText());}}
}

Qt自定义一个下拉框(使用基础组件组合)相关推荐

  1. Android自定义spinner下拉框实现的实现

    一:前言 本人参考博客:http://blog.csdn.net/jdsjlzx/article/details/41316417 最近在弄一个下拉框,发现Android自带的很难实现我的功能,于是去 ...

  2. 自定义Select下拉框

    背景 经常写Web页面的同学可能会碰到如下的诉求: 新增一个下拉框 要求做的好看一点(鼠标放上去的颜色与原生Select不同,Select背景色也要有所变化) 下拉框中的元素需要分组,分组以后最好还能 ...

  3. Django通过一个下拉框确定另外一个下拉框的值,并关联起来

    1.通常,在web开发中,有这样一种页面,比如下拉框选择一个类型,这个类型底下又细分了很多种相关的描述,因此就有了这样一种需求. 下面用这样一个例子:人员类型,可以分为大学学生,大学教师,学生底下又分 ...

  4. html下拉框内容变更,Javascript根据另一个下拉框值更改下拉框选项

    参见英文答案 > Populate one dropdown based on selection in another                                    3 ...

  5. 根据一个下拉框改变另外一个下拉框内容

    一.前言 在编写网页的时候,有时候需要用到多重内容选择,例如先选择省市,再选择县镇等过程.这里简单实现了根据第一个下拉框点击的时候修改另外一个下拉框的内容,希望能对大家有所帮助. 二.实现思路 定义两 ...

  6. 用友uap nc65 如何实现一个下拉框(枚举类型实体)

    用友uap  nc65 如何实现一个下拉框(枚举类型实体) 如上图所示: 1.新建一个bmf文件. 2.建立一个枚举. 3.给枚举赋值.注意枚举值从0开始 4.右键发布元数据. 5.在需要引用的元数据 ...

  7. react ant protable自定义搜索下拉框

    1.背景 select选择框很常见,这里实现 react ant protable实现自定义搜索下拉框 2.coding const [selectEnum, setSelectEnum] = use ...

  8. 在 easyexcel 2.0.5 下自定义实现下拉框

    在 easyexcel  2.0.5 下实现下拉框,由于easyexcel 并没有提供下拉框的api 只能自己去实现了,阿里提供一个接口WriteHandler 该接口就是用来自己自定义的功能了 第一 ...

  9. Android UI自定义Spinner下拉框(用popuwindow实现)-转

    定义出第一个图片的布局和弹出框(一个listView)的布局,,这里就不在多说了~ListView需要自己定义一个MyspinnerAdapter~做好这些准备之后,就是弹出框的实现了~  prote ...

最新文章

  1. win7怎么清理java缓存文件夹_Win7怎么清除浏览器缓存?清除电脑缓存的妙招
  2. hihoCoder1690 (动态规划)
  3. 关于ie7下display:inline-block;不支持的解决方案。
  4. 树莓派写入SD卡时在内存卡格式化之后仍然不能写入.img文件提示 Error 5:拒绝访问的解决办法
  5. 如何把Tomcat 9 的默认8080端口变成80端口
  6. 常用的项目管理工具有哪些?
  7. OpenCV之图像锐化
  8. 新版UI切片源码 m3u8云切片程序PHP视频切片转码系统易语言源码 云转码工具源码 代码完全开源
  9. 爬虫实战之爬取电影天堂全部电影信息
  10. Springboot+Mybatis接口快速上手
  11. [硬核教程]如何解决电脑假死问题——适用于调用GPU有声音,无画面的情况。
  12. ARM CORTEX-M3 内核架构理解归纳
  13. 供应链服务平台方案:助供应链服务公司实现商品+决策+物流+售后协同办公
  14. 游戏原画和3D游戏建模,哪个更胜一筹?
  15. 2022-2028年全球与中国近红外光谱仪行业竞争格局与投资战略研究
  16. 2、视觉基础知识问答
  17. Spring 发送Email
  18. 文献阅读:SNCSE: Contrastive Learning for Unsupervised Sentence Embedding with Soft Negative Samples
  19. Spring Cloud 微服务及相关技术总结
  20. python类的使用的生物学应用_Python 类的使用

热门文章

  1. 2017年上半年国内智能手机保有量TOP15排名:OPPO成为行业第一
  2. const引用const指针以及constexpr
  3. 【Django】使用谷歌身份验证Google authenticator
  4. ubuntu16.04 配置显卡驱动+cuda8.0+cudnn+pytorch
  5. 如何用纯 CSS 创作一个小球上台阶的动画
  6. 未来十年,最赚钱的17大行业全在这
  7. 自下而上的分析法——算符优先分析法
  8. 用VBS操作Excel常见方法总结!
  9. 午后札记(2011.6.4)
  10. 共享洗车、洗车O2O,都将被全自动洗车颠覆?