Qt 學習之路 2(42):QListWidget、QTreeWidget 和 QTableWidget
上一章我們瞭解了 model/view 架構的基本概念。現在我們從最簡單的QListWidget
、QTreeWidget
和QTableWidget
三個類開始瞭解最簡單的 model/view 的使用。這部分內容的確很難組織。首先,從最標準的 model/view 開始,往往會糾結於複雜的程式碼;但是,如果從簡單的 QListWidget
、QTreeWidget
和QTableWidget
開始,由於這三個類都是繼承自各自的 view 類,很難避免 model/view 的相關內容。於是,我們這部分的組織是,首先進行簡單的資料顯示,更復雜的設定則放在後面的章節。
QListWidget
我們要介紹的第一個是QListWidget
。先來看下面的程式碼示例:
C/C++
28 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
label = new QLabel(this);
label->setFixedWidth(70);
listWidget = new QListWidget(this);
new QListWidgetItem(QIcon(":/Chrome.png"), tr("Chrome"), listWidget);
new QListWidgetItem(QIcon(":/Firefox.png"), tr("Firefox"), listWidget);
listWidget->addItem(new QListWidgetItem(QIcon(":/IE.png"), tr("IE")));
listWidget->addItem(new QListWidgetItem(QIcon(":/Netscape.png"), tr("Netscape")));
listWidget->addItem(new QListWidgetItem(QIcon(":/Opera.png"), tr("Opera")));
listWidget->addItem(new QListWidgetItem(QIcon(":/Safari.png"), tr("Safari")));
listWidget->addItem(new QListWidgetItem(QIcon(":/TheWorld.png"), tr("TheWorld")));
listWidget->addItem(new QListWidgetItem(QIcon(":/Traveler.png"), tr("Traveler")));
QListWidgetItem *newItem = new QListWidgetItem;
newItem->setIcon(QIcon(":/Maxthon.png"));
newItem->setText(tr("Maxthon"));
listWidget->insertItem(3, newItem);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(label);
layout->addWidget(listWidget);
setLayout(layout);
connect(listWidget, SIGNAL(currentTextChanged(QString)),
label, SLOT(setText(QString)));
QListWidget
是簡單的列表元件。當我們不需要複雜的列表時,可以選擇QListWidget
。QListWidget
中可以新增QListWidgetItem
型別作為列表項,QListWidgetItem
即可以有文字,也可以有圖示。上面的程式碼顯示了三種向列表中新增列表項的方法(實際是兩種,後兩種其實是一樣的),我們的列表元件是listWidget
,那麼,向listWidget
新增列表項可以:第一,使用下面的語句
C/C++
1 lines
1
new QListWidgetItem(QIcon(":/Chrome.png"), tr("Chrome"), listWidget);
第二,使用
C/C++
6 lines
1
2
3
4
5
6
listWidget->addItem(new QListWidgetItem(QIcon(":/IE.png"), tr("IE")));
// 或者
QListWidgetItem *newItem = new QListWidgetItem;
newItem->setIcon(QIcon(":/Maxthon.png"));
newItem->setText(tr("Maxthon"));
listWidget->insertItem(3, newItem);
注意這兩種新增方式的區別:第一種需要在構造時設定所要新增到的QListWidget
物件;第二種方法不需要這樣設定,而是要呼叫addItem()
或者insertItem()
自行新增。如果你仔細查閱QListWidgetItem
的建構函式,會發現有一個預設的type
引數。該引數有兩個合法值:QListWidgetItem::Type
(預設)和QListWidgetItem::UserType
。如果我們繼承QListWidgetItem
,可以設定該引數,作為我們子類的一種區別,以便能夠在QListWidget
區別處理不同子類。
我們的程式的執行結果如下:
我們可以利用QListWidget
發出的各種訊號來判斷是哪個列表項被選擇,具體細節可以參考文件。另外,我們也可以改變列表的顯示方式。前面的列表是小圖示顯示,我們也可以更改為圖示顯示,只要新增一行語句:
C/C++
1 lines
1
listWidget->setViewMode(QListView::IconMode);
結果如下:
QTreeWidget
我們要介紹的第二個元件是QTreeWidget
。顧名思義,這是用來展示樹型結構(也就是層次結構)的。同前面說的QListWidget
類似,這個類需要同另外一個輔助類QTreeWidgetItem
一起使用。不過,既然是提供方面的封裝類,即便是看上去很複雜的樹,在使用這個類的時候也是顯得比較簡單的。當不需要使用複雜的QTreeView
特性的時候,我們可以直接使用QTreeWidget
代替。
下面我們使用程式碼構造一棵樹:
C/C++
14 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
QTreeWidget treeWidget;
treeWidget.setColumnCount(1);
QTreeWidgetItem *root = new QTreeWidgetItem(&treeWidget,
QStringList(QString("Root")));
new QTreeWidgetItem(root, QStringList(QString("Leaf 1")));
QTreeWidgetItem *leaf2 = new QTreeWidgetItem(root, QStringList(QString("Leaf 2")));
leaf2->setCheckState(0, Qt::Checked);
QList<QTreeWidgetItem *> rootList;
rootList << root;
treeWidget.insertTopLevelItems(0, rootList);
treeWidget.show();
首先,我們建立了一個QTreeWidget
例項。然後我們呼叫setColumnCount()
函式設定欄數。這個函式的效果我們會在下文了解到。最後,我們向QTreeWidget
新增QTreeWidgetItem
。QTreeWidgetItem
有很多過載的建構函式。我們在這裡看看其中的一個,其餘的請自行查閱文件。這個建構函式的簽名如下:
C/C++
1 lines
1
QTreeWidgetItem(QTreeWidget *parent, const QStringList &strings, int type = Type);
這裡有 3 個引數,第一個引數用於指定這個項屬於哪一個樹,類似前面的QListWidgetItem
,如果指定了這個值,則意味著該項被直接新增到樹中;第二個引數指定顯示的文字;第三個引數指定其型別,同QListWidgetItem
的type
引數十分類似。值得注意的是,第二個引數是QStringList
型別的,而不是QString
型別。我們會在下文了解其含義。
在這段程式碼中,我們建立了作為根的QTreeWidgetItem
root。然後添加了第一個葉節點,之後又新增一個,而這個則設定了可選標記。最後,我們將這個 root 新增到一個QTreeWidgetItem
的列表,作為QTreeWidget
的資料項。此時你應該想到,既然QTreeWidget
接受QList
作為項的資料,它就能夠支援多棵樹的一起顯示,而不僅僅是單根樹。下面我們來看看執行結果:
從程式碼來看,我們能夠想象到這個樣子,只是這個樹的頭上怎麼會有一個 1?還記得我們跳過去的那個函式嗎?下面我們修改一下程式碼看看:
C/C++
20 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
QTreeWidget treeWidget;
QStringList headers;
headers << "Name" << "Number";
treeWidget.setHeaderLabels(headers);
QStringList rootTextList;
rootTextList << "Root" << "0";
QTreeWidgetItem *root = new QTreeWidgetItem(&treeWidget, rootTextList);
new QTreeWidgetItem(root, QStringList() << QString("Leaf 1") << "1");
QTreeWidgetItem *leaf2 = new QTreeWidgetItem(root,
QStringList() << QString("Leaf 2") << "2");
leaf2->setCheckState(0, Qt::Checked);
QList<QTreeWidgetItem *> rootList;
rootList << root;
treeWidget.insertTopLevelItems(0, rootList);
treeWidget.show();
這次我們沒有使用setColumnCount()
,而是直接使用QStringList
設定了 headers,也就是樹的表頭。接下來我們使用的還是QStringList
設定資料。這樣,我們實現的是帶有層次結構的樹狀表格。利用這一屬性,我們可以比較簡單地實現類似 Windows 資源管理器的介面。
如果你不需要顯示這個表頭,可以呼叫setHeaderHidden()
函式將其隱藏。
QTableWidget
我們要介紹的最後一個是 QTableWidget
。QTableWidget
並不比前面的兩個複雜到哪裡去,這點我們可以從程式碼看出來:
C/C++
16 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
QTableWidget tableWidget;
tableWidget.setColumnCount(3);
tableWidget.setRowCount(5);
QStringList headers;
headers << "ID" << "Name" << "Age" << "Sex";
tableWidget.setHorizontalHeaderLabels(headers);
tableWidget.setItem(0, 0, new QTableWidgetItem(QString("0001")));
tableWidget.setItem(1, 0, new QTableWidgetItem(QString("0002")));
tableWidget.setItem(2, 0, new QTableWidgetItem(QString("0003")));
tableWidget.setItem(3, 0, new QTableWidgetItem(QString("0004")));
tableWidget.setItem(4, 0, new QTableWidgetItem(QString("0005")));
tableWidget.setItem(0, 1, new QTableWidgetItem(QString("20100112")));
tableWidget.show();
這段程式碼執行起來是這樣子的:
首先我們建立了QTableWidget
物件,然後設定列數和行數。接下來使用一個QStringList
,設定每一列的標題。我們可以通過呼叫setItem()
函式來設定表格的單元格的資料。這個函式前兩個引數分別是行索引和列索引,這兩個值都是從 0 開始的,第三個引數則是一個QTableWidgetItem
物件。Qt 會將這個物件放在第 row 行第 col 列的單元格中。有關QTableWidgetItem
的介紹完全可以參見上面的QListWidgetItem
和QTreeWidgetItem
。
上一章我們瞭解了 model/view 架構的基本概念。現在我們從最簡單的QListWidget
、QTreeWidget
和QTableWidget
三個類開始瞭解最簡單的 model/view 的使用。這部分內容的確很難組織。首先,從最標準的 model/view 開始,往往會糾結於複雜的程式碼;但是,如果從簡單的 QListWidget
、QTreeWidget
和QTableWidget
開始,由於這三個類都是繼承自各自的 view 類,很難避免 model/view 的相關內容。於是,我們這部分的組織是,首先進行簡單的資料顯示,更復雜的設定則放在後面的章節。
QListWidget
我們要介紹的第一個是QListWidget
。先來看下面的程式碼示例:
C/C++
28 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
label = new QLabel(this);
label->setFixedWidth(70);
listWidget = new QListWidget(this);
new QListWidgetItem(QIcon(":/Chrome.png"), tr("Chrome"), listWidget);
new QListWidgetItem(QIcon(":/Firefox.png"), tr("Firefox"), listWidget);
listWidget->addItem(new QListWidgetItem(QIcon(":/IE.png"), tr("IE")));
listWidget->addItem(new QListWidgetItem(QIcon(":/Netscape.png"), tr("Netscape")));
listWidget->addItem(new QListWidgetItem(QIcon(":/Opera.png"), tr("Opera")));
listWidget->addItem(new QListWidgetItem(QIcon(":/Safari.png"), tr("Safari")));
listWidget->addItem(new QListWidgetItem(QIcon(":/TheWorld.png"), tr("TheWorld")));
listWidget->addItem(new QListWidgetItem(QIcon(":/Traveler.png"), tr("Traveler")));
QListWidgetItem *newItem = new QListWidgetItem;
newItem->setIcon(QIcon(":/Maxthon.png"));
newItem->setText(tr("Maxthon"));
listWidget->insertItem(3, newItem);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(label);
layout->addWidget(listWidget);
setLayout(layout);
connect(listWidget, SIGNAL(currentTextChanged(QString)),
label, SLOT(setText(QString)));
QListWidget
是簡單的列表元件。當我們不需要複雜的列表時,可以選擇QListWidget
。QListWidget
中可以新增QListWidgetItem
型別作為列表項,QListWidgetItem
即可以有文字,也可以有圖示。上面的程式碼顯示了三種向列表中新增列表項的方法(實際是兩種,後兩種其實是一樣的),我們的列表元件是listWidget
,那麼,向listWidget
新增列表項可以:第一,使用下面的語句
C/C++
1 lines
1
new QListWidgetItem(QIcon(":/Chrome.png"), tr("Chrome"), listWidget);
第二,使用
C/C++
6 lines
1
2
3
4
5
6
listWidget->addItem(new QListWidgetItem(QIcon(":/IE.png"), tr("IE")));
// 或者
QListWidgetItem *newItem = new QListWidgetItem;
newItem->setIcon(QIcon(":/Maxthon.png"));
newItem->setText(tr("Maxthon"));
listWidget->insertItem(3, newItem);
注意這兩種新增方式的區別:第一種需要在構造時設定所要新增到的QListWidget
物件;第二種方法不需要這樣設定,而是要呼叫addItem()
或者insertItem()
自行新增。如果你仔細查閱QListWidgetItem
的建構函式,會發現有一個預設的type
引數。該引數有兩個合法值:QListWidgetItem::Type
(預設)和QListWidgetItem::UserType
。如果我們繼承QListWidgetItem
,可以設定該引數,作為我們子類的一種區別,以便能夠在QListWidget
區別處理不同子類。
我們的程式的執行結果如下:
我們可以利用QListWidget
發出的各種訊號來判斷是哪個列表項被選擇,具體細節可以參考文件。另外,我們也可以改變列表的顯示方式。前面的列表是小圖示顯示,我們也可以更改為圖示顯示,只要新增一行語句:
C/C++
1 lines
1
listWidget->setViewMode(QListView::IconMode);
結果如下:
QTreeWidget
我們要介紹的第二個元件是QTreeWidget
。顧名思義,這是用來展示樹型結構(也就是層次結構)的。同前面說的QListWidget
類似,這個類需要同另外一個輔助類QTreeWidgetItem
一起使用。不過,既然是提供方面的封裝類,即便是看上去很複雜的樹,在使用這個類的時候也是顯得比較簡單的。當不需要使用複雜的QTreeView
特性的時候,我們可以直接使用QTreeWidget
代替。
下面我們使用程式碼構造一棵樹:
C/C++
14 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
QTreeWidget treeWidget;
treeWidget.setColumnCount(1);
QTreeWidgetItem *root = new QTreeWidgetItem(&treeWidget,
QStringList(QString("Root")));
new QTreeWidgetItem(root, QStringList(QString("Leaf 1")));
QTreeWidgetItem *leaf2 = new QTreeWidgetItem(root, QStringList(QString("Leaf 2")));
leaf2->setCheckState(0, Qt::Checked);
QList<QTreeWidgetItem *> rootList;
rootList << root;
treeWidget.insertTopLevelItems(0, rootList);
treeWidget.show();
首先,我們建立了一個QTreeWidget
例項。然後我們呼叫setColumnCount()
函式設定欄數。這個函式的效果我們會在下文了解到。最後,我們向QTreeWidget
新增QTreeWidgetItem
。QTreeWidgetItem
有很多過載的建構函式。我們在這裡看看其中的一個,其餘的請自行查閱文件。這個建構函式的簽名如下:
C/C++
1 lines
1
QTreeWidgetItem(QTreeWidget *parent, const QStringList &strings, int type = Type);
這裡有 3 個引數,第一個引數用於指定這個項屬於哪一個樹,類似前面的QListWidgetItem
,如果指定了這個值,則意味著該項被直接新增到樹中;第二個引數指定顯示的文字;第三個引數指定其型別,同QListWidgetItem
的type
引數十分類似。值得注意的是,第二個引數是QStringList
型別的,而不是QString
型別。我們會在下文了解其含義。
在這段程式碼中,我們建立了作為根的QTreeWidgetItem
root。然後添加了第一個葉節點,之後又新增一個,而這個則設定了可選標記。最後,我們將這個 root 新增到一個QTreeWidgetItem
的列表,作為QTreeWidget
的資料項。此時你應該想到,既然QTreeWidget
接受QList
作為項的資料,它就能夠支援多棵樹的一起顯示,而不僅僅是單根樹。下面我們來看看執行結果:
從程式碼來看,我們能夠想象到這個樣子,只是這個樹的頭上怎麼會有一個 1?還記得我們跳過去的那個函式嗎?下面我們修改一下程式碼看看:
C/C++
20 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
QTreeWidget treeWidget;
QStringList headers;
headers << "Name" << "Number";
treeWidget.setHeaderLabels(headers);
QStringList rootTextList;
rootTextList << "Root" << "0";
QTreeWidgetItem *root = new QTreeWidgetItem(&treeWidget, rootTextList);
new QTreeWidgetItem(root, QStringList() << QString("Leaf 1") << "1");
QTreeWidgetItem *leaf2 = new QTreeWidgetItem(root,
QStringList() << QString("Leaf 2") << "2");
leaf2->setCheckState(0, Qt::Checked);
QList<QTreeWidgetItem *> rootList;
rootList << root;
treeWidget.insertTopLevelItems(0, rootList);
treeWidget.show();
這次我們沒有使用setColumnCount()
,而是直接使用QStringList
設定了 headers,也就是樹的表頭。接下來我們使用的還是QStringList
設定資料。這樣,我們實現的是帶有層次結構的樹狀表格。利用這一屬性,我們可以比較簡單地實現類似 Windows 資源管理器的介面。
如果你不需要顯示這個表頭,可以呼叫setHeaderHidden()
函式將其隱藏。
QTableWidget
我們要介紹的最後一個是 QTableWidget
。QTableWidget
並不比前面的兩個複雜到哪裡去,這點我們可以從程式碼看出來:
C/C++
16 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
QTableWidget tableWidget;
tableWidget.setColumnCount(3);
tableWidget.setRowCount(5);
QStringList headers;
headers << "ID" << "Name" << "Age" << "Sex";
tableWidget.setHorizontalHeaderLabels(headers);
tableWidget.setItem(0, 0, new QTableWidgetItem(QString("0001")));
tableWidget.setItem(1, 0, new QTableWidgetItem(QString("0002")));
tableWidget.setItem(2, 0, new QTableWidgetItem(QString("0003")));
tableWidget.setItem(3, 0, new QTableWidgetItem(QString("0004")));
tableWidget.setItem(4, 0, new QTableWidgetItem(QString("0005")));
tableWidget.setItem(0, 1, new QTableWidgetItem(QString("20100112")));
tableWidget.show();
這段程式碼執行起來是這樣子的:
首先我們建立了QTableWidget
物件,然後設定列數和行數。接下來使用一個QStringList
,設定每一列的標題。我們可以通過呼叫setItem()
函式來設定表格的單元格的資料。這個函式前兩個引數分別是行索引和列索引,這兩個值都是從 0 開始的,第三個引數則是一個QTableWidgetItem
物件。Qt 會將這個物件放在第 row 行第 col 列的單元格中。有關QTableWidgetItem
的介紹完全可以參見上面的QListWidgetItem
和QTreeWidgetItem
。
https://www.devbean.net/2013/02/qt-study-road-2-qlistwidget-qtreewidget-qtablewidget/