I am designing an UI for instrumentation control with wxPython-4.2.3 (Python3.11.5, Win10, and pyVisa for the instrument control). I would like my widgets to be in a wx.Frame class, then I would like to have my own classes to handle the instruments and so on. Ideally the wxPython classes would interact with the other classes and have the job done independently of the wxPython stuff. Indeed this instrument job has nothing to do with wxPython so I though it would work to separate the classes. Below I have a MWE. The various widgets of the interface would allow me to set frequencies, amplitudes and so on. The basic thing first is to connect and close the connection properly, this is where I am stuck. The PyVisa interaction is simulated (but the commands are still here as a comment). InstrumentManager would be responsible of the connection, the communication and so on and technically I would also have other classes to handle data saving processing and so on. When I click on the button 'DISCONNECT ALL' I get the following error message : `AttributeError: 'Mywin' object has no attribute 'AWG'. Why does Mywin has to know about this variable AWG while it is only used in InstrumentManager ? Is there a way to have calls made in Mywin so I can have those two separate classes doing different jobs ? Or do I have to create variables within Mywin and constantly have to pass them from and to InstrumentManager ? This last scenario would be tedious. I am new to wxPython so there is surely things I got wrong about this event handling, how to call functions and pass arguments with buttons spinboxes and so on. # import pyvisa # from pyvisa.constants import StopBits, Parity import wx class InstrumentManager: ''' Class to open and close connection with instruments using pyvisa. It is also setting the internal parameters of the devices. ''' def __init__(self): ''' Define the addresses of the various instruments connected to the computer. ''' self.AWG_address = 'USB::0x05E6::0x3390::8011219::INSTR' # Keithley AWG 3390 self.AFG_address = 'USB::0x0699::0x0353::1650326::INSTR' # Tektronix AFG 1062 self.TAC_address = 'ASRL4::INSTR' # SR620 TAC # self.DSP_address = 'ASRL7::INSTR' # DSP-3005 DC power supply self.FAG_address = 'USB0::0x1AB1::0x0642:G1ZA254205102::INSTR' # Rigol DG1022 # Connecting to devices def connect_to_devices(self, event): ''' Connect to instruments with PyVisa. Here it is simulated. ''' # rm = pyvisa.ResourceManager() self.AWG = 'Simulate PyVisa resource' # rm.open_resource(self.AWG_address) self.AFG = 'Simulate PyVisa resource' # rm.open_resource(self.AFG_address) self.FAG = 'Simulate PyVisa resource' # rm.open_resource(self.FAG_address) self.TAC = 'Simulate PyVisa resource' # rm.open_resource(self.TAC_address, # baud_rate = 19200, # data_bits = 8, # stop_bits = StopBits(20), # parity = Parity(0), # read_termination='\r\n') def close_connection(self, event): ''' Closes connection with instruments. ''' self.AWG.close() self.AFG.close() self.FAG.close() self.TAC.close() class Mywin(wx.Frame, InstrumentManager): def __init__(self): InstrumentManager.__init__(self) wx.Frame.__init__(self, None, title = 'Hello') self.__Do_layout() def __Do_layout(self): ##################################### # MAIN FRAME self.SetInitialSize((300,300)) # set initial size of the panel # main panel window panel = wx.Panel(self) # main vbox vbox = wx.GridBagSizer(wx.VERTICAL) # vbox.SetMinSize(self,(600,800)) BoxGlobalSizer = wx.StaticBoxSizer(wx.VERTICAL, panel, 'Terminal output :') BoxGlobalGrid = wx.GridBagSizer(hgap=5, vgap=5) ##################################### # G L O B A L C O N T R O L S self.okButton = wx.Button(panel, -1, 'CONNECT ALL') BoxGlobalGrid.Add(self.okButton, pos=(0,0), span=(2,2), flag = wx.ALL|wx.LEFT) self.okButton.Bind(wx.EVT_BUTTON, self.connect_to_devices) self.cancelButton = wx.Button(panel, -1, 'DISCONNECT ALL') BoxGlobalGrid.Add(self.cancelButton, pos=(0,2), span=(2,2), flag = wx.ALL|wx.LEFT) self.cancelButton.Bind(wx.EVT_BUTTON, self.close_connection) ##################################### # FINISH THE LAYOUT # add each grid to its sizer BoxGlobalSizer.Add(BoxGlobalGrid, 0, wx.ALL|wx.LEFT, 10) # Add each sizer to the main vertical sizer vbox vbox.Add(BoxGlobalSizer,(6,0),(1,10), wx.EXPAND | wx.ALL|wx.LEFT, 5) # add vbox to panel panel.SetSizer(vbox) class MyApp(wx.App): def OnInit(self): frame = Mywin() frame.SetIcon(wx.Icon("Images\icons8-control-98_2.png")) frame.Show() self.SetTopWindow(frame) return True def main(): app = MyApp(redirect=False) app.MainLoop() if __name__ == "__main__" : main() Continue reading...