Archiwa tagu: qt

Qt Unit Test – projekt z kilkoma klasami testowymi

Mając chwilowe problemy z dotychczasowym frameworkiem do testów jednostkowych postanowiłem przyjrzeć się frameworkowi wbudowanemu w Qt: Qt Test.

Pierwszy problem pojawia się gdy po stworzeniu nowego projektu Qt Unit Test w Qt Creatorze próbujemy go odpalić w konfiguracji debug. Kończy się to błędem „moc: Too many input files specified: „. Problem wynika ze spacji w ścieżce. Można go rozwiązać usuwając jedną linię z pliku *.pro:

Druga sprawa dotyczy architektury frameworka Qt Unit Test. Domyślny projekt testowy stworzony w Qt Creatorze zawiera tylko jedną klasę testową. W plikach źródłowych Qt każda klasa testowa jest osobnym projektem, a te projekty połączone są w strukturę drzewa za pomocą projektów subdirs. Domyślnie funkcja main w projektach testowych jest implementowana poprzez makro

i pozwala na dodanie tylko jednej klasy z testami jednostkowymi. Aby móc stworzyć projekt zawierający kilka klas z testami i jedną funkcją main wystarczy tę funkcję main ręcznie zaimplementować:

Link do kompletnego projektu: Qt-simple-examples/QTestMultipleTestClasses

Innym sprawą, która skłoniła mnie do przejścia z Catcha na Qt Unit Test był problem związany z obsługą biblioteki Catch przez Qt Creatora. Podczas zmiany nazwy metody lub klasy za pomocą polecenia Refactor -> Reaname Symbol Under Cursor, Qt Creator widzi jedynie użycia zmienianej metody lub klasy w projekcie aplikacji, natomiast nie widzi wystąpień tych nazw w projekcie test (który używa Catcha). Gdy w projekcie test użyta zostanie biblioteka Qt Test to Qt Creator nie będzie miał już problemów i zmieni nazwy wszystkich wystąpień edytowanej nazwy.

Qt test – unresolved external symbol metaObject – rozwiązanie

Dotychczasowy framework do testów jednostkowych Catch nie chciał zbytnio współpracować z klasami dziedziczącymi po QObject. Przy próbie kompilacji zwracał błąd: „LNK2001: unresolved external symbol „public: virtual struct QMetaObject const * __cdecl BlocksDescriptionField::metaObject(void)const”. Rozwiązaniem okazało się dodanie plików nagłówkowych w pliku *.pro:

Qt Deployment, czyli tworzenie wersji release ze wszystkimi plikami *.dll

QT Creator domyślnie tworzy aplikacje z linkowaniem dynamicznym (shared). Jeśli korzystamy z darmowej, otwartoźródłowej wersji QT to jest to zgodnie z licencją jedyna opcja. W związku z tym razem z publikowanym plikiem *.exe projektu trzeba dostarczyć skompilowane pliki biblioteki od których jest on zależny. Pomoże nam w tym windeployqt.exe (Qt Deployment Tool) znajdujący się w katalogu Qt\Qt5.8.0\5.8\msvc2015_64\bin. Odpalamy ten plik w cmd.exe, jako argument podając ścieżkę do pliku wykonywalnego projektu, np. C:\QT Projects\nonograms\app\release\project1.exe. Po tej operacji w folderze release znajdują się wszystkie pliki potrzebne do działania aplikacji, a nawet więcej. Aby usunąć niepotrzebne pliki wystarczy odpalić aplikację project1.exe i w czasie jej działania spróbować usunąć pozostałe pliki z folderu. Niepotrzebne pliki powinny zostać usunięte a wymagane przez aplikację zostaną pominięte. Sposób ten opisany jest tutaj: Deploy an Application on Windows

Więcej na stronie QT: Qt for Windows – Deployment

Lepsze podpowiadanie składni kodu w Qt Creatorze, czyli ClangCodeModel

