เหตุการณ์ Qt และสัญญาณ / สล็อต


99

ในโลก Qt เหตุการณ์และสัญญาณ / สล็อตต่างกันอย่างไร?

หนึ่งแทนที่อีกคนหนึ่งหรือไม่? เหตุการณ์เป็นนามธรรมของสัญญาณ / สล็อตหรือไม่?

คำตอบ:


29

เอกสาร Qtอาจจะอธิบายได้ดีที่สุด:

ใน Qt เหตุการณ์คือวัตถุที่ได้มาจากQEventคลาสนามธรรมซึ่งแสดงถึงสิ่งต่างๆที่เกิดขึ้นภายในแอปพลิเคชันหรือเป็นผลมาจากกิจกรรมภายนอกที่แอปพลิเคชันจำเป็นต้องรู้ กิจกรรมสามารถรับและจัดการได้โดยอินสแตนซ์ของQObjectคลาสย่อยใด ๆแต่จะเกี่ยวข้องกับวิดเจ็ตโดยเฉพาะ เอกสารนี้อธิบายถึงวิธีการจัดส่งและจัดการเหตุการณ์ในแอปพลิเคชันทั่วไป

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

สัญญาณและสล็อตนั้นง่ายกว่ามากในการสร้างและรับและคุณสามารถเชื่อมต่อสองQObjectคลาสย่อยใดก็ได้ พวกเขาได้รับการจัดการผ่าน Metaclass (ดูไฟล์ moc_classname.cpp ของคุณสำหรับข้อมูลเพิ่มเติม) แต่การสื่อสารระหว่างคลาสส่วนใหญ่ที่คุณจะสร้างอาจใช้สัญญาณและสล็อต สัญญาณสามารถส่งได้ทันทีหรือเลื่อนผ่านคิว (หากคุณใช้เธรด)

สามารถสร้างสัญญาณได้


คิวที่รอการตัดบัญชีเหมือนกับการวนซ้ำเหตุการณ์ของคิวหรือมีอยู่สองคิว? หนึ่งสำหรับสัญญาณ deffered และสำหรับเหตุการณ์?
Guillaume07

31
@ ราฟาเอลอัปยศคุณที่ยอมรับคำตอบนี้ - ย่อหน้าที่อ้างถึงไม่มีแม้แต่คำว่า "สัญญาณ" หรือ "ช่อง"!
Robert Siemer

1
@neuronet: ย่อหน้าจะถูกยกมาด้วย“ [มัน] อธิบายได้ดีที่สุด” ซึ่งมันไม่ได้ ไม่ใช่เลย. ไม่แม้แต่น้อย.
Robert Siemer

@ โรเบิร์ตดังนั้นหากบรรทัดแนะนำเล็ก ๆ น้อย ๆ เปลี่ยนเป็น "ก่อนอื่นให้พิจารณาว่าเอกสารอธิบายเหตุการณ์อย่างไรก่อนที่จะดำเนินการต่อเพื่อพิจารณาว่าเกี่ยวข้องกับสัญญาณอย่างไร" คุณจะโอเคกับคำตอบหรือไม่ ถ้าเป็นเช่นนั้นเราสามารถแก้ไขคำตอบเพื่อปรับปรุงได้เนื่องจากเป็นประเด็นเล็กน้อยและฉันยอมรับว่าควรใช้คำที่ดีกว่านี้ [แก้ไขเป็นคำถามที่แท้จริง: เนื่องจากฉันไม่แน่ใจว่าส่วนที่เหลือจะดีกว่ามาก .... แต่เพียงเพราะส่วนที่ยกมาไม่ได้กล่าวถึงสัญญาณดูเหมือนจะเป็นกังวลเพียงผิวเผินหากส่วนที่เหลือนั้นดีจริงซึ่งฉันก็เป็น ไม่ได้ทะลึ่ง ]
eric

