1

私は wxPython アプリケーション (以下のドキュメント) を作成しました。チェックボックスやテキストラインなど、私が望むすべての方法があります。唯一の問題は、これをアプリケーションのメイン フレームとして作成したことです。

私が本当に望んでいるのは、これをウィジェットに変換して、最終的なアプリケーション フレームでそれらのいくつかをインスタンス化できるようにすることです。しかし、wx.Frame ではなく wx.Panel からウィジェットを継承させてから、ウィジェットを Frame クラスにインスタンス化しようとすると、中性子星のように崩壊しました。

私の 2 つのコード例を見て、何が問題なのかを確認してください。

これは、私のウィジェットが 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()

次に、これをカスタム ウィジェットにして、そのうちの 1 つを 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()

繰り返しますが、最初のコード サンプルは基本的に希望どおりに動作しますが、最終的なプログラムでは 1 つのウィジェットにする必要があります。wx.Frame から継承するクラスでそれをインスタンス化しようとすると、書式設定が消えてすべてが重なり合うのはなぜですか?

よろしくお願いします。他に提供する必要がある情報があれば教えてください。

4

1 に答える 1

3

コードをフレームからカスタムパネルに変換したときに、余分なパネルを削除するのを忘れていました。ISC_status(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 に答える