Qt之QComboBox定製

    提及下拉框,想必你們都比較熟悉,在咱們註冊一些網站的時候,會出現大量的地區數據供咱們選擇,這個時候出現的就是下拉框列表,再好比字體選擇的時候也是使用的下拉框,如圖1所示。下拉框處處可見,做爲一個圖形庫,qt也提供了QtComboBox類來供咱們使用,可是有些時候簡單的下拉列表已經知足不了咱們的需求,如圖2所示,是一個下拉表格,這個時候就須要咱們本身定製一下QComboBox。app

image圖1ide

    image圖2函數

    上邊說了咱們需求的變化,接下來我就講述一下關於QComboBox定製的一些內容,本片文章我就只講述兩種經常使用的下拉選項控制,分別是列表表格post

1、列表的實現字體

    首先我上一張qq的登陸框,如圖3所示,下拉列表裏不只僅是一個文字描述或者複選框,而是含有圖片文字和關閉按鈕的複雜窗口,那麼這個時候簡單的QComboBox是完成不了這項功能的,要作到像qq這樣美觀的功能是須要咱們本身作必定的處理網站

image圖3ui

    列表窗口定製步驟以下:this

一、首先咱們須要自定義一個窗口,上邊有咱們須要操做的內容,這個窗口講會是QComboBox下拉框中的一項,我本身定義的類名爲CActionContentWidget,頭文件以下:url

 1 class CActionContentWidget : public QWidget
 2 {
 3     Q_OBJECT
 4 signals:
 5     void IconClicked();
 6     void showText(const QString &);
 7 
 8 public:
 9     CActionContentWidget(const QString & text, QWidget * parent = nullptr);
10     ~CActionContentWidget();
11 
12 public:
13     void SetContentText(const QString & text);//設置顯示文字
14     void SetItemIcon(const QString & icon, const QString & hover);//設置圖標
15 
16 public:
17     void SetBackgroundRole(bool hover);
18 
19 protected:
20     virtual void enterEvent(QEvent *) Q_DECL_OVERRIDE;//暫時沒用
21     virtual void leaveEvent(QEvent *) Q_DECL_OVERRIDE;//暫時沒用
22     virtual bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;
23     virtual void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE;
24 
25 
26     virtual void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE;
27 
28 private:
29     void InitializeUI();
30 
31 private:
32     bool m_Mouse_press = false;
33     QWidget * m_ContentWidget = nullptr;
34     QPushButton * m_ActIcon = nullptr;
35     QLabel * m_ActText = nullptr;
36 };

    這個窗口支持鼠標hover事件,而且我本身實現了鼠標按下和彈起方法,爲的是本身控制QComboBox下拉框的隱藏,接口SetBackgroundRole是控制窗口背景色變化的函數,因爲enterEvent和leaveEvent方法在成爲了代理窗口後,事件觸發我本身也沒有搞清楚是怎麼回事,所以我使用了installEventFilter方法把該窗口的事件放到父窗口去處理,在窗口中判斷鼠標當前位置和CActionContentWidget 窗口之間的關係來判斷鼠標是否進入該窗口。spa

QQ圖片20160726180015圖4

二、如圖4所示,是我實現的結果預覽,接下來咱們須要把定製的窗口放到QComboBox的下拉框中,代碼以下:

 1 class combobox : public QWidget
 2 {
 3     Q_OBJECT
 4 
 5 public:
 6     combobox(QWidget *parent = 0);
 7     ~combobox();
 8 
 9 protected:
10     virtual bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;
11 
12 private:
13     void ConstructList();//列表定製
14     void ConstructTable();//表格定製
15 
16 private:
17     Ui::comboboxClass ui;
18 };

    ConstructList方法是列表的定製,也就是上圖4所示的效果,ConstructTable方法內封裝的是定製表格,後續我會講解。

三、上邊提到定製的窗口和鼠標位置的判斷是在父窗口中進行的,那麼接下來我就解釋下父窗口的eventFIlter方法。代碼比較簡單,我就不一一進行解釋了

 1 bool combobox::eventFilter(QObject * watched, QEvent * event)
 2 {
 3     if (watched->inherits("QWidget") && event->type() == QEvent::Paint)
 4     {
 5         if (CActionContentWidget * actionItem = dynamic_cast<CActionContentWidget *>(watched))
 6         {
 7             if (actionItem->rect().contains(actionItem->mapFromGlobal(QCursor::pos())))
 8             {
 9                 actionItem->SetBackgroundRole(true);
10             }
11             else
12             {
13                 actionItem->SetBackgroundRole(false);
14             }
15         }
16     }
17 
18     return QWidget::eventFilter(watched, event);
19 }

