I have a code. When it runs, you click on add contact button and add some contact. When you press on each contact, it just shows you the last contact information you have added. But when I press on each contact, I want it to instead show me the information for the contact I have clicked. Who can help me to solve this problem?
import wx
from wx._core import RB_GROUP, TE_READONLY
import sys
import os
from _ssl import nid2obj
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(500,500))
self.panel = wx.Panel(self, -1)
self.contactslist =[]
self.path = os.getcwd()+'\\contacts-db'
self.nc = wx.Button(self.panel, label='new contact')
self.nc.Bind(wx.EVT_BUTTON, self.newcontact)
self.displaycontacts()
self.Show(True)
def displaycontacts(self):
for roots, dirs, files in os.walk(self.path):
for filename in files:
#self.contactslist.append(filename)
self.cntct = wx.Button(self.panel, label=filename)
self.cntct.Bind(wx.EVT_BUTTON, self.clickcontacts)
def clickcontacts(self, e):
self.oc =self.path+'\\'+self.cntct.GetLabel()
self.oc2 = open(self.oc, 'r')
prt = wx.TextCtrl(self.panel, value=self.oc2.read())
def newcontact(self, e):
self.val = ''
self.f1 = wx.TextCtrl(self.panel, value='enter your first name', pos=(0,0))
self.f1.SetFocus()
self.f2 = wx.TextCtrl(self.panel, value='enter your last name', pos=(0,50))
self.rbm = wx.RadioButton(self.panel, label='male', style=RB_GROUP, pos=(0,100))
self.rbm.Bind(wx.EVT_RADIOBUTTON, self.male)
self.rbf = wx.RadioButton(self.panel, label='female')
self.rbf.Bind(wx.EVT_RADIOBUTTON, self.female)
self.btn = wx.Button(self.panel, label='show', pos=(0,200))
self.btn.Bind(wx.EVT_BUTTON, self.showform)
self.s = wx.TextCtrl(self.panel, value=self.val, style=wx.TE_MULTILINE, size=(800,800))
self.clrbtn = wx.Button(self.panel, label='clear', pos=(800,800))
self.clrbtn.Bind(wx.EVT_BUTTON, self.onclear)
self.af = wx.Button(self.panel, label='add additional field')
self.af.Bind(wx.EVT_BUTTON, self.additionalfield)
self.sv = wx.Button(self.panel, label='save')
self.sv.Bind(wx.EVT_BUTTON, self.save)
def showform(self, e):
self.s.SetValue('first name: '+self.f1.GetValue()+'\nlast name: '+self.f2.GetValue()+self.val)
def male(self, e):
self.val=''
self.val = '\ngender: male'
def female(self, e):
self.val=''
self.val='\ngender: female'
def onclear(self, e):
self.s.Clear()
self.f1.Clear()
self.f2.Clear()
def additionalfield(self, e):
self.x = wx.TextCtrl(self.panel, value='\nenter field name: ')
self.x.SetFocus()
self.y = wx.TextCtrl(self.panel, value='enter information ')
self.add = wx.Button(self.panel, label='add')
self.add.Bind(wx.EVT_BUTTON, self.additionalfieldappend)
def additionalfieldappend(self, e):
self.s.AppendText('\n'+self.x.GetValue()+': '+self.y.GetValue())
self.x.Destroy()
self.y.Destroy()
def save(self, e):
if not os.path.exists(self.path):
os.makedirs(self.path)
cnt = open(self.path+'\\'+self.f1.GetValue()+self.f2.GetValue()+'.txt', 'x')
cnt.write(self.s.GetValue())
nid2obj
app = wx.App()
frame = MyFrame(None, 'contact form')
app.MainLoop()
Everyone will develop their own style when using wxPython. As Rolf has suggested, you do not just add widgets to a frame, but you need to add a panel. I have added a basic contact add screen below. The 'New' button creates an instance of a wx.Dialog, which captures the details of a contact. These are then available to the MainFrame where you can save them if you want.
Note that I have freely created new classes in the application to handle the different areas of concern. GUI apps can become very complex, and in my opinion, there is no substitute for factoring each bit of functionality into its own method or class.
Not everything needs to be a member of the frame class.
Note also the I have used sizers and not absolute positions.
This code does not do everything that you want to do, but it might help get you started.
import wx
BORDER = 5
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(None, *args, **kwargs)
self.size = (400, 1000)
self.Title = 'Contacts'
self.Bind(wx.EVT_CLOSE, self.on_quit_click)
self.panel = MainPanel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel)
self.SetSizer(sizer)
self.Center()
self.Show()
def new_contact(self, event):
del event
contact_add_screen = NewContact(self)
try:
contact_add_screen.ShowModal()
if contact_add_screen.state == wx.ID_OK:
print(contact_add_screen.first_name)
print(contact_add_screen.last_name)
# This is where you can save your contacts
finally:
contact_add_screen.Destroy()
def on_quit_click(self, event):
del event
wx.CallAfter(self.Destroy)
class MainPanel(wx.Panel):
"""Create a panel class to contain screen widgets."""
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.parent = parent
cmd_new_contact = wx.Button(self, id= wx.ID_NEW)
cmd_new_contact.Bind(wx.EVT_BUTTON, parent.new_contact)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(cmd_new_contact, flag=wx.ALL, border = BORDER)
self.SetSizer(sizer)
class NewContact(wx.Dialog):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.state = None
self.first_name = None
self.last_name = None
self.parent = parent
self.SetTitle('Add Contact')
self.panel = ContactAddPanel(self)
sizer = wx.BoxSizer()
sizer.Add(self.panel)
self.SetSizerAndFit(sizer)
def on_cmd_save_click(self, event):
del event
self.first_name = self.panel.txt_first_name.GetValue()
self.last_name = self.panel.txt_last_name.GetValue()
self.state = wx.ID_OK
self.Destroy()
def on_quit_click(self, event):
del event # unused
self.Destroy()
class ContactAddPanel(wx.Panel):
TEXT_SIZE = (450, -1)
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.parent = parent
contact_sizer = self._contact_sizer()
button_panel = ButtonPanel(self, wx.ID_SAVE,
self.parent.on_cmd_save_click,
self.parent.on_quit_click)
self.txt_first_name.SetFocus()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(contact_sizer)
sizer.Add(button_panel, flag=wx.EXPAND|wx.TOP, border=BORDER)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(sizer, flag=wx.ALL, border=BORDER)
self.SetSizer(main_sizer)
def _contact_sizer(self):
lbl_first_name= wx.StaticText(self, label='First name: ')
self.txt_first_name= wx.TextCtrl(self, size=self.TEXT_SIZE)
lbl_last_name = wx.StaticText(self, label='Last name:')
self.txt_last_name = wx.TextCtrl(self, size=self.TEXT_SIZE)
sizer = wx.GridBagSizer(BORDER, BORDER)
sizer.Add(lbl_first_name, pos=(0, 0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.txt_first_name, pos=(0, 1))
sizer.Add(lbl_last_name, pos=(1, 0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.txt_last_name, pos=(1, 1))
return sizer
class ButtonPanel(wx.Panel):
def __init__(self, parent, ok_id, ok_bind, cancel_bind, *args, **kwargs):
super(ButtonPanel, self).__init__(parent, *args, **kwargs)
self.cmd_action = wx.Button(self, ok_id)
cmd_cancel = wx.Button(self, wx.ID_CANCEL)
self.cmd_action.Bind(wx.EVT_BUTTON, ok_bind)
cmd_cancel.Bind(wx.EVT_BUTTON, cancel_bind)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.cmd_action)
sizer.Add((0, 0), proportion=1)
sizer.Add(cmd_cancel)
self.SetSizer(sizer)
if __name__ == '__main__':
wx_app = wx.App()
MainFrame()
wx_app.MainLoop()
Related
I have a python 3 (wxpython phoenix) app which has two TABs, each TAB has a OnDropFiles box, but I just can't get it working. I have a simple stripped down example below, which should print the file URL on each drop, but not working, if someone could show a working example please, or point me in the right direcion, I would be very gratefull.
I'm using Python 3.10.5 and wxpython 4.2.
import wx
class ScrolledWindow(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(510, 330), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER |
wx.MAXIMIZE_BOX))
run_params = {}
self.tabbed = wx.Notebook(self, -1, style=(wx.NB_TOP))
self.filePrep = PrepFile(self.tabbed, self, run_params)
self.fileCheck = CheckFile(self.tabbed, self, run_params)
self.tabbed.AddPage(self.filePrep, "File Prep")
self.tabbed.AddPage(self.fileCheck, "File Check")
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.switchSize)
self.Centre()
self.Show()
def switchSize(self, e):
page = self.tabbed.GetPageText(self.tabbed.GetSelection())
if page == 'File Prep':
self.SetSize((510, 330))
elif page == 'File Check':
self.SetSize((510, 510))
self.fileCheck.setSubmissionDrop(self)
class PrepFile(wx.Panel):
def __init__(self, parent, frame, run_params):
wx.Panel.__init__(self, parent)
self.run_params = run_params
self.parent = parent
self.frame = self
self.selectedFiles = ""
outputtxt3 = '''Drag and Drop files'''
wx.StaticText(self, -1, outputtxt3, pos=(25, 180), style=wx.ALIGN_CENTRE)
self.drop_target = MyFileDropTarget(self)
self.SetDropTarget(self.drop_target)
self.tc_files = wx.TextCtrl(self, wx.ID_ANY, pos=(28, 200), size=(360, 25))
self.tc_files.SetFocus()
self.Show()
def setSubmissionDrop(self, dropFiles):
"""Called by the FileDropTarget when files are dropped"""
print(dropFiles)
self.tc_files.SetValue(','.join(dropFiles))
self.selectedFiles = dropFiles
class CheckFile(wx.Panel):
def __init__(self, parent, frame, run_params):
wx.Panel.__init__(self, parent)
self.run_params = run_params
self.parent = parent
self.frame = self
self.selectedFiles = ""
wx.StaticText(self, -1, '''Drag and Drop files''', pos=(25, 10), style=wx.ALIGN_CENTRE)
self.drop_target = MyFileDropTarget(self)
self.SetDropTarget(self.drop_target)
self.tc_files = wx.TextCtrl(self, wx.ID_ANY, pos=(25, 30), size=(302, 25))
self.tc_files.SetFocus()
self.Show()
def setSubmissionDrop(self, dropFiles):
"""Called by the FileDropTarget when files are dropped"""
print(dropFiles)
self.selectedFiles = dropFiles
class MyFileDropTarget(wx.FileDropTarget):
""""""
def __init__(self, window):
wx.FileDropTarget.__init__(self)
self.window = window
def OnDropFiles(self, x, y, filenames):
print(filenames)
self.window.setSubmissionDrop(filenames)
return True
app = wx.App()
ScrolledWindow(None, -1, 'File Prep ')
app.MainLoop()
We want this to be event driven, so you should define an event, from wx.lib.newevent.
I assume you want the drop zone to be the textctrl not the whole panel, so it's that that needs to be set as the target.
BIND the event.
In the FileDropTarget class we define the event and fire it.
In each drop event callback, we accept the event as a parameter and unpack whatever we packed into the event.
One last thing, in this case, you are getting back a list.
It's simple but every time you decide to use it, it trips you up, I don't know why.
import wx
import wx.lib.newevent
drop_event, EVT_DROP_EVENT = wx.lib.newevent.NewEvent()
class ScrolledWindow(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(510, 330), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER |
wx.MAXIMIZE_BOX))
run_params = {}
self.tabbed = wx.Notebook(self, -1, style=(wx.NB_TOP))
self.filePrep = PrepFile(self.tabbed, self, run_params)
self.fileCheck = CheckFile(self.tabbed, self, run_params)
self.tabbed.AddPage(self.filePrep, "File Prep")
self.tabbed.AddPage(self.fileCheck, "File Check")
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.switchSize)
self.Centre()
self.Show()
def switchSize(self, e):
page = self.tabbed.GetPageText(self.tabbed.GetSelection())
if page == 'File Prep':
self.SetSize((510, 330))
elif page == 'File Check':
self.SetSize((510, 510))
class PrepFile(wx.Panel):
def __init__(self, parent, frame, run_params):
wx.Panel.__init__(self, parent)
self.run_params = run_params
self.parent = parent
self.frame = self
self.selectedFiles = ""
outputtxt3 = '''Drag and Drop files'''
wx.StaticText(self, -1, outputtxt3, pos=(25, 180), style=wx.ALIGN_CENTRE)
self.tc_files = wx.TextCtrl(self, wx.ID_ANY, pos=(28, 200), size=(360, 25))
self.drop_target = MyFileDropTarget(self)
self.tc_files.SetDropTarget(self.drop_target)
self.Bind(EVT_DROP_EVENT, self.setSubmissionDrop)
self.tc_files.SetFocus()
self.Show()
def setSubmissionDrop(self, event):
"""Called by the FileDropTarget when files are dropped"""
files = event.data
print("\nprep event", files)
self.tc_files.SetValue(','.join(files))
self.selectedFiles = files
class CheckFile(wx.Panel):
def __init__(self, parent, frame, run_params):
wx.Panel.__init__(self, parent)
self.run_params = run_params
self.parent = parent
self.frame = self
self.selectedFiles = ""
wx.StaticText(self, -1, '''Drag and Drop files''', pos=(25, 10), style=wx.ALIGN_CENTRE)
self.tc_files = wx.TextCtrl(self, wx.ID_ANY, pos=(25, 30), size=(302, 25))
self.drop_target = MyFileDropTarget(self)
self.tc_files.SetDropTarget(self.drop_target)
self.Bind(EVT_DROP_EVENT, self.setSubmissionDrop)
self.tc_files.SetFocus()
self.Show()
def setSubmissionDrop(self, event):
"""Called by the FileDropTarget when files are dropped"""
files = event.data
print("\ncheck event", files)
self.tc_files.SetValue(','.join(files))
self.selectedFiles = files
class MyFileDropTarget(wx.FileDropTarget):
""""""
def __init__(self, window):
wx.FileDropTarget.__init__(self)
self.obj = window
def OnDropFiles(self, x, y, filenames):
drp_evt = drop_event(data=filenames)
wx.PostEvent(self.obj, drp_evt)
return True
app = wx.App()
ScrolledWindow(None, -1, 'File Prep ')
app.MainLoop()
I want to start an app with several panels hidden from the user and show them per request when interacting with the menu.
So far the `budget_panel' that I want to be initially hidden is always on display.
My code is as follows (likely it can be dramatically improved as it is my first time using wxwidgets and OOP in Python).
#!/usr/bin/python3
import sqlite3
import wx
class DB():
def __init__(self):
self.db = sqlite3.connect(':memory:')
self.cursor = self.db.cursor()
self.cursor.execute('CREATE TABLE invoices (id INT PRIMARY KEY, client TEXT)')
self.cursor.execute('INSERT INTO invoices (client) VALUES ("Empresa A")')
self.db.commit()
def myget(self, id):
return self.cursor.execute('SELECT * FROM {}'.format(id)).fetchall()
class BudgetPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(sizer)
self.choices = ["Empresa A", "Empresa B"]
self.choice = wx.Choice(parent, id=wx.ID_ANY, choices = self.choices)
sizer.Add(self.choice)
class EmptyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent = parent)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
text = wx.StaticText(self, -1, 'Text', style = wx.ALIGN_CENTER | wx.TE_READONLY)
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"Empresa",
size=(800,600))
self.db = DB()
self.menu()
self.empty_panel = EmptyPanel(self)
self.budget_panel = BudgetPanel(self)
self.panels = {1000 : self.empty_panel, 2001 : self.budget_panel}
for key in self.panels.keys():
if key == 1000:
self.panels[key].Show()
else:
self.panels[key].Hide()
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.empty_panel, 1, wx.EXPAND)
self.sizer.Add(self.budget_panel, 1, wx.EXPAND)
self.SetSizer(self.sizer)
def menu(self):
menubar = wx.MenuBar()
main_menu = wx.Menu()
budget_menu = main_menu.Append(2001, 'Presupuestos')
self.Bind(wx.EVT_MENU, self.change_panel, budget_menu)
menubar.Append(main_menu, '&GestiĆ³n')
self.SetMenuBar(menubar)
def change_panel(self, event):
for key in self.panels.keys():
if event.GetId() == key:
self.panels[key].Show()
else:
self.panels[key].Hide()
self.Layout()
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
'''
i use wxpython for python3
i try to creat my simple application and i 'm try to create the menu and with 2 panels
i need to add a file dialog when the user click in the button OPEN in the menu to chose the file , i don't know how can add it in my code
this is my code :
import wx
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super(MainFrame, self).__init__(None, *args, **kwargs)
self.Title = 'premier app (Menu+2windows)'
self.SetMenuBar(MenuBar(self))
self.ToolBar = MainToolbar(self)
self.status_bar = StatusBar(self).status_bar
self.Bind(wx.EVT_CLOSE, self.on_quit_click)
panel = MainPanel(self)
sizer = wx.BoxSizer()
sizer.Add(panel)
self.SetSizerAndFit(sizer)
self.Centre()
self.Show()
def on_quit_click(self, event):
del event
wx.CallAfter(self.Destroy)
class MainPanel(wx.Panel):
def __init__(self, parent):
wx.Frame.__init__(self, parent,size = (500,500))
self.splitter = wx.SplitterWindow(self, -1, size = (500,500))
# 1er panel
pan1 = wx.Window(self.splitter, style=wx.BORDER_SUNKEN)
pan1.SetBackgroundColour("yellow")
wx.StaticText(pan1, -1)
#2em panel
pan2 = wx.Window(self.splitter, style=wx.BORDER_SUNKEN)
pan2.SetBackgroundColour("blue")
wx.StaticText(pan2, -1)
self.splitter.SplitVertically(pan1, pan2, 100)
class MenuBar(wx.MenuBar):
"""creation de menu."""
def __init__(self, parent, *args, **kwargs):
super(MenuBar, self).__init__(*args, **kwargs)
# menu
File_menu = wx.Menu()
Edit_menu = wx.Menu()
Help_menu = wx.Menu()
self.Append(File_menu, '&File')
self.Append(Edit_menu, '&Edit')
self.Append( Help_menu, '&Help')
quit_menu_item = wx.MenuItem(File_menu, wx.ID_EXIT)
parent.Bind(wx.EVT_MENU, parent.on_quit_click, id=wx.ID_EXIT)
open_menu_item = wx.MenuItem(File_menu, wx.ID_OPEN)
new_menu_item = wx.MenuItem(File_menu,wx.ID_NEW)
File_menu.Append(open_menu_item)
File_menu.Append(new_menu_item)
File_menu.Append(quit_menu_item)
class MainToolbar(wx.ToolBar):
"""creation toolbar."""
def __init__(self, parent, *args, **kwargs):
super(MainToolbar, self).__init__(parent, *args, **kwargs)
class StatusBar(object):
def __init__(self, parent):
self.status_bar = parent.CreateStatusBar()
if __name__ == '__main__':
"""Run the application."""
screen_app = wx.App()
main_frame = MainFrame()
screen_app.MainLoop()
need some help
thank u
With this code:
quit_menu_item = wx.MenuItem(File_menu, wx.ID_EXIT)
parent.Bind(wx.EVT_MENU, parent.on_quit_click, id=wx.ID_EXIT)
you are binding the Quit menu item to a Quit function.
Do the same for the Open function i.e. Bind it to something like parent.on_open_file
In that function, do something like this.
def self.on_open_file(self, event):
dlg = wx.FileDialog(self, message="Choose file", defaultDir = "/home", defaultFile = "",\
wildcard = "", style=wx.FD_OPEN)
if dlg.ShowModal() == wx.ID_OK:
print(dlg.GetDirectory(), dlg.GetFilename())
dlg.Destroy()
I would like to assign the value of a menu click to a class variable so I can use that value throughout multiple classes. Any help would be greatly appreciated!
import wx
class TrackPanel (wx.Panel):
""""""
def __init__(self, parent, *args, **kwargs):
"""Constructor"""
wx.Panel.__init__(self, parent, *args, **kwargs)
mainSizer =wx.BoxSizer(wx.VERTICAL)
track = MasterPage.track_selected # This is where i would like access the variable
title = wx.StaticText(self, wx.ID_ANY, label = track)
mainSizer.Add(title, 0,wx.ALL | wx.EXPAND | wx.CENTER)
self.SetSizerAndFit(mainSizer)
self.Layout()
class MasterPage (wx.Frame):
track_selected = ' '
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
menubar = wx.MenuBar()
tracksopt = wx.Menu()
track_command = wx.MenuItem(tracksopt, wx.ID_ANY, 'Atlanta')
tracksopt.Append(track_command)
self.Bind(wx.EVT_MENU, self.change_track, track_command)
track_command2 = wx.MenuItem(tracksopt, wx.ID_ANY, 'Texas')
tracksopt.Append(track_command2)
self.Bind(wx.EVT_MENU, self.change_track, track_command2)
menubar.Append(tracksopt, '&Tracks')
self.SetMenuBar(menubar)
def change_track (self, event):
"""Changes the tack_selected variable based on the menu item picked"""
id_selected = event.GetId()
obj = event.GetEventObject()
track_id= obj.GetLabel(id_selected)
MasterPage.track_selected = track_id
You must create a link to the master in the tracker in order for the tracker to access values in the master.
import wx
class Track (wx.Frame):
def __init__(self, link):
wx.Frame.__init__(self, None)
self.link = link
self.tc = wx.TextCtrl(self, style=wx.TE_MULTILINE)
self.bt = wx.Button(self, label="tracker (push to read master)")
self.bt.Bind(wx.EVT_BUTTON, self.on_read_master)
self.Title = 'Tracker'
sz_1 = wx.BoxSizer(wx.HORIZONTAL)
sz_2 = wx.BoxSizer(wx.VERTICAL)
sz_2.Add(self.tc, 1, wx.EXPAND, 0)
sz_2.Add(self.bt, 0, wx.EXPAND, 0)
sz_1.Add(sz_2, 1, wx.EXPAND, 0)
self.SetSizer(sz_1)
self.Layout()
self.SetSize((250, 100))
def on_read_master(self, evt):
self.tc.SetValue(self.link.track_selected) # here you access the variable)
class Master(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.track_selected = '0'
self.tc = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE)
self.bt = wx.Button(self, wx.ID_ANY, "master (push to send)")
self.bt.Bind(wx.EVT_BUTTON, self.change_track)
self.Title = 'Master'
self.tc.SetValue('enter value to be read by the tracker')
sz_1 = wx.BoxSizer(wx.HORIZONTAL)
sz_2 = wx.BoxSizer(wx.VERTICAL)
sz_2.Add(self.tc, 1, wx.EXPAND, 0)
sz_2.Add(self.bt, 0, wx.EXPAND, 0)
sz_1.Add(sz_2, 1, wx.EXPAND, 0)
self.SetSizer(sz_1)
self.Layout()
self.SetSize((250, 100))
def change_track (self, evt):
"""Changes variable based on text entered"""
self.track_selected = self.tc.GetValue()
if __name__ == "__main__":
app = wx.App(0)
master = Master()
track = Track(master)
master.Show()
track.Show()
app.MainLoop()
This is the fast and dirty method I generally use. If you want something more sophisticated, there is a dedicated library to pass messages between frames: pubsub. A good tutorial of how to use it can be found in the Mike Driscoll blog
When I try to run the code below, I get this error:
Can't create window of class wxWindowNR (error 1406: cannot create a top-level child window.)
What is the problem here?
Code:
import os
import sys
import wx
from datetime import datetime, timedelta
szflags = wx.EXPAND | wx.ALL
min_height = 50
height_ratio = 4
pborder = 10
lborder = 5
class TangoArtProvider(wx.ArtProvider):
def __init__(self):
super(TangoArtProvider, self).__init__()
self.path = os.path.join(os.getcwd(), "icons")
self.bmps = [bmp.replace('.png', '')
for bmp in os.listdir(self.path)
if bmp.endswith('.png')]
print self.bmps
def CreateBitmap(self, id, client=wx.ART_OTHER, size=wx.DefaultSize):
if wx.Platform == '__WXGTK__':
return wx.NullBitmap
bmp = wx.NullBitmap
if id in self.bmps:
path = os.path.join(self.path, id+'.png')
bmp = wx.Bitmap(path)
else:
pass
return bmp
class ChartPanel(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
self.SetBackgroundColour('GREEN')
self.st = wx.StaticText(self, label='CHART PANEL')
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.st, 0 , szflags , lborder)
self.SetSizer(sizer)
class NotebookPage(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
self.chartPanel = ChartPanel(self, name='Notebook_Page_ChartPanel')
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.chartPanel, height_ratio, szflags, pborder)
self.SetSizer(sizer)
class Notebook(wx.Notebook):
def __init__(self, *args, **kwargs):
wx.Notebook.__init__(self, *args, **kwargs)
#self.SetBackgroundColour('PINK')
self.nbPages = {}
fleets = ["333"]
page_ix = 0
for fleet in fleets:
self.nbPages[fleets.index(fleet)] = NotebookPage(self, name='NotebookPage0')
for fleet in fleets:
self.AddPage(self.nbPages[fleets.index(fleet)], fleet, True)
class ChartPanel(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
#self.st = wx.StaticText(self, label='Chart Panel')
self.noteBook = Notebook(self, name='Notebook')
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.noteBook, 1, szflags)
self.SetSizer(sizer)
class SettingsPanel(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
self.st = wx.StaticText(self, label='Settings Panel')
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.st, 0, szflags)
self.SetSizer(self.sizer)
class OutputPanel(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
self.st = wx.StaticText(self, label='Output Panel')
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.st, 0, szflags)
self.SetSizer(self.sizer)
class ProportionalSplitter(wx.SplitterWindow):
def __init__(self,parent, id = -1, proportion=0.66, size = wx.DefaultSize, **kwargs):
wx.SplitterWindow.__init__(self,parent,id,wx.Point(0, 0),size, **kwargs)
self.SetMinimumPaneSize(50) #the minimum size of a pane.
self.proportion = proportion
if not 0 < self.proportion < 1:
raise ValueError, "proportion value for ProportionalSplitter must be between 0 and 1."
self.ResetSash()
self.Bind(wx.EVT_SIZE, self.OnReSize)
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged, id=id)
##hack to set sizes on first paint event
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.firstpaint = True
def SplitHorizontally(self, win1, win2):
if self.GetParent() is None: return False
return wx.SplitterWindow.SplitHorizontally(self, win1, win2,
int(round(self.GetParent().GetSize().GetHeight() * self.proportion)))
def SplitVertically(self, win1, win2):
if self.GetParent() is None: return False
return wx.SplitterWindow.SplitVertically(self, win1, win2,
int(round(self.GetParent().GetSize().GetWidth() * self.proportion)))
def GetExpectedSashPosition(self):
if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
else:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
return int(round(tot * self.proportion))
def ResetSash(self):
self.SetSashPosition(self.GetExpectedSashPosition())
def OnReSize(self, event):
"Window has been resized, so we need to adjust the sash based on self.proportion."
self.ResetSash()
event.Skip()
def OnSashChanged(self, event):
"We'll change self.proportion now based on where user dragged the sash."
pos = float(self.GetSashPosition())
if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
else:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
self.proportion = pos / tot
event.Skip()
def OnPaint(self,event):
if self.firstpaint:
if self.GetSashPosition() != self.GetExpectedSashPosition():
self.ResetSash()
self.firstpaint = False
event.Skip()
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.SetBackgroundColour('YELLOW')
self.CreateStatusBar(2)
self.SetStatusWidths([-2, -1])
#=======================================================================
# toolbar = self.CreateToolBar()
# toolbar.SetToolBitmapSize((20,20))
# icon_size = (32,32)
#
# wx.ArtProvider.PushProvider(TangoArtProvider())
#
# run = wx.ArtProvider.GetBitmap("forward", wx.ART_TOOLBAR, icon_size)
# settings = wx.ArtProvider.GetBitmap("tools", wx.ART_TOOLBAR, icon_size)
# quit = wx.ArtProvider.GetBitmap("quit", wx.ART_TOOLBAR, icon_size)
# toolbar.AddSimpleTool(1, run, "Run", "Run the report")
# toolbar.AddSimpleTool(2, settings, "Settings", "Change program settings")
# toolbar.AddSimpleTool(3, quit, "Quit", "Exit Program")
#
# toolbar.Realize()
#=======================================================================
self.split1 = ProportionalSplitter(self,-1, 0.66)
self.split2 = ProportionalSplitter(self.split1,-1, 0.50)
print "line 200"
self.rightpanel = ChartPanel(self.split1)
self.rightpanel.SetBackgroundColour('cyan')
print "line 203"
self.topleftpanel = SettingsPanel(self.split2)
self.topleftpanel.SetBackgroundColour('pink')
print "line 206"
self.bottomleftpanel = OutputPanel(self.split2)
self.bottomleftpanel.SetBackgroundColour('sky Blue')
## add your controls to the splitters:
self.split1.SplitVertically(self.split2, self.rightpanel)
self.split2.SplitHorizontally(self.topleftpanel, self.bottomleftpanel)
class App(wx.App):
def OnInit(self):
self.mainFrame = MainFrame(None,
size=(1000, 80*10),
title='Report', name='MainFrame')
wx.GetApp().SetTopWindow( self.mainFrame )
self.mainFrame.Show()
return True
def main(*args, **kwargs):
"""A nice place to process things before MainLoop"""
global app
import wx.lib.inspection
app = App()
#wx.lib.inspection.InspectionTool().Show()
app.MainLoop()
if __name__ == "__main__":
app = None
main()
There is a infinite loop in your code:
ChartPanel --> Notebook --> NotebookPage --> ChartPanel