4
@neuronet ถ้าคุณลบคำพูดทั้งหมดมันจะช่วยเพิ่มคำตอบในสายตาของฉัน - หากคุณลบคำตอบทั้งหมดออกจะเป็นการปรับปรุง QA ทั้งหมดนี้
Robert Siemer

153

ใน Qt สัญญาณและเหตุการณ์ต่างก็เป็นการนำรูปแบบผู้สังเกตการณ์มาใช้ ใช้ในสถานการณ์ที่แตกต่างกันเนื่องจากมีจุดแข็งและจุดอ่อนที่แตกต่างกัน

ก่อนอื่นมากำหนดสิ่งที่เราหมายถึงโดย 'Qt event' กันอย่างแน่นอนนั่นคือฟังก์ชันเสมือนในคลาส Qt ซึ่งคุณคาดว่าจะนำมาใช้ใหม่ในคลาสพื้นฐานของคุณหากคุณต้องการจัดการกับเหตุการณ์ มันเกี่ยวข้องกับรูปแบบวิธีการแม่แบบ

สังเกตว่าฉันใช้คำว่า " จัดการ " อย่างไร นี่คือความแตกต่างพื้นฐานระหว่างเจตนาของสัญญาณและเหตุการณ์:

  • คุณ " จัดการ " เหตุการณ์
  • คุณ " ได้รับการแจ้งเตือน " การปล่อยสัญญาณ

ความแตกต่างก็คือเมื่อคุณ "จัดการ" เหตุการณ์นั้นคุณจะต้องรับผิดชอบในการ "ตอบสนอง" ด้วยพฤติกรรมที่เป็นประโยชน์นอกชั้นเรียน ตัวอย่างเช่นพิจารณาแอปที่มีปุ่มพร้อมตัวเลข แอปต้องให้ผู้ใช้โฟกัสปุ่มและเปลี่ยนหมายเลขโดยกดแป้นคีย์บอร์ด "ขึ้น" และ "ลง" มิฉะนั้นปุ่มควรทำงานเหมือนปกติQPushButton(สามารถคลิกได้ ฯลฯ ) ใน Qt สิ่งนี้ทำได้โดยการสร้าง "องค์ประกอบ" ที่สามารถนำกลับมาใช้ใหม่ได้ (คลาสย่อยQPushButton) ของคุณเองซึ่งเป็นการเติมQWidget::keyPressEventเต็ม รหัสเทียม:

class NumericButton extends QPushButton
    private void addToNumber(int value):
        // ...

    reimplement base.keyPressEvent(QKeyEvent event):
        if(event.key == up)
            this.addToNumber(1)
        else if(event.key == down)
            this.addToNumber(-1)
        else
            base.keyPressEvent(event)

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

  • เนื่องจากเรานำระบบเสมือนมาใช้ใหม่การติดตั้งของเราจึงถูกห่อหุ้มในชั้นเรียนของเราโดยอัตโนมัติ หากนักออกแบบของ Qt keyPressEventส่งสัญญาณเราจะต้องตัดสินใจว่าจะรับช่วงต่อQPushButtonหรือเพียงแค่เชื่อมต่อกับสัญญาณภายนอก แต่นั่นจะเป็นเรื่องโง่เนื่องจากใน Qt คุณมักจะคาดหวังว่าจะได้รับมรดกเมื่อเขียนวิดเจ็ตด้วยพฤติกรรมที่กำหนดเอง (ด้วยเหตุผลที่ดี - การใช้ซ้ำ / การแยกส่วน) ดังนั้นการkeyPressEventจัดกิจกรรมจึงสื่อถึงเจตนาของพวกเขาซึ่งkeyPressEventเป็นเพียงส่วนประกอบพื้นฐานของฟังก์ชันการทำงาน หากเป็นสัญญาณมันจะดูเหมือนสิ่งที่ผู้ใช้หันหน้าเข้าหาเมื่อไม่ได้ตั้งใจ
  • เนื่องจากมีการใช้งานฟังก์ชันระดับพื้นฐานเราจึงใช้รูปแบบห่วงโซ่แห่งความรับผิดชอบได้อย่างง่ายดายโดยจัดการกรณีพิเศษของเรา (ปุ่มขึ้นและลง) และปล่อยส่วนที่เหลือไปยังคลาสพื้นฐาน คุณจะเห็นว่าสิ่งนี้แทบจะเป็นไปไม่ได้เลยหากkeyPressEventเป็นสัญญาณ

การออกแบบ Qt นั้นถูกคิดมาอย่างดี - ทำให้เราตกอยู่ในหลุมแห่งความสำเร็จด้วยการทำให้ง่ายต่อการทำสิ่งที่ถูกต้องและยากที่จะทำในสิ่งที่ผิด (โดยการทำให้ keyPressEvent เป็นเหตุการณ์)

ในทางกลับกันให้พิจารณาการใช้งานที่ง่ายที่สุดQPushButton- เพียงแค่สร้างอินสแตนซ์และรับการแจ้งเตือนเมื่อคลิก :

button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())

ผู้ใช้คลาสนี้หมายถึงสิ่งนี้อย่างชัดเจน:

  • หากเราต้องคลาสย่อยQPushButtonทุกครั้งที่เราต้องการให้ปุ่มบางปุ่มแจ้งให้เราทราบถึงการคลิกนั่นจะต้องมีคลาสย่อยจำนวนมากโดยไม่มีเหตุผลที่ดี! วิดเจ็ตที่แสดงคำว่า "สวัสดีชาวโลก" เสมอmessageboxเมื่อคลิกจะมีประโยชน์ในกรณีเดียวเท่านั้นดังนั้นจึงไม่สามารถใช้ซ้ำได้ทั้งหมด อีกครั้งเราไม่มีทางเลือกอื่นนอกจากทำในสิ่งที่ถูกต้อง - โดยการเชื่อมต่อกับภายนอก
  • เราอาจต้องการเชื่อมต่อหลายช่องเข้าclicked()- หรือเชื่อมต่อสัญญาณsayHello()ต่างๆ ด้วยสัญญาณไม่มีความยุ่งยาก ด้วยคลาสย่อยคุณจะต้องนั่งไตร่ตรองแผนภาพชั้นเรียนจนกว่าจะตัดสินใจออกแบบที่เหมาะสม

โปรดทราบว่าหนึ่งในสถานที่ที่QPushButtonปล่อยออกมาclicked()นั้นกำลังmousePressEvent()ดำเนินการอยู่ นั่นไม่ได้หมายความว่าclicked()และmousePressEvent()เปลี่ยนกันได้ - เพียงแค่ว่ามันเกี่ยวข้องกัน

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


ฉันได้รับความคิด เหตุการณ์เป็นต่อคลาสอินสแตนซ์ทั้งหมดของคลาสจะตอบสนองเหมือนกันทั้งหมดจะเรียกเหตุการณ์ QClassName :: เดียวกัน แต่สัญญาณเป็นสิ่งต่อวัตถุแต่ละวัตถุสามารถมีการเชื่อมต่อช่องสัญญาณที่ไม่ซ้ำกันได้
炸鱼薯条德里克

39

ฉันไม่ชอบคำตอบจนถึงตอนนี้ - ให้ฉันจดจ่อกับส่วนนี้ของคำถาม:

เหตุการณ์เป็นนามธรรมของสัญญาณ / สล็อตหรือไม่?

คำตอบสั้น ๆ : ไม่ คำตอบที่ยาวทำให้เกิดคำถาม“ ดีกว่า”: สัญญาณและเหตุการณ์เกี่ยวข้องกันอย่างไร?

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

ผลลัพธ์ของการเรียก select () นั้นอาจเป็น: ข้อมูลใหม่บนซ็อกเก็ตเชื่อมต่อกับ X11 แพ็คเก็ตไปยังพอร์ต UDP ที่เราฟังเข้ามา ฯลฯ - สิ่งนั้นไม่ใช่สัญญาณ Qt หรือเหตุการณ์ Qt และ Qt main loop จะตัดสินใจเองว่าจะเปลี่ยนข้อมูลใหม่ให้เป็นข้อมูลใหม่หรือไม่อีกอันหนึ่งหรือละเว้น

Qt สามารถเรียกเมธอด (หรือหลายวิธี) เช่น keyPressEvent () เปลี่ยนเป็นเหตุการณ์ Qt ได้อย่างมีประสิทธิภาพ หรือ Qt ปล่อยสัญญาณซึ่งจะมีผลค้นหาฟังก์ชันทั้งหมดที่ลงทะเบียนสำหรับสัญญาณนั้นและเรียกใช้ทีละรายการ

ความแตกต่างอย่างหนึ่งของแนวคิดทั้งสองนี้สามารถมองเห็นได้ที่นี่: สล็อตไม่มีการโหวตว่าสล็อตอื่น ๆ ที่ลงทะเบียนกับสัญญาณนั้นจะถูกเรียกหรือไม่ - เหตุการณ์เป็นเหมือนห่วงโซ่มากกว่าและตัวจัดการเหตุการณ์จะตัดสินใจว่าจะขัดจังหวะห่วงโซ่นั้นหรือไม่ สัญญาณมีลักษณะเหมือนดาวหรือต้นไม้ในแง่นี้

เหตุการณ์สามารถกระตุ้นหรือเปลี่ยนเป็นสัญญาณทั้งหมดได้ (เพียงแค่ส่งเสียงออกมาอย่าเรียกว่า“ super ()”) สัญญาณสามารถเปลี่ยนเป็นเหตุการณ์ได้ (เรียกตัวจัดการเหตุการณ์)

สิ่งที่เป็นนามธรรมคืออะไรขึ้นอยู่กับกรณี: clicked () - สัญญาณนามธรรมเหตุการณ์ของเมาส์ (ปุ่มจะเลื่อนลงและขึ้นอีกครั้งโดยไม่ต้องขยับไปมามากเกินไป) เหตุการณ์แป้นพิมพ์เป็นนามธรรมจากระดับที่ต่ำกว่า (เช่น果หรือéคือการกดแป้นหลายครั้งในระบบของฉัน)

บางที focusInEvent () อาจเป็นตัวอย่างของสิ่งที่ตรงกันข้าม: มันสามารถใช้ (และทำให้เป็นนามธรรม) สัญญาณ clicked () แต่ฉันไม่รู้ว่ามันทำได้จริงหรือเปล่า


4
ฉันพบส่วนนี้: "สล็อตไม่มีการโหวตว่าสล็อตอื่น ๆ ที่ลงทะเบียนกับสัญญาณนั้นจะถูกเรียกหรือไม่" ให้ความกระจ่างมากสำหรับความแตกต่างระหว่างสัญญาณและเหตุการณ์ อย่างไรก็ตามฉันมีคำถามที่เกี่ยวข้อง: ข้อความคืออะไรและข้อความเกี่ยวข้องกับสัญญาณและเหตุการณ์อย่างไร (ถ้าเกี่ยวข้อง) ข้อความเป็นนามธรรมสำหรับสัญญาณและเหตุการณ์หรือไม่? สามารถใช้อธิบายปฏิสัมพันธ์ระหว่าง QObjects (หรือวัตถุอื่น ๆ ได้หรือไม่)
user1284631

@axeoth: ใน Qt ไม่มี "ข้อความ" มีกล่องข้อความ แต่ก็เกี่ยวกับมัน
Unslander Monica

@KubaOber: ขอบคุณครับ ฉันหมายถึง "เหตุการณ์"
user1284631