四、ConstructList列表實現,代碼以下:

 1 void combobox::ConstructList()
 2 {
 3     QListWidget * listWidget = new QListWidget;
 4     listWidget->setViewMode(QListView::ListMode);
 5 
 6     for (int i = 0; i < 5; i++)
 7     {
 8         CActionContentWidget * itemWidget = new CActionContentWidget("fawefawe");
 9         connect(itemWidget, &CActionContentWidget::showText, this, [this, listWidget](const QString & text){
10             ui.comboBox->hidePopup();
11             if (ui.comboBox->isEditable())
12             {
13                 ui.comboBox->setCurrentText(text);
14             }
15             else
16             {
17                 for (int c = 0; c < listWidget->count(); ++c)
18                 {
19                     CActionContentWidget * itemWidget = dynamic_cast<CActionContentWidget *>(listWidget->itemWidget(listWidget->item(c)));
20                     if (itemWidget == sender())
21                     {
22                         ui.comboBox->setCurrentIndex(c);
23                     }
24                 }
25             }
26         });
27         itemWidget->SetItemIcon(":/combobox/Resources/icon1.jpg", ":/combobox/Resources/icon1.jpg");
28         itemWidget->setFixedHeight(45);
29         itemWidget->setFixedWidth(150);
30          QListWidgetItem * item = new QListWidgetItem(listWidget);
31         item->setText(QStringLiteral("%1").arg(i));
32     //    item->setCheckState(Qt::Checked);
33         listWidget->setItemWidget(item, itemWidget);
34         listWidget->addItem(item);
35         itemWidget->installEventFilter(this);
36     }
37 
38     ui.comboBox->setModel(listWidget->model());
39     ui.comboBox->setView(listWidget);
40     ui.comboBox->setEditable(true);//是否支持下拉框可編輯
41     ui.comboBox->setMaxVisibleItems(3);
42 
43     setStyleSheet("QComboBox{border:1px solid gray;}"
44         "QComboBox QAbstractItemView::item{height:45px;}" //下拉選項高度
45         "QComboBox::down-arrow{image:url(:/combobox/Resources/icon1.jpg);}" //下拉箭頭
46         "QComboBox::drop-down{border:0px;}"); //下拉按鈕
47 }
View Code

    其中的setStyleSheet是用來設置下拉框中每一項的信息的,咱們本身定製的窗口只是覆蓋在原有窗口之上而已,原有的窗口仍是存在的,所以咱們的窗口必須和定製的窗口大小同樣,負責會出現一些意外的狀況。初次以外還須要注意的是:設置下拉框是否可編輯,如圖5幫助文檔所描述,QComboBox在可編輯狀態下能夠經過setCurrentText來設置displayText,可是若是不可編輯,他則會顯示當前原有窗口的text,而非咱們本身定製的窗口內容,所以我在showText信號的處理槽中,判斷了下下拉框是否可編輯,並作相應的處理。

image圖5

    還有幾個設置下拉框屬性的接口,我就不一一細說了,想了解的同窗本身看幫助文檔吧。其中setModel和setView是兩居重點的代碼,千萬不能忘記,這兩句代碼是把QComboBox的視圖和數據跟QListWidget綁定在一塊兒了。QListWidget還支持ViewMode::IconMode這種現實模式,可是咱們的下拉框定製用不到,所以我就不講解這個了。

五、到此咱們的列表定製就完成了。

2、表格實現

    看明白了列表的實現,表格的實現就不在話下,不過咱們列表的實現和表格的實現我在實現的時候仍是有必定的區別的,有興趣的同窗能夠接着往下看。首先就說下拉框的隱藏這一事件就和列表不同,表格我是使用QTableWidget,內容使用QCheckBox,我本身重寫了QCheckBox,並從新是了hitButton這個方法,由於當這個方法返回false時,鼠標點擊不會選中/取消選中選擇框,這個時候事件循環應該是傳遞到了父窗口上,而窗口把彈框隱藏了,這樣作顯然不知足咱們的需求,有時候咱們可能須要進行多個選擇。說完需求以後咱們來看代碼。

