Qt 5 C++ – Một số lớp hữu ích

4.8/5 - (5 votes)

Trong phần này chúng ta sẽ học về một số lớp dùng để lưu trữ dữ liệu trong Qt 5. Đó là các lớp QVector, QList, QStringList, QSet, và QMap.

Trong thư viện chuẩn của C++ là Standard Template Library (STL) cũng có một số lớp có chức năng tương tự. Bạn có thể dùng các lớp đó hoặc các lớp mình sắp nói dưới đây, cái nào cũng tốt cả.

Các lớp này được chia làm hai loại, loại thứ nhất lưu dữ liệu theo kiểu danh sách, loại thứ hai lưu theo kiểu các cặp khóa-giá trị (key-value). QList, QVector, QLinkedList là các lớp lưu theo kiểu danh sách; còn QMap và QHash lưu theo kiểu cặp khóa-giá trị.

QVector

QVector lưu trữ dữ liệu theo kiểu danh sách. Các phần tử  trong QVector nằm kế tiếp nhau trong bộ nhớ và có thể truy cập thông qua chỉ số nên có tốc độ truy xuất dữ liệu rất nhanh nếu số lượng phần tử không nhiều. Nếu dữ liệu cần lưu trữ quá lớn thì tốt nhất là bạn nên dùng QList thay thế.

#include <QVector>
#include <QTextStream>

int main(void) {

    QTextStream out(stdout);

    QVector<int> vals = {1, 2, 3, 4, 5};
    
    out << "The size of the vector is: " << vals.size() << endl;
       
    out << "The first item is: " << vals.first() << endl;
    out << "The last item is: " << vals.last() << endl;
    
    vals.append(6);
    vals.prepend(0);   
    
    out << "Elements: "; 
    
    for (int val : vals) {
        out << val << " ";
    }    
    
    out << endl;
   
    return 0;
}

Ví dụ trên tạo ra một vector lưu trữ các số nguyên.

QVector<int> vals = {1, 2, 3, 4, 5};

Khởi tạo vector

out << "The size of the vector is: " << vals.size() << endl;

Phương thức size() trả về kích thước của vector – số lượng các phần tử có trong vector.

out << "The first item is: " << vals.first() << endl;

Truy xuất phần tử đầu tiên với phương thức first().

out << "The last item is: " << vals.last() << endl;

Truy xuất phần tử cuối cùng với phương thức last().

vals.append(6);

Phương thức append() chèn một phần tử vào sau vector.

vals.prepend(0);

Phương thức prepend() chèn một phần tử vào đầu vector.

for (int val : vals) {
    out << val << " ";
}    

Chúng ta duyệt qua vector và in các phần tử ra màn hình.

The size of the vector is: 5
The first item is: 1
The last item is: 5
Elements: 0 1 2 3 4 5 6 

QList

QList cũng có chức năng tương tự như QVector. Nó cũng lưu trữ dữ liệu theo kiểu danh sách và truy xuất các phần tử thông qua chỉ số, nhưng tốc độ chèn và xóa dữ liệu nhanh hơn QVector. Đây là một trong những lớp hay dùng nhất trong Qt

#include <QTextStream>
#include <QList>
#include <algorithm>

int main(void) {

    QTextStream out(stdout);

    QList<QString> authors = {"Balzac", "Tolstoy", "Gulbranssen", "London"};
  
    for (int i=0; i < authors.size(); ++i) {
        out << authors.at(i) << endl;
    }  
  
    authors << "Galsworthy" << "Sienkiewicz";
    
    out << "***********************" << endl;

    std::sort(authors.begin(), authors.end());

    out << "Sorted:" << endl;
    for (QString author : authors) {  
        out << author << endl;
    }  
}

Ví dụ cách sử dụng QList.

QList<QString> authors = {"Balzac", "Tolstoy", "Gulbranssen", "London"};

Khởi tạo QList là danh sách tên các nhà văn.

for (int i=0; i < authors.size(); ++i) {
    out << authors.at(i) << endl;
}  

Ta duyệt qua QList bằng vòng lặp for và in dữ liệu ra màn hình bằng phương thức at(). Phương thức này nhận tham số đầu vào là chỉ số phần tử.

authors << "Galsworthy" << "Sienkiewicz";

Dùng toán tử << để chèn một phần tử mới vào sau QList.

std::sort(authors.begin(), authors.end());

Phương thức std::sort() sắp xếp các phần tử trong QList.