3
@axeoth: คำถามของคุณก็ไร้สาระ มีข้อความว่า "เหตุการณ์คืออะไรและเหตุการณ์เกี่ยวข้องกับสัญญาณและเหตุการณ์อย่างไร"
Unslander Monica

@ KubaOber: ฉันจำบริบทหนึ่งปีต่อมาไม่ได้ อย่างไรก็ตามดูเหมือนว่าฉันถามเกือบจะเหมือนกันกับ OP: อะไรคือความแตกต่างระหว่างเหตุการณ์เหตุการณ์และเหตุการณ์ที่เกี่ยวข้องกับสัญญาณและสล็อตอย่างไร ในตอนนั้นจริงๆแล้ว IIRC คืออะไรฉันกำลังมองหาวิธีที่จะตัดคลาสสัญญาณ Qt / สล็อตที่ขับเคลื่อนด้วยคลาสที่ไม่ใช่ Qt บางประเภทดังนั้นฉันจึงมองหาวิธีที่จะสั่งสิ่งแรกจากภายในตัวหลัง ฉันคิดว่าฉันกำลังพิจารณาที่จะส่งเหตุการณ์ไปให้พวกเขาเนื่องจากนั่นหมายความว่าฉันต้องรวมส่วนหัว Qt เท่านั้นและไม่บังคับให้ชั้นเรียนของฉันใช้สัญญาณ / สล็อต
user1284631

16

เหตุการณ์จะถูกส่งโดยการวนซ้ำเหตุการณ์ โปรแกรม GUI แต่ละโปรแกรมต้องการลูปเหตุการณ์ไม่ว่าคุณจะเขียน Windows หรือ Linux โดยใช้ Qt, Win32 หรือไลบรารี GUI อื่น ๆ แต่ละเธรดก็มีลูปเหตุการณ์ของตัวเองเช่นกัน ใน Qt "GUI Event Loop" (ซึ่งเป็นลูปหลักของแอปพลิเคชัน Qt ทั้งหมด) ถูกซ่อนไว้ แต่คุณเริ่มเรียก:

QApplication a(argc, argv);
return a.exec();

ระบบปฏิบัติการข้อความและแอปพลิเคชันอื่น ๆ ที่ส่งไปยังโปรแกรมของคุณจะถูกส่งเป็นเหตุการณ์

สัญญาณและช่องเป็นกลไก Qt ในกระบวนการคอมไพล์โดยใช้ moc (meta-object compiler) จะเปลี่ยนเป็นฟังก์ชันเรียกกลับ

เหตุการณ์ควรมีผู้รับหนึ่งคนซึ่งควรส่งไป ไม่มีใครควรได้รับเหตุการณ์นั้น

ช่องทั้งหมดที่เชื่อมต่อกับสัญญาณที่ปล่อยออกมาจะถูกดำเนินการ

คุณไม่ควรคิดว่าสัญญาณเป็นเหตุการณ์เพราะคุณสามารถอ่านได้ในเอกสาร Qt:

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

เมื่อคุณส่งเหตุการณ์จะต้องรอสักครู่จนกว่าการวนซ้ำของเหตุการณ์จะส่งเหตุการณ์ทั้งหมดที่มาก่อนหน้านี้ ด้วยเหตุนี้การดำเนินการของรหัสหลังจากส่งเหตุการณ์หรือสัญญาณจึงแตกต่างกัน โค้ดหลังจากส่งเหตุการณ์จะทำงานทันที ด้วยกลไกสัญญาณและสล็อตขึ้นอยู่กับประเภทการเชื่อมต่อ โดยปกติจะดำเนินการหลังจากสล็อตทั้งหมด การใช้ Qt :: QueuedConnection จะดำเนินการทันทีเช่นเดียวกับเหตุการณ์ ตรวจสอบประเภทการเชื่อมต่อทั้งหมดในเอกสาร Qt


ประโยคนี้ทำให้ฉันเข้าใจอย่างกระชับเกี่ยวกับความแตกต่างระหว่าง Qt signal-slot และ events:When you send an event, it must wait for time when event loop dispatch all events that came earlier. Because of this, execution of the cod after sending event or signal is different
swdev

7

มีบทความที่กล่าวถึงการประมวลผลเหตุการณ์โดยละเอียด: http://www.packtpub.com/article/events-and-signals

จะกล่าวถึงความแตกต่างระหว่างเหตุการณ์และสัญญาณที่นี่:

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

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


หมายเหตุโปรดดูความคิดเห็นที่เป็นประโยชน์ด้านล่างเกี่ยวกับคำตอบนี้จาก Kuba Ober ซึ่งทำให้ฉันสงสัยว่ามันอาจจะง่ายไปหน่อย


ฉันมองไม่เห็นว่ามันเป็นกลไกสองอย่างที่ใช้ในการทำสิ่งเดียวกันให้สำเร็จได้อย่างไร - ฉันคิดว่ามันเป็นลักษณะทั่วไปที่ไร้ประโยชน์ที่ช่วยให้ไม่มีใคร
Unslander Monica

1
@KubaOber ไม่ช่วยหลีกเลี่ยงรายละเอียดระดับล่าง คุณจะบอกว่า Python ไม่มีประโยชน์เพราะคุณสามารถเขียนสิ่งเดียวกันกับรหัสเครื่องได้หรือไม่? :)
eric

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

1
"เหตุการณ์และสัญญาณเป็นกลไกแบบคู่ขนานสองแบบที่ใช้เพื่อทำสิ่งเดียวกันให้สำเร็จภายในขอบเขตแคบ ๆ ของวิดเจ็ต / การควบคุม UI บางอย่าง " ส่วนที่เป็นตัวหนาขาดหายไปอย่างมากและทำให้คำพูดไม่เป็นประโยชน์ ถึงกระนั้นเราก็สามารถตั้งคำถามได้ว่า "สิ่งเดียวกัน" นั้นประสบความสำเร็จมากแค่ไหน: สัญญาณช่วยให้คุณตอบสนองต่อเหตุการณ์การคลิกโดยไม่ต้องติดตั้งตัวกรองเหตุการณ์บนวิดเจ็ต (หรือได้มาจากวิดเจ็ต) การทำโดยไม่มีสัญญาณจะยุ่งยากกว่ามากและจับคู่รหัสไคลเอ็นต์ให้แน่นกับตัวควบคุม นั่นเป็นการออกแบบที่ไม่ดี
Unslander Monica

1
เหตุการณ์ที่เกิดขึ้นเป็นที่แพร่หลายแนวคิด การดำเนินการโดยเฉพาะอย่างยิ่งใน Qt รูปธรรมeventชุดพวกเขาเป็นโครงสร้างข้อมูลที่ส่งผ่านไปยัง สัญญาณและสล็อตเป็นวิธีการที่เป็นรูปธรรมในขณะที่กลไกการเชื่อมต่อเป็นโครงสร้างข้อมูลที่ช่วยให้สัญญาณเรียกใช้สล็อตอย่างน้อยหนึ่งช่องที่แสดงว่าเชื่อมต่อกับมัน ฉันหวังว่าคุณจะเห็นว่าการพูดถึงสัญญาณ / สล็อตในฐานะ "เซตย่อย" หรือ "ตัวแปร" ของเหตุการณ์นั้นเป็นเรื่องไร้สาระและในทางกลับกัน พวกเขาเป็นสิ่งที่แตกต่างกันที่เกิดขึ้นเพื่อใช้กับจุดจบที่คล้ายกันในบริบทของวิดเจ็ตบางอย่าง แค่นั้นแหละ. ยิ่งคุณสรุปมากเท่าไหร่คุณก็จะกลายเป็น IMHO น้อยลงเท่านั้น
Unslander Monica