Qt Creator domyślnie ma włączone „jakieś” podpowiadanie kodu, które cośtam podpowiada, jednak nie jest ono zbyt dobre. Problem pojawia się, gdy przeciążymy operator[], aby zwracał obiekt z naszego kontenera. Przykład:

Po instalacji Qt Creatora opcja Clang Code Model domyślnie jest wyłączona. Jeśli teraz w programie chcemy odwołać się do obiektu klasy Pixel przez zwykły getter:

to podpowiadanie składni zadziała normalnie pokazując listę dostępnych składowych na każdym poziomie. Natomiast gdy zrobimy to samo przez przeciążony operator[] jak tutaj:

to podpowiadanie składni zgłupieje i nic nam nie pomoże. Po wpisaniu „lineOfPixels[1].” nie otrzymamy żadnej podpowiedzi.
Aby podpowiadanie składni działało poprawnie w każdych warunkach, trzeba włączyć plugin ClangCodeModel, zaznaczając opcję w Help → About Plugins… → C++ → ClangCodeModel.

Link: Parsing C++ Files with the Clang Code Model

QT Creator – dodanie niestandardowego widgetu w edytorze interfejsu graficznego

Dodanie customowego widgetu. Z menu po lewej stronie edytora interfejsu przeciągamy obiekt „Widget” w docelowe miejsce. Klikamy prawym przyciskiem myszy na widget → „Promote to …”. W oknie Promoted Widgets wpisujemy do „Promoted class name” nazwę naszej klasy, np. DrawingAreaView, natomiast w polu „Header file” ścieżkę pliku nagłówkowego, np. widgets/DrawingAreaView.h. Klikamy Add, zaznaczamy nowo dodany wpis i klikamy Promote. Nasz widget został dodany w miejsce zwykłego QWidgetu.

Layout dla każdego (QWidgetu) czyli co zrobić, gdy kontrolki wewnątrz layoutu nie skalują się wraz z oknem

Dziś trochę o layoutach i definiowaniu interfejsu graficznego. Po dodaniu kilku kontrolek do layoutu zauważyłem, że podczas skalowania okna znajdujące się w jego wnętrzu kontrolki nie zmieniają swojego rozmiaru i kształtu. Efekt, który chciałem osiągnąć to skalowanie kontrolek wewnątrz okna wraz ze zmianą rozmiaru okna. Chwila w kwakania w Duck Duck Go zaprowadziła mnie do rozwiązania problemu. Mianowicie każde okno (QMainWindow) i każdy obszar typu QScrollArea powinien mieć ustawiony layout. W edytorze interfejsu po prawej stronie mamy okno z drzewem widżetów. Dla nowo stworzonego projektu zaraz pod elementem MainWindow znajduje się centralWidget. Jest to serce całego interfejsu, najważniejszy widget w oknie. Po jego lewej stronie znajduje się ikonka layoutu z czerwonym znacznikiem informującym, że layout nie został ustawiony. Aby ustawić layout wystarczy kliknąć prawym przyciskiem myszy na MainWindow → Lay Out → Lay Out Horizontaly (bądź inny wybrany przez nas layout). Można też tego dokonać klikając na MainWindow a następnie ikonkę Lay Out Horizontaly na pasku ponad oknem edycji GUI albo używając skrótu klawiszowego CTRL + H.

Po ustawieniu layoutu zawartość okna powinna zmieniać rozmiar razem z nim:

Simple Drawing Application – prosta aplikacja QT5 znaleziona w Internecie

Znalazłem w Internecie całkiem schludnie napisaną a jednocześnie w miarę prostą aplikację w QT 5 z użyciem widgetów. Aplikacja ta korzysta z frameworka testów jednostkowych Catch. Autor inspirował się książką Roberta C. Martina – Agile Software Development, Principles, Patterns, and Practices. Osobiście czytałem inną książkę Roberta C. Martina – Czysty kod, którą przy okazji mogę polecić gdyż w prosty sposób przedstawia jak pisać czytelny i łatwy do zrozumienia kod.
Link do aplikacji na GitHubie:
https://github.com/bruceoutdoors/DrawingApp