out << "Sorted:" << endl;
for (QString author : authors) {
    out << author << endl;
} 

In ra danh sách đã được sắp xếp.

Balzac
Tolstoy
Gulbranssen
London
***********************
Sorted:
Balzac
Galsworthy
Gulbranssen
London
Sienkiewicz
Tolstoy

QStringList

QStringList cũng giống như QList nhưng chuyên để làm việc với string.

#include <QTextStream>
#include <QList>

int main(void) {

    QTextStream out(stdout);

    QString string = "coin, book, cup, pencil, clock, bookmark";
    QStringList items = string.split(",");
    QStringListIterator it(items);
    
    while (it.hasNext()) {
        out << it.next().trimmed() << endl;    
    }
}

Ví dụ trên tạo ra một danh sách các string và in các phần tử trong danh sách ra màn hình.

QString string = "coin, book, cup, pencil, clock, bookmark";
QStringList items = string.split(",");

Phương thức split() tách một chuỗi thành nhiều chuỗi con dựa vào dấu phân tách mà ta đưa vào.

QStringListIterator it(items);

QStringListIterator là một lớp chuyên dùng để thao tác với QStringList.

while (it.hasNext()) {
    out << it.next().trimmed() << endl;    
}

Sau khi đã khởi tạo iterator, chúng ta in từng phần tử ra màn hình. Phương thức trimmed() sẽ xóa các khoảng trống thừa trong chuỗi.

coin
book
cup
pencil
clock
bookmark

QSet

QSet lưu trữ các phần tử dữ liệu đơn lẻ. Các phần tử trong QSet không được lưu theo một thứ tự nào cả.

#include <QSet>
#include <QList>
#include <QTextStream>
#include <algorithm>

int main(void) {
    
    QTextStream out(stdout);

    QSet<QString> cols1 = {"yellow", "red", "blue"};
    QSet<QString> cols2 = {"blue", "pink", "orange"};
      
    out << "There are " << cols1.size() << " values in the set" << endl;
   
    cols1.insert("brown");
   
    out << "There are " << cols1.size() << " values in the set" << endl;
    
    cols1.unite(cols2);
    
    out << "There are " << cols1.size() << " values in the set" << endl;
    
    for (QString val : cols1) {
        out << val << endl;
    }
    
    QList<QString> lcols = cols1.values();
    std::sort(lcols.begin(), lcols.end());
    
    out << "*********************" << endl;
    out << "Sorted:" << endl;
    
    for (QString val : lcols) {
        out << val << endl;
    }    
   
   return 0;
}

Ví dụ trên tạo ra các QSet lưu tên của các màu. Không có phần tử nào xuất hiện hai lần trở lên – tức là giá trị của mỗi phần tử là khác nhau.

QSet<QString> cols1 = {"yellow", "red", "blue"};
QSet<QString> cols2 = {"blue", "pink", "orange"};

Chúng ta có hai tập dữ liệu, hai tập này chứa một phần tử chung là “blue”.

out << "There are " << cols1.size() << " values in the set" << endl;

Phương thức size() trả về kích thước của tập.

cols1.insert("brown");

Chúng ta thêm một phần tử mới vào tập bằng phương thức insert().

cols1.unite(cols2);

Phương thức unite() thực hiện phép hợp hai tập này. Tập cols1 sẽ thêm vào các phần tử có trong tập cols2 mà chưa có trong tập cols1, mà ở đây chính là phần tử “blue”.

for (QString val : cols1) {
    out << val << endl;
}

Ta dùng vòng lặp for để in các phần tử ra của tập cols1 màn hình.

QList<QString> lcols = cols1.values();
std::sort(lcols.begin(), lcols.end());

Chúng ta không thể sắp xếp một tập hợp. Nếu cần bạn có thể tạo ra một QList rồi sắp xếp, phương thức values() sẽ trả về một QList chứa các phần tử trong tập, nhưng thứ tự của các phần tử trong tập là ngẫu nhiên.

There are 3 values in the set
There are 4 values in the set
There are 6 values in the set
pink
orange
brown
blue
yellow
red
*********************
Sorted:
blue
brown
orange
pink
red
yellow

QMap

QMap lưu dữ liệu theo kiểu các cặp khóa-giá trị (key-value). Chúng ta có thể truy xuất phần tử thông qua key.

#include <QTextStream>
#include <QMap>