5

TL; DR: สัญญาณและช่องเป็นการเรียกวิธีทางอ้อม เหตุการณ์คือโครงสร้างข้อมูล ดังนั้นพวกมันจึงเป็นสัตว์ที่แตกต่างกันมาก

เวลาเดียวที่จะรวมกันคือเมื่อมีการเรียกสล็อตข้ามขอบเขตเธรด อาร์กิวเมนต์การโทรของช่องถูกบรรจุในโครงสร้างข้อมูลและส่งเป็นเหตุการณ์ไปยังคิวเหตุการณ์ของเธรดการรับ ในเธรดการรับQObject::eventเมธอดจะคลายแพ็กอาร์กิวเมนต์เรียกใช้งานและอาจส่งคืนผลลัพธ์หากเป็นการเชื่อมต่อที่บล็อก

หากเรายินดีที่จะพูดถึงการให้อภัยเราอาจคิดว่าเหตุการณ์เป็นวิธีการเรียกใช้eventเมธอดของวัตถุเป้าหมาย นี่เป็นการเรียกวิธีทางอ้อมหลังจากแฟชั่น - แต่ฉันไม่คิดว่ามันจะเป็นวิธีที่มีประโยชน์ในการคิดแม้ว่าจะเป็นคำพูดที่แท้จริงก็ตาม


2

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

QEvent และคลาสย่อยเป็นเพียงแพ็คเกจข้อมูลมาตรฐานเพียงเล็กน้อยสำหรับเฟรมเวิร์กในการสื่อสารกับโค้ดของคุณ หากคุณต้องการให้ความสนใจกับเมาส์ในทางใดทางหนึ่งคุณจะต้องดูที่ QMouseEvent API เท่านั้นและนักออกแบบไลบรารีไม่จำเป็นต้องสร้างวงล้อใหม่ทุกครั้งที่คุณต้องคิดว่าเมาส์ทำอะไรในบางมุมของ Qt API

เป็นเรื่องจริงที่ว่าหากคุณกำลังรอเหตุการณ์ (อีกครั้งในกรณีทั่วไป) ของบางประเภทสล็อตของคุณจะยอมรับคลาสย่อย QEvent เป็นอาร์กิวเมนต์

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


2
"โดยทั่วไปเหตุการณ์จะถูกจัดการใน Qt ด้วยสัญญาณ / สล็อต" - จริง ๆ แล้วไม่ใช่ ... ออบเจ็กต์ QEvent มักจะส่งผ่านไปมาผ่าน virtuals ที่โอเวอร์โหลด ตัวอย่างเช่นไม่มีสัญญาณ "keyDown" ใน QWidget แต่ keyDown เป็นฟังก์ชันเสมือนแทน
Stefan Monov

เห็นด้วยกับสเตฟานจริงๆแล้ว Qt ที่สับสน
Harald Scheirich

1
@ Stefan: ฉันจะเถียงว่าแอป Qt ไม่กี่ตัวที่เพียงพอจะแทนที่ keyDown (และส่วนใหญ่จะใช้สัญญาณเช่น QAbstractButton :: clicked และ QLineEdit :: editFinished) เพื่อปรับ "โดยทั่วไป" ฉันเคยป้อนข้อมูลแป้นพิมพ์มาก่อนอย่างแน่นอน แต่ไม่ใช่วิธีการจัดการเหตุการณ์ปกติ
jkerian

หลังจากแก้ไข (ชี้แจงความหมายของ "เหตุการณ์") ตอนนี้โพสต์ของคุณถูกต้องแล้ว ฉันละเว้นจากการนำคำแบบนั้นมาใช้ซ้ำ สิ่งต่างๆมีโคลนเพียงพอโดยไม่ต้องเรียกสัญญาณว่า "เหตุการณ์ประเภทหนึ่ง"
Stefan Monov

2