一、首先我本身重寫了QCheckBox,頭文件代碼以下:

 1 class CheckBox : public QCheckBox
 2 {
 3 public:
 4     CheckBox(QWidget * parent = nullptr) :QCheckBox(parent){}
 5     ~CheckBox(){};;
 6 
 7 protected:
 8     virtual void checkStateSet() Q_DECL_OVERRIDE;
 9     virtual bool hitButton(const QPoint & pos) const Q_DECL_OVERRIDE;
10     virtual void nextCheckState() Q_DECL_OVERRIDE;
11 };

    大多數函數都是沒有作處理,僅僅對hitButton方法作了重寫,返回值直接返回true。這個時候就咱們就能夠進行多項選擇,而彈框也不會消失。最終的實現效果如圖6所示

QQ圖片20160727123954圖6

二、ConstructTable方法的實現以下:

 1 void combobox::ConstructTable()
 2 {
 3     setStyleSheet("QComboBox QAbstractItemView {selection-background-color: transparent;}");
 4 
 5     QTableWidget * tableWidget = new QTableWidget(3, 3);
 6     tableWidget->verticalHeader()->setVisible(false);
 7     tableWidget->horizontalHeader()->setVisible(false);
 8     tableWidget->setShowGrid(false);
 9     for (int i = 0; i < 3; ++i)
10     {
11         tableWidget->setColumnWidth(i, 49);
12         tableWidget->setRowHeight(i, 50);
13         for (int j = 0; j < 3; ++j)
14         {
15         /*    CActionContentWidget *itemWidget = new CActionContentWidget("fawefawe");
16             itemWidget->SetItemIcon(":/combobox/Resources/icon1.jpg", ":/combobox/Resources/icon1.jpg");
17             itemWidget->setFixedHeight(50);
18             itemWidget->setFixedWidth(50);*/
19             CheckBox * itemWidget = new CheckBox;
20             itemWidget->setFixedSize(50, 50);
21             itemWidget->setStyleSheet(QString("QCheckBox {background-color:lightgray;}"
22                 "QCheckBox:checked{background-color:white;}"));
23             connect(itemWidget, &QCheckBox::clicked, this, [this]{
24                 QObject * sender = this->sender();
25                 if (QCheckBox * item = dynamic_cast<QCheckBox *>(sender))
26                 {
27                     QString text = ui.comboBox->currentText();
28                     if (text.isEmpty() == false)
29                     {
30                         if (item->isChecked())
31                         {
32                             if (text.split("|").indexOf(item->text()) == -1)
33                             {
34                                 text.append("|" + item->text());
35                             }
36                         }
37                         else
38                         {
39                             text.remove("|" + item->text());
40                             text.remove(item->text());
41                             if (text.size() != 0 && text.at(0) == '|')
42                             {
43                                 text.remove(0, 1);
44                             }
45                         }
46                     }
47                     else
48                     {
49                         if (item->isChecked())
50                         {
51                             text.append(item->text());
52                         }
53                     }
54                     ui.comboBox->setCurrentText(text);
55                 }
56             });
57             itemWidget->setText(QStringLiteral("好%1").arg(i));
58             itemWidget->setCheckable(true);
59         //    tableWidget->setItem(i, j, new QTableWidgetItem(QStringLiteral("熱分%1").arg(i)));
60             tableWidget->setCellWidget(i, j, itemWidget);
61 
62             itemWidget->installEventFilter(this);
63         }
64     }
65 
66     ui.comboBox->setModel(tableWidget->model());
67     ui.comboBox->setView(tableWidget);
68 //    ui.comboBox->setEditable(true);
69 }
View Code

    上邊的代碼都比較簡單,我就很少了,我只說一個點,在設置表格列寬度的時候設置的爲49,由於表格具備boder,若是設置50就會超出tableWidget,而出現左右滾動的現象

demo下載連接:http://download.csdn.net/detail/qq_30392343/9587529

 

若是您以爲文章不錯,不妨給個 打賞,寫做不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!! 

 


 

  


很重要--轉載聲明

  1. 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。 

 

相關文章
相關標籤/搜索