2015-10-12 7 views
9

के बीच डेटा साझा करने का सबसे अच्छा तरीका क्या है, मैं PyQt4 के साथ अपना पहला जीयूआई एप्लीकेशन लिखने की प्रक्रिया में हूं और मैं एक प्रश्न पर आया हूं जो बहुत बुनियादी लगता है, फिर भी मुझे अच्छा जवाब नहीं दिख रहा है:पीईक्यूटी में, मुख्य विंडो और थ्रेड

मैं मुख्य विंडो को अवरुद्ध किए बिना लगातार दोहराए गए कार्य को करने के लिए थ्रेड का उपयोग कर रहा हूं। थ्रेड को मुख्य विंडो (जैसे स्पिनबॉक्स का वर्तमान मान) से कुछ जानकारी चाहिए जो थ्रेड के रनटाइम के दौरान भी बदल सकती है। इस स्थिति में, मुख्य विंडो और धागे के बीच इस तरह के डेटा साझा करने का सही तरीका क्या है?

भोलेपन से, मैं निम्नलिखित संभावनाओं के साथ आ सकता है:

  1. धागा के लिए मेजबान खिड़की के लिए एक संदर्भ में बताएं, और इस का उपयोग प्रश्न में चर (नीचे उदाहरण देखें) के वर्तमान मूल्य को पुनः प्राप्त करने।
  2. थ्रेड में चर की एक प्रति रखें और जब भी यह बदलता है सिग्नल उत्सर्जित करके इसे मुख्य विंडो के साथ सिंक्रनाइज़ रखें।
  3. वैश्विक चर का उपयोग करें।

सभी तीन विकल्प मेरे विशेष उपयोग मामले (हालांकि 2 थोड़ा जटिल हो जाएगा) के लिए सबसे अधिक संभावना है, लेकिन मुझे लगता है कि वहां एक बेहतर/अधिक पायथनिक/अधिक क्यूटी जैसी तरह होना चाहिए।

from PyQt4 import QtGui, QtCore 
import time, sys 

class MainWindow(QtGui.QWidget): 
    def __init__(self): 
     super(MainWindow, self).__init__() 
     self.layout = QtGui.QVBoxLayout(self) 
     self.spinbox = QtGui.QSpinBox(self) 
     self.spinbox.setValue(1) 
     self.layout.addWidget(self.spinbox) 
     self.output = QtGui.QLCDNumber(self) 
     self.layout.addWidget(self.output) 

     self.worker = Worker(self) 
     self.connect(self.worker, QtCore.SIGNAL('beep'), self.update) 
     self.worker.start() 

    def update(self, number): 
     self.output.display(number) 


class Worker(QtCore.QThread): 
    def __init__(self, host_window): 
     super(Worker, self).__init__() 
     self.host = host_window 
     self.running = False 

    def run(self): 
     self.running = True 
     i = 0 
     while self.running: 
      i += 1 
      self.emit(QtCore.SIGNAL('beep'), i) 
      sleep_time = self.host.spinbox.value() 
      time.sleep(sleep_time) 

    def stop(self): 
     self.running = False 


app = QtGui.QApplication(sys.argv) 
window = MainWindow() 
window.show() 
app.exec_() 

पुनश्च::

यहाँ एक न्यूनतम काम कर उदाहरण illustrating क्या मैं इस मामले में क्या करना है, विकल्प 1 का उपयोग करना चाहते हैं जब से मैं PyQt के साथ पूरी तरह अनुभवहीन हूँ यह संभव नहीं दिखता नहीं है वहाँ के साथ अन्य समस्याओं हैं कि कोड या सवाल अस्पष्ट है। इस मामले में, कृपया प्रश्न टिप्पणी या संपादित करने के लिए स्वतंत्र महसूस करें।

+0

मेरा उत्तर के बावजूद, अपने कोड को ठीक से काम करने लगता है का उपयोग करें, तो शायद मैं मैं गलत हूं या कुछ और मुझे नहीं मिला है। – Mel

+1

