[Kurs Qt] Operacje na plikach i tekście

Witam w kolejnej części kursu Qt, dzisiaj napiszemy sobie program, którego zadaniem będzie zamiana jakiegoś ciągu znaków na inny, tzn. jego działanie będzie analogiczne do opcji dostępnych w wielu edytorach tekstu: Znajdź i zamień (zazwyczaj ta opcja jest pod skrótem Ctrl + H).

Wspomniana opcja w Visual Studio

Na początku przygotujemy sobie nasze okno tak aby zawierało wszystkie potrzebne elementy, chcemy aby okno posiadało:

  • na pasku narzędzi kategorię Plik, a w nim opcje: Otwórz…, Zapisz jako…, Zapisz, Zamknij;
  • 2 pola tekstowe odpowiadające za to jaki tekst ma zastać wyszukany i na jaki zamieniony;
  • 1 duże pole tekstowe gdzie będziemy przechowywali tekst;
  • przycisk do zamiany tekstu.

Sam proces ustawiania poszczególnych obiektów w oknie jest pokazany na filmie poniżej:

Dzięki opcji „Lay out in Grid” wszystkie elementy będą automatycznie skalowane do zmienianej wielkości okna, skoro nasze okno składa się już ze wszystkich potrzebnych do elementów to czas rozpocząć ich okodowanie tak aby nasz program był w pełni funkcjonalny.

W edytorze przejdźmy do mainwindow.cpp i utwórzmy zmienne globalne:

Operacje na plikach


Zanim zaczniemy zamieniać tekst to musimy go jeszcze jakoś zdobyć, np poprzez wczytanie go z pliku. Do wywołania standardowego okna, które pozwala nam wybrać plik jaki chcemy otworzyć służy: QFileDialog, które należy zaincludować:

#include <QFileDialog>

Teraz dodajemy kilka nowych funkcji, slotów w pliku mainwindow.h:

Chciałbym was poinformować, że to są tylko funkcje/sloty, które teraz dodaliśmy, bez tych które były wcześniej. Kilka słów komentarza do tego kodu, dlaczego dodajemy specjalne funkcje do otwierania/zapisywania pliku, zamiast dodać ten kod bezpośrednio do slotu?

Ponieważ tak jest wygodniej, jeżeli chcielibyśmy aby np. możliwość otwierania pliku dodać przez przycisk w oknie programu a nie tylko z paska narzędzi to byśmy byli zmuszeni do skopiowania tego kodu i wklejenia pod odpowiedni slot lub sztucznego aktywowania sygnału wciśnięcia opcji Otwórz… z paska narzędzi.

Z kolei sloty jesteśmy zmuszeni pisać w ten sposób o ile nie chcemy bawić się funkcją connect(), skorzystanie z tego makra jest wygodniejsze, bo polega na napisaniu: funkcji on_nazwaElementu_typSygnalu(). Typy sygnałów możecie znaleźć w dokumentacji każdego elementu QT.

Przejdźmy do implementacji otwierania pliku.

W obecnej chwili wywołujemy jedynie okno, które zwróci nam ścieżkę pliku do otwarcia, przy czym wyszukujemy jedynie pliki z rozszerzeniem .txt, jeżeli chcemy wyszukiwać inne musimy podać w nawiasie kolejne rozszerzenia, np (*.png *.xpm *.jpg).

Efekt działania kodu w obecnej chwili

Teraz czas na wczytanie kodu, na szczęście nie musimy się zbytnio martwić o poinformowanie użytkownika że dany plik nie istnieje ponieważ w takim wypadku QT samo utworzy odpowiedni komunikat. Do wczytania pliku musimy dołączyć kolejny nagłówek.

Klasa służąca do manipulowania plikami jest bardzo podobna do tej znanej nam ze standardu c++, jednak pod pewnymi względami jest wygodniejsza. Po wczytaniu pliku umieszczamy nasz tekst do zmiennej, z kolei stamtąd kopiujemy go do text box’a, po czym zamykamy plik.

W dalszej części kursu przydałby nam się oczywiście jakiś tekst, którym moglibyśmy manipulować, ja będę korzystał z kodu tego programu zapisanego jako plik txt.

Skoro mamy już wczytywanie pliku to czas na dodanie możliwości zapisania pliku. Jednakże mamy tam dwie opcje, Zapisz oraz Zapisz jako. Jeżeli pomyślimy przez chwilę to zauważymy, że Zapisz działa w ten sposób że nadpisuje wcześniej zapisywany lub otwierany plik, jeżeli nie otwierano wcześniej żadnego pliku to działa tak jak Zapisz jako, które zawsze wywołuje okno do wyboru ścieżki do zapisu.

