การใช้ emit vs การเรียกสัญญาณราวกับว่ามันเป็นฟังก์ชันปกติใน Qt


97

สมมติว่าฉันมีสัญญาณนี้:

signals:
    void progressNotification(int progress);

ฉันเพิ่งเรียนรู้เกี่ยวกับคีย์เวิร์ด emit ใน Qt จนถึงตอนนี้ฉันเคยเรียกใช้สัญญาณโดยเรียกมันเหมือนฟังก์ชันปกติ แทนที่จะเป็น:

emit progressNotification(1000 * seconds);

ฉันจะเขียน:

progressNotification(1000 * seconds);

การเรียกพวกเขาแบบนั้นดูเหมือนจะใช้งานได้และสล็อตที่เชื่อมต่อทั้งหมดจะทำงานดังนั้นการใช้คีย์เวิร์ดที่ปล่อยออกมาจะทำให้เกิดพฤติกรรมที่แตกต่างกันหรือเป็นเพียงแค่น้ำตาลในวากยสัมพันธ์?


17
+1 ไม่เคยรู้emitไม่จำเป็น เป็นเรื่องแปลกที่คุณได้เรียนรู้เกี่ยวกับการemitเรียกสัญญาณโดยตรงมาเป็นเวลานานเนื่องจากระบบช่องสัญญาณเป็นหนึ่งในสิ่งแรก ๆ ที่ต้องเรียนรู้เกี่ยวกับ Qt
Christian Rau

คำตอบ:


89

emitเป็นเพียงน้ำตาลวากยสัมพันธ์ หากคุณดูที่เอาต์พุตฟังก์ชันก่อนการประมวลผลที่ส่งสัญญาณคุณจะเห็นว่าemitหายไปแล้ว

"เวทมนตร์" เกิดขึ้นในรหัสที่สร้างขึ้นสำหรับฟังก์ชันการเปล่งสัญญาณซึ่งคุณสามารถดูได้โดยการตรวจสอบรหัส C ++ ที่สร้างโดย moc

ตัวอย่างเช่นfooสัญญาณที่ไม่มีพารามิเตอร์จะสร้างฟังก์ชันสมาชิกนี้:

void W::foo()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);
}

และรหัสemit foo();จะถูกประมวลผลล่วงหน้าเพียงfoo();

emitถูกกำหนดไว้ในQt/qobjectdefs.h(ในรสชาติโอเพ่นซอร์สของแหล่งที่มา) เช่นนี้:

#ifndef QT_NO_EMIT
# define emit
#endif

(ตัวป้องกันกำหนดคืออนุญาตให้คุณใช้ Qt กับเฟรมเวิร์กอื่น ๆ ที่มีชื่อชนกันผ่านno_keywordsตัวเลือกการกำหนดค่าQMake)


14
คุณรู้หรือไม่ว่าเคยมีการนำไปใช้ (หรือการใช้งานตามแผน) emitที่ทำมากกว่าอะไร? ฉันพบว่าการมี 'syntactic sugar' ในกรณีนี้ทำให้มือใหม่สับสน (หรืออย่างน้อยฉันก็ตอนที่ฉันยังเป็นผู้ใช้ Qt มือใหม่) - ดูเหมือนว่ามีบางสิ่งที่มหัศจรรย์หรือสำคัญเกิดขึ้นกับemitคีย์เวิร์ดหลอกเมื่อมันไม่ได้ทำอะไรเลย ทั้งหมด - เวทมนตร์ทั้งหมดเกิดขึ้นในฟังก์ชั่นเก่าทั่วไปที่mocสร้างขึ้น ( mocคือเวทมนตร์สำหรับสัญญาณ Qt และสล็อต) emitเป็นการตกแต่งที่ไม่จำเป็นซึ่งไม่ได้ทำอะไรเลย แต่ดูเหมือนสำคัญ
Michael Burr

12
Emit ไม่ได้เป็นเพียงแค่การตกแต่งเท่านั้น emitบอกคนที่อ่านการโทรว่าเวทมนตร์กำลังจะเกิดขึ้น (นั่นคือจะเรียกโค้ดในวัตถุที่คลาสนี้อาจไม่เคยได้ยินมาก่อนและการโทรเหล่านี้อาจซิงโครนัสหรืออะซิงโครนัส) ซึ่งโดยพื้นฐานแล้วจะหายไปโดยสิ้นเชิงหากคุณไม่ใส่คีย์เวิร์ด ใช้มัน. เป็นเอกสารอัตโนมัติ "สามเณร" ควรอ่านเอกสารและแบบฝึกหัดและemitอยู่ที่นั่นเสมอ (ในเอกสารอย่างเป็นทางการ) การค้นพบว่าคุณสามารถเรียกใช้ฟังก์ชันนี้ได้ควรเกิดขึ้นหลังจากที่คุณ "เห็นแสงสว่าง" แล้ว - คุณไม่ใช่มือใหม่อีกต่อไปในตอนนั้น
จ้า

