一、前言

  在部分界面开发中,有时需要动态添加控件或按钮到面板中,在不需要时又需要删除该控件,故模仿视频开发中的设置屏蔽词,通过自己绘制的按钮与排布面板控件实现。

  实现效果如下:

  

  说明:

  1、输入框可设置背景色、圆角角度、颜色高亮等

  2、采用圆角输入框输入字符,回车或点击“添加”可触发信号,获取输入字符串

  3、字符以圆角按钮控件显示,点击“X”可删除该按钮

  4、面版自动排布,删除中间的圆角按钮,后续的会往前移

  5、添加的屏蔽词都放在后面,已有屏蔽词会提示已存在,删除屏蔽词后可再次添加

二、实现过程

  1、运行环境Qt5.5 VS2013

  2、制作圆角按钮

  1)继承QWidget,封装KeyButton控件

 1 #ifndef KEYBUTTON
2 #define KEYBUTTON
3
4 #include <QEvent>
5 #include <QWidget>
6 #include <QMouseEvent>
7 #include <QResizeEvent>
8
9 class KeyButton : public QWidget
10 {
11 Q_OBJECT
12
13 public:
14 KeyButton(QWidget *parent = 0);
15
16 public:
17 void setBorderColor(const QString &);
18 void setHoverColor(const QString &);
19
20 void setText(const QString &);
21 QString getText();
22
23 signals:
24 void closeSig();
25
26 protected:
27 bool eventFilter(QObject *, QEvent *);
28 void paintEvent(QPaintEvent *event);
29 void leaveEvent(QEvent *);
30 void resizeEvent(QResizeEvent *);
31 void mouseReleaseEvent(QMouseEvent *e);
32 void mouseMoveEvent(QMouseEvent *e);
33
34 private:
35 void drawIcon(QPainter *painter, const QRect &rect, int icon);
36
37 private:
38 bool m_IsHover;
39 QString bgColor; //背景色
40 QString borderColor; //边框颜色
41 QString hoverColor; //高亮字体颜色
42 QString text; //字体文本
43 QString textColor; //文本正常颜色
44 int padding; //左侧右侧间距
45 int iconSize; //图标大小
46 QRect rightRect; //右侧图标区域
47 bool pressed; //鼠标是否按下
48 QPoint lastPoint; //鼠标按下处的坐标
49
50 QPoint m_Point;
51 QPixmap m_Pixmap;
52 };
53
54 #endif // KEYBUTTON

圆角按钮

  2)重写paintEvent事件,绘制按钮圆角按钮,包括字符

 1 void KeyButton::paintEvent(QPaintEvent *event)
2 {
3 QPainter painter(this);
4 painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
5
6 //绘制背景+边框
7 painter.setPen(borderColor);
8 painter.setBrush(QColor(bgColor));
9 int min = qMin(this->rect().width(), this->rect().height());
10 int radius = min / 2;
11 //画圆角矩形
12 QPainterPath path;
13 QRect rect = this->rect();
14 path.moveTo(rect.bottomRight() - QPointF(0, radius));
15 path.lineTo(rect.topRight() + QPointF(0, radius));
16 path.arcTo(QRectF(QPointF(rect.topRight() - QPointF(radius * 2, 0)), QSize(radius * 2, radius *2)), 0, 90);
17 path.lineTo(rect.topLeft() + QPointF(radius, 0));
18 path.arcTo(QRectF(QPointF(rect.topLeft()), QSize(radius * 2, radius * 2)), 90, 90);
19 path.lineTo(rect.bottomLeft() - QPointF(0, radius));
20 path.arcTo(QRectF(QPointF(rect.bottomLeft() - QPointF(0, radius * 2)), QSize(radius * 2, radius * 2)), 180, 90);
21 path.lineTo(rect.bottomLeft() + QPointF(radius, 0));
22 path.arcTo(QRectF(QPointF(rect.bottomRight() - QPointF(radius * 2, radius * 2)), QSize(radius * 2, radius * 2)), 270, 90);
23 painter.drawPath(path);
24
25 QFont font = qApp->font();
26 font.setPixelSize(12);
27 painter.setFont(font);
28
29 //绘制文字
30 if (!text.isEmpty())
31 {
32 if(m_IsHover)
33 painter.setPen(hoverColor);
34 else
35 painter.setPen(textColor);
36 QRect textRect(padding * 1.5, 0, this->width(), this->height());
37 painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
38 }
39 //绘制右侧图标
40 font.setPixelSize(15);
41 painter.setFont(font);
42 painter.drawText(rightRect, Qt::AlignHCenter | Qt::AlignVCenter, "X");
43 }

绘制事件

  3)继承resizeEvent事件,计算“X”的绘制位置

1 void KeyButton::resizeEvent(QResizeEvent *)
2 {
3 //重新计算图标位置区域
4 int height = this->height() / 2 - m_Pixmap.height() / 2;
5 m_Point = QPoint(this->width() - (iconSize * 1) - padding, height);
6 rightRect = QRect(this->width() - (iconSize * 1) - padding, 0, iconSize, this->height());
7 }

绘制位置

  4)继承mouseReleaseEvent事件,用户点击“X”后触发删除信号

1 void KeyButton::mouseReleaseEvent(QMouseEvent *e)
2 {
3 pressed = true;
4 lastPoint = e->pos();
5 this->update();
6
7 if (rightRect.contains(lastPoint))
8 emit closeSig();
9 }

信号触发

  3、面板自动布局

  1)继承QWidget,自定义PanelWidget控件

 1 #ifndef PANEL_WIDGET_H
2 #define PANEL_WIDGET_H
3
4 #include <QWidget>
5
6 class QScrollArea;
7 class QFrame;
8 class QVBoxLayout;
9 class QGridLayout;
10 class QSpacerItem;
11
12 class PanelWidget : public QWidget
13 {
14 Q_OBJECT
15 public:
16 explicit PanelWidget(QWidget *parent = 0);
17
18 protected:
19 void resizeEvent(QResizeEvent *);
20 void showEvent(QShowEvent *event);
21
22 public:
23 QSize sizeHint() const;
24 QSize minimumSizeHint() const;
25
26 void setWidgets(QList<QWidget *> widgets);
27 void setWidget(QWidget *widget);
28 void delWidget(QWidget *widget);
29 void setColumnCount(int nColumn);
30 void setMargin(int left, int top, int right, int bottom);
31 void setMargin(int margin);
32 void setSpacing(int space);
33 void resetLayout();
34
35 private:
36 void initFrom();
37 void hideWidget();
38 void showPanel();
39
40 private:
41 QList<QWidget *> m_widgets;
42 int m_nColumn{ 0 };
43
44 private:
45 QScrollArea *scrollArea;
46 QWidget *scrollAreaWidgetContents;
47 QFrame *frame;
48 QVBoxLayout *verticalLayout;
49 QGridLayout *gridLayout;
50
51 QSpacerItem *m_HorizontalSpacer;
52 QSpacerItem *m_VerticalSpacer;
53
54 bool m_IsShow;
55 };
56
57 #endif // PANEL_WIDGET_H

面版类

  2)考虑增加的控件可能比较多,采用QScrollArea控件(存储不下时可左右拉动显示)

 1 void PanelWidget::initFrom()
2 {
3 scrollArea = new QScrollArea(this);
4 scrollArea->setObjectName("scrollAreaMain");
5 scrollArea->setWidgetResizable(true);
6
7 scrollAreaWidgetContents = new QWidget();
8 scrollAreaWidgetContents->setGeometry(QRect(0, 0, 100, 100));
9 scrollAreaWidgetContents->setStyleSheet("border:none;");
10
11 verticalLayout = new QVBoxLayout(scrollAreaWidgetContents);
12 verticalLayout->setSpacing(0);
13 verticalLayout->setContentsMargins(0, 0, 0, 0);
14
15 frame = new QFrame(scrollAreaWidgetContents);
16 frame->setObjectName("panelWidget");
17
18 gridLayout = new QGridLayout(frame);
19 gridLayout->setSpacing(6);
20
21 verticalLayout->addWidget(frame);
22 scrollArea->setWidget(scrollAreaWidgetContents);
23 }

创建面板

  3)通过setWidget和setWidgets,更新面板内的控件

 1 void PanelWidget::setWidgets(QList<QWidget *> widgets)
2 {
3 m_widgets = widgets;
4 //先清空原有所有元素
5 QList<QWidget *> widgetList = frame->findChildren<QWidget *>();
6 foreach(QWidget *w, widgetList)
7 w->hide();
8
9 resetLayout();
10 }
11
12 void PanelWidget::setWidget(QWidget *widget)
13 {
14 if (!m_widgets.contains(widget))
15 {
16 m_widgets << widget;
17 resetLayout();
18 }
19 }

面板更新

  4)更新面版内容后,通过QGridLayout更新控件的布局

 1 void PanelWidget::resetLayout()
2 {
3 int row = 0;
4 int column = 0;
5 int index = 0;
6
7 for (QWidget *widget : m_widgets)
8 {
9 gridLayout->addWidget(widget, row, column);
10 widget->setVisible(true);
11 column++;
12 index++;
13
14 if (index % m_nColumn == 0) {
15 row++;
16 column = 0;
17 }
18 }
19 if (NULL == m_HorizontalSpacer)
20 m_HorizontalSpacer = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
21 if(1 == m_widgets.count())
22 gridLayout->addItem(m_HorizontalSpacer, 0, m_nColumn);
23 row++;
24 if (NULL == m_VerticalSpacer)
25 m_VerticalSpacer = new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding);
26 gridLayout->addItem(m_VerticalSpacer, row, 0);
27 }

