1

我已经编写了一个 wxPython 应用程序(遵循文档),它几乎可以完成我想要的一切。它有我想要的所有方式的复选框和文本行等。唯一的问题是我把它作为我的应用程序的主要框架。

我真正想要的是把它变成一个小部件,这样我就可以在我的最终应用程序框架中实例化其中的一些。然而,当我试图让我的小部件从 wx.Panel 而不是 wx.Frame 继承,然后将一个小部件实例化到我的 Frame 类中时,它像中子星一样自行塌陷。

请看一下我的两个代码示例,看看你是否知道出了什么问题。

这是我的小部件直接在从 wx.Frame 继承的类中构建的版本:

#!/usr/bin/env python

"""
This demo attempts to override the C++ MainLoop and implement it
in Python.
"""

import time
import wx
import serial                
from serial.tools.list_ports import comports

#str1 = '[12:28:14]fxn_name() ***ISCFLAGS***1***0***0***0***3.19***00-1C-FA-F1-00-09-F1-EE***\r\n'
logAll = 1

"""lowBat1 = 0
pir1 = 0
batVolt1 = 0
tamp1 = 0
supervise1 = 0
mac1 = 0"""
######################################################################################
class ETL_test(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(275, 200))
        self.initGUI()
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
        self.Show()

    def initGUI(self):
        #main container panel for all of the ISC status information
        self.checkBoxPanel = wx.Panel(self,-1,size=(100,200),style= wx.SUNKEN_BORDER)

        self.checkBoxVbox = wx.BoxSizer(wx.VERTICAL)

        #make the three individual checkboxes
        self.superviseCheck = wx.CheckBox(self.checkBoxPanel,-1,'Supervisory Trouble')
        self.pirCheck = wx.CheckBox(self.checkBoxPanel,-1,'PIR Activity')
        self.tamperCheck = wx.CheckBox(self.checkBoxPanel,-1,'Tamper Tripped')

        #make the MAC hbox section
        self.macHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.macLabel = wx.StaticText(self.checkBoxPanel,-1,'MAC ADDR: ')
        macFont1 = wx.Font(10, wx.FONTFAMILY_DEFAULT,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_BOLD)
        self.macLabel.SetFont(macFont1)
        macFont2 = wx.Font(10, wx.FONTFAMILY_DEFAULT,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_NORMAL)
        self.macAddr = wx.StaticText(self.checkBoxPanel,-1,'001CFAF10009F1EE')
        self.macAddr.SetFont(macFont2)
        self.macHbox.Add(self.macLabel,0,wx.RIGHT,5)
        self.macHbox.Add(self.macAddr,0,0,0)

        #make the low battery hbox section
        self.lowBatCheck = wx.CheckBox(self.checkBoxPanel,-1,'Low Battery Voltage')
        self.batVoltText = wx.StaticText(self.checkBoxPanel,-1, '9.9V')
        self.lowBatHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.lowBatHbox.Add(self.lowBatCheck, 0,wx.RIGHT,20)
        self.lowBatHbox.Add(self.batVoltText, 0,wx.ALL,0)

        #make the pirCount hbox section
        self.pirCountHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.pirCountNumber = 3
        self.pirLabel = wx.StaticText(self.checkBoxPanel,-1,'PIR Count: ')
        self.pirCount = wx.StaticText(self.checkBoxPanel,-1,str(self.pirCountNumber))
        self.pirReset = wx.Button(self.checkBoxPanel,-1,label='Reset PIR Count')
        self.pirCountHbox.Add(self.pirLabel,0,wx.RIGHT,3)
        self.pirCountHbox.Add(self.pirCount,0,wx.RIGHT, 40)
        self.pirCountHbox.Add(self.pirReset,0,wx.ALIGN_RIGHT,0)
        self.pirReset.Bind(wx.EVT_BUTTON,self.resetPIR)

        #add all the parts to the main vbox
        self.checkBoxVbox.Add(self.macHbox,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.superviseCheck,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.lowBatHbox,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.tamperCheck,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.pirCheck,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.pirCountHbox,0,wx.ALL,5)
        self.checkBoxPanel.SetSizer(self.checkBoxVbox)

        #setup the 1 sec timer to update all the data based on the global data
        #self.updateTimer = wx.Timer(self)
        #self.Bind(wx.EVT_TIMER,self.updateData,self.updateTimer)
        #self.updateTimer.Start(500)

    #The event handler for pushing the PIR reset button
    def resetPIR(self,event):
        self.pirCountNumber = 0
        self.pirCount.SetLabel(str(self.pirCountNumber))
        self.Show()

    #The event handler for the 1 sec timer to update the data fields based on last flags msg