Dlatego zmodyfikujmy nasz obecnie napisany kod:

Teraz zajmijmy się właściwą funkcją, która wygląda w sposób analogiczny do otwierania pliku:

Nie będę się tutaj rozpisywał jak ona działa, bo jest to zupełnie analogiczny sposób działania jak w przypadku otwierania, w razie wątpliwości odsyłam do dokumentacji.

Mamy tutaj 2 sloty odpowiadające odpowiednio za zapisywanie, które może służyć jako nadpisywanie oraz za zapisywanie jako, czyli tworzenie nowego pliku.

Kończąc temat slotów…


Brakuje nam jeszcze możliwości zamykania aplikacji z paska narzędzi:

A także przycisk do zamieniania tekstu na inny, tam wywołamy po prostu nowo utworzoną metodę:

Zamienianie ciągu znaków na inny


Czyli wreszcie przechodzimy do meritum naszego programu, czyli do czegoś raczej banalnego jeżeli zostawimy to w najprostszej formie. Jeżeli będziesz chciał będziesz mógł nieco usprawnić sam program przez to, że podczas wyszukiwania np. litery „a” to ta litera zostanie zamieniona tylko i wyłączenie w przypadku gdy będzie stała pojedynczo, a nie w każdym wyrazie ją zawierającym.

Ten prosty kod ma za zadanie jedynie zamienić dany ciąg znaków na inny, nie powinno być z nim problemów. Dodam jeszcze, że MessageBox na końcu trzeba oczywiście zanicludować (#include <QMessageBox>).

Ostatnie poprawki


Nasz program w obecnej chwili jest w pełni funkcjonalny, jednak można poprawić kilka rzeczy w kwestii wizualnej. Jeżeli przejdziemy do zakładki Design, następnie klikniemy klikniemy np. „Zapisz” z naszego toolbara (naszego programu) i znajdziemy opcję shortcut to będziemy mogli dodać skrót, który będzie aktywował tę opcję.

Jeżeli klikniemy na nasze okno, to w opcji windowTitle możemy zmienić nazwę naszego okna.

Możemy także zmienić ikonę okna w sposób pokazany poniżej (link do ikony):

Dzisiejsza część poradnika była mieszana, może za niedługo jednak przekonam się do nagrywania w całości poradnika, a nie tylko fragmentów, to tyle jeżeli chodzi o ten program i dzisiejszą lekcję.

[GitHub]


  • Htfhere

    Super kurs! Czy mógłbym prosić o udostępnienie gotowego programu napisanego w tej części kursu?

    • Przecież przycisk „GitHub” odsyła do konkretnego kodu z tej lekcji.

  • Daniel Rupek

    Świetna lekcja!
    Jeden szczegół, który zauważyłem – funkcja zamień nie
    działa tak, jak chcemy w przypadku, gdy zamiennik ma więcej znaków niż
    szukany_tekst. Jeśli przyjąć, że zamiennik ma m znaków, a szukany_tekst n
    znaków, to m-n znaków po każdym wystąpieniu wyrazu szukany_tekst
    zostaje zmienionych zgodnie z żądaniem – na przykład wczytany z pliku
    tekst „Ala ma kota” zostanie zamieniony na „Alibabakota”, gdy w okienku
    edycyjnym wyszukaj wpiszemy Ala, a w zamien_na Alibaba

    • Dzięki za zwrócenie uwagi, w metodzie replace powinniśmy brać pod uwagę rozmiar szukango tekstu, a nie zamiennika. Już poprawiłem kod i powinno działać 😉

      • Daniel Rupek

        Fakt, po zmianie parametrów replace’a chodzi bez problemu.
        Dzięki za pomoc 🙂

  • mvxxx

    Dotarłem do kodu, który znajduje się przed: „W obecnej chwili wywołujemy jedynie okno, które zwróci nam ścieżkę pliku do otwarcia, przy” i po tym program nie chce się kompilować, wyrzuca takie błędy jak:
    build-Zamiennik-Desktop_Qt_5_6_1_MinGW_32bit-Debugdebugmoc_mainwindow.cpp:85: błąd: undefined reference to `MainWindow::on_przycisk_clicked()’
    i wszystkich tych, które były pod „private slots”
    oraz jeszcze jeden:
    collect2.exe:-1: błąd: error: ld returned 1 exit status
    brak pliku collect2.exe