面板布局

Qt 圆角按钮,面版自动布局的更多相关文章

  1. Qt设置按钮为圆形

    通过Qt 的样式表实现圆形按钮,其也可以实现圆角按钮,当然也可以使用其他的方式,比如说,通过派生按钮类使用绘图事件,进行一个图形的绘制,或者是通过自定义一个类,通过信号与槽的机制与绘图事件的配合也能实 ...

  2. android 圆角按钮和按钮颜色

    1. android 设置圆角按钮后,按下按钮后,还能改变按钮的颜色 <?xml version="1.0" encoding="UTF-8"?> ...

  3. win10 uwp 圆角按钮

    本文讲的是如何做圆角按钮,我们在UWP本来的按钮都是矩形,圆角Radius没有,所以本文就用简单方法去做圆角按钮. 我们按钮需要圆角,而自带没有,其实做一个很简单,把原来的按钮变为背景透明,然后使用矩 ...

  4. iOS中创建自定义的圆角按钮

    iOS中很多时候都需要用到指定风格的圆角按钮,尽管UIButton提供了一个方式创建圆角按钮: + (id)buttonWithType:(UIButtonType)buttonType;//指定bu ...

  5. Qt浮动按钮的实现(使用窗口背景透明、实现只显示浮动按钮的目的)

    Qt浮动按钮的实现 效果如下: 图3 估计很多做Qt有一定经验的朋友会觉得这个效果不难,但是这是一个需求奇葩的实际业务中做出的效果.笔者会想讲下客户的需求和整体框架的矛盾. 整个项目主要是由Qt搭建的 ...

  6. xamarin UWP自定义圆角按钮

    uwp自带的button本身不支持圆角属性,所以要通过自定义控件实现. 通过设置Button的Background=“{x:Null}”设置为Null使背景为空,再设置Button.Content中的 ...

  7. Android Shape自定义纯色圆角按钮

    版权声明:分享技术,传播快乐.如果本博客对你有帮助,请在我的博客首页为我打赏吧! 在Android开发中,为响应美化应用中控件的效果,使用Shape定义图形效果,可以解决图片过多的问题. 首先看一下效 ...

  8. android 带边框的圆角按钮

    新建buttonstyle.xml 代码如下 <?xml version="1.0" encoding="UTF-8"?> <layer-li ...

  9. 无需图片,使用CSS3实现圆角按钮[转]

    首先来看看效果:   事例HTML代码: <a href="#" class="button green">button</a> < ...

随机推荐

  1. kubernetes CRD

    官方文档:https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions ...

  2. 孙悟空的身外身法术使用了Java设计模式:原型模式

    目录 定义 意图 主要解决问题 何时使用 优缺点 结构 简单形式的原型模式 登记形式的原型模式 两种形式比较 浅克隆和深克隆 孙悟空的身外身法术 浅克隆实现 深克隆实现 定义 原型模式属于对象的创建型 ...

  3. Selenium 3 常用 API

    元素定位 获取页面元素属性 元素判断 元素操作 操作输入框/单击 双击 下拉框操作 键盘操作 鼠标操作 单选框操作 多选框操作 拖动窗口 操作 JS 框 切换 frame 使用 JS 操作页面对象 操 ...

  4. aws EKS EFS storageclass PV PVC Pod

    storageclass [root@localhost specs]# cat storageclass.yaml kind: StorageClass apiVersion: storage.k8 ...

  5. 【项目管理】关于Issue/Milestone的使用指导

    b[red] { color: rgba(255, 0, 0, 1) } 前言 本指导内容主要基于: 和邹欣老师的语音交流结论 邹欣老师<构建之法>的相关章节内容 现有开源项目在类似情况下 ...

  6. Faiss源码剖析:类结构分析

    摘要:在下文中,我将尝试通过Faiss源码中各种类结构的设计来梳理Faiss中的各种概念以及它们之间的关系. 本文分享自华为云社区<Faiss源码剖析(一):类结构分析>,原文作者:HW0 ...

  7. 1086 Tree Traversals Again

    An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example ...

  8. 从Android设备中提取内核和逆向分析

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/57074695 一.手机设备环境 Model number: Nexus 5 OS ...

  9. Windows核心编程笔记之进程

    改变进程基址,获取进程基址 #include <Windows.h> #include <iostream> #include <strsafe.h> #inclu ...

  10. Spring Security 入门(基本使用)

    Spring Security 入门(基本使用) 这几天看了下b站关于 spring security 的学习视频,不得不说 spring security 有点复杂,脑袋有点懵懵的,在此整理下学习内 ...