##    def updateData(self,event):
##        global batVolt1
##        self.pirCountNumber += 1;
##        self.pirCount.SetLabel(str(self.pirCountNumber))
##        self.batVoltText.SetLabel(str(batVolt1)+'V')

    #The event handler for closing the window
    def OnCloseWindow(self, event):
        app.keepGoing = False
        self.Destroy()
        logFile.close()

    def updateOnSerial(self,flags):
        self.superviseCheck.SetValue(flags[0] == 1)
        self.pirCheck.SetValue(flags[1] == 1)
        if flags[1] == 1:
            self.pirCountNumber += 1
        self.pirCount.SetLabel(str(self.pirCountNumber))
        self.tamperCheck.SetValue(flags[2] == 1)
        self.lowBatCheck.SetValue(flags[3] == 1)
        self.batVoltText.SetLabel(str(flags[4])+'V')
        self.macAddr.SetLabel(str(flags[5]))

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

class MyApp(wx.App):
    def MainLoop(self):
        # Create an event loop and make it active
        evtloop = wx.EventLoop()
        old = wx.EventLoop.GetActive()
        wx.EventLoop.SetActive(evtloop)

        # This outer loop determines when to exit the application
        while self.keepGoing:
            # call_my_code_here()
            line = ser.readline()
            parsedLines = line.split('***')
            global logAll
            if len(parsedLines) > 4 and parsedLines[1] == 'ISCFLAGS': #got a flags msg
                print('Now parsing a ISCFLAGS msg!')
                self.parseFlagsMsg(parsedLines)
                logFile.write(str(line))
            elif logAll > 0 and len(parsedLines) < 2: #logAll is on and it's not a flags msg
                logFile.write(str(line))
            # This inner loop will process any GUI events
            # until there are no more waiting.
            while evtloop.Pending():
                evtloop.Dispatch()

            # Send idle events to idle handlers. 
            # I'll just snooze a little...
            time.sleep(0.10)
            self.ProcessIdle()

        wx.EventLoop.SetActive(old)

    def parseFlagsMsg(self):
        global lowBat1
        global pir1
        global batVolt1
        global tamp1
        global supervise1
        global mac1
        if len(parsedLines) != 10:
            print('ERROR: not enough flag tokens!!')
            return False
        else:
            camID = parsedLines[2];#1,2, or 3
        # TODO: array of testApps... testApp[camID].updateOnSerial()
        # This passes the 4th element through the 8th element
        testApp.updateOnSerial(parsedLines[3:8]) 

    def OnInit(self):
        testApp = ETL_test(None, -1, "Alarm.com 2GIG Image Sensor ETL Test Application")
        testApp.Show(True)
        self.SetTopWindow(testApp)

        self.keepGoing = True
        return True

app = MyApp(False)
logFile = open('C:/Python26/temp/test.txt', 'w')
ser = serial.Serial('com5',115200,timeout=0.01)
app.MainLoop()

然后这是我尝试将其设为自定义小部件的版本,然后在我的 wx.Frame 类中实例化其中一个:

#!/usr/bin/env python

"""
This demo attempts to override the C++ MainLoop and implement it
in Python.
"""

import time
import wx
import serial                
from serial.tools.list_ports import comports

