🔥 Selamat datang di Pokerstars Casino Bonus Code — Jelajahi tren terbaru tentang new-australian-betting-sites!
Pendahuluan
Dalam pemrograman GUI, ketika kita mengubah satu widget, kita sering ingin widget lain diberi tahu. Secara lebih umum, kita ingin objek dari jenis apa pun dapat berkomunikasi satu sama lain. Misalnya, jika pengguna mengklik tombol Close, kita mungkin ingin fungsi close() dari jendela dipanggil.
Toolkit lain mencapai komunikasi semacam ini menggunakan panggilan balik. Panggilan balik adalah pointer ke suatu fungsi, sehingga jika Anda ingin suatu fungsi pemrosesan memberi tahu Anda tentang suatu peristiwa, Anda mengirimkan pointer ke fungsi lain (panggilan balik) ke fungsi pemrosesan tersebut. Fungsi pemrosesan kemudian memanggil panggilan balik pada saat yang tepat. Meskipun kerangka kerja yang sukses menggunakan metode ini ada, panggilan balik bisa tidak intuitif dan mungkin mengalami masalah dalam memastikan ketepatan tipe argumen panggilan balik.
Sinyal dan Slot
Di Qt, kami memiliki alternatif untuk teknik panggilan balik: Kami menggunakan sinyal dan slot. Sinyal dipancarkan ketika suatu peristiwa tertentu terjadi. Widget Qt memiliki banyak sinyal yang telah ditentukan, tetapi kita selalu dapat membuat subkelas widget untuk menambahkan sinyal kita sendiri. Slot adalah fungsi yang dipanggil sebagai respons terhadap sinyal tertentu. Widget Qt memiliki banyak slot yang telah ditentukan, tetapi praktik umum adalah membuat subkelas widget dan menambahkan slot sendiri sehingga Anda dapat menangani sinyal yang Anda minati.
Mekanisme sinyal dan slot adalah type safe: Signature sinyal harus cocok dengan signature slot penerima. (Sebenarnya slot dapat memiliki signature yang lebih pendek dari sinyal yang diterimanya karena dapat mengabaikan argumen tambahan.) Karena signature kompatibel, kompiler dapat membantu kita mendeteksi ketidakcocokan tipe saat menggunakan sintaks berbasis pointer fungsi. Sintaks SIGNAL dan SLOT berbasis string akan mendeteksi ketidakcocokan tipe saat runtime. Sinyal dan slot terhubung secara longgar: Kelas yang memancarkan sinyal tidak tahu dan tidak peduli slot mana yang menerima sinyal. Mekanisme sinyal dan slot Qt memastikan bahwa jika Anda menghubungkan sinyal ke slot, slot akan dipanggil dengan parameter sinyal pada waktu yang tepat. Sinyal dan slot dapat mengambil sejumlah argumen dari tipe apa pun. Mereka sepenuhnya type safe.
Semua kelas yang mewarisi dari QObject atau salah satu subkelasnya (mis., QWidget) dapat berisi sinyal dan slot. Sinyal dipancarkan oleh objek ketika mereka mengubah statusnya dengan cara yang mungkin menarik bagi objek lain. Ini semua yang dilakukan objek untuk berkomunikasi. Ia tidak tahu dan tidak peduli apakah ada yang menerima sinyal yang dipancarkannya. Ini adalah enkapsulasi informasi yang benar, dan memastikan bahwa objek dapat digunakan sebagai komponen perangkat lunak.
Slot dapat digunakan untuk menerima sinyal, tetapi mereka juga merupakan fungsi anggota normal. Sama seperti objek tidak tahu apakah ada yang menerima sinyalnya, slot tidak tahu apakah ada sinyal yang terhubung dengannya. Ini memastikan bahwa komponen yang benar-benar independen dapat dibuat dengan Qt.
Anda dapat menghubungkan sebanyak mungkin sinyal ke satu slot, dan satu sinyal dapat dihubungkan ke sebanyak mungkin slot yang Anda butuhkan. Bahkan dimungkinkan untuk menghubungkan sinyal langsung ke sinyal lain. (Ini akan memancarkan sinyal kedua segera setelah yang pertama dipancarkan.)
Bersama-sama, sinyal dan slot membentuk mekanisme pemrograman komponen yang kuat.
Sinyal
Sinyal dipancarkan oleh suatu objek ketika keadaan internalnya telah berubah dengan cara yang mungkin menarik bagi klien atau pemilik objek. Sinyal adalah fungsi akses publik dan dapat dipancarkan dari mana saja, tetapi kami merekomendasikan untuk hanya memancarkannya dari kelas yang mendefinisikan sinyal dan subkelasnya.
Ketika suatu sinyal dipancarkan, slot yang terhubung dengannya biasanya dieksekusi segera, seperti panggilan fungsi normal. Ketika ini terjadi, mekanisme sinyal dan slot sama sekali independen dari event loop GUI. Eksekusi kode setelah pernyataan emit akan terjadi setelah semua slot kembali. Situasinya sedikit berbeda ketika menggunakan koneksi antrian; dalam kasus tersebut, kode setelah kata kunci emit akan melanjutkan segera, dan slot akan dieksekusi nanti.
Jika beberapa slot terhubung ke satu sinyal, slot akan dieksekusi satu per satu, dalam urutan koneksi, ketika sinyal dipancarkan.
Sinyal secara otomatis dihasilkan oleh moc dan tidak boleh diimplementasikan dalam file.cpp.
Catatan tentang argumen: Pengalaman kami menunjukkan bahwa sinyal dan slot lebih dapat digunakan kembali jika mereka tidak menggunakan tipe khusus. Jika QScrollBar::valueChanged() menggunakan tipe khusus seperti QScrollBar::Range hipotetis, itu hanya dapat dihubungkan ke slot yang dirancang khusus untuk QScrollBar. Menghubungkan widget input yang berbeda akan menjadi tidak mungkin.
Slot
Suatu slot dipanggil ketika sinyal yang terhubung dengannya dipancarkan. Slot adalah fungsi C++ normal dan dapat dipanggil secara normal; satu-satunya fitur khusus mereka adalah bahwa sinyal dapat dihubungkan ke mereka.
Karena slot adalah fungsi anggota normal, mereka mengikuti aturan C++ normal ketika dipanggil secara langsung. Namun, sebagai slot, mereka dapat dipanggil oleh komponen apa pun, terlepas dari tingkat aksesnya, melalui koneksi sinyal-slot. Ini berarti bahwa sinyal yang dipancarkan dari instance kelas sembarang dapat menyebabkan slot privat dipanggil di instance kelas yang tidak terkait.
Anda juga dapat mendefinisikan slot sebagai virtual, yang menurut kami cukup berguna dalam praktik.
Dibandingkan dengan panggilan balik, sinyal dan slot sedikit lebih lambat karena fleksibilitas yang mereka berikan, meskipun perbedaannya untuk aplikasi nyata tidak signifikan. Secara umum, memancarkan sinyal yang terhubung ke beberapa slot kira-kira sepuluh kali lebih lambat daripada memanggil penerima secara langsung, dengan panggilan fungsi non-virtual. Ini adalah overhead yang diperlukan untuk menemukan objek koneksi, untuk mengiterasi semua koneksi dengan aman (mis., memeriksa bahwa penerima berikutnya belum dihancurkan selama emisi), dan untuk marshalling parameter secara generik. Meskipun sepuluh panggilan fungsi non-virtual mungkin terdengar banyak, ini jauh lebih sedikit overhead daripada operasi new atau delete, misalnya. Segera setelah Anda melakukan operasi string, vektor, atau daftar yang di balik layar memerlukan new atau delete, overhead sinyal dan slot hanya bertanggung jawab untuk sebagian kecil dari total biaya panggilan fungsi. Hal yang sama berlaku setiap kali Anda melakukan panggilan sistem dalam slot; atau secara tidak langsung memanggil lebih dari sepuluh fungsi. Kesederhanaan dan fleksibilitas mekanisme sinyal dan slot sepadan dengan overhead, yang bahkan tidak akan disadari oleh pengguna Anda.
Perhatikan bahwa pustaka lain yang mendefinisikan variabel yang disebut signals atau slots dapat menyebabkan peringatan dan kesalahan kompiler ketika dikompilasi bersama dengan aplikasi berbasis Qt. Untuk mengatasi masalah ini, gunakan #undef pada simbol preprocessor yang bermasalah.
Contoh Kecil
Deklarasi kelas C++ minimal mungkin seperti ini:
class Counter{public: Counter() { m_value = 0; } int value() const { return m_value; } void setValue(int value);private: int m_value;};
Kelas kecil berbasis QObject mungkin seperti ini:
#include
class Counter: public QObject{ Q_OBJECT // Catatan: Makro Q_OBJECT memulai bagian privat. // Untuk mendeklarasikan anggota publik, gunakan pengubah akses 'public:'.public: Counter() { m_value = 0; } int value() const { return m_value; }public slots: void setValue(int value);signals: void valueChanged(int newValue);private: int m_value;};
Versi berbasis QObject memiliki status internal yang sama, dan menyediakan metode publik untuk mengakses status, tetapi juga memiliki dukungan untuk pemrograman komponen menggunakan sinyal dan slot. Kelas ini dapat memberi tahu dunia luar bahwa statusnya telah berubah dengan memancarkan sinyal, valueChanged(), dan memiliki slot yang dapat digunakan objek lain untuk mengirim sinyal.
Semua kelas yang berisi sinyal atau slot harus menyebutkan Q_OBJECT di bagian atas deklarasi mereka. Mereka juga harus menurun (secara langsung atau tidak langsung) dari QObject.
Slot diimplementasikan oleh programmer aplikasi. Berikut adalah kemungkinan implementasi dari slot Counter::setValue():
void Counter::setValue(int value){ if (value!= m_value) { m_value = value; emit valueChanged(value); }}
Baris emit memancarkan sinyal valueChanged() dari objek, dengan nilai baru sebagai argumen.
Dalam potongan kode berikut, kita membuat dua objek Counter dan menghubungkan sinyal valueChanged() dari objek pertama ke slot setValue() objek kedua menggunakan QObject::connect():
Counter a, b; QObject::connect(&a, &Counter::valueChanged, &b, &Counter::setValue); aue(12); // a() == 12, b() == 12 bue(48); // a() == 12, b() == 48
Memanggil aue(12) membuat a memancarkan sinyal valueChanged(12), yang akan diterima b di slot setValue() -nya, yaitu bue(12) dipanggil. Kemudian b memancarkan sinyal valueChanged() yang sama, tetapi karena tidak ada slot yang terhubung ke sinyal valueChanged() milik b, sinyal tersebut diabaikan.
Perhatikan bahwa fungsi setValue() mengatur nilai dan memancarkan sinyal hanya jika value!= m_value. Ini mencegah perulangan tak terbatas dalam kasus koneksi siklik (mis., jika bhanged() terhubung ke aue() ).
Secara default, untuk setiap koneksi yang Anda buat, satu sinyal dipancarkan; dua sinyal dipancarkan untuk koneksi duplikat. Anda dapat memutuskan semua koneksi ini dengan satu panggilan disconnect(). Jika Anda memberikan tipe Qt::UniqueConnection, koneksi hanya akan dibuat jika bukan duplikat. Jika sudah ada duplikat (sinyal yang persis sama ke slot yang persis sama pada objek yang sama), koneksi akan gagal dan connect akan mengembalikan false.
Contoh ini menggambarkan bahwa objek dapat bekerja sama tanpa perlu mengetahui informasi apa pun tentang satu sama lain. Untuk memungkinkan ini, objek hanya perlu dihubungkan bersama, dan ini dapat dicapai dengan beberapa panggilan fungsi QObject::connect() yang sederhana, atau dengan fitur koneksi otomatis uic.
Contoh Nyata
Berikut adalah contoh header dari kelas widget sederhana tanpa fungsi anggota. Tujuannya adalah untuk menunjukkan bagaimana Anda dapat memanfaatkan sinyal dan slot dalam aplikasi Anda sendiri.
#ifndef LCDNUMBER_H#define LCDNUMBER_H#include class LcdNumber: public QFrame{ Q_OBJECT
LcdNumber mewarisi QObject, yang memiliki sebagian besar pengetahuan sinyal-slot, melalui QFrame dan QWidget. Ini agak mirip dengan widget QLCDNumber bawaan.
Makro Q_OBJECT diperluas oleh preprocessor untuk mendeklarasikan beberapa fungsi anggota yang diimplementasikan oleh moc; jika Anda mendapatkan kesalahan kompiler seperti "undefined reference to vtable for `LcdNumber`", Anda mungkin lupa menjalankan moc atau menyertakan output moc dalam perintah link.
public: LcdNumber(QWidget *parent = nullptr);signals: void overflow();
Setelah konstruktor kelas dan anggota publik, kami mendeklarasikan signals kelas. Kelas LcdNumber memancarkan sinyal, overflow(), ketika diminta untuk menampilkan nilai yang tidak mungkin.
Jika Anda tidak peduli dengan overflow, atau Anda tahu bahwa overflow tidak dapat terjadi, Anda dapat mengabaikan sinyal overflow(), mis. jangan menghubungkannya ke slot mana pun.
Jika di sisi lain Anda ingin memanggil dua fungsi kesalahan yang berbeda ketika angka meluap, cukup hubungkan sinyal ke dua slot yang berbeda. Qt akan memanggil keduanya (dalam urutan koneksi).
public slots: void display(int num); void display(double num); void display(const QString &str); void setHexMode(); void setDecMode(); void setOctMode(); void setBinMode(); void setSmallDecimalPoint(bool point);};#endif
Slot adalah fungsi penerima yang digunakan untuk mendapatkan informasi tentang perubahan status di widget lain. LcdNumber menggunakannya, seperti yang ditunjukkan kode di atas, untuk mengatur nomor yang ditampilkan. Karena display() adalah bagian dari antarmuka kelas dengan program lainnya, slot tersebut publik.
Beberapa program contoh menghubungkan sinyal valueChanged() dari QScrollBar ke slot display(), sehingga nomor LCD terus menampilkan nilai scroll bar.
Perhatikan bahwa display() di-overload. Sinyal dan slot Qt memberi Anda koneksi yang strongly-typed. Mereka lebih aman pada waktu kompilasi daripada callback tradisional. Dengan callback, Anda memerlukan nama fungsi yang berbeda dan pelacakan tipe manual. Tetapi dengan fungsi yang di-overload, Anda perlu menentukan versi mana yang akan digunakan. Bagian berikutnya menunjukkan caranya.
Menghubungkan ke Sinyal dan Slot yang Di-overload
Ketika sinyal atau slot di-overload (memiliki beberapa versi dengan parameter berbeda), Anda perlu secara eksplisit menentukan versi mana yang ingin Anda hubungkan menggunakan sintaks pointer fungsi. Anda dapat menggunakan qOverload() atau static_cast untuk membedakan:
// Menghubungkan ke overload int dari QComboBox::currentIndexChanged(int)connect(comboBox, qOverload(&QComboBox::currentIndexChanged), this, &MyClass::handleIndexChanged);// Atau memilih QLCDNumber::display(int) saat menghubungkan dari QSlider::valueChanged(int)connect(slider, &QSlider::valueChanged, lcd, qOverload(&QLCDNumber::display));// Menggunakan static_cast (lebih verbose):connect(comboBox, static_cast(&QComboBox::currentIndexChanged), this, &MyClass::handleIndexChanged);// Atau menggunakan lambda untuk memanggil overload yang benar:connect(slider, &QSlider::valueChanged, this, [lcd](int value) { lcd->display(value); });
Manajemen Koneksi Otomatis
Qt secara otomatis mengelola masa pakai koneksi antara tipe yang diturunkan dari QObject. Ketika objek pengirim atau penerima dihancurkan, koneksi secara otomatis dihapus, mencegah panggilan ke objek yang telah dihapus. Ini berlaku untuk sintaks pointer fungsi dan sintaks SIGNAL/SLOT berbasis string.
Untuk koneksi lambda, berikan objek konteks (biasanya this ) untuk memastikan lambda diputus ketika konteks dihancurkan:
connect(button, &QPushButton::clicked, this, [this]{ handleClick();});
Sementara Qt melindungi terhadap pengiriman sinyal ke objek yang sepenuhnya dihancurkan, sinyal mungkin masih dikirimkan selama penghancuran objek setelah destruktor kelas turunan selesai tetapi sebelum mencapai ~QObject. Keterbatasan ini berlaku khususnya untuk koneksi yang dibuat dengan sintaks pointer fungsi. Ini dapat terjadi ketika destruktor kelas dasar memancarkan sinyal yang terhubung ke kelas turunan yang sudah dihancurkan. Pertimbangkan untuk secara eksplisit memutuskan sinyal tersebut di destruktor jika ini dapat menjadi masalah untuk kelas Anda.
Sinyal dan Slot dengan Argumen Default
Signature sinyal dan slot dapat berisi argumen, dan argumen dapat memiliki nilai default. Pertimbangkan QObject::destroyed():
void destroyed(QObject* = nullptr);
Ketika QObject dihapus, ia memancarkan sinyal QObject::destroyed(). Kami ingin menangkap sinyal ini, di mana pun kami mungkin memiliki referensi menggantung ke QObject yang dihapus, sehingga kami dapat membersihkannya. Signature slot yang sesuai mungkin:
void objectDestroyed(QObject* obj = nullptr);
Untuk menghubungkan sinyal ke slot, kita menggunakan QObject::connect(). Ada beberapa cara untuk menghubungkan sinyal dan slot. Yang pertama adalah menggunakan pointer fungsi:
connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);
Ada beberapa keuntungan menggunakan QObject::connect() dengan pointer fungsi. Pertama, ini memungkinkan kompiler memeriksa apakah argumen sinyal kompatibel dengan argumen slot. Argumen juga dapat dikonversi secara implisit oleh kompiler, jika diperlukan.
Anda juga dapat menghubungkan ke functor atau lambda C++11:
connect(sender, &QObject::destroyed, this, [=](){ this->m_objects.remove(sender);});
Dalam kedua kasus ini, kami memberikan this sebagai konteks dalam panggilan ke connect(). Objek konteks memberikan informasi tentang di thread mana penerima harus dieksekusi. Ini penting, karena memberikan konteks memastikan bahwa penerima dieksekusi di thread konteks.
Lambda akan diputus ketika pengirim atau konteks dihancurkan. Anda harus berhati-hati bahwa objek apa pun yang digunakan di dalam functor masih hidup ketika sinyal dipancarkan.
Cara lain untuk menghubungkan sinyal ke slot adalah menggunakan QObject::connect() dan makro SIGNAL dan SLOT. Aturan tentang apakah akan menyertakan argumen atau tidak dalam makro SIGNAL() dan SLOT(), jika argumen memiliki nilai default, adalah bahwa signature yang diteruskan ke makro SIGNAL() harus tidak memiliki lebih sedikit argumen daripada signature yang diteruskan ke makro SLOT().
Semua ini akan berfungsi:
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));
Tapi yang ini tidak akan berfungsi:
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed(QObject*)));...karena slot akan mengharapkan QObject yang tidak akan dikirim oleh sinyal. Koneksi ini akan melaporkan kesalahan runtime.
Perhatikan bahwa argumen sinyal dan slot tidak diperiksa oleh kompiler saat menggunakan overload QObject::connect() ini.
Penggunaan Sinyal dan Slot Tingkat Lanjut
Untuk kasus di mana Anda mungkin memerlukan informasi tentang pengirim sinyal, Qt menyediakan fungsi QObject::sender(), yang mengembalikan pointer ke objek yang mengirim sinyal.
Ekspresi Lambda adalah cara yang nyaman untuk meneruskan argumen khusus ke slot:
connect(action, &QAction::triggered, engine, [=]() { engine->processAction(action->text());});
Menggunakan Qt dengan Sinyal dan Slot Pihak Ketiga
Dimungkinkan untuk menggunakan Qt dengan mekanisme sinyal/slot pihak ketiga. Anda bahkan dapat menggunakan kedua mekanisme dalam proyek yang sama. Untuk melakukannya, tulis yang berikut ini ke file proyek CMake Anda:
target_compile_definitions(my_app PRIVATE QT_NO_KEYWORDS)
Dalam file proyek qmake (.pro), Anda perlu menulis:
CONFIG += no_keywords
Ini memberi tahu Qt untuk tidak mendefinisikan kata kunci moc signals, slots, dan emit, karena nama-nama ini akan digunakan oleh pustaka pihak ketiga, mis. Boost. Kemudian untuk terus menggunakan sinyal dan slot Qt dengan flag no_keywords, ganti saja semua penggunaan kata kunci moc Qt dalam sumber Anda dengan makro Qt yang sesuai Q_SIGNALS (atau Q_SIGNAL), Q_SLOTS (atau Q_SLOT), dan Q_EMIT.
Sinyal dan slot di pustaka berbasis Qt
API publik dari pustaka berbasis Qt harus menggunakan kata kunci Q_SIGNALS dan Q_SLOTS alih-alih signals dan slots. Jika tidak, sulit untuk menggunakan pustaka semacam itu dalam proyek yang mendefinisikan QT_NO_KEYWORDS.
Untuk menegakkan pembatasan ini, pembuat pustaka dapat menetapkan define preprocessor QT_NO_SIGNALS_SLOTS_KEYWORDS saat membangun pustaka.
Define ini mengecualikan signals dan slots tanpa memengaruhi apakah kata kunci khusus Qt lainnya dapat digunakan dalam implementasi pustaka.
Kasino
Olahraga
real-money-online-casino