Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 4120 razy

Kontrolka QListView wizualnie przypomina wcześniej omawianą kontrolkę QListWidget, jednakże funkcjonuje ona na nieco innej zasadzie i umożliwia znacznie większą elastyczność sterowania jej funkcjonalnością i wyglądem. Niestety jest to obarczone nieco bardziej złożonym procesem obsługi tej kontrolki. W przykładzie, który mam zamiar pokazać wyeliminowałem konieczność tworzenia dodatkowych kontrolek do wprowadzania danych przez użytkownika do mojej listy. W kontrolce QListView po odpowiednim ustawieniu jej właściwości metodą setEditTriggers i zaznaczeniu myszką jednej z dostępnych pozycji można zmienić jej zawartość wpisując po prostu tekst. Klawisz enter zatwierdza zmianę. To samo można zrobić klikając dwukrotnie na danym elemencie listy i edytując zawarty w nim tekst.

Zanim przejdę do kodu warto zerknąć łaskawym okiem na wygląd samego graficznego interfejsu użytkownika, na który składa się tylko jedna kontrolka QListView, która zastąpi wszystkie dodatkowe przyciski i kontrolkę QLineEdit z poprzedniej strony.

Qt Creator - interfejs graficzny z kontrolką QListView
Rys. 1
Qt Creator - interfejs graficzny z kontrolką QListView

W kodzie obiekt klasy QListView nazwałem countriesList.

Kod programu w pliku mainwindow.h:

#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QStringListModel> #include <QDebug> #include <QMessageBox> #include <QShortcut> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT QStringListModel *countriesListModel; // model, który zostanie podpięty pod kontrolkę QListView QString country; // pomocnicza zmienna konieczna do przechowywania informacji o tekście zawartym w danym elemencie kontrolki przed jego modyfikacją QShortcut *shDelete; // skrót klawiaturowy do podpięcia slotu onDeleteItem public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: // slot podpięty pod sygnał wysyłany, gdy tekst w elementach kontrolki został zmieniony void countryDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int> ()); // slot podpięty pod sygnał wysyłany, gdy element w kontrolce został kliknięty dwa razy (co będzie oznaczało edycję tekstu kontrolki void on_countriesList_doubleClicked(const QModelIndex &index); // slot podpięty pod skrót klawiaturowy oznaczający usuwanie elementu zaznaczonego void onDeleteItem(); // slot podpięty pod sygnał wysyłany, gdy wcześniej zaznaczony na liście element został nadpisany poprzez rozpoczęcie wpisywania tekstu void on_countriesList_pressed(const QModelIndex &index); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H

Kontrolka QListView do dodawania elementów listy wykorzystuje obiekt klasy QStringListModel, który po utworzeniu trzeba podpiąć pod obiekt klasy QListView wykorzystując jej metodę setModel. Wszystko to zostanie uczynione w konstruktorze klasy MainWindow w pliku mainwindow.cpp:

#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); countriesListModel = new QStringListModel(this); // tworzenie nowego obiektu modelu countriesListModel->setStringList( {"Polska", "Czechy", "Słowacja"} // dodaję parę początkowych pozycji ); ui->countriesList->setModel(countriesListModel); // podpinam model pod kontrolkę QListView ui->countriesList->setEditTriggers( QAbstractItemView::AnyKeyPressed | // edycja zaznaczonego elementu na dowolny znak tekstowy QAbstractItemView::DoubleClicked // edycja elementu po dwukrotnym kliknięciu lewym przyciskiem myszy ); int row = countriesListModel->rowCount(); // pobieram liczbę wierszy countriesListModel->insertRow(row); // wstawiam dodatkowy wiersz na końcu QModelIndex index = countriesListModel->index(row, 0); // pobieram obiekt wstawionego indeksu countriesListModel->setData(index, QVariant("*")); // i ustawiam jego tekst // podpięcie sygnału dataChanged obiektu countriesListModel pod slot countryDataChanged okna głównego QObject::connect(countriesListModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(countryDataChanged(QModelIndex,QModelIndex,QVector<int>))); // tworzę skrót klawiaturowy podpięty pod kontrolkę QListView QShortcut* shDelete = new QShortcut(QKeySequence(Qt::Key_Delete), ui->countriesList); // podpinam sygnał obiektu shDelete pod slot onDeleteItem okna głównego connect(shDelete, SIGNAL(activated()), this, SLOT(onDeleteItem())); } MainWindow::~MainWindow() { delete ui; } void MainWindow::countryDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles){ if(topLeft != bottomRight) // jak więcej niż dwa elementy są edytowane to nie wykonuj dalszych działań return; int rowCount = countriesListModel->rowCount(); // pobieram liczbę wierszy // jeżeli tekst jest pusty if(topLeft.data().toString() == ""){ countriesListModel->setData(topLeft, country); // to przywracam pierwotne ustawienie return; } // wyszukuję elementy pasujące do wprowadzonego tekstu QModelIndexList finded = countriesListModel->match(countriesListModel->index(0, 0), Qt::DisplayRole, topLeft.data(), -1, Qt::MatchExactly); // jak znaleziono więcej niż jeden to znaczy, że taki element już istniał if(finded.size() > 1){ QMessageBox::warning(this, "Uwaga!", "Kraj o nazwie: " + topLeft.data().toString() + " już jest na liście"); countriesListModel->setData(topLeft, country); }else if(topLeft.row() == rowCount - 1){ // jeżeli edytowany był ostatni element if(topLeft.data().toString() != "*"){ // i tekst nie jest "*" to countriesListModel->insertRow(rowCount); // dodaję nową pozycję QModelIndex index = countriesListModel->index(rowCount, 0); // pobieram jej obiekt countriesListModel->setData(index, QVariant("*")); // i ustawiam tekst na "*" } } } void MainWindow::on_countriesList_doubleClicked(const QModelIndex &index) { country = index.data().toString(); // zapamiętywanie początkowej wartości edytowanego indeksu } void MainWindow::onDeleteItem(){ int row = ui->countriesList->currentIndex().row(); // pobieram indeks if(row != countriesListModel->rowCount() - 1){ // jak nie jest równy ostatniemu elementowi to countriesListModel->removeRow(row); // usuwam wiersz } } void MainWindow::on_countriesList_pressed(const QModelIndex &index) { country = index.data().toString(); // zapamiętywanie początkowej wartości edytowanego indeksu }
Strony powiązane
strony powiązane
  1. doc.qt.io/qt-5/qlistview.html#dataChanged - opis klasy QListView na stronie dokumentacji Qt
Layout wykonany przez autora strony, wszelkie prawa zastrzeżone. Jakiekolwiek użycie części lub całości grafik znajdujących się na tej stronie bez pisemnej zgody jej autora surowo zabronione.