2.1. Adresy (Qt5)¶
Niniejszy scenariusz pokazuje, jak zacząć programowanie z wykorzystaniem biblioteki Qt w wersji 5 przy użyciu dedykowanego środowiska IDE Qt Creator. Celem jest stworzenie prostej 1-okienkowej książki adresowej, w której można dodawać dane adresowe powiązane z określoną nazwą, np. imieniem i nazwiskiem.
2.1.1. Nowy projekt¶
Po uruchomieniu aplikacji Qt Creator wybieramy przycisk „New Project”, który uruchamia kreatora aplikacji.
W pierwszym oknie „Applications” i „Qt Widget Applications”, co oznacza, że chcemy utworzyć program z interfejsem graficznym oparty na klasie QWidget. W następnym oknie podajemy nazwę projektu, np, „adresy”, oraz wskazujemy ścieżkę do katalogu, w którym będą zapisywane pliki wchodzące w skład projektu. W następnym oknie wybieramy tzw. „kit”, czyli zestaw definiujący docelowe środowisko, kompilator itp. ustawienia. Dostępne zestawy muszą być wcześniej określone w ustawieniach Qt Creatora
Kolejne okno pozwala definiować nazwę klasy głównej i klasę podstawową, podajemy „adresy” i wybieramy „QWidget”. W następnym ostatnim oknie niczego nie zmieniamy, kończymy kliknięciem przycisku „Finish”.
Efektem działania kreatora będzie utworzenie następujących plików:
1)
adresy.h
- plik nagłówkowy, tutaj będziemy deklarować wszystkie używane w programie obiekty (elementy interfejsu), a także publiczne sloty, czyli funkcje powiązanie z określonymi sygnałami (zdarzeniami).2)
adresy.cpp
- plik źródłowy, tu znajdzie się kod tworzący obiekty interfejsu, łączący sygnały ze slotami, a wreszcie implementacja slotów.3)
main.cpp
- plik źródłowy, w którym tworzona i uruchamiana jest instancja naszej aplikacji.4)
adresy.ui
- jak wskazuje rozszerzenie („ui” - ang. user interface), plik zawierać będzie opis graficznego interfejsu aplikacji zapisany za pomocą znaczników XML.
2.1.2. Tworzenie interfejsu¶
Zaczniemy od utworzenia głównego okna naszej aplikacji. W tym celu dwa razy klikamy plik adresy.ui i przechodzimy do tworzenia formularza.
Na początku klikamy obiekt „Grid Layout” z kategorii „Layouts” i rysujemy prostokąt na formularzu tak, aby nie wypełniał go w całości. Dodana kontrolka umożliwia porządkowanie innych elementów tworzących interfejs w prostokątnej siatce. Dalej dodamy dwie etykiety, czyli obiekty „Label” z kategorii „Display Widgets”. Staramy się je umieścić jedna nad drugą w dodanej przed chwilą siatce.
Wskazówka
Po wybraniu obiektu i najechaniu na Grid Layout należy obserwować niebieskie podświetlenia, które pojawiają się w pionie i poziomie, wskazują one, gdzie umieszczony zostanie dodawany obiekt.
Po dwukrotnym kliknięciu na dodane etykiety możemy zmienić treść przez nie wyświetlaną. Modyfikujemy w ten sposób właściwość text danego obiektu. Etykieta górna powinna zawierać tekst „Nazwa”, dolna - „Adresy”.
Informacja
Lista wszystkich obiektów wyświetlana jest po prawej stronie na górze w oknie Hierarchia obiektów. W kolumnie Obiekt widzimy tam nazwy dodanych obiektów, a w kolumnie Klasa nazwy klas, które reprezentują. Po wskazaniu myszą dowolnego obiektu możemy edytować wszystkie jego właściwości poniżej. Np. nazwę obiektu zmienimy w polu objectName.
Nazwę etykiety górnej ustalamy na „nazwaLbl”, dolnej - na „adresyLbl”.
Wskazówka
Konwencji nazywania obiektów jest wiele, ważne żeby konsekwentnie trzymać się wybranej. Tutaj proponujemy uwzględnianie w nazwie typu obiektu przy użyciu skrótu pisanego z dużej litery, np. „nazwaLbl”.
Po prawej stronie etykiety „Nazwa” dodajemy kontrolkę Line Edit z grupy Input Widgets o nazwie „nazwaLine”. Poniżej, czyli w drugiej kolumnie, tworzymy obiekt Text Edit z tej samej grupy, co poprzedni o nazwie „adresText”. Powinniśmy uzyskać poniższy układ:
Czas na dodanie przycisków pozwalających inicjować działanie aplikacji. Dodajemy więc 5 przycisków PushButton z kategorii Buttons po prawej stronie i poza(!) obiektem GridLayouts jeden pod drugim. Na samym dole umieszczamy kontrolkę Vertical Spacer z kategorii Spacers. Następnie zaznaczamy wszystkie dodane obiekty, obrysowując je myszką, i klikamy ikonę Rzmieść w pionie (CTRL+L) na pasku narzędziowym. Teraz stworzoną grupę przeciągamy na siatkę jako 3. kolumnę.
Musimy zmienić nazwy i tekst dodanych przycisków. Od góry ustawiamy kolejne właściwości (nazwa/tekst): „dodajBtn/Dodaj”, „zapiszBtn/Zapisz”, „anulujBtn/Anuluj”, „edytujBtn/Edytuj”, „usunBtn/Usuń”. W efekcie powinniśmy uzyskać następującą formatkę:
Musimy dodać jeszcze 3 przyciski pozwalające na nawigację między adresami i wyjście z programu. Poniżej obiektu siatki umieszczamy więc 2 przyciski (PushButton), zaznaczamy je i klikamy ikonę Rozmieść poziomo w splitterze, następnie przeciągamy grupę na dół 2. kolumny siatki. Na koniec dodajemy jeszcze jeden przycisk na dole 3. kolumny. Dodanym obiektom zmieniamy właściwości (nazwa/tekst): „poprzBtn/Porzedni”, „nastBtn/Następny”, „koniecBtn/Koniec”.
Na koniec zaznaczamy formularz główny, na którym znajdują się wszystkie elementy interfejsu i klikamy przycisk Rozmieść w siatce (CTRL+G). Dzięki temu kontrolki będą skalowane wraz ze zmianą rozmiaru okna.
W sumie uzyskujemy poniższy projekt:
Możemy uruchomić naszą aplikację, wybierając Budowanie/Uruchom (CTRL+R) lub klikając trzecią od dołu ikonę zielonego trójkąta w lewej kolumnie Qt Creatora. Powinniśmy zobaczyć podobne do poniższego okno:
2.1.3. Deklaracje i implementacje¶
Po dodaniu elementów interfejsu musimy zadeklarować zmienne, za pomocą
których będziemy mogli nimi manipulować. Przechodzimy do pliku adresy.h
i wprowadzamy poniższe zmiany:
1#ifndef ADRESY_H
2#define ADRESY_H
3
4#include <QWidget>
5#include <QLineEdit>
6#include <QTextEdit>
7#include <QPushButton>
8#include <QTextCodec>
9
10namespace Ui {
11class adresy;
12}
13
14class adresy : public QWidget
15{
16 Q_OBJECT
17
18public:
19 explicit adresy(QWidget *parent = 0);
20 ~adresy();
21
22private:
23 Ui::adresy *ui;
24 QPushButton *dodajBtn;
25 QPushButton *zapiszBtn;
26 QPushButton *anulujBtn;
27 QPushButton *poprzBtn;
28 QPushButton *nastBtn;
29 QPushButton *edytujBtn;
30 QPushButton *usunBtn;
31 QPushButton *koniecBtn;
32 QLineEdit *nazwaLine;
33 QTextEdit *adresText;
34};
35
36#endif // ADRESY_H
Na początku musimy zaimportować klasy, z których skorzystaliśmy przy budowie
interfejsu. Najważniejszą jest klasa podstawowa wszystkich elementów interfejsu,
czyli QWidget
. Kolejne trzy odpowiadają wykorzystanym przez nas kontrolkom
edycyjnym i przyciskom. Dodatkowa klasa QTextCodec
pozwoli poprawnie wyświetlać
polskie znaki. W wewnątrz naszej klasy głównej, której deklaracja
rozpoczyna się w linii 14., deklarujemy prywatne (private) właściwości,
których nazwy odpowiadają nazwom wcześniej dodanych elementów interfejsu
graficznego. Formalnie każda zmienna jest wskaźnikiem do obiektu odpowiedniego typu.
W pliku adresy.cpp
korzystamy ze zadekarowanych zmiennych, aby ustawić początkowe
właściwości obiektów składających się na interfejs użytkownika.
1#include "adresy.h"
2#include "ui_adresy.h"
3
4adresy::adresy(QWidget *parent) :
5 QWidget(parent),
6 ui(new Ui::adresy)
7{
8 ui->setupUi(this);
9
10 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
11
12 nazwaLine = new QLineEdit;
13 nazwaLine = ui->nazwaLine;
14 nazwaLine->setReadOnly(true);
15
16 adresText = new QTextEdit;
17 adresText = ui->adresText;
18 adresText->setReadOnly(true);
19
20 dodajBtn = new QPushButton;
21 dodajBtn = ui->dodajBtn;
22
23 zapiszBtn = new QPushButton;
24 zapiszBtn = ui->zapiszBtn;
25 zapiszBtn->hide();
26
27 anulujBtn = new QPushButton;
28 anulujBtn = ui->anulujBtn;
29 anulujBtn->hide();
30
31 nastBtn = new QPushButton;
32 nastBtn = ui->nastBtn;
33 nastBtn->setEnabled(false);
34
35 poprzBtn = new QPushButton;
36 poprzBtn = ui->poprzBtn;
37 poprzBtn->setEnabled(false);
38
39 edytujBtn = new QPushButton;
40 edytujBtn = ui->edytujBtn;
41 edytujBtn->setEnabled(false);
42
43 usunBtn = new QPushButton;
44 usunBtn = ui->usunBtn;
45 usunBtn->setEnabled(false);
46
47 koniecBtn = new QPushButton;
48 koniecBtn = ui->koniecBtn;
49 koniecBtn->setEnabled(true);
50
51 setWindowTitle(trUtf8("Prosta książka adresowa"));
52}
53
54adresy::~adresy()
55{
56 delete ui;
57}
W obrębie konstruktora głównej klasy naszej aplikacji o nazwie adresy
,
którego definicja rozpoczyna się w linii 4., tworzymy instancje
klas użytych w interfejsie graficznym. Do zmiennych zadeklarownych w pliku
adresy.h
przypisujemy obiekty utworzone za pomocą operatora new
, a następnie
definiujemy ich początkowe właściwości.
Konstruktorowi odpowiada zawzwyczaj destruktur, a więc działanie, które
usuwa stworzony obiekt, w tym wypadku interfejs użytkownika: adresy::~adresy()
.
Aby określić stan elementów interfejsu wykorzystujemy odpowiednie właściwości
i metody reprezentujących je obiektów. Np. właściwość setReadOnly(true)
blokuje
edycję danego elementu, a właściwość setEnabled(false)
uniemożliwia kliknięcie
danego przycisku. Metoda hide()
ukrywa obiekt.
Instrukcja QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"))
określa kodowanie komunikatów w standardzie „UTF-8” używanych w aplikacji,
które wprowadzane są dalej za pomocą funkcji trUtf8()
. Tak dzieje się np.
podczas określania tytułu okna w wywołaniu setWindowTitle()
.
Wskazówka
W środowisku MS Windows kodowanie powinno zostać ustawione na Windows-1250
.
Dzięki powyższym uzupełnieniom po uruchomieniu aplikacji pola nazwy i adresu
będą nieaktywne, będziemy mogli natomiast użyć przycisków Dodaj
, aby utworzyć
nowy wpis, lub Koniec
, aby zakończyć aplikację.
2.1.4. Sygnały i sloty¶
Działanie aplikacji z interfejsem graficznym polega w uproszczeniu na reagowaniu na działania użytkownika, takie jak np. kliknięcie, naciśnięcie klawisza, przeciągnięcie itp. Wszystkie zdarzenia generowane z poziomu interfejsu użytkownika w terminologii biblioteki Qt emitują tzw. sygnały. Programista decyduje o tym, które z nich i jak są obsługiwane, definiując tzw. sloty, czyli funkcje powiązane z określonymi zdarzeniami. Mechanizm sygnałów i slotów umożliwia komunikację między obiektami aplikacji.
Każda z funkcji obsługujących zdarzenia musi zostać najpierw zadeklarowana w pliku
adresy.h
w sekcji public slots:
, ich implementację musimy dopisać
później do pliku adresy.cpp
.
18public:
19 explicit adresy(QWidget *parent = 0);
20 ~adresy();
21
22 enum Tryb { nawigujT, dodajT, edytujT };
23
24public slots:
25 void dodajKontakt();
26 void koniec();
27
28private:
29 Ui::adresy *ui;
30 QPushButton *dodajBtn;
31 QPushButton *zapiszBtn;
32 QPushButton *anulujBtn;
33 QPushButton *poprzBtn;
34 QPushButton *nastBtn;
35 QPushButton *edytujBtn;
36 QPushButton *usunBtn;
37 QPushButton *koniecBtn;
38 QLineEdit *nazwaLine;
39 QTextEdit *adresText;
40
41 Tryb aktTryb;
42 void aktGui(Tryb tryb);
43 QString staraNazwa;
44 QString staryAdres;
45 QMap<QString,QString> kontakty;
46
47};
48
49#endif // ADRESY_H
Oprócz deklaracji slotów w liniach 24-26 dopisujemy deklaracje kilku potrzebnych
zmiennych. Definiujemy więc typ wyliczeniowy Tryb
, z którego
korzystamy deklarując zmienną aktTryb
oraz prywatną funkcję pomocniczą
aktGui
. Posłużą one do określania 1 z 3 stanów działania aplikacji, takich jak:
przeglądanie wpisów, dodawanie i ich edycja.
Dalej dopisujemy deklaracje zmiennych pomocniczych staraNazwa
i staryAdres
.
Korzystamy tu z typu QString
oznaczającego dane tekstowe.
Na końcu deklarujemy specjalną zmienną kontakty
, która posłuży
do przechowywania nazw i skojarzonych z nimi adresów w postaci słownika
typu QMap
. Poszczególne elementy takiej listy mają postać skojarzonych
ze sobą par (klucz, wartość)
.
53 connect(dodajBtn, SIGNAL(clicked()), this, SLOT(dodajKontakt()));
54 connect(koniecBtn,SIGNAL(clicked()),this, SLOT(koniec()));
55}
56
57adresy::~adresy()
58{
59 delete ui;
60}
61
62void adresy::dodajKontakt() {
63 staraNazwa = nazwaLine->text();
64 staryAdres = adresText->toPlainText();
65
66 nazwaLine->clear();
67 adresText->clear();
68
69 aktGui(dodajT);
70}
71
72void adresy::aktGui(Tryb tryb) {
73 aktTryb=tryb;
74 switch (aktTryb) {
75 case dodajT:
76 case edytujT:
77 nazwaLine->setReadOnly(false);
78 nazwaLine->setFocus(Qt::OtherFocusReason);
79 adresText->setReadOnly(false);
80
81 dodajBtn->setEnabled(false);
82 edytujBtn->setEnabled(false);
83 usunBtn->setEnabled(false);
84
85 zapiszBtn->show();
86 anulujBtn->show();
87
88 nastBtn->setEnabled(false);
89 poprzBtn->setEnabled(false);
90 break;
91 case nawigujT:
92 if (kontakty.isEmpty()) {
93 nazwaLine->clear();
94 adresText->clear();
95 }
96 nazwaLine->setReadOnly(true);
97 adresText->setReadOnly(true);
98 dodajBtn->setEnabled(true);
99
100 int ile=kontakty.size();
101 edytujBtn->setEnabled(ile >= 1);
102 usunBtn->setEnabled(ile >=1 );
103 nastBtn->setEnabled(ile > 1);
104 poprzBtn->setEnabled(ile > 1);
105
106 zapiszBtn->hide();
107 anulujBtn->hide();
108 break;
109 }
110}
111
112void adresy::koniec() {
113 adresy::close();
114}
Powiązania między sygnałami i slotami ustalamy w pliku adresy.cpp
za pomocą poleceń typu: connect(dodajBtn, SIGNAL(clicked()), this, SLOT(dodajKontakt()));
.
Funkcja conect()
jako pierwszy argument wymaga zmiennej wskazującej obiekt, który
emituje sygnał określony w 2. argumencie (np. SIGNAL(clicked())
, czyli kliknięcie),
3. argument określa obiekt, który zostaje powiadomiony o zdarzeniu, w ostatnim
argumencie podajemy funkcję, która ma zostać wykonana (SLOT(dodajKontakt())
).
Jak widać powyżej, na końcu konstruktora naszej klasy adresy
wiążemy kliknięcia przycisków
dodajBtn
i koniecBtn
z funkcjami dodajKontakt()
i koniec()
.
Funkcja dodajKontakt()
przygotowuje aplikację do przełączenia w stan
dodawania nowych danych. W tym celu najpierw zapamiętujemy
dotychczasową nazwę i adres, a następnie wywołujemy funkcję
pomocniczą z argumentem typu Tryb
oznaczającym wymagany stan aplikacji:
aktGui(dodajT)
.
Działanie funkcji aktGui()
, obsługującej stany aplikacji, polega na uaktywnianiu lub
wyłączaniu określonych elementów interfejsu w zależności od przeprowadzanej
przez użytkownika czynności. Np. w trybie dodawania i edycji odblokowujemy
możliwość wprowadzania tekstu w polach nazwy (nazwaLine->setReadOnly(false);
)
i adresu (adresText->setReadOnly(false);
), pokazujemy przyciski
pozwlające na zapis lub anulowanie wywołując metodę show()
. Wyłączamy
również nawigację, blokując odpowiednie przyciski (metoda setEnabled(false)
).
Po wejściu w tryb nawigacji czyścimy (clear()
) zawartość pól nazwy i adresu, o ile
lista kontaktów jest pusta (if (kontakty.isEmpty())
). Następnie uaktywniamy
przyciski edycji, usuwania i przeglądania, jeżeli mamy jakieś kontakty. Ilość
kontaktów zapisujemy wcześniej w osobnej zmiennej (int ile=kontakty.size();
).
Na koniec przyciski zapisu i anulowania zostają zablokowane.
Slot koniec()
wywoływany jest po kliknięciu przycisku Koniec i powoduje
zamknięcie aplikacji przy użyciu metody close()
. Wywołuje ona m.in.
destruktor klasy, co powoduje – w naszym przypadku – usunięcie instancji
obiektu interfejsu graficznego (delete ui;
).
2.1.5. Dodawanie adresów¶
Pora zaimplementować obsługę trybu dodawania danych adresowych. Najpierw do pliku nagłówkowego dopisujemy deklaracje odpowiednich slotów:
25public slots:
26 void dodajKontakt();
27 void koniec();
28 void zapiszKontakt();
29 void anuluj();
Musimy też na początku pliku dodać import klasy QMessageBox
pozwalającej
wyświetlać informacje użytkownikowi.
Następnie przechodzimy do pliku adresy.cpp
, w którym trzeba powiązać
sloty zapiszKontakt()
i anuluj()
ze zdarzeniem kliknięcia przycisków
zapiszBtn
i anulujBtn
. Zadanie to proponujemy wykonać samodzielnie :-).
Na końcu pliku musimy dopisać definicje powiązanych funkcji:
118void adresy::zapiszKontakt() {
119 QString nazwa = nazwaLine->text();
120 QString adres = adresText->toPlainText();
121
122 if (nazwa == "" || adres == "") {
123 QMessageBox::information(this, trUtf8("Puste pole"),trUtf8("Proszę wpisać nazwę i adres."));
124 return;
125 }
126
127 if (aktTryb == dodajT) {
128 if (!kontakty.contains(nazwa)) {
129 kontakty.insert(nazwa, adres);
130 QMessageBox::information(this, trUtf8("Dodano wpis"),
131 trUtf8("Kontakt \"%1\" dodano do książki adresowej.").arg(nazwa));
132 } else {
133 QMessageBox::information(this, trUtf8("Nie dodano wpisu"),
134 trUtf8("Przykro, ale kontakt \"%1\" jest już w książce adresowej.").arg(nazwa));
135 }
136 }
137
138 aktGui(nawigujT);
139}
140
141void adresy::anuluj() {
142 nazwaLine->setText(staraNazwa);
143 adresText->setText(staryAdres);
144 aktGui(nawigujT);
145}
Funkcja zapiszKontakt()
pobiera tekst wpisany w pola edycyjne za pomocą
metod text()
oraz toPlainText()
i zapisuje je w zmiennych tekstowych.
Następnie sprawdza, czy użytkownik wprowadził obydwie informacje. Jeżeli
nie, wyświetla odpowiedni komunikat przy użyciu metody QMessageBox::information()
.
Pierwszy tekst, który przekazujemy do tej funkcji to tytuł okna dialogowego, drugi –
właściwy komunikat. Następnie, jeżeli aplikacja jest w trybie dodawania, sprawdza,
czy podana nazwa nie została zapisana wcześniej na liście kontakty
. Jeśli
nie (if (!kontakty.contains(nazwa))
), dodaje nowe dane (kontakty.insert(nazwa, adres);
) i wyświetla
potwierdzenie. W przeciwnym razie informuje użytkownika o duplikacie.
Na końcu aktywuje tryb nawigacji (aktGui(nawigujT);
).
Jeżeli użytkownik rozmyśli się i kliknie odpowiedni przycisk, wywoływana jest
funkcja anuluj()
. Jak widać, przywraca ona w polach edycyjnych poprzednio
wprowadzane dane i również aktywuje tryb nawigacji.
2.1.6. Tryb nawigacji¶
Obsługa nawigacji wymaga napisania funkcji obsługujących naciśnięcie przycisków
Następny i Poprzedni, które stają się aktywne, jeżeli mamy więcej niż
1 dodany adres. Jak zwykle, zaczynamy od zadeklarowania publicznych slotów nast()
i poprz()
w pliku nagłówkowym. Dopisanie tych 2 linijek pozostawiamy
do samodzielnego wykonania. Podobnie powiązanie zadeklarowanych slotów
z sygnałami (kliknięciami) obiektów nastBtn
i poprzBtn
w konstruktorze
klasy adresy
.
Następnie dopisujemy implementację zadeklarowanych funkcji na końcu pliku adresy.cpp
:
Na końcu pliku musimy dopisać definicje powiązanych funkcji:
149void adresy::nast() {
150 QString nazwa = nazwaLine->text();
151 QMap<QString, QString>::iterator i = kontakty.find(nazwa);
152 if (i != kontakty.end()) i++;
153 if (i == kontakty.end()) i = kontakty.begin();
154 nazwaLine->setText(i.key());
155 adresText->setText(i.value());
156}
157
158 void adresy::poprz() {
159 QString nazwa = nazwaLine->text();
160 QMap<QString, QString>::iterator i = kontakty.find(nazwa);
161 if (i == kontakty.begin()) i = kontakty.end();
162 i--;
163 nazwaLine->setText(i.key());
164 adresText->setText(i.value());
165 }
Wyświetlając kolejną parę powiązanych danych, tzn. nazwę i przypisany jej adres(y),
musimy sprawdzić w fukcji nast()
, czy mamy kolejny wpis, czy też aktualny jest ostatni.
Wtedy należałoby wyświetlić wpis pierwszy. W tym celu pobieramy nazwę
aktualnie wyświetlonego wpisu i tworzymy obiekt tzw. iteratora
inicjowanego
przez metodę find()
i przypisanego do zmiennej i
: QMap<QString, QString>::iterator i = kontakty.find(nazwa);
.
Iterator umożliwia łatwe poruszanie się po liście słowników zapisanych w zmiennej kontakty
.
Metoda i.key()
zwraca nam klucz, a i.value()
przypisaną mu wartość.
Jeżeli bieżący wpis nie jest ostatnim inkrementujemy wartość iteratora (if (i != kontakty.end()) i++;
).
W przeciwnym wypadku ustawiamy go na pierwszy wpis (i = kontakty.begin();
);
Na koniec pozostaje wczytanie nazwy (i.key()
) i przypisanych jej danych
(i.value()
) do odpowiednich pól interfejsu.
Funkcja poprz()
zaczyna się tak samo jak poprzednia, czyli od utworzenia
iteratora wskazującego na bieżący wpis. Jeżeli jesteśmy na początku listy,
ustawiamy iterator na element końcowy. Następnie przechodzimy do elementu
końcowego (i--
) i wyświetlamy odpowiednie dane.
Informacja
Metoda .end()
klasy QMap
zwraca iterator wskazujący na wirtualny (!)
element po ostatnim elemencie listy. Dlatego, aby uzyskać dostęp do niego,
musimy iterator dekrementować (i--
).
2.1.7. Edycja i usuwanie¶
Do oprogramowania zostay jeszcze dwa przyciski: btnEdytuj
, którego
kliknięcie powinno wywołać funkcję edytujKontakt()
, oraz btnUsun
,
który wywołuje funkcję usunKontakt()
. Samodzielnie dopisujemy
deklaracje funkcji do pliku nagłówkowego, a ich powiązania z sygnałami
umieszczamy w pliku źródłowym.
Następnie implementujemy funkcje:
185void adresy::edytujKontakt() {
186 staraNazwa = nazwaLine->text();
187 staryAdres = adresText->toPlainText();
188 aktGui(edytujT);
189}
190
191void adresy::usunKontakt() {
192 QString nazwa = nazwaLine->text();
193 QString adres = adresText->toPlainText();
194
195 if (kontakty.contains(nazwa)) {
196 int button = QMessageBox::question(this,trUtf8("Potwierdź usunięcie"),
197 trUtf8("Czy na pewno usunąć kontakt \"%1\"?").arg(nazwa),
198 QMessageBox::Yes|QMessageBox::No);
199 if (button == QMessageBox::Yes) {
200 poprz();
201 kontakty.remove(nazwa);
202 QMessageBox::information(this,trUtf8("Usunięto"),
203 trUtf8("Usunięto kontakt \"%1\".").arg(nazwa));
204 }
205 }
206 aktGui(nawigujT);
207}
Przejście do trybu edycji, czyli działanie funkcji edytujKontak()
,
polega na zapisaniu aktualnie wyświetlanych danych (przydatne, jeżeli
użytkownik anuluje zmiany) i uaktywnieniu trybu (aktGui(edytujT);
),
tzn. odblokowaniu pól tekstowych i odpowiednich przycisków.
Usuwanie kontaktów również jest proste. Na początku pobieramy nazwę i związany
z nim adres(y). Metoda .contains(nazwa)
pozwala sprawdzić, czy lista kontaktów
zawiera słownik o podanym kluczu. Natępnie prosimy użytkownika o potwierdzenie
operacji. Po jego uzyskaniu najpierw wyświetlamy w aplikacji dane poprzedniego
wpisu dzięki wywołaniu zdefiniowanej wcześniej funkcji poprz()
, później
dopiero usuwamy wpis za pomocą metody .remove(nazwa)
i wyświetlamy potwierdzenie.
Na koniec aktywujemy tryb nawigacji.
2.1.7.1. Poćwicz sam¶
Spróbuj rozszerzyć napisaną aplikację o możliwość przechowywania danych w pliku lub w bazie na dysku.
2.1.8. Materiały¶
- Utworzony:
2024-04-23 o 08:28 w Sphinx 7.3.7