@tmoreau। इस विशेष मामले में, कार्यकर्ता थ्रेड बस स्पिन-बॉक्स से मूल्य तक पहुंचता है। यदि उसने * मूल्य * को बदलने का प्रयास किया है, तो समस्या होने की संभावना अधिक होगी (क्योंकि इसका परिणामस्वरूप जीयूआई अपडेट हो सकता है)।हालांकि, 'मान() 'को कॉल करना अभी भी थ्रेड-सुरक्षित नहीं है, क्योंकि उपयोगकर्ता एक ही समय में स्पिन-बॉक्स मान बदल सकता है, और संभवतः ऐसे परिवर्तन * परमाणु * संचालन नहीं हैं। फिर भी, सबसे खराब हो सकता है कि कार्यकर्ता थ्रेड को स्पिन-बॉक्स से "पुराना" मान मिल सकता है। – ekhumoro

उत्तर

8

विजेट सुरक्षित थ्रेड नहीं कर रहे हैं, Threads and QObjects देखें:

हालांकि QObject रैत्रांत है, जीयूआई वर्गों, विशेष रूप से QWidget और अपने सभी उपवर्गों, रैत्रांत नहीं हैं। उनका उपयोग केवल मुख्य धागे से किया जा सकता है।

और देखने के अधिक यहाँ परिभाषाएँ: Reentrancy and Thread-Safety


आप केवल मुख्य थ्रेड में विगेट्स का उपयोग करना चाहिए, और संकेत और स्लॉटों का इस्तेमाल अन्य धागे के साथ संवाद करने।

मुझे नहीं लगता कि एक वैश्विक चर काम करेगा, लेकिन मैं ईमानदारी से क्यों नहीं जानता कि क्यों।


इस उदाहरण में संकेतों का उपयोग कैसे करें:

#in main 
self.worker = Worker(self.spinbox.value()) 
self.worker.beep.connect(self.update) 
self.spinbox.valueChanged.connect(self.worker.update_value) 

class Worker(QtCore.QThread): 
    beep=QtCore.pyqtSignal(int) 

    def __init__(self,sleep_time): 
     super(Worker, self).__init__() 
     self.running = False 
     self.sleep_time=sleep_time 

    def run(self): 
     self.running = True 
     i = 0 
     while self.running: 
      i += 1 
      self.beep.emit(i) 
      time.sleep(self.sleep_time) 

    def stop(self): 
     self.running = False 

    def update_value(self,value): 
     self.sleep_time=value 

एनबी: मैं नई शैली संकेत और स्लॉट

+0

संदर्भ के लिए बहुत बहुत धन्यवाद। तो आप कह रहे हैं विकल्प 1 और 3 का उपयोग नहीं किया जाना चाहिए। क्या आप कुछ संकेत दे सकते हैं कि धागे के बीच केवल सिग्नल का उपयोग करके वांछित व्यवहार कैसे प्राप्त किया जाएगा? मेरे लिए यह एक बुनियादी कार्य की एक भयानक जटिलता प्रतीत होता है (कम से कम जब मैं कई अलग-अलग सूचनाओं से निपट रहा हूं जिन्हें मैं साझा करना चाहता हूं)। – Emil

+0

ठीक है, मुझे लगता है कि थ्रेड का उपयोग करना कभी बुनियादी नहीं होता है। लेकिन मुझे अभी भी हैरान है कि उपरोक्त आपका कोड पूरी तरह से ठीक काम करता है, जब मुझे लगता है कि प्रत्येक प्रलेखन दोहराना है "मुख्य धागे की तुलना में किसी भी चीज़ से विजेट को बदलें/एक्सेस न करें"। वैसे भी, सिग्नल के साथ एक उदाहरण के लिए संपादन देखें। – Mel

+0

अतिरिक्त उदाहरण के लिए फिर से धन्यवाद! यह बहुत बुरा नहीं लग रहा है। :) मैं अभी भी बनाए रखूंगा कि दो स्थानों पर एक ही जानकारी की दो प्रतियां मुझे अजीब लगती हैं, लेकिन अब यह है कि मैं क्या कर रहा हूं। मैंने मुख्य धागे में यथासंभव अधिक से अधिक जानकारी को संभालने के लिए कोड भी बदल दिया, ताकि मुझे धागे के बीच न्यूनतम संख्या में मूल्यों को संवाद करने की आवश्यकता हो। – Emil

संबंधित मुद्दे