int main(void) {

    QTextStream out(stdout);

    QMap<QString, int> items = { {"coins", 5}, {"books", 3} };
    
    items.insert("bottles", 7);
    
    QList<int> values = items.values();
    
    out << "Values:" << endl;

    for (int val : values) {
        out << val << endl;
    }
    
    QList<QString> keys = items.keys();

    out << "Keys:" << endl;
    for (QString key : keys) {
        out << key << endl;
    }    
    
    QMapIterator<QString, int> it(items);
    
    out << "Pairs:" << endl;
    
    while (it.hasNext()) {
        it.next();
        out << it.key() << ": " << it.value() << endl;    
    }
}

Trong ví dụ trên, chúng ta có các cặp key, mỗi key có một value.

QMap<QString, int> items = { {"coins", 5}, {"books", 3} };

Ta tạo ra một QMap chứa hai cặp key-value.

items.insert("bottles", 7);

Ta thêm một cặp key-value bằng phương thức insert().

QList<int> values = items.values();

out << "Values:" << endl;

for (int val : values) {
    out << val << endl;
}

Chúng ta in toàn bộ các cặp ra màn hình. Ngoài ra ta có thể dùng phương thức values() để lấy về một QList chứa các value.

QList<QString> keys = items.keys();

out << "Keys:" << endl;
for (QString key : keys) {
    out << key << endl;
} 

Ta in các key ra màn hình. Cũng giống như trên, ta có thể dùng phương thức keys() để lấy về một QList các key.

QMapIterator<QString, int> it(items);

QMapIterator là biến lặp iterator cho QMap, dùng để thao tác với QMap.

while (it.hasNext()) {
    it.next();
    out << it.key() << ": " << it.value() << endl;    
}

Ta dùng iterator này để duyệt qua QMap. Phương thức key() sẽ trả về khóa và phương thức value() sẽ trả về giá trị.

Values:
3
7
5
Keys:
books
bottles
coins
Pairs:
books: 3
bottles: 7
coins: 5

Sắp xếp các lớp do người dùng định nghĩa

Trong ví dụ dưới đây, chúng ta sẽ sắp xếp một QList chứa các đối tượng thuộc lớp Book do chúng ta tự định nghĩa.

class Book {
    
    public:
        Book(QString, QString);
        QString getAuthor() const;
        QString getTitle() const;
        
    private:            
        QString author;
        QString title;    
};

Đây là file header của lớp Book.

#include <QString>
#include "book.h"

Book::Book(QString auth, QString tit) {
    
    author = auth;
    title = tit;
}

QString Book::getAuthor() const {
    
    return author;
}

QString Book::getTitle() const {
    
    return title;
}

Đây là file cài dặt các phương thức của lớp Book, trong lớp này ta cài đặt hai phương thức truy xuất dữ liệu.

#include <QTextStream>
#include <QList>
#include <algorithm> 
#include "book.h"

bool compareByTitle(const Book &b1, const Book &b2) {
    
  return b1.getTitle() < b2.getTitle();
}

int main(void) {

    QTextStream out(stdout);

    QList<Book> books = {
        Book("Jack London", "The Call of the Wild"),
        Book("Honoré de Balzac", "Father Goriot"),
        Book("Leo Tolstoy", "War and Peace"),
        Book("Gustave Flaubert", "Sentimental education"),
        Book("Guy de Maupassant", "Une vie"),
        Book("William Shakespeare", "Hamlet")
    };
    
    std::sort(books.begin(), books.end(), compareByTitle);
    
    for (Book book : books) {
        out << book.getAuthor() << ": " << book.getTitle() << endl;
    }
}

Ta tạo ra vài đối tượng Book, đưa chúng vô QList và sắp xếp với hàm std::sort.

bool compareByTitle(const Book &b1, const Book &b2) {    
  return b1.getTitle() < b2.getTitle();
}

Phương thức compareByTitle() là phương thức so sánh sẽ được sử dụng bởi hàm sort.

std::sort(oks.begin(), books.end(), compareByTitle);

Hàm std::sort sẽ sắp xếp các book dựa theo tựa book.

Honoré de Balzac: Father Goriot
William Shakespeare: Hamlet
Gustave Flaubert: Sentimental education
Jack London: The Call of the Wild
Guy de Maupassant: Une vie
Leo Tolstoy: War and Peace

Trong bài này, chúng ta đã học về một số lớp lưu trữ dữ liệu thường dùng trong Qt 5.

5 1 vote
Article Rating
Subscribe
Thông báo cho tôi qua email khi
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments