初始化與參數調節面板
這一節將繪製出如下圖所示的參數調節面板
對於上圖來說,BoxSizer佈局十分傻瓜,所以這裏主要有兩個方面需要注意,其一是opti
和source
這兩個選項卡的實現,其二則是如何同時創建多個滾動條。
對於前者比較容易,無非是多用一個控件而已,即wx.NoteBook
,使用方法乏善可陳,看代碼即可學會。
對於後者當然也可以很容易,只要無腦羅列即可,只不過對於五個不同的參數就意味着要新建五組滾動條,要就要新建五個控制函數,而這五個控制函數的功能幾乎是完全一樣的。顯然,這很愚蠢,所以我們採用瞭如下的辦法對代碼進行精簡。
def InitPanel(self):
self.drawPanel = wx.Panel(self) #繪圖面板
#########初始化paraBook
paraBook = wx.Notebook(self,size=(300,-1))
optiPanel = wx.Panel(paraBook)
sourcePanel = wx.Panel(paraBook)
paraBook.AddPage(optiPanel,'opti')
paraBook.AddPage(sourcePanel,'source')
###需要初始化edge
self.setEdge()
####################optiBox###################
self.paraSliders = {}
optiBox = wx.BoxSizer(wx.VERTICAL)
for key in self.optiDict:
self.paraSliders[key]=wx.Slider(
optiPanel,minValue=1,maxValue=1000,size=(200,-1))
self.paraSliders[key].Bind(wx.EVT_SCROLL,
lambda evt,mark=key: self.OnSliderScroll(evt,mark))
optiBox.Add(self.paraSliders[key],proportion=1,
flag=wx.LEFT|wx.CENTER)
optiBox.Add(wx.StaticText(optiPanel,size=(120,30),label=key,
style=wx.ALIGN_RIGHT),proportion=1,
flag=wx.ALIGN_CENTER, border=10)
self.testFlag = wx.TextCtrl(
optiPanel,size=(250,400),value='hellos',style=wx.TE_MULTILINE)
optiBox.Add(self.testFlag,proportion=1,
flag=wx.ALIGN_CENTER|wx.ALL|wx.ALIGN_RIGHT,border=0)
optiPanel.SetSizer(optiBox)
####################sourceBox###################
sourceBox = wx.BoxSizer(wx.VERTICAL)
for key in self.sourceDict:
self.paraSliders[key]=wx.Slider(
sourcePanel,minValue=1,maxValue=1000,size=(200,-1))
self.paraSliders[key].Bind(wx.EVT_SCROLL,
lambda evt,mark=key: self.OnSliderScroll(evt,mark))
sourceBox.Add(self.paraSliders[key],proportion=1,
flag=wx.LEFT|wx.CENTER)
sourceBox.Add(wx.StaticText(sourcePanel,size=(120,30),label=key,
style=wx.ALIGN_RIGHT),proportion=1,
flag=wx.ALIGN_CENTER, border=10)
sourcePanel.SetSizer(sourceBox)
mainBox = wx.BoxSizer()
mainBox.Add(self.drawPanel,proportion=1,flag=wx.ALL|wx.EXPAND,border=10)
mainBox.Add(paraBook,proportion=0,flag=wx.ALL|wx.EXPAND,border=10)
self.SetSizer(mainBox)
def OnSliderScroll(self,evt,mark):
paraArea = {'ySource':[-300,300],'xSource':[0,1000],
'xPos':[0,1200],'Diameter':[0,500],
'lFocal':[-1000,1000],'rFocal':[-1000,1000],
'theta':[0,np.pi*2],'nOpti':[0.1,10]}
pValue = self.paraSliders[mark].GetValue()
pMin,pMax=paraArea[mark]
if mark in self.optiDict:
self.optiDict[mark] = pMin+(pMax-pMin)/1000*pValue
elif mark in self.sourceDict:
self.sourceDict[mark]=pMin+(pMax-pMin)/1000*pValue
pStr = ''
for key in self.optiDict:
pStr += key+':'+str(self.optiDict[key])+'\n'
self.setEdge() #設置光學元件
self.getRay() #計算
self.DrawPath() #繪圖
在上面的代碼中,關鍵之處在於使用了一個lambda
表達式,使得事件函數可以傳入兩個參數,也就完成了一次性創建多個控件的目的。
分解來看,首先創建一個滾動條字典self.paraSliders = {}
,其鍵爲變量名稱,值則對應一個滾動條控件。實現方式爲
self.paraSliders[key]=wx.Slider(optiPanel,minValue=1,maxValue=1000,size=(200,-1))
然後對於每個滾動條,通過lambda
綁定事件函數:
self.paraSliders[key].Bind(wx.EVT_SCROLL,lambda evt,mark=key: self.OnSliderScroll(evt,mark))
其中,wx.EVT_SCROLL
爲滾動事件,lambda方法將evt和mark分別傳入到事件函數self.OnSliderScroll(evt,mark)
中,其中mark的值即爲當前的鍵值。
最後,將滾動條壓入到Boxsizer中。
在其調用的OnSliderScroll中,首先定義參數字典,從而確定了不同滾動條的滾動範圍,通過mark值,使得參數和滾動條能夠一一對應。然後然後設置成員變量self.optiDict
以及self.sourceDict
。