19
อืมฉันไม่แน่ใจว่าฉันเห็นด้วยกับคุณว่าemit'คีย์เวิร์ด' มีค่าแค่ไหน ฉันคิดว่าฉันชอบที่จะใช้หลักการตั้งชื่อหากจำเป็นต้องระบุให้ชัดเจนว่าการเรียกใช้ฟังก์ชันเป็นสัญญาณ
Michael Burr

2
ฉันไม่เห็นด้วยอย่างยิ่งกับเรื่องนี้ :) การบังคับใช้หลักการตั้งชื่อเป็นสิ่งที่คุณสามารถทำได้ด้วยตัวเองในโครงการ / ที่ทำงานของคุณ Qt ไม่ได้ป้องกันสิ่งนั้น Qt ไม่ได้บังคับให้คุณใช้ "คำหลัก" และยังช่วยให้คุณสามารถปิดได้หากขัดแย้งกับส่วนอื่น ๆ ของโค้ดของคุณ ในความคิดของวิธีการคำหลักจะดีกว่า - คอมไพเลอร์ไม่สามารถช่วยคุณบังคับใช้นโยบายการตั้งชื่อ emitแต่มันจะจับสะกดผิด
จ้า

15
เพื่อความชัดเจน - ฉันไม่ได้สนับสนุนให้ใช้รูปแบบการตั้งชื่อ - เพียงแค่ว่าหากเหตุผลของemitคำหลัก - คำหลัก - ความคิดเห็นคือการทำให้ชัดเจนว่ามีการเรียกสัญญาณจากนั้นหลักการตั้งชื่อก็สามารถทำได้เช่นเดียวกันโดยไม่มี ลึกลับและมีประโยชน์ที่คล้ายคลึงกัน Qt ไม่สามารถบังคับใช้หลักการตั้งชื่อได้ (จริงๆแล้วmocสามารถบังคับใช้ได้ - แต่ฉันไม่สนับสนุนอย่างนั้น) แต่ Qt ไม่สามารถบังคับใช้emitอย่างใดอย่างหนึ่ง และในขณะที่คุณสามารถ 'ปิด' ได้emitหากมีการปะทะกันของชื่อ แต่ก็ไม่ได้ช่วยอะไรมากหากคุณมีไฟล์ต้นฉบับจำนวนมากที่ใช้งานอยู่ (โดยไม่จำเป็นเพื่อบูต)
Michael Burr

2

หลังจากผ่านไป 18 เดือน ... ฉันเริ่มแสดงความคิดเห็นใต้คำตอบของ @ Mat และกำลังจะหมดห้องอย่างรวดเร็ว ดังนั้นคำตอบ

IMO emitไม่ใช่ทั้งน้ำตาลที่เป็นประโยคและคำหลักง่ายๆในแง่นั้น

  1. มันสร้างรหัส (ตามคำอธิบายของ @Mat ด้านบน)
  2. ช่วยให้connectกลไกรับรู้ว่าแท้จริงแล้วคือ a signalและ
  3. ทำให้สัญญาณของคุณเป็นส่วนหนึ่งของระบบที่ "ใหญ่กว่า" ซึ่งสัญญาณและการตอบสนอง (สล็อต) สามารถดำเนินการแบบซิงโครนัสหรืออะซิงโครนัสหรือเข้าคิวขึ้นอยู่กับตำแหน่งและวิธีการปล่อยสัญญาณ นี่เป็นคุณสมบัติที่มีประโยชน์อย่างยิ่งของระบบสัญญาณ / สล็อต

ระบบสัญญาณ / สล็อตทั้งหมดเป็นสำนวนที่แตกต่างจากการเรียกใช้ฟังก์ชันธรรมดา ฉันเชื่อว่ามันเกิดจากรูปแบบของผู้สังเกตการณ์ นอกจากนี้ยังมีความแตกต่างที่สำคัญระหว่าง a signalและ a slot: ไม่จำเป็นต้องใช้สัญญาณในขณะที่สล็อตต้องเป็น !

คุณกำลังเดินไปตามถนนและเห็นบ้านหลังหนึ่งถูกไฟไหม้ (สัญญาณ) คุณกด 911 ( เชื่อมต่อสัญญาณไฟกับช่องตอบกลับ 911 ) สัญญาณถูกปล่อยออกมาเท่านั้นในขณะที่หน่วยดับเพลิงได้รับการติดตั้ง อาจจะไม่ชัดเจน แต่คุณเข้าใจ มาดูตัวอย่าง OP

วัตถุแบ็กเอนด์บางตัวรู้ว่ามีความคืบหน้ามากเพียงใด มันก็emit progressNotification(...)ส่งสัญญาณได้ ขึ้นอยู่กับคลาสที่แสดงแถบความคืบหน้าจริงเพื่อรับสัญญาณนี้และดำเนินการกับมัน แต่มุมมองเชื่อมต่อกับสัญญาณนี้อย่างไร? ยินดีต้อนรับสู่ระบบสัญญาณ / สล็อตของ Qt หนึ่งสามารถตอนนี้ตั้งครรภ์ของชั้นผู้จัดการ (โดยปกติจะเป็นเครื่องมือของการเรียงลำดับ) ซึ่งประกอบไปด้วยมุมมองวัตถุและข้อมูลการคำนวณวัตถุ (ทั้งเป็นQObjects) connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress)อาจดำเนินการ

อย่าเข้าสู่ด้านการออกแบบของคลาสผู้จัดการ แต่พอจะบอกได้ว่านี่คือจุดที่ระบบสัญญาณ / สล็อตส่องสว่าง ฉันสามารถมุ่งเน้นไปที่การออกแบบสถาปัตยกรรมที่สะอาดมากสำหรับแอปพลิเคชันของฉัน ไม่เสมอไป แต่บ่อยครั้งที่ผมพบว่าผมแค่ปล่อยสัญญาณ แต่ใช้ช่อง

หากเป็นไปได้ที่จะใช้ / เรียกใช้วิธีการส่งสัญญาณโดยไม่เคยเปล่งออกมาแสดงว่าคุณไม่จำเป็นต้องใช้ฟังก์ชันนั้นเป็นสัญญาณตั้งแต่แรก


6
ไม่emitเป็นเพียงมาโครเปล่าและเป็นทางเลือกเท่านั้น ไม่ใช่คำหลักsignalและคำหลักslotที่ประมวลผลโดย moc signalใช้เพื่อจัดเตรียมการใช้งานฟังก์ชันslotใช้ในการสร้างรายการ meta object เพื่อให้พบกับSLOT(MySlot())มาโครหรือใน QML emitคือ suggar วากยสัมพันธ์ ไม่มีอะไรจะบ่นถ้าคุณเขียนemit i++;(แต่อาจเป็นเพื่อนร่วมงานของคุณ) และคุณยังไม่สามารถเชื่อมต่อi++ได้
derM

-4

ตัวเลือกที่สองจะบอกเป็นนัยว่าคุณรู้อยู่เสมอว่าชื่อฟังก์ชันและพารามิเตอร์ของฟังก์ชันคืออะไรและอ็อบเจ็กต์ที่คุณส่งไปนั้นเป็นที่รู้จักโดยฟังก์ชันนั้น ๆ สองกรณีนี้ไม่เป็นความจริงเสมอไปนั่นคือสองสิ่งหลักที่ทำให้เกิดช่องและสัญญาณ "under-the-hood" กลไกสัญญาณและสล็อตเป็นเพียงตารางที่มีตัวชี้ไปยังทุกฟังก์ชันที่เชื่อมต่อ

นอกจากนี้โปรดดู PDF นี้ซึ่งอธิบายลักษณะของสัญญาณและกลไกสล็อตอย่างชัดเจน: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf


ทั้งสองวิธีต้องการทราบชื่อสัญญาณและพารามิเตอร์ - คุณกำลังเปล่งมันออกมาคุณจะปล่อยสิ่งที่คุณไม่รู้ออกมาได้อย่างไร? ทั้งสองมีความหมายเหมือนกันเหมือนกันเหมือนกัน
จ้า

1
บางทีคุณอาจจะยุ่งกับการโทรสัญญาณด้วยการโทรแบบสล็อตโดยตรง? แต่ฉันต้องยอมรับว่าฉันก็สงสัยเกี่ยวกับชื่อคำถามในตอนแรกเนื่องจากฉันไม่เคยรู้มาก่อนว่าemitเป็นเพียงแค่การไม่ทำ แต่ในกรณีนี้การอ่านเนื้อหาคำถามก็ควรจะเคลียร์สิ่งต่างๆได้ดังนั้น -1
Christian Rau
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.