str1 = '[12:28:14]fxn_name() ***ISCFLAGS***1***0***0***0***3.19***00-1C-FA-F1-00-09-F1-EE***\r\n'
logAll = 1

"""lowBat1 = 0
pir1 = 0
batVolt1 = 0
tamp1 = 0
supervise1 = 0
mac1 = 0"""
#---------------------------------------------------------------------------       
class ISC_status(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id, size=(275, 200))
        self.initGUI()
        #self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
        self.Show()

    def initGUI(self):
        #main container panel for all of the ISC status information
        self.checkBoxPanel = wx.Panel(self,-1,size=(100,200),style= wx.SUNKEN_BORDER)

        self.checkBoxVbox = wx.BoxSizer(wx.VERTICAL)

        #make the three individual checkboxes
        self.superviseCheck = wx.CheckBox(self.checkBoxPanel,-1,'Supervisory Trouble')
        self.pirCheck = wx.CheckBox(self.checkBoxPanel,-1,'PIR Activity')
        self.tamperCheck = wx.CheckBox(self.checkBoxPanel,-1,'Tamper Tripped')

        #make the MAC hbox section
        self.macHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.macLabel = wx.StaticText(self.checkBoxPanel,-1,'MAC ADDR: ')
        macFont1 = wx.Font(10, wx.FONTFAMILY_DEFAULT,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_BOLD)
        self.macLabel.SetFont(macFont1)
        macFont2 = wx.Font(10, wx.FONTFAMILY_DEFAULT,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_NORMAL)
        self.macAddr = wx.StaticText(self.checkBoxPanel,-1,'001CFAF10009F1EE')
        self.macAddr.SetFont(macFont2)
        self.macHbox.Add(self.macLabel,0,wx.RIGHT,5)
        self.macHbox.Add(self.macAddr,0,0,0)

        #make the low battery hbox section
        self.lowBatCheck = wx.CheckBox(self.checkBoxPanel,-1,'Low Battery Voltage')
        self.batVoltText = wx.StaticText(self.checkBoxPanel,-1, '9.9V')
        self.lowBatHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.lowBatHbox.Add(self.lowBatCheck, 0,wx.RIGHT,20)
        self.lowBatHbox.Add(self.batVoltText, 0,wx.ALL,0)

        #make the pirCount hbox section
        self.pirCountHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.pirCountNumber = 3
        self.pirLabel = wx.StaticText(self.checkBoxPanel,-1,'PIR Count: ')
        self.pirCount = wx.StaticText(self.checkBoxPanel,-1,str(self.pirCountNumber))
        self.pirReset = wx.Button(self.checkBoxPanel,-1,label='Reset PIR Count')
        self.pirCountHbox.Add(self.pirLabel,0,wx.RIGHT,3)
        self.pirCountHbox.Add(self.pirCount,0,wx.RIGHT, 40)
        self.pirCountHbox.Add(self.pirReset,0,wx.ALIGN_RIGHT,0)
        self.pirReset.Bind(wx.EVT_BUTTON,self.resetPIR)

        #add all the parts to the main vbox
        self.checkBoxVbox.Add(self.macHbox,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.superviseCheck,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.lowBatHbox,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.tamperCheck,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.pirCheck,0,wx.ALL,5)
        self.checkBoxVbox.Add(self.pirCountHbox,0,wx.ALL,5)
        self.checkBoxPanel.SetSizer(self.checkBoxVbox)

        #setup the 1 sec timer to update all the data based on the global data
        #self.updateTimer = wx.Timer(self)
        #self.Bind(wx.EVT_TIMER,self.updateData,self.updateTimer)
        #self.updateTimer.Start(500)

    #The event handler for pushing the PIR reset button
    def resetPIR(self,event):
        self.pirCountNumber = 0
        self.pirCount.SetLabel(str(self.pirCountNumber))
        self.Show()

    #The event handler for the 1 sec timer to update the data fields based on last flags msg
