2017-06-06 64 views
0

我的.py和.kv文件中包含以下相關部分。引用.kv文件中的類屬性

class DrillScreen(Screen): 
    def __init__(self, **kwargs): 
     super(DrillScreen, self).__init__(**kwargs) 
     self.thedrill = drill(kwargs['options']) 
     self.thedrill.bind(on_answer = self.printtest) 


    def printtest(self,*args): 
     self.ids.answerlabel.text = self.thedrill.answer 
     print(self.ids.answerlabel.text) 

    def startdrill(self): 
     Process(target=self.thedrill.run).start() 

<DrillScreen>: 
    FloatLayout: 
     FloatLayout: 
      size_hint: 1.0, None 
      height: self.width 
      pos_hint: {'center_x':0.5,'center_y':0.5} 
      id: wheelbox 
      background_color: 1,1,1,1 
      pos: 0, 200 
      Label: 
       id: answerlabel 
       pos_hint: {'center_x':0.5, 'center_y':0.5} 
       text: root.thedrill.answer 
     Button: 
      text: 'Start' 
      size_hint: 0.5, 0.1 
      on_release: root.startdrill() 
     Button: 
      text: 'Back' 
      size_hint: 0.5, 0.1 
      pos_hint: {'x':0.5} 

這給了我一個錯誤AttributeError: 'DrillScreen' object has no attribute 'thedrill'。如果我將標籤文本中的root.thedrill.answer更改爲某個文字字符串,它運行良好,並且從printtest()的輸出中我看到它在內部發生更改,但其顯示不會更新。我想要從.kv文件訪問類屬性,或者從.py文件設置標籤顯示。謝謝。

編輯:在約阿夫Glazner的建議 出發,我嘗試添加一個按鈕,也結合printtest()功能,看看發生了什麼事情,我很困惑地看到,從不同綁定呼叫產生不同的輸出。下面是從的.py修改後的類:

class DrillScreen(Screen): 
    answer = StringProperty('alo') 
    def __init__(self, **kwargs): 
     self.thedrill = drill(kwargs['options']) 
     self.thedrill.bind(on_answer = self.printtest) 
     super(DrillScreen, self).__init__(**kwargs) 
     self.answer = self.thedrill.answer 

     b = Button(text = 'Test', 
      size_hint = [0.1,0.1], 
      pos_hint = {'top':1,'right':1}) 
     b.bind(on_release = self.printtest) 

     self.ids.wheelbox.add_widget(b) 

    def printtest(self,*args): 
     self.answer = self.thedrill.answer 
     print('This is printtest(): ', self.ids.answerlabel.text) 

    def startdrill(self): 
     Process(target=self.thedrill.run).start() 

到.kv文件的唯一變化是,標籤文本點root.answer。當我運行它(並點擊.kv中調用startdrill()的按鈕)時,thedrill定期發送它的on_answer事件,並且我還單擊新創建的按鈕以手動調用printtest,並在終端中產生此類輸出:

('This is printtest(): ', 'ti') 
('This is printtest(): ', 're') 
('This is printtest(): ', 'Default') 
('This is printtest(): ', 'Default') 
('This is printtest(): ', 'so') 
('This is printtest(): ', 'Default') 
('This is printtest(): ', 'le') 
('This is printtest(): ', 'Default') 

與音節的線是的thedrillon_answer調度的結果,並與「默認」的那些是從按鈕的點擊。我無法想象會有什麼影響差異。在檢查drill類時,我認爲沒有理由立即恢復到以前的值(它實際上在.answer的行後設置sleep(1)並分派事件)。也許我錯過了一些東西,如果沒有更合理的解釋存在,我可以發佈代碼。

EDIT2: 這是一個可運行的示例。 的.kv文件:

<DrillScreen>: 
    FloatLayout: 
     FloatLayout: 
      id: wheelbox 
      size_hint: 1.0, None 
      height: self.width 
      pos_hint: {'center_x':0.5,'center_y':0.5} 
      background_color: 1,1,1,1 
      pos: 0, 200 
      Label: 
       id: answerlabel 
       pos_hint: {'center_x':0.5, 'center_y':0.5} 
       text: root.answer 
     Button: 
      text: 'Start' 
      size_hint: 0.5, 0.1 
      on_release: root.startdrill() 

和的.py:

from kivy.app import App 
from random import choice 
from time import sleep 
from kivy.event import EventDispatcher 
from kivy.uix.screenmanager import ScreenManager, Screen 
from kivy.uix.button import Button 
from kivy.properties import StringProperty 
from multiprocessing import Process 

class DrillScreen(Screen): 
    answer = StringProperty('Initialized.') 
    def __init__(self, **kwargs): 
     self.thedrill = drill() 
     self.thedrill.bind(on_answer = self.printtest) 
     super(DrillScreen, self).__init__(**kwargs) 
     self.answer = self.thedrill.answer 

     b = Button(
       text = 'printtest()', 
       size_hint = [ 0.1, 0.1 ], 
       pos_hint = {'center_x':0.75,'center_y':0.5}, 
       ) 
     b.bind(on_release = self.printtest) 
     print(self.ids) 
     self.ids.wheelbox.add_widget(b) 

    def printtest(self,*args): 
     self.answer = self.thedrill.answer 
     print('This is printtest(): ', self.ids.answerlabel.text) 

    def startdrill(self): 
     Process(target=self.thedrill.run).start() 

class drill(EventDispatcher): 
    def __init__(self): 
     self.register_event_type('on_answer') 
     self.answer = 'Default' 

    def on_answer(self,*args): 
     pass 

    def run(self): 

     while True: 

      self.answer = str(choice(range(100))) 
      self.dispatch('on_answer', self.answer) 
      sleep(1) 

class Manager(ScreenManager): 
    pass 

class TestingApp(App): 
    def build(self): 
     sm = Manager() 
     s = DrillScreen(name='ds') 
     sm.add_widget(s) 
     sm.current = 'ds' 
     return sm 

TestingApp().run() 

點擊開始按鈕開始thedrill.run在自己的進程,隨地吐痰的隨機數到終端每一秒,而它正在運行,單擊printtest()按鈕輸出「Default」作爲標籤文本值。輸出示例:

('This is printtest(): ', '8') 
('This is printtest(): ', '60') 
('This is printtest(): ', '6') 
('This is printtest(): ', 'Default') 
('This is printtest(): ', '66') 
('This is printtest(): ', '68') 
('This is printtest(): ', 'Default') 
('This is printtest(): ', '89') 
('This is printtest(): ', '69') 

回答

0

您需要更改順序的__init__功能:

thedrill = ObjectProperty(None) # not really needed ... 

def __init__(self, **kwargs): 
    self.thedrill = drill(kwargs['options']) 
    self.thedrill.bind(on_answer = self.printtest) 
    super(DrillScreen, self).__init__(**kwargs) # this will trigger the kv file section that exploded before ... 

也就是說,使用過程因爲每個進程都有它的內存不會與你的榜樣工作,直接處理UI。您應該使用流程隊列或移至線程。只記得從主線程更新UI。(使用時鐘@mainthread

玩得開心......

+0

的'沒有attribute'抱怨走了,但在外觀上依然標籤甚至不更新時'printtest() '語句向終端輸出正確的值。我也嘗試使用'answer = StringProperty('')',直接爲'root.answer'標籤和'printtest'定義設置'self.answer'。它只是開始與我初始化「答案」,並永遠不會改變。另外,如果我將它初始化爲'def __init__'前面的'test',但在'super'之前設置'self.answer = self.thedrill.answer',它會被正確設置。 'printtest'內的相同語句失敗。 – kuoytfouy

+0

可能需要一個小的運行示例來查看這個... –

+0

Galazner我包括一個。我懷疑這與'drrill.run'運行在一個單獨的過程中有關,但我不能勝任,以弄清楚如何。 – kuoytfouy