Qt Quick ile proje geliştirirken en ideal mimari prensip: “Arayüz QML’de, İş Mantığı ve Donanım Erişimi C++’ta” kuralıdır. QML görsel akıcılıkta rakipsizken; yüksek hesaplama gücü, seri port/CAN bus donanım haberleşmesi ve veritabanı erişimi C++’ın uzmanlık alanıdır. Bu iki dünyayı birbirine bağlayan köprü olan C++ ve QML entegrasyonu, projenin performansını ve kod kalitesini belirleyen en kritik adımdır.
Bu rehberde; QPROPERTY makrosunun anatomisini, C++ sınıflarını QML motoruna tanıtmanın iki yolunu (setContextProperty ve qmlRegisterType), C++ metodlarını QML’den çağırmayı (QINVOKABLE) ve C++ sinyalleriyle QML arayüzünü anlık güncellemeyi inceleyeceğiz.
Entegrasyon Yöntemleri Karşılaştırması
C++ nesnelerini QML ile buluşturmanın iki ana yaklaşımı vardır:
| Yöntem | Açıklama | Kullanım Senaryosu |
|---|---|---|
setContextProperty | Tek bir C++ nesnesini global singleton gibi QML köküne enjekte eder. | Genel Sistem Yöneticisi, Tekil Servisler (Backend Controller). |
qmlRegisterType | C++ sınıfını doğrudan yeni bir QML ögesi (etiket) gibi kaydeder. | QML içinde birden fazla üretilebilen özel bileşenler. |
Adım 1: C++ Backend Sınıfını Hazırlamak
Gelin bir donanım sensör yöneticisi tasarlayalım (SensorController). Bu sınıf sıcaklık değerini okusun, bir fanı açıp kapatsın ve QML arayüzüne anlık bildirim göndersin.
sensorcontroller.h
#ifndef SENSORCONTROLLER_H
#define SENSORCONTROLLER_H
#include <QObject>
#include <QTimer>
class SensorController : public QObject {
Q_OBJECT
// Q_PROPERTY ile C++ değişkenini QML'e tanıtıyoruz
Q_PROPERTY(double temperature READ temperature NOTIFY temperatureChanged)
Q_PROPERTY(bool fanRunning READ isFanRunning WRITE setFanRunning NOTIFY fanStatusChanged)
public:
explicit SensorController(QObject *parent = nullptr);
double temperature() const { return m_temperature; }
bool isFanRunning() const { return m_fanRunning; }
// QML'den doğrudan çağrılabilen C++ metodu
Q_INVOKABLE void emergencyStop();
public slots:
void setFanRunning(bool running);
signals:
void temperatureChanged(double newTemp);
void fanStatusChanged(bool running);
void alertTriggered(const QString &message);
private slots:
void updateSensorData();
private:
double m_temperature = 24.5;
bool m_fanRunning = false;
QTimer *m_timer = nullptr;
};
#endif // SENSORCONTROLLER_H
sensorcontroller.cpp
#include "sensorcontroller.h"
#include <QRandomGenerator>
SensorController::SensorController(QObject *parent) : QObject(parent) {
// Sensör simülasyonu için timer
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &SensorController::updateSensorData);
m_timer->start(1000); // Her saniye oku
}
void SensorController::setFanRunning(bool running) {
if (m_fanRunning == running) return;
m_fanRunning = running;
emit fanStatusChanged(m_fanRunning);
}
void SensorController::emergencyStop() {
setFanRunning(false);
emit alertTriggered("Acil Durum: Fanlar durduruldu!");
}
void SensorController::updateSensorData() {
// Sıcaklığı rastgele dalgalandır
double delta = (QRandomGenerator::global()->bounded(100) - 50) / 100.0;
m_temperature += delta;
emit temperatureChanged(m_temperature);
// Eşik değer kontrolü
if (m_temperature > 40.0 && !m_fanRunning) {
setFanRunning(true);
emit alertTriggered("Aşırı Isınma: Fan otomatik başlatıldı!");
}
}
Önemli İpucu (QINVOKABLE): QML’den C++ fonksiyonu çağırmak istiyorsanız fonksiyonu ya
public slots:altına koymalı ya da başınaQINVOKABLEmakrosu eklemelisiniz. Standart C++ fonksiyonları QML tarafından görülemez.
Adım 2: main.cpp İçinde QML’e Enjekte Etmek
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "sensorcontroller.h"
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
// C++ Backend nesnesini oluştur
SensorController backend;
// Yöntem 1: QML'e global erişilebilir 'backend' adıyla tanıt
engine.rootContext()->setContextProperty("backend", &backend);
// QML dosyasını yükle
const QUrl url(QStringLiteral("qrc:/main.qml"));
engine.load(url);
return app.exec();
}
Adım 3: QML Arayüzünde Kullanım
Artık main.qml dosyasında backend nesnesi sanki yerel bir QML ögesiymiş gibi davranır:
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 400
height: 350
title: "Sensör İzleme Paneli"
color: "#2c3e50"
Column {
anchors.centerIn: parent
spacing: 20
// 1. C++'tan gelen canlı sıcaklık verisi (Otomatik Reaktif!)
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: backend.temperature.toFixed(1) + " °C"
font.pixelSize: 42
font.bold: true
color: backend.temperature > 35.0 ? "#e74c3c" : "#2ecc71"
}
// 2. C++ fan durumu anahtarı
Switch {
anchors.horizontalCenter: parent.horizontalCenter
text: "Soğutma Fanı"
checked: backend.fanRunning
onToggled: {
// QML'den C++ setter fonksiyonunu tetikle
backend.fanRunning = checked
}
}
// 3. Q_INVOKABLE buton çağrısı
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: "Acil Durdurma"
onClicked: {
backend.emergencyStop()
}
}
// 4. Uyarı mesajı alanı
Text {
id: alertLabel
anchors.horizontalCenter: parent.horizontalCenter
text: ""
color: "#f39c12"
font.pixelSize: 14
}
}
// 5. C++ Sinyallerini Dinlemek: Connections Bileşeni
Connections {
target: backend
function onAlertTriggered(message) {
alertLabel.text = message
}
}
}
Özet
C++ ve QML birlikteliği, Qt platformunun en güçlü silahıdır. QPROPERTY ile iki yönlü reaktif veri akışını kurabilir, QINVOKABLE ile donanım ve iş mantığını tetikleyebilir ve Connections ile C++ sinyallerini akıcı görsel bildirimlere dönüştürebilirsiniz.