##    def updateData(self,event):
##        global batVolt1
##        self.pirCountNumber += 1;
##        self.pirCount.SetLabel(str(self.pirCountNumber))
##        self.batVoltText.SetLabel(str(batVolt1)+'V')



    def updateOnSerial(self,flags):
        self.superviseCheck.SetValue(flags[0] == 1)
        self.pirCheck.SetValue(flags[1] == 1)
        if flags[1] == 1:
            self.pirCountNumber += 1
        self.pirCount.SetLabel(str(self.pirCountNumber))
        self.tamperCheck.SetValue(flags[2] == 1)
        self.lowBatCheck.SetValue(flags[3] == 1)
        self.batVoltText.SetLabel(str(flags[4])+'V')
        self.macAddr.SetLabel(str(flags[5]))
#---------------------------------------------------------------------------
class ETL_test(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(275, 200))
        self.initGUI()
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
        self.Show()

    def initGUI(self):
        panel = wx.Panel(self)
        ISC1 = ISC_status(self,-1)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(ISC1,1,wx.ALL|wx.EXPAND,5)
        panel.SetSizer(sizer)
        self.Layout()
        self.Show()

    #The event handler for closing the window
    def OnCloseWindow(self, event):
        app.keepGoing = False
        self.Destroy()
        logFile.close()
#---------------------------------------------------------------------------

class MyApp(wx.App):
    def MainLoop(self):
        # Create an event loop and make it active
        evtloop = wx.EventLoop()
        old = wx.EventLoop.GetActive()
        wx.EventLoop.SetActive(evtloop)

        # This outer loop determines when to exit the application
        while self.keepGoing:
            # call_my_code_here()
            line = ser.readline()
            parsedLines = line.split('***')
            global logAll
            if len(parsedLines) > 4 and parsedLines[1] == 'ISCFLAGS': #got a flags msg
                print('Now parsing a ISCFLAGS msg!')
                self.parseFlagsMsg(parsedLines)
                logFile.write(str(line))
            elif logAll > 0 and len(parsedLines) < 2: #logAll is on and it's not a flags msg
                logFile.write(str(line))
            # This inner loop will process any GUI events
            # until there are no more waiting.
            while evtloop.Pending():
                evtloop.Dispatch()

            # Send idle events to idle handlers. 
            # I'll just snooze a little...
            time.sleep(0.10)
            self.ProcessIdle()

        wx.EventLoop.SetActive(old)

    def parseFlagsMsg(self):
        global lowBat1
        global pir1
        global batVolt1
        global tamp1
        global supervise1
        global mac1
        if len(parsedLines) != 10:
            print('ERROR: not enough flag tokens!!')
            return False
        else:
            camID = parsedLines[2];#1,2, or 3
        # TODO: array of testApps... testApp[camID].updateOnSerial()
        # This passes the 4th element through the 8th element
        testApp.updateOnSerial(parsedLines[3:8]) 

    def OnInit(self):
        testApp = ETL_test(None, -1, "Alarm.com 2GIG Image Sensor ETL Test Application")
        testApp.Show(True)
        self.SetTopWindow(testApp)

        self.keepGoing = True
        return True

app = MyApp(False)
logFile = open('C:/Python26/temp/test.txt', 'w')
ser = serial.Serial('com5',115200,timeout=0.01)
app.MainLoop()

重申一下:第一个代码示例基本上可以按我的意愿工作,但这需要是我最终程序中的一个小部件。为什么当我尝试在从 wx.Frame 继承的类中实例化它时,格式会消失并且所有内容都位于彼此之上?

在此先感谢您的帮助。如果我需要提供任何其他信息,请告诉我。

4

1 回答 1

3

当您将代码从框架转换为自定义面板时,您忘记删除额外的面板;ISC_status(a wx.Panel)在内部创建了另一个面板,由于缺少额外的尺寸器,布局被忽略(当主框架重新计算布局时,它无法到达内部面板)。

我已经移除了那个内部面板(以及一些使它保持小的功能,抱歉),现在它应该可以按照你想要的方式工作:

import wx

