一、前言
在部分界面開發中,有時需要動態添加控制元件或按鈕到面板中,在不需要時又需要洗掉該控制元件,故模仿視頻開發中的設定屏蔽詞,通過自己繪制的按鈕與排布面板控制元件實作,
實作效果如下:

說明:
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 }面板布局
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/285502.html
標籤:C++
