Qt - kontrolka QListView

Stronę tą wyświetlono już: 38 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:

Listing 1
  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. #include <QStringListModel>
  5. #include <QDebug>
  6. #include <QMessageBox>
  7. #include <QShortcut>
  8. namespace Ui {
  9. class MainWindow;
  10. }
  11. class MainWindow : public QMainWindow
  12. {
  13. Q_OBJECT
  14. QStringListModel *countriesListModel; // model, który zostanie podpięty pod kontrolkę QListView
  15. QString country; // pomocnicza zmienna konieczna do przechowywania informacji o tekście zawartym w danym elemencie kontrolki przed jego modyfikacją
  16. QShortcut *shDelete; // skrót klawiaturowy do podpięcia slotu onDeleteItem
  17. public:
  18. explicit MainWindow(QWidget *parent = 0);
  19. ~MainWindow();
  20. private slots:
  21. // slot podpięty pod sygnał wysyłany, gdy tekst w elementach kontrolki został zmieniony
  22. void countryDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int> ());
  23. // slot podpięty pod sygnał wysyłany, gdy element w kontrolce został kliknięty dwa razy (co będzie oznaczało edycję tekstu kontrolki
  24. void on_countriesList_doubleClicked(const QModelIndex &index);
  25. // slot podpięty pod skrót klawiaturowy oznaczający usuwanie elementu zaznaczonego
  26. void onDeleteItem();
  27. // slot podpięty pod sygnał wysyłany, gdy wcześniej zaznaczony na liście element został nadpisany poprzez rozpoczęcie wpisywania tekstu
  28. void on_countriesList_pressed(const QModelIndex &index);
  29. private:
  30. Ui::MainWindow *ui;
  31. };
  32. #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:

Listing 2
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. MainWindow::MainWindow(QWidget *parent) :
  4. QMainWindow(parent),
  5. ui(new Ui::MainWindow)
  6. {
  7. ui->setupUi(this);
  8. countriesListModel = new QStringListModel(this); // tworzenie nowego obiektu modelu
  9. countriesListModel->setStringList(
  10. {"Polska", "Czechy", "Słowacja"} // dodaję parę początkowych pozycji
  11. );
  12. ui->countriesList->setModel(countriesListModel); // podpinam model pod kontrolkę QListView
  13. ui->countriesList->setEditTriggers(
  14. QAbstractItemView::AnyKeyPressed | // edycja zaznaczonego elementu na dowolny znak tekstowy
  15. QAbstractItemView::DoubleClicked // edycja elementu po dwukrotnym kliknięciu lewym przyciskiem myszy
  16. );
  17. int row = countriesListModel->rowCount(); // pobieram liczbę wierszy
  18. countriesListModel->insertRow(row); // wstawiam dodatkowy wiersz na końcu
  19. QModelIndex index = countriesListModel->index(row, 0); // pobieram obiekt wstawionego indeksu
  20. countriesListModel->setData(index, QVariant("*")); // i ustawiam jego tekst
  21. // podpięcie sygnału dataChanged obiektu countriesListModel pod slot countryDataChanged okna głównego
  22. QObject::connect(countriesListModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(countryDataChanged(QModelIndex,QModelIndex,QVector<int>)));
  23. // tworzę skrót klawiaturowy podpięty pod kontrolkę QListView
  24. QShortcut* shDelete = new QShortcut(QKeySequence(Qt::Key_Delete), ui->countriesList);
  25. // podpinam sygnał obiektu shDelete pod slot onDeleteItem okna głównego
  26. connect(shDelete, SIGNAL(activated()), this, SLOT(onDeleteItem()));
  27. }
  28. MainWindow::~MainWindow()
  29. {
  30. delete ui;
  31. }
  32. void MainWindow::countryDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles){
  33. if(topLeft != bottomRight) // jak więcej niż dwa elementy są edytowane to nie wykonuj dalszych działań
  34. return;
  35. int rowCount = countriesListModel->rowCount(); // pobieram liczbę wierszy
  36. // jeżeli tekst jest pusty
  37. if(topLeft.data().toString() == ""){
  38. countriesListModel->setData(topLeft, country); // to przywracam pierwotne ustawienie
  39. return;
  40. }
  41. // wyszukuję elementy pasujące do wprowadzonego tekstu
  42. QModelIndexList finded = countriesListModel->match(countriesListModel->index(0, 0), Qt::DisplayRole, topLeft.data(), -1, Qt::MatchExactly);
  43. // jak znaleziono więcej niż jeden to znaczy, że taki element już istniał
  44. if(finded.size() > 1){
  45. QMessageBox::warning(this, "Uwaga!", "Kraj o nazwie: " + topLeft.data().toString() + " już jest na liście");
  46. countriesListModel->setData(topLeft, country);
  47. }else if(topLeft.row() == rowCount - 1){ // jeżeli edytowany był ostatni element
  48. if(topLeft.data().toString() != "*"){ // i tekst nie jest "*" to
  49. countriesListModel->insertRow(rowCount); // dodaję nową pozycję
  50. QModelIndex index = countriesListModel->index(rowCount, 0); // pobieram jej obiekt
  51. countriesListModel->setData(index, QVariant("*")); // i ustawiam tekst na "*"
  52. }
  53. }
  54. }
  55. void MainWindow::on_countriesList_doubleClicked(const QModelIndex &index)
  56. {
  57. country = index.data().toString(); // zapamiętywanie początkowej wartości edytowanego indeksu
  58. }
  59. void MainWindow::onDeleteItem(){
  60. int row = ui->countriesList->currentIndex().row(); // pobieram indeks
  61. if(row != countriesListModel->rowCount() - 1){ // jak nie jest równy ostatniemu elementowi to
  62. countriesListModel->removeRow(row); // usuwam wiersz
  63. }
  64. }
  65. void MainWindow::on_countriesList_pressed(const QModelIndex &index)
  66. {
  67. country = index.data().toString(); // zapamiętywanie początkowej wartości edytowanego indeksu
  68. }
Strony powiązane
strony powiązane
  1. doc.qt.io/qt-5/qlistview.html#dataChanged - opis klasy QListView na stronie dokumentacji Qt

Komentarze