ฉันพบคำถามนี้ขณะอ่าน"การประมวลผลเหตุการณ์"โดย Leow Wee Kheng นอกจากนี้ยังกล่าวว่า:

ป้อนคำอธิบายภาพที่นี่

Jasmine Blanchetteพูดว่า:

เหตุผลหลักว่าทำไมคุณถึงใช้เหตุการณ์มากกว่าการเรียกใช้ฟังก์ชันมาตรฐานหรือสัญญาณและสล็อตคือเหตุการณ์สามารถใช้ได้ทั้งแบบซิงโครนัสและอะซิงโครนัส (ขึ้นอยู่กับว่าคุณเรียก sendEvent () หรือ postEvents ()) ในขณะที่เรียกใช้ฟังก์ชันหรือเรียกใช้ สล็อตจะซิงโครนัสเสมอ ข้อดีอีกอย่างของเหตุการณ์คือสามารถกรองได้


1

ข้อควรพิจารณาในทางปฏิบัติเล็กน้อยอีกประการหนึ่ง: การเปล่งหรือรับสัญญาณจำเป็นต้องมีการสืบทอดQObjectในขณะที่วัตถุของการสืบทอดใด ๆ สามารถโพสต์หรือส่งเหตุการณ์ (เนื่องจากคุณเรียกใช้QCoreApplication.sendEvent()หรือpostEvent()) ซึ่งโดยปกติจะไม่ใช่ปัญหา แต่: ในการใช้สัญญาณ PyQt อย่างแปลกต้องQObjectเป็นซุปเปอร์คลาสแรก และคุณอาจไม่ต้องการจัดเรียงลำดับการสืบทอดของคุณใหม่เพียงเพื่อให้สามารถส่งสัญญาณได้)


-1

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

connect(this, &MyItem::mouseMove, [this](QMouseEvent*){});

จะแทนที่mouseMoveEvent()ฟังก์ชันอำนวยความสะดวกที่พบในQWidget(แต่ไม่ใช่ในQQuickItemอีกต่อไป) และจะจัดการกับmouseMoveสัญญาณที่ผู้จัดการฉากจะปล่อยออกมาสำหรับรายการนั้น ความจริงที่ว่าสัญญาณถูกปล่อยออกมาในนามของสินค้าโดยหน่วยงานภายนอกบางส่วนนั้นไม่สำคัญและเกิดขึ้นบ่อยครั้งในโลกของส่วนประกอบ Qt แม้ว่าจะไม่ได้รับอนุญาตก็ตาม (ส่วนประกอบ Qt มักหลีกเลี่ยงกฎนี้) แต่ Qt เป็นกลุ่ม บริษัท ของการตัดสินใจในการออกแบบที่แตกต่างกันจำนวนมากและค่อนข้างหล่อด้วยหินเพราะกลัวว่าจะทำลายรหัสเก่า (ซึ่งเกิดขึ้นบ่อยพอสมควร)


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

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

1
โดยพื้นฐานแล้วคุณเป็นเพียงการนำเหตุการณ์ไปใช้ใหม่หากคุณทำตามที่คุณแนะนำ
Fabio

@FabioA. นั่นคือประเด็นของคำถามของ OP เหตุการณ์และสัญญาณสามารถ / สามารถแทนที่กันได้
user1095108

หากคุณนำเหตุการณ์ไปใช้ซ้ำแสดงว่าคุณไม่ได้แทนที่เหตุการณ์ ยิ่งไปกว่านั้น: มีการนำสัญญาณมาใช้เหนือเหตุการณ์ คุณต้องมี "ระบบเหตุการณ์" ประเภทต่างๆเพื่อที่จะบอกเหตุการณ์ที่เกิดขึ้นอื่น ๆ ซึ่งอาจจะเป็นเธรดที่ไม่ใช่ของคุณซึ่งบางครั้งในอนาคตจะต้องเรียกใช้ฟังก์ชันที่กำหนด
Fabio
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.