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 have a wx application where the main frame has several sub panels. I'd like to have a menu bar in the main frame, where each of the menus is associated with a panel. This means that the creation of menu items and binding them to event handlers should be done in the individual panels and not in the main frame. Here is a minimal example:
import wx
class myPanel1(wx.Panel):
def __init__(self, parent, menubar):
super().__init__(parent=parent)
menu = wx.Menu()
menuAction1 = menu.Append(wx.ID_ANY, 'Action1')
menuAction2 = menu.Append(wx.ID_ANY, 'Action2')
menubar.Append(menu, '&Actions')
# This does not work because the EVT_MENU is only seen by the main frame(?)
self.Bind(wx.EVT_MENU, self.onAction1, menuAction1)
self.Bind(wx.EVT_MENU, self.onAction2, menuAction2)
def onAction1(self, event):
print('Hello1')
def onAction2(self, event):
print('Hello2')
class mainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.menubar = wx.MenuBar()
# There are more panels in my actual program
self.panel1 = myPanel1(self, self.menubar)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.panel1, flag=wx.EXPAND, proportion=1)
self.SetSizerAndFit(sizer)
self.SetMenuBar(self.menubar)
self.Layout()
class myApp(wx.App):
def OnInit(self):
frame = mainWindow(parent=None, title='Title')
self.SetTopWindow(frame)
frame.Show()
return True
if __name__ == '__main__':
app = myApp()
app.MainLoop()
The problem is now that myPanel1.onAction1 is not called because the menu event from the main frame does not propagate to the sub panel.
Is there any neat way to do this?
Meanwhile I've found the answer myself. It's as simple as changing
self.Bind(wx.EVT_MENU, self.onAction1, menuAction1)
in myPanel1.__init__ to
self.GetParent().Bind(wx.EVT_MENU, self.onAction1, menuAction1)
Anyway, thanks everyone who thought about this question for their effort.
I'm using the code below to test some of the features from AUI. If you run the code, you should find a frame with 2 panels in it that can be detached/floated. However, the panel can be dragged anywhere on the screen. I'd like to prevent the panel from leaving the main frame. Is this possible? I thought there would be a flag or something that I can change, but I haven't been able to find anything yet.
Thanks!
Code:
import wx
from wx.lib.agw import aui
class TestPanel(wx.Panel):
def __init__(self, *args, **keys):
wx.Panel.__init__(self, *args, **keys)
self.textCtrl = wx.StaticText( self, wx.ID_ANY, 'AGW is a very nice library!' )
class TestFrame(wx.Frame):
def __init__(self, *args, **keys):
wx.Frame.__init__(self, *args, **keys)
self.mgr = mgr = aui.AuiManager_DCP()
mgr.SetManagedWindow( self )
mgr.AddPane( TestPanel(self), aui.AuiPaneInfo().Name('p1').Caption('p1').Right().BestSize((100,100)) )
mgr.AddPane( TestPanel(self), aui.AuiPaneInfo().Name('p2').Caption('p2').Bottom().BestSize((100,100)) )
mgr.Update()
if __name__ == '__main__':
app = wx.App( redirect = False )
frame = TestFrame( None, title = 'AUI test', size = (300, 400) )
frame.Show()
app.MainLoop()
In AuiPaneInfo() you can add Floatable(False) to the pane you dont want it to float:
wx.aui.AuiPaneInfo().Left().Floatable(False)
I have several CollapsiblePanes in a vertical BoxSizer. I would like to be able to expand and collapse them without having them run into each other. I am running wxPython 2.8.10.1 on Windows 7.
Runnable sample application demonstrating the problem is below.
import wx
class SampleCollapsiblePane(wx.CollapsiblePane):
def __init__(self, *args, **kwargs):
wx.CollapsiblePane.__init__(self,*args,**kwargs)
sizer = wx.BoxSizer(wx.VERTICAL)
for x in range(5):
sizer.Add(wx.Button(self.GetPane(), label = str(x)))
self.GetPane().SetSizer(sizer)
class Main_Frame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.main_panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
for x in range(5):
sizer.Add(SampleCollapsiblePane(self.main_panel, label = str(x)), 1)
self.main_panel.SetSizer(sizer)
class SampleApp(wx.App):
def OnInit(self):
frame = Main_Frame(None, title = "Sample App")
frame.Show(True)
frame.Centre()
return True
def main():
app = SampleApp(0)
app.MainLoop()
if __name__ == "__main__":
main()
The documentation explicitly states that you should use proportion=0 when adding collapsible panes to a sizer.
http://docs.wxwidgets.org/stable/wx_wxcollapsiblepane.html
So, first, change the 1 at the end of this line to a 0:
sizer.Add(SampleCollapsiblePane(self.main_panel, label = str(x)), 1)
Next, add this to your SampleCollapsiblePane to force the parent frame to re-layout when a pane is collapsed or expanded:
def __init__(...):
...
self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.on_change)
def on_change(self, event):
self.GetParent().Layout()
There might be a better way, but this is what I've got working at the moment. I'm good with wxPython but haven't used CollapsiblePanes before.
I am trying to learn Python and WxPython. I have been a SAS programmer for years. This OOP stuff is slowly coming together but I am still fuzzy on a lot of the concepts. Below is a section of code. I am trying to use a button click to create an instance of another class. Specifically-I have my main panel in one class and I wanted to instance a secondary panel when a user clicked on one of the menu items on the main panel. I made all of this work when the secondary panel was just a function. I can't seem to get ti to work as a class.
Here is the code
import wx
class mainPanel(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, 'directEDGAR Supplemental Tools', size=(450, 450))
wx.Panel(self,-1)
wx.StaticText(self,-1, "This is where I will describe\n the purpose of these tools",(100,10))
menubar = wx.MenuBar()
parser = wx.Menu()
one =wx.MenuItem(parser,1,'&Extract Tables with One Heading or Label')
two =wx.MenuItem(parser,1,'&Extract Tables with Two Headings or Labels')
three =wx.MenuItem(parser,1,'&Extract Tables with Three Headings or Labels')
four =wx.MenuItem(parser,1,'&Extract Tables with Four Headings or Labels')
quit = wx.MenuItem(parser, 2, '&Quit\tCtrl+Q')
parser.AppendItem(one)
parser.AppendItem(two)
parser.AppendItem(three)
parser.AppendItem(four)
parser.AppendItem(quit)
menubar.Append(parser, '&Table Parsers')
textRip = wx.Menu()
section =wx.MenuItem(parser,1,'&Extract Text With Section Headings')
textRip.AppendItem(section)
menubar.Append(textRip, '&Text Rippers')
dataHandling = wx.Menu()
deHydrate =wx.MenuItem(dataHandling,1,'&Extract Data from Tables')
dataHandling.AppendItem(deHydrate)
menubar.Append(dataHandling, '&Data Extraction')
self.Bind(wx.EVT_MENU, self.OnQuit, id=2)
this is where I think I am being clever by using a button click to create an instance
of subPanel.
self.Bind(wx.EVT_MENU, self.subPanel(None, -1, 'TEST'),id=1)
self.SetMenuBar(menubar)
self.Centre()
self.Show(True)
def OnQuit(self, event):
self.Close()
class subPanel(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, 'directEDGAR Supplemental Tools', size=(450, 450))
wx.Panel(self,-1)
wx.StaticText(self,-1, "This is where I will describe\n the purpose of these tools",(100,10))
getDirectory = wx.Button(panel, -1, "Get Directory Path", pos=(20,350))
getDirectory.SetDefault()
getTerm1 = wx.Button(panel, -1, "Get Search Term", pos=(20,400))
getTerm1.SetDefault()
#getDirectory.Bind(wx.EVT_BUTTON, getDirectory.OnClick, getDirectory.button)
self.Centre()
self.Show(True)
app = wx.App()
mainPanel(None, -1, '')
app.MainLoop()
I don't know wxWidgets, but based on what I know of Python, I'm guessing that you need to change:
self.Bind(wx.EVT_MENU, self.subPanel(None, -1, 'TEST'),id=1)
to:
self.Bind(wx.EVT_MENU, subPanel(None, -1, 'TEST'),id=1)
"subPanel" is a globally defined class, not a member of "self" (which is a mainPanel).
Edit: Ah, "Bind" seems to bind an action to a function, so you need to give it a function that creates the other class. Try the following. It still doesn't work, but at least it now crashes during the subPanel creation.
self.Bind(wx.EVT_MENU, lambda(x): subPanel(None, -1, 'TEST'),id=1)
You should handle the button click event, and create the panel in your button handler (like you already do with your OnQuit method).
I think the following code basically does what you're after -- creates a new Frame when the button is clicked/menu item is selected.
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, title="My Frame", num=1):
self.num = num
wx.Frame.__init__(self, parent, -1, title)
panel = wx.Panel(self)
button = wx.Button(panel, -1, "New Panel")
button.SetPosition((15, 15))
self.Bind(wx.EVT_BUTTON, self.OnNewPanel, button)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
# Now create a menu
menubar = wx.MenuBar()
self.SetMenuBar(menubar)
# Panel menu
panel_menu = wx.Menu()
# The menu item
menu_newpanel = wx.MenuItem(panel_menu,
wx.NewId(),
"&New Panel",
"Creates a new panel",
wx.ITEM_NORMAL)
panel_menu.AppendItem(menu_newpanel)
menubar.Append(panel_menu, "&Panels")
# Bind the menu event
self.Bind(wx.EVT_MENU, self.OnNewPanel, menu_newpanel)
def OnNewPanel(self, event):
panel = MyFrame(self, "Panel %s" % self.num, self.num+1)
panel.Show()
def OnCloseWindow(self, event):
self.Destroy()
def main():
application = wx.PySimpleApp()
frame = MyFrame(None)
frame.Show()
application.MainLoop()
if __name__ == "__main__":
main()
Edit: Added code to do this from a menu.
You need an event handler in your bind expression
self.bind(wx.EVT_MENU, subPanel(None, -1, 'TEST'),id=1)
needs to be changed to:
self.bind(wx.EVT_MENU, <event handler>, <id of menu item>)
where your event handler responds to the event and instantiates the subpanel:
def OnMenuItem(self, evt): #don't forget the evt
sp = SubPanel(self, wx.ID_ANY, 'TEST')
#I assume you will add it to a sizer
#if you aren't... you should
test_sizer.Add(sp, 1, wx.EXPAND)
#force the frame to refresh the sizers:
self.Layout()
Alternatively, you can instantiate the subpanel in your frame's __init__ and call a subpanel.Hide() after instantiation, and then your menuitem event handler and call a show on the panel subpanel.Show()
Edit: Here is some code that will do what I think that you are asking:
#!usr/bin/env python
import wx
class TestFrame(wx.Frame):
def __init__(self, parent, *args, **kwargs):
wx.Frame.__init__(self, parent, *args, **kwargs)
framesizer = wx.BoxSizer(wx.VERTICAL)
mainpanel = MainPanel(self, wx.ID_ANY)
self.subpanel = SubPanel(self, wx.ID_ANY)
self.subpanel.Hide()
framesizer.Add(mainpanel, 1, wx.EXPAND)
framesizer.Add(self.subpanel, 1, wx.EXPAND)
self.SetSizerAndFit(framesizer)
class MainPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
wx.Panel.__init__(self, parent, *args, **kwargs)
panelsizer = wx.BoxSizer(wx.VERTICAL)
but = wx.Button(self, wx.ID_ANY, "Add")
self.Bind(wx.EVT_BUTTON, self.OnAdd, but)
self.panel_shown = False
panelsizer.Add(but, 0)
self.SetSizer(panelsizer)
def OnAdd(self, evt):
if not self.panel_shown:
self.GetParent().subpanel.Show()
self.GetParent().Fit()
self.GetParent().Layout()
self.panel_shown = True
else:
self.GetParent().subpanel.Hide()
self.GetParent().Fit()
self.GetParent().Layout()
self.panel_shown = False
class SubPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
wx.Panel.__init__(self, parent, *args, **kwargs)
spsizer = wx.BoxSizer(wx.VERTICAL)
text = wx.StaticText(self, wx.ID_ANY, label='I am a subpanel')
spsizer.Add(text, 1, wx.EXPAND)
self.SetSizer(spsizer)
if __name__ == '__main__':
app = wx.App()
frame = TestFrame(None, wx.ID_ANY, "Test Frame")
frame.Show()
app.MainLoop()