2014-03-03 15 views
2

級別:初級添加面板使用線程GUI來在wxPython中

我一直在努力與wxPython的一個月。我幾乎完全是我的GUI應用程序,但是當它涉及到線程時,我卡住了。我使用python V2.7和V3.0的wxPython和操作系統是Windows 7

我的GUI應用程序:那麼在我的GUI應用程序,我從服務器讀取一些值,然後基於這些值的數量我在我的GUI中創建面板。然後每個面板將以staticText的形式表示值。爲例如:如果我從服務器接收1,2,3值,則我創建的每個顯示分別,和 面板。直到這裏一切工作正常。

問題:我想每5秒鐘檢查一次服務器來獲取值並相應地更新我的GUI,即。我必須添加新面板才能顯示新值。我在SC上閱讀了關於使用線程的一些教程&,我也瞭解了一些基本事實。不幸的是,我不明白如何將這個概念應用於我的問題。我想我必須把檢查服務器的值的代碼放在線程循環中。但我不明白還有什麼要做。我想我可能不得不改變我的代碼的邏輯(創建面板部分)以使用線程。 如果我可以爲我的這個特殊問題得到一個可行的例子,那我就可以將它應用到我的應用程序的其餘部分了。

代碼:我爲這個特殊問題創建了一個簡短的示例代碼。 class labels中的getLabels()僅通過生成一些隨機值並將它們返回到列表中來模擬服務器。然後這些值由createPanels()用於創建面板並顯示這些值。如果有人能教我如何使用線程向我的GUI添加新面板而不凍結/阻止我的GUI,那將是非常好的。

下載:整個代碼可以在下面找到,也可以是downloaded from here,以避免任何識別問題。

#!/usr/bin/env python 

from random import randrange 
import wx 
import wx.lib.scrolledpanel 

class GUI(wx.Frame): 

    def __init__(self, parent, id, title): 
     screenWidth = 800 
     screenHeight = 450 
     screenSize = (screenWidth, screenHeight) 
     wx.Frame.__init__(self, None, id, title, size=screenSize) 
     self.locationFont = locationFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD) 
     mainSizer = wx.BoxSizer(wx.VERTICAL) 
     self.sizer = sizer = wx.BoxSizer(wx.VERTICAL) 
     self.panel = panel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER) 
     panel.SetupScrolling() 
     panel.SetBackgroundColour('#FFFFFF') 
     self.createPanels() 
     panel.SetSizer(sizer) 
     mainSizer.Add(panel, 15, wx.EXPAND|wx.ALL) 
     self.SetSizer(mainSizer) 

    def createPanels(self): 
     k = 0 
     labelObj = labels() 
     locations = labelObj.getLabel() 
     print locations 
     for i in locations: 
      sPanels = 'sPanel'+str(k) 
      sPanels = wx.Panel(self.panel) 
      label = str(k+1) 
      text = wx.StaticText(sPanels, -1, label) 
      text.SetFont(self.locationFont) 
      text.SetForegroundColour('#0101DF') 
      self.sizer.Add(sPanels, 0, wx.ALL, 5) 
      self.sizer.Add(wx.StaticLine(self.panel), 0, wx.ALL|wx.EXPAND, 0) 
      k += 1 

################################################ 
class labels(): 
    def getLabel(self): 
    mylist =[] 
    i = randrange(10) 
    for k in range(1,i+1): 
     list.append(k) 
    return mylist 
############################################### 

if __name__=='__main__': 
app = wx.App() 
frame = GUI(parent=None, id=-1, title="Test") 
frame.Show() 
app.MainLoop() 

如果您沒有看到執行的代碼後,任何面板然後請重新執行代碼。

謝謝你的時間。

回答

1

希望這段代碼將包含一些答案。基本上:將接口放到服務器的一個線程中,並使用wx.CallAfter與wx中的組件交談。使用pubsub在GUI中的元素之間進行對話。該代碼創建了一個線程,每5秒執行一次,並且它通過直接方法調用來進行通信,以獲得一個您有句柄的wx元素,並通過pubsub與一個您不需要的元素進行通信。

#!/usr/bin/env python 

from random import randrange 
import wx 
import wx.lib.scrolledpanel 

# imports added by GreenAsJade 
import time 
import threading 
from wx.lib.pubsub import setupkwargs 
from wx.lib.pubsub import pub 

class GUI(wx.Frame): 

    def __init__(self, parent, id, title): 
     screenWidth = 800 
     screenHeight = 450 
     screenSize = (screenWidth, screenHeight) 
     wx.Frame.__init__(self, None, id, title, size=screenSize) 
     self.locationFont = locationFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD) 
     mainSizer = wx.BoxSizer(wx.VERTICAL) 
     self.sizer = sizer = wx.BoxSizer(wx.VERTICAL) 
     self.panel = panel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER) 
     panel.SetupScrolling() 
     panel.SetBackgroundColour('#FFFFFF') 
     panel.SetSizer(sizer) 
     mainSizer.Add(panel, 15, wx.EXPAND|wx.ALL) 
     self.SetSizer(mainSizer) 

     pub.subscribe(self.OnNewLabels, "NEW_LABELS") 


    def OnNewLabels(self, labels): 
     k = 0 
     locations = labels 
     print locations 
     for i in locations: 
      sPanels = 'sPanel'+str(k) 
      sPanels = wx.Panel(self.panel) 
      label = str(k+1) 
      print "doing", label 
      text = wx.StaticText(sPanels, -1, label) 
      text.SetFont(self.locationFont) 
      text.SetForegroundColour('#0101DF') 
      self.sizer.Add(sPanels, 0, wx.ALL, 5) 
      self.sizer.Add(wx.StaticLine(self.panel), 0, wx.ALL|wx.EXPAND, 0) 
      k += 1 
     self.sizer.Layout() 


