Sintaks Sinyal Slot Baru - Qt Wiki
Sintaks Sinyal Slot Baru - Qt Wiki
Halaman ini digunakan untuk mendeskripsikan sintaks sinyal dan slot baru selama pengembangannya. Fitur ini sekarang sudah dirilis dengan Qt 5.
- Perbedaan antara Koneksi Berbasis String dan Berbasis Functor (Dokumentasi resmi)
- Pengantar
- Detail Implementasi
Catatan: Ini adalah tambahan dari sintaks berbasis string lama yang masih berlaku.
Menghubungkan di Qt 5
Ada beberapa cara untuk menghubungkan sinyal di Qt 5.
Sintaks Lama
Qt 5 terus mendukung sintaks berbasis string lama untuk menghubungkan sinyal dan slot yang didefinisikan dalam QObject atau kelas apa pun yang mewarisi dari QObject (termasuk QWidget):
connect(sender, SIGNAL(valueChanged(QString, QString)), receiver, SLOT(updateValue(QString)));
Baru: Menghubungkan ke anggota QObject
Ini adalah cara baru Qt 5 untuk menghubungkan dua QObject dan melewatkan objek non-string:
connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);
Kelebihan
- Pemeriksaan waktu kompilasi terhadap keberadaan sinyal dan slot, tipe, atau jika Q_OBJECT hilang.
- Argumen dapat berupa typedef atau dengan penentu namespace yang berbeda, dan tetap berfungsi.
- Kemungkinan untuk secara otomatis mentransmisikan tipe jika ada konversi implisit (misalnya dari QString ke QVariant).
- Dapat terhubung ke fungsi anggota QObject apa pun, bukan hanya slot.
Kekurangan
- Sintaks yang lebih rumit? (Anda perlu menentukan tipe objek Anda).
- Sintaks yang sangat rumit dalam kasus kelebihan fungsi (lihat di bawah).
- Argumen default dalam slot tidak lagi didukung.
Baru: Menghubungkan ke fungsi sederhana
Sintaks baru bahkan dapat terhubung ke fungsi, bukan hanya QObject:
connect(sender, &Sender::valueChanged, someFunction);
Kelebihan
- Dapat digunakan dengan std::bind:
connect(sender, &Sender::valueChanged, std::bind(&Receiver::updateValue, receiver, "senderValue", std::placeholders::_1)); - Dapat digunakan dengan ekspresi lambda C++11:
connect(sender, &Sender::valueChanged, [=](const QString &newValue) { receiver->updateValue("senderValue", newValue); });
Kekurangan
- Tidak ada pemutusan otomatis ketika 'receiver' dihancurkan karena berupa functor tanpa QObject. Namun, sejak versi 5.2 ada kelebihan yang menambahkan "objek konteks". Ketika objek itu dihancurkan, koneksi akan terputus (konteks juga digunakan untuk afinitas thread: lambda akan dipanggil di thread dari event loop objek yang digunakan sebagai konteks).
Memutuskan Koneksi di Qt 5
Cara Lama
Anda dapat memutuskan koneksi dengan cara lama (menggunakan SIGNAL, SLOT) tetapi hanya jika:
- Anda terhubung menggunakan cara lama, atau
- Jika Anda ingin memutuskan semua slot dari sinyal tertentu menggunakan karakter wildcard.
Simetris dengan pointer fungsi
disconnect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue); Hanya berfungsi jika Anda terhubung dengan panggilan simetris, dengan pointer fungsi (atau Anda juga dapat menggunakan 0 untuk wildcard). Secara khusus, tidak bekerja dengan fungsi statis, functor, atau fungsi lambda.
Cara Baru menggunakan QMetaObject::Connection
QMetaObject::Connection m_connection; m_connection = QObject::connect(/*...*/); QObject::disconnect(m_connection); Bekerja dalam semua kasus, termasuk fungsi lambda atau functor.
Asynchronous yang Lebih Mudah
Dengan C++11, kode dapat tetap inline:
void doYourStuff(const QByteArray &page) { QTcpSocket *socket = new QTcpSocket; QObject::connect(socket, &QTcpSocket::connected, [socket, page]() { socket->write(QByteArray("GET " + page + "")); }); QObject::connect(socket, &QTcpSocket::readyRead, [socket]() { qDebug() << "DATA DITERIMA " << socket->readAll(); }); QObject::connect(socket, &QTcpSocket::disconnected, [socket]() { qDebug() << "TERPUTUS "; socket->deleteLater(); }); QObject::connect(socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error), [socket](QAbstractSocket::SocketError) { qDebug() << "KESALAHAN " << socket->errorString(); socket->deleteLater(); }); socket->connectToHost("qt", 80); } Berikut adalah QDialog tanpa memasuki eventloop lagi, dan menjaga kode tetap di tempat yang seharusnya:
void Doc::saveDocument() { QFileDialog *dlg = new QFileDialog(); dlg->open(); QObject::connect(dlg, &QDialog::finished, [dlg, this](int result) { if (result) { QFile file(dlg->selectedFiles().first()); // ... } dlg->deleteLater(); }); } Contoh lain menggunakan QHttpServer.
Pelaporan Kesalahan
Diuji dengan GCC. Untungnya, IDE seperti Qt Creator menyederhanakan penamaan fungsi.
Q_OBJECT Hilang dalam Definisi Kelas
#include <QtCore> class Goo : public QObject { Goo() { connect(this, &Goo::someSignal, this, &QObject::deleteLater); } signals: void someSignal(); }; Pesan kesalahan kompiler: qobject.h:... error: void value not ignored as it ought to be
Ketidakcocokan Tipe
#include <QtCore> class Goo : public QObject { Q_OBJECT public: Goo() { connect(this, &Goo::someSignal, this, &Goo::someSlot1); // Kesalahan connect(this, &Goo::someSignal, this, &Goo::someSlot2); // Berhasil } signals: void someSignal(const QString &); public: void someSlot1(int); void someSlot2(const QVariant &); }; Pesan kesalahan kompiler: qobject.h:... error: no type named 'IncompatibleSignalSlotArguments' ... error: cannot convert 'QtPrivate::RemoveRef<QString>::Type' to 'int'
Pertanyaan Terbuka
Argumen Default dalam Slot
Jika Anda memiliki kode seperti ini: class A : public QObject { Q_OBJECT public slots: void someSlot(int foo = 0); }; Metode lama memungkinkan Anda menghubungkan slot tersebut ke sinyal yang tidak memiliki argumen. Ini tidak berfungsi dengan sintaks baru secara langsung. Masalah ini dapat diatasi dengan bantuan fungsi lambda kecil: connect(m_timer, &QTimer::timeout, this, [this]() { m_a->someSlot(); });
Kelebihan Fungsi (Overload)
Seperti yang terlihat pada contoh di atas, menghubungkan ke QAbstractSocket::error tidak cantik karena error memiliki kelebihan fungsi, dan mengambil alamat fungsi yang kelebihan memerlukan casting eksplisit. Misalnya, koneksi yang sebelumnya dibuat seperti: connect(mySpinBox, SIGNAL(valueChanged(int)), mySlider, SLOT(setValue(int)); tidak dapat langsung diubah menjadi: connect(mySpinBox, &QSpinBox::valueChanged, mySlider, &QSlider::setValue); karena QSpinBox memiliki dua sinyal bernama valueChanged() dengan argumen berbeda. Sebagai gantinya, kode baru harus: connect(mySpinBox, qOverload<int>(&QSpinBox::valueChanged), mySlider, &QSlider::setValue); (untuk C++14 ke atas) atau connect(mySpinBox, QOverload<int>::of(&QSpinBox::valueChanged), mySlider, &QSlider::setValue); (untuk C++11). qOverload dan kelas pembantunya QOverload ditambahkan di Qt5.7. Untuk versi yang lebih lama, konstruksi berikut harus digunakan: connect(mySpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), mySlider, &QSlider::setValue);
Callback
Fungsi seperti QHostInfo::lookupHost (hingga Qt 5.9) atau QTimer::singleShot (hingga Qt 5.4) atau QFileDialog::open membutuhkan receiver QObject dan slot char*. Ini tidak berfungsi untuk metode baru. Jika seseorang ingin melakukan callback dengan cara C++, harus menggunakan std::function.
Platform Lainnya
Berita Piala Dunia
winaday casino no deposit bonus
Jika Anda memiliki pertanyaan, silakan kirim email ke [email protected]