Stworzenie projektu, commit i push na githuba

Nadszedł czas aby skupić się na kodzie programu i zapełnić święcące dotychczas pustkami repozytorium projektu: Obrazki logiczne. Poniżej przedstawiam krok po kroku tworzenie nowego projektu w Qt Creatorze i umieszczanie go na githubie.

Krok po kroku

W Qt Creatorze stworzyłem nowy projekt jako Qt Widgets Application i od razu dodałem do gita. W karcie „projects” odznaczyłem „Shadow build” dla wszystkich konfiguracji po to aby mieć wszystkie pliki wynikowe w podkatalogach debug i release w głównym katalogu projektu. Do akcji związanych z gitem używam Git Gui (Qt Creator → Tools → Git → Git Tools → Git Gui). Przy pierwszym uruchomieniu Git Gui trzeba go skonfigurować. Wchodzimy w Edit → Options… i podajemy User Name oraz Email Address – nazwa użytkownika i e-mail konta na githubie. Ustawiamy kodowanie znaków na UTF-8, resztę można pozostawić bez zmian. Klikamy Save i wracamy do ekranu głównego. Jeśli w oknie Unstaged changes pojawiły się jakieś pliki, których nie chcemy zamieszczać w repozytorium (np. pliki generowane przez IDE lub kompilator) to musimy stworzyć plik .gitignore w głównym katalogu projektu. W pliku .gitignore będą znajdowały się wyrażenia regularne określające pliki wykluczone z repozytorium. Zawartość pliku .gitignore dla projektu stworzonego w Qt:

Po stworzeniu i uzupełnieniu pliku .gitignore wracamy do Git Gui. Po kliknięciu Rescan niechciane pliki powinny zniknąć. Teraz w oknie Unstaged changes powinny znajdować się jedynie pliki źródłowe i główny plik projektu. Kliknięcie Stage Changed przenosi pliki do okna Staged Changes, które zawiera wszystkie pliki, które zostaną dodane do przyszłego commitu. Wypełniamy opis zmian i klikamy commit, który dodaje pliki do lokalnego repozytorium. Zaznaczenie opcji Ammend Last Commit pozwala na modyfikację ostatniego commitu – dzięki temu można uniknąć niepotrzebnego rozrostu listy edycji, w sytuacji gdy zapomnieliśmy dodać jakiegoś pliku lub źle opisaliśmy poprzedni commit. Jednak warto być tutaj ostrożnym gdyż komenda ammend zastępuje całkowicie poprzedni commit bez śladu w historii zmian. Powinno się unikać komendy Ammend w publicznych repozytoriach.

Przed pierwszym wysłaniem kodu do githuba trzeba skonfigurować zdalne repozytorium. W Git Gui klikamy Remote → Add. W polu Name wpisujemy nazwę repozytorium np. „nonograms”, a w polu Location adres repozytorium „https://github.com/ololuki/nonograms”. Po kliknięciu Add możemy wykonać pierwszy „Push”. Po kliknięciu przycisku Push w oknie Push, trzeba będzie podać nazwę użytkownika i hasło z githuba. Jeśli wszystko poszło jak trzeba nasz kod pojawi się na githubie.

Możliwe problemy

Jeśli używamy oprogramowania SPICE to mogą pojawić się problemy z lokalizacją plików ustawień gita. Domyślnie znajdują się one w katalogu domowym użytkownika ~/ czyli w Windowsie w C:\Users\username\ natomiast SPICE (orCAD) wprowadza zmienną środowiskową HOME z dziwną ścieżką, na przykład C:\Users\LUK\AppData\Roaming\SPB_16.6 więc po zainstalowaniu orCADa pliki ustawień gita a także kilku innych programów mogą trafić do tego śmiesznego katalogu. Aby to naprawić wystarczy przenieść zawartość katalogu znajdującego się pod zmienną środowiskową HOME do naszego katalogu domowego (C:\Users\username\) a następnie usunąć zmienną środowiskową HOME z systemu. Po wszystkim konieczne jest ponowne uruchomienie komputera.