class ISC_status(wx.Panel):
    def __init__(self, parent, id=wx.ID_ANY):
        wx.Panel.__init__(self, parent, id, style=wx.SUNKEN_BORDER)
        self.initGUI()
# NOTE: remove next line for 'best fit' instead of 275x200
        self.SetMinSize((275, 200))
        self.Layout()
        self.Show()

    def initGUI(self):
# NOTE: here you created an additional (inner) panel
        #main container panel for all of the ISC status information
        sizer = wx.BoxSizer(wx.VERTICAL)
        #make the three individual checkboxes
        self.superviseCheck = wx.CheckBox(self,-1,'Supervisory Trouble')
        self.pirCheck = wx.CheckBox(self,-1,'PIR Activity')
        self.tamperCheck = wx.CheckBox(self,-1,'Tamper Tripped')
        #make the MAC hbox section
        self.macHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.macLabel = wx.StaticText(self,-1,'MAC ADDR: ')
        macFont1 = wx.Font(10, wx.FONTFAMILY_DEFAULT,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_BOLD)
        self.macLabel.SetFont(macFont1)
        macFont2 = wx.Font(10, wx.FONTFAMILY_DEFAULT,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_NORMAL)
        self.macAddr = wx.StaticText(self,-1,'001CFAF10009F1EE')
        self.macAddr.SetFont(macFont2)
        self.macHbox.Add(self.macLabel,0,wx.RIGHT,5)
        self.macHbox.Add(self.macAddr,0,0,0)
        #make the low battery hbox section
        self.lowBatCheck = wx.CheckBox(self,-1,'Low Battery Voltage')
        self.batVoltText = wx.StaticText(self,-1, '9.9V')
        self.lowBatHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.lowBatHbox.Add(self.lowBatCheck, 0,wx.RIGHT,20)
        self.lowBatHbox.Add(self.batVoltText, 0,wx.ALL,0)
        #make the pirCount hbox section
        self.pirCountHbox = wx.BoxSizer(wx.HORIZONTAL)
        self.pirCountNumber = 3
        self.pirLabel = wx.StaticText(self,-1,'PIR Count: ')
        self.pirCount = wx.StaticText(self,-1,str(self.pirCountNumber))
        self.pirReset = wx.Button(self,-1,label='Reset PIR Count')
        self.pirCountHbox.Add(self.pirLabel,0,wx.RIGHT,3)
        self.pirCountHbox.Add(self.pirCount,0,wx.RIGHT, 40)
        self.pirCountHbox.Add(self.pirReset,0,wx.ALIGN_RIGHT,0)
        self.pirReset.Bind(wx.EVT_BUTTON,self.resetPIR)
        #add all the parts to the main vbox
        sizer.Add(self.macHbox,0,wx.ALL,5)
        sizer.Add(self.superviseCheck,0,wx.ALL,5)
        sizer.Add(self.lowBatHbox,0,wx.ALL,5)
        sizer.Add(self.tamperCheck,0,wx.ALL,5)
        sizer.Add(self.pirCheck,0,wx.ALL,5)
        sizer.Add(self.pirCountHbox,0,wx.ALL,5)
# NOTE: here you set the sizer to the inner panel but there was
#       no sizer to connect it to ISC_status itself so it was
#       unreachable for the main frame and the layout was ignored
        self.SetSizer(sizer)

    def resetPIR(self,event):
        pass

    def updateOnSerial(self,flags):
        pass

class TestFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None)
        sizer = wx.BoxSizer(wx.VERTICAL)
        row = wx.BoxSizer(wx.HORIZONTAL)
# NOTE: set proportion to 0 if you want them 'fixed size'
        row.Add(ISC_status(self),1,wx.ALL,5)
        row.Add(ISC_status(self),1,wx.ALL,5)
        sizer.Add(row,0,wx.EXPAND)
        self.SetSizerAndFit(sizer)

app = wx.PySimpleApp()
frame = TestFrame().Show()
app.MainLoop()
于 2012-11-15T06:43:02.463 回答