天天看点

Qt 圆角按钮,面版自动布局

一、前言

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

  实现效果如下:

  

Qt 圆角按钮,面版自动布局

  说明:

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

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

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

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

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

二、实现过程

  1、运行环境Qt5.5 VS2013

  2、制作圆角按钮

  1)继承QWidget,封装KeyButton控件

Qt 圆角按钮,面版自动布局
Qt 圆角按钮,面版自动布局

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事件,绘制按钮圆角按钮,包括字符

Qt 圆角按钮,面版自动布局
Qt 圆角按钮,面版自动布局
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”的绘制位置

Qt 圆角按钮,面版自动布局
Qt 圆角按钮,面版自动布局
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”后触发删除信号

Qt 圆角按钮,面版自动布局
Qt 圆角按钮,面版自动布局
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控件

Qt 圆角按钮,面版自动布局
Qt 圆角按钮,面版自动布局
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控件(存储不下时可左右拉动显示)

Qt 圆角按钮,面版自动布局
Qt 圆角按钮,面版自动布局
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 }      

创建面板

Qt 圆角按钮,面版自动布局
Qt 圆角按钮,面版自动布局
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 }      

面板更新

Qt 圆角按钮,面版自动布局
Qt 圆角按钮,面版自动布局
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 }      

面板布局

继续阅读