############################### 
# 
# 

def InterfaceThread(id, log): 
    label_generator = Labels() 
    while True: 
     labels = label_generator.getLabel() # get the info from the server 
     # Tell the GUI about them 
     wx.CallAfter(pub.sendMessage, "NEW_LABELS", labels = labels) 
     # Tell the logger about them 
     wx.CallAfter(log.AppendText, "Sent %s \n" % str(labels)) 
     time.sleep(5) 


class ServerInterface(wx.Frame): 

    def __init__(self, parent, id, title): 
     wx.Frame.__init__(self, None, id, title) 
     self.log = wx.TextCtrl(self, style = wx.TE_MULTILINE) 
     interface_thread = threading.Thread(target = InterfaceThread, args = (1, self.log)) 
     interface_thread.start() 



################################################ 
class Labels(): 
    def getLabel(self): 
     mylist =[] 
     i = 4 #randrange(10) 
     for k in range(1,i+1): 
      mylist.append(k) 
     return mylist 
############################################### 

if __name__=='__main__': 
    app = wx.App() 
    frame = GUI(parent=None, id=-1, title="Test") 
    frame.Show() 
    server_interface = ServerInterface(parent = None, id=-1, title="Server Log") 
    server_interface.Show() 
    app.MainLoop() 
+0

注意:ServerInterface不一定是圖形元素。它可能只是一個普通的類 - 我將它作爲一個圖形對象,僅用於展示如何實現圖形界面以及從線程(在哪裏有句柄)與其進行通信。 – GreenAsJade

+0

我首先感謝您考慮我的問題。我執行了你的代碼。大多數部分按我的意願工作。現在的問題是,當服務器發送它正在主面板上創建新面板的值時。我的問題是,當服務器發送值時,這些值應該被替換/更新舊值。它不應該添加具有新值的新面板。如果您只是使用我的代碼並儘可能簡化答案,那將非常棒。您也可以刪除服務器GUI。 –

+0

我認爲我已經回答了您的問題,即「如何設置線程服務器接口」。如果你還有其他問題,你應該接受我的答案,並提出一個單獨的問題。這聽起來像你想問:「我如何更換面板與新的?」。或者,您可能希望代碼更新現有面板中的值?無論你想要什麼,確定問題,然後問問:) – GreenAsJade

0

followup:這裏是一個版本,其中SeverInterface不是一個圖形元素,爲清晰起見。

#!/usr/bin/env python 

from random import randrange 
import wx 
import wx.lib.scrolledpanel 

# imports added by GreenAsJade 
import time 
import threading 
from wx.lib.pubsub import setupkwargs 
from wx.lib.pubsub import pub 

class GUI(wx.Frame): 

    def __init__(self, parent, id, title): 
     screenWidth = 800 
     screenHeight = 450 
     screenSize = (screenWidth, screenHeight) 
     wx.Frame.__init__(self, None, id, title, size=screenSize) 
     self.locationFont = locationFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD) 
     mainSizer = wx.BoxSizer(wx.VERTICAL) 
     self.sizer = sizer = wx.BoxSizer(wx.VERTICAL) 
     self.panel = panel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER) 
     panel.SetupScrolling() 
     panel.SetBackgroundColour('#FFFFFF') 
     panel.SetSizer(sizer) 
     mainSizer.Add(panel, 15, wx.EXPAND|wx.ALL) 
     self.SetSizer(mainSizer) 

     pub.subscribe(self.OnNewLabels, "NEW_LABELS") 


    def OnNewLabels(self, labels): 
     k = 0 
     locations = labels 
     print locations 
     for i in locations: 
      sPanels = 'sPanel'+str(k) 
      sPanels = wx.Panel(self.panel) 
      label = str(k+1) 
      print "doing", label 
      text = wx.StaticText(sPanels, -1, label) 
      text.SetFont(self.locationFont) 
      text.SetForegroundColour('#0101DF') 
      self.sizer.Add(sPanels, 0, wx.ALL, 5) 
      self.sizer.Add(wx.StaticLine(self.panel), 0, wx.ALL|wx.EXPAND, 0) 
      k += 1 
     self.sizer.Layout() 


############################### 
# 
# 

def InterfaceThread(): 
    label_generator = Labels() 
    while True: 
     labels = label_generator.getLabel() # get the info from the server 
     # Tell the GUI about them 
     wx.CallAfter(pub.sendMessage, "NEW_LABELS", labels = labels) 
     time.sleep(5) 


class ServerInterface(): 

    def __init__(self): 
     interface_thread = threading.Thread(target = InterfaceThread, args =()) 
     interface_thread.start() 



################################################ 
class Labels(): 
    def getLabel(self): 
     mylist =[] 
     i = 4 #randrange(10) 
     for k in range(1,i+1): 
      mylist.append(k) 
     return mylist 
############################################### 

if __name__=='__main__': 
    app = wx.App() 
    frame = GUI(parent=None, id=-1, title="Test") 
    frame.Show() 
    server_interface = ServerInterface() 
    app.MainLoop() 

正如我在其他的答案中提到 - 如果你想更新StaticTexts,然後把它們放入數組當您創建它們,並通過OnNewLabels陣列與迭代更新SetLabel他們()。

+1

感謝您的努力,我會在接受您的解決方案之前編輯我的問題,因爲它不是我尋找的實際解決方案。我會很快發佈我的新問題,如果你能幫助我,我也會很感激。 :) –