Hakan Kaya

Qt5 Dersleri – 001: Sıfırdan İlk Pencere Oluşturma (Windows, CMake)

Merhabalar, Qt5 kurulumunun Windows işletim sisteminde nasıl yapılabileceğinden bahsetmiştim. Buradaki linkten yazıyı okuyabilirsiniz. Şimdi sıfırdan ilk penceremizi nasıl oluşturabiliriz ona bakalım.

Bu yazıda değineceğim başlıklar;

Dersin ihtiyaçları olarak;

Not: Benim geliştirme ortamımda yaptığım projeleri Windows 10 Pro işletim sistemi üzerinde, CLion IDE’si üzerinden, Qt 5.15.2 sürümü ve CMake 3.19 sürümü ile gerçekleştirmekteyim. Sürüm farklılıklarından dolayı zamanla güncelliğini yitiren noktalar olabilir.

Yeni proje ve dosya yapısı

CLion yada herhangi kullandığınız geliştirme editörünüzde yeni bir proje yeni boş bir klasör (folder) açarak başlayalım.

Genellikle yaygın kullanılan Qt için C++ projelerinin dosya yapısı şu şekildedir;

<Proje Klasörü>
├── src
│   ├── main.cpp
│   ├── headers...
│   ├── sources...
│   ├── modules...
│   └── unit tests...
└── resources
│   ├── img/...
│   ├── qrc/...
│   └── css/...
├── doc
│   └── documentation...
└── CMakeLists.txt

Kaynak kodlarımızı koyacağımız src (source kısaltması) oluşturup için main.cpp source file’ımızı ve MainWindow class’ını (MainWindow.cpp source file, Maindow.h header file) ekleyelim. Bunlar ile birlikte projemizi derlerken kullanacağımız CMakeLists.txt dosyamızı ekleyelim.

Özetle şu şekilde olmalı;

Basit pencere projesinin dosya yapısı

CMakeLists.txt dosyasını düzenleme

CMake yazımı oldukça kolay script dosyasıdır. Cross platform (aynı anda farklı işletim sistemlerinde çalışma) desteği nedeniyle kullanılan CMake sürümü önemlilik arz etmekte. Bu nedenle CMakeLists.txt dosyası yazacağımız ilk komut;

cmake_minimum_required(VERSION 3.9)

Derleme işlemi yapabilmesi için CMake projemize isim vermemizi istemektedir. Bunun için; (tabi istediğiniz ismi verebilirsiniz)

project(firstWindow)

CMake’e şimdi kaynak dosyalarımızı tanıtmalıyız. src klasörü içindeki tüm “*.cpp”,”* .c”, “*.h” ve “*.hpp” uzantılı dosyalar bizim kaynak dosyalarımız olacağından tek tek tanıtmadan şu şekilde ekleyebiliriz;

# START SOURCE FILES
message("--> Kaynak dosyalari araniyor...")

file(GLOB SOURCE_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp
                       ${PROJECT_SOURCE_DIR}/src/*.c
                       ${PROJECT_SOURCE_DIR}/src/*.hpp
                       ${PROJECT_SOURCE_DIR}/src/*.h)

# Source Files Dump
foreach(_file ${SOURCE_FILES})
    message("Dosya: ${_file}")
endforeach()
# END SOURCE FILES

${PROJECT_SOURCE_DIR} komutu CMakeLists.txt dosyasının olduğu konumu gösterir. “*” ifade dosya adı ne olursa olsun uzantısı eğer “cpp” ise dahil etmesini söyler.

Şimdi CMake projemize Qt5 paketlerinin dahil edilmesini söyleyeceğiz.

find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets)

İleride projemizde gerekli gördüğünüz componentlere göre buraya ekleme veya çıkarma yapacağız. Qt5’in tüm component listesine buradaki linkten göz atarak daha fazla bilgi alabilirsiniz.

Son olarak executable file (çalıştırılabilir dosya) eklemek için ve library’leri (kütüphane) projemize eklemek için aşağıdaki kod ile bitiriyoruz;

add_executable(${PROJECT_NAME} ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Widgets)

Aslında kısaca CMakeLists.txt dosyasında yapılan işlemler sırasıyla şunlardır;

Bir CMakeLists.txt oluşturmanın kesin kuralları yoktur. Çok farklı anlayışlara sahip farklı tanımlamalar görebilirsiniz. İşin özünde GCC compiler için sizin kaynak kodlarınızı göstererek Makefile yaratır. Final olarak tamamlanmış hali böyle olmalıdır;

cmake_minimum_required(VERSION 3.9)

project(firstWindow)

# START SOURCE FILES
message("--> Kaynak dosyalari araniyor...")

file(GLOB SOURCE_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp
                       ${PROJECT_SOURCE_DIR}/src/*.c
                       ${PROJECT_SOURCE_DIR}/src/*.hpp
                       ${PROJECT_SOURCE_DIR}/src/*.h)

# Source Files Dump
foreach(_file ${SOURCE_FILES})
    message("Found: ${_file}")
endforeach()
# END SOURCE FILES

find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets)

add_executable(${PROJECT_NAME} ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Widgets)

main.cpp düzenlemesi

Biliyorsunuz ki tüm C veya C++ projeleri main.cpp dosyası ile başlamalıdır. Qt projelerinde QApplication main.cpp üzerindeki yükü kendi üzerine almak için çağrılan bir sınıftır.

int main(int argc, char **argv){

 return 0;
}

şeklindeki main.cpp executable dosyasına kaç adet parametre ile verildiğinin bilgisini argc (argument counter) ve bunların neler olduğunu argv ( argument variables) taşır. Bunları QApplication class’ı ile aktarmayı şu şekilde yapabiliriz;

#include <QApplication>

int main(int argc, char **argv){

   QApplication app(argc, argv);

   return app.exec();
}

Not: char **argv yerine char *argv[] şeklinde de yazımı görebilirsiniz, ikisi de aynı anlamdadır.

Bu bize bir pencere başlattırmayacaktır. GUI ile ilgili herhangi bir tanımla yapmadığımız için QApp arka planda boş olarak çalışacaktır.

QMainWindow class’ından türetilerek yapılmış MainWindow class’ımızı main fonksiyonu içerisine şu şekilde çağırdığımızda main ile ilgili kısım tamamlanmış olacaktır.

MainWindow window;
window.show();

main.cpp tam hali;

// Qt Libraries
#include <QApplication>

// User header
#include "MainWindow.h"

int main(int argc, char **argv){

    QApplication app(argc, argv);

    MainWindow window;
    window.show();
    
    return app.exec();
}

MainWindow class’ının düzenlenmesi

MainWindow.h dosyamızla başlayalım.

Header dosyalarında yapacağımız ilk şey #ifndef makro tanımlamalarını yapmak olacaktır. Bu header dosyasının tekrar tekrar tanımlanmasını engelleyecektir.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H


class MainWindow {

};


#endif //MAINWINDOW_H

QtWidgets kütüphanesi tüm Qt Widget kütüphanelerini tek bir dosyada çağrılmış halidir. Tek tek onlarca header tanımlamaktansa bir tane header’la tüm header’lar çağrılır.

MainWindow class’ımızı QMainWindow class’ının public özellikleriyle türetilmesi gerekiyor. Yani bizim kendi MainWindow class’ımız QMainWindow’un alt class’ıdır. Bu bizi QMainWindow’un hazır sunmuş olduğu bir çok özellikleri de beraberinde getirecektir. Bunun için;

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtWidgets>

class MainWindow : public QMainWindow{

};


#endif //MAINWINDOW_H

Kurucu fonksiyonlarımı ve QOBject makromuzu ekledikten sonra MainWindow.h dosyası böyle olmalı;

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtWidgets>

class MainWindow : public QMainWindow {
Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = nullptr);

};


#endif //MAINWINDOW_H

Qt objelerinin parent-child (aile-çocuk) ilişkisi bulunduğundan kurucu fonksiyonumuza eğer başlangıçta atama yapılmaz ise nullptr almasını söyleyerek tanımladık. Böylece bizim kendi projemizdeki en yüksek seviye parent olacaktır.

Q_OBJECT makrosunun ne işe yaradığını buradaki yazımda bahsettim.

Şimdi sırada MainWindow.cpp dosyamızı düzenleyelim;

// Main Header File
#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
    
    
}

Bu tanımlama QMainWindow’un kurucu fonksiyonu çağrılacağını sonra bizim kurucu fonksiyonumuzun çalışacağını gösterir.

Bir kaç süsleme yapalım.

// Main Header File
#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){

    // Pencere başlığı
    setWindowTitle("First Window");
    
    // Sabit pencere boyutu
    setFixedSize(500, 400);
}

Ekran görüntüsü

Exit mobile version