I have textctrl in wxPython toolbar, I couldn't figure out how to align it with icons(22x22) and have some spacing/padding between toolbar icons and text control and also to frame borders.
import wx
class MyGUI(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(500, 500))
menubar = wx.MenuBar()
file = wx.Menu()
help = wx.Menu()
file.Append(101, '&Open', 'Open a new document')
file.Append(102, '&Save', 'Save the document')
file.AppendSeparator()
quit = wx.MenuItem(file, 105, '&Quit\tCtrl+Q', 'Quit the Application')
quit.SetBitmap(wx.Image('media/22/actions/system-log-out.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap())
file.AppendItem(quit)
menubar.Append(file, '&File')
menubar.Append(help, '&Help')
self.SetMenuBar(menubar)
self.CreateStatusBar()
self.toolbar = self.CreateToolBar()
textctrl = self.toolbar.AddControl( wx.TextCtrl( self.toolbar, wx.ID_ANY,size=(100, -1)))
tconn = self.toolbar.AddLabelTool(wx.ID_UNDO, '', wx.Bitmap('media/22/actions/server-connect-icon.png'))
tplay = self.toolbar.AddLabelTool(wx.ID_REDO, '', wx.Bitmap('media/22/actions/media-playback-start.png'))
self.toolbar.AddSeparator()
texit = self.toolbar.AddLabelTool(wx.ID_EXIT, '', wx.Bitmap('media/22/actions/stop.png'))
self.toolbar.EnableTool(wx.ID_EXIT, False)
self.toolbar.Realize()
class MyApp(wx.App):
def OnInit(self):
frame = MyGUI(None, -1, 'MyGUI')
frame.SetBackgroundColour('#004681')
frame.SetIcon(wx.Icon('media/launch.ico', wx.BITMAP_TYPE_ICO))
frame.Show(True)
return True
if __name__ == '__main__':
app = MyApp(0)
app.MainLoop()
The toolbar widget follows the look-and-feel of the OS's native toolbar, so there's really no way to change that. See the following thread:
http://wxpython-users.1045709.n5.nabble.com/wxToolBar-Icon-Spacing-td3406146.html
In it there are a couple of workarounds using blank images or labels for spacing. Alternatively, you could just create your own toolbar with a horizontal box sizer and add all the widgets to it. Then you'll be able to use the sizer to space things out a bit.
Related
I'm trying to display the connection settings, that are required for an ssh connection, i'm using the wx.BoxSizer to arrange the layout, unfortunately the layout doesn't work and stacks all elements in the top left corner (Until i resize the window by scaling/maximizing).
I've already tried to use:self.Update(),self.Refresh() and self.Layout()
after i called self.Show(True) method but this doesn't work for me.
If i remove the section 'statusbar setup' and 'creating the menubar' it works but i need those.
import wx
import connectionSettingsProperties
import connectionSettings
from pubsub import pub
class MyFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self, parent, title = title, size = (1600,800))
panel = wx.Panel(self)
#statusbar setup
self.CreateStatusBar()
# menu setup
filemenu = wx.Menu()
# creating the menubar
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"Menu")
self.SetMenuBar(menuBar)
#connectionstatus init
self.ipLabel = wx.StaticText(panel, label = 'ip:')
self.usernameLabel = wx.StaticText(panel, label = 'username:')
#building layout
vboxMain = wx.BoxSizer(wx.VERTICAL)
hboxConnection = wx.BoxSizer(wx.HORIZONTAL)
hboxConnection.Add(self.ipLabel)
hboxConnection.Add(self.usernameLabel)
vboxMain.Add(hboxConnection)
panel.SetSizer(vboxMain)
#show content
self.Show(True)
app = wx.App(False)
frame = MyFrame(None, 'MyApp')
app.MainLoop()
this is what it's initially showing: https://imgur.com/VQebA9t
and this is how it's supposed to look like: https://imgur.com/60V1tcF
The second result is showing as soon as i rescale the window.
You are really close. You should only add the line:
vboxMain.Fit(panel)
below the line:
panel.SetSizer(vboxMain)
I'm trying to understand wxPython, but most of the documentation out there just presents programs in a monkey-see-monkey-do way without explaining the fundamentals of the library.
Consider this snippet of code:
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, (-1, -1), wx.Size(250, 50))
panel = wx.Panel(self, -1)
box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(wx.Button(panel, -1, 'Button1'), 1 )
box.Add(wx.Button(panel, -1, 'Button2'), 1 )
box.Add(wx.Button(panel, -1, 'Button3'), 1 )
panel.SetSizer(box)
self.Centre()
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, 'wxboxsizer.py')
frame.Show(True)
return True
app = MyApp(0)
app.MainLoop()
I see three containers here -
A frame, a panel, and a box.
And then there are three buttons.
Can someone explain which container goes inside which one?
Does the panel go into the frame? If so, where is it added to the frame?
What about the box? Does it go into the panel, or does the panel go into it?
Were do the buttons go? Is it into the box?
Why is panel.SetSizer() used in one place and box.Add() used in another place?
Let us slowly develop a wxPython application to see how it works.
This is the least amount of code required to make a wxPython application. It contains a wx.Frame (you may understand this as a window). There is nothing in the window. app.MainLoop() is the loop that captures any events such as mouse-clicks, closing or minimizing windows.
import wx
app = wx.App()
frame = wx.Frame(None, -1, 'A Frame')
frame.Show()
app.MainLoop()
A window on its own is not very interesting but is still fairly powerful. We can add things like menu items and titles and even select styles such as No Maximize button. Let's do all that.
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar() # Create a menubar
fileMenu = wx.Menu() # Create the file menu
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application') # Add a quit line
menubar.Append(fileMenu, '&File') # Add the File menu to the Menubar
self.SetMenuBar(menubar) # Set the menubar as THE menu bar
self.Bind(wx.EVT_MENU, self.OnQuit, fitem) # Bind the quit line
self.Show() # Show the frame
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # Some styles
app.MainLoop()
You'll notice things got a little more complicated fairly quickly. It's actually to help us stay organized. We moved our frame into its own class and we defined some characteristics. We asked for a menu, bound the menu item to the OnQuit() method which close the application. This is all at the most basic layer.
Let's add a panel. A panel is like a chalkboard. It sits on top of a wx.Frame (like a Chalkboard sits against a wall). Once we have a panel, we can start adding sizers and widgets.
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1) # Added a panel!
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
You'll notice a slight difference depending on your platform. The window is now filled in, with a lighter colour. That's our panel. Now let's add some buttons.
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.') # Add a button
btn.Bind(wx.EVT_BUTTON, self.OnQuit) # Bind the first button to quit
btn2 = wx.Button(panel, label='I am a do nothing button.') # Add a second
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
Now we have buttons that sit on the panel. But they look awful. They're stuck one on top of another. We could manually position them using the pos=(x,y) attribute but that's very tedious. Let's call in our friend the boxsizer.
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.')
btn.Bind(wx.EVT_BUTTON, self.OnQuit)
btn2 = wx.Button(panel, label='I am a do nothing button.')
vbox = wx.BoxSizer(wx.VERTICAL) # Create a vertical boxsizer
vbox.Add(btn) # Add button 1 to the sizer
vbox.Add(btn2) # Add button 2 to the sizer
panel.SetSizer(vbox) # Tell the panel to use this sizer as its sizer.
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
That's already much better! Let's see what a horizontal sizer looks like.
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.')
btn.Bind(wx.EVT_BUTTON, self.OnQuit)
btn2 = wx.Button(panel, label='I am a do nothing button.')
vbox = wx.BoxSizer(wx.VERTICAL) # A vertical sizer
hbox = wx.BoxSizer(wx.HORIZONTAL) # And a horizontal one?? but why?
hbox.Add(btn) # Let's add the buttons first
hbox.Add(btn2)
panel.SetSizer(hbox) # see why we need to tell the panel which sizer to use? We might have two!
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
Interesting! Notice how I kept our vbox? Let's try combining the two. We'll need lots more buttons and maybe some TextCtrls too.
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.')
btn.Bind(wx.EVT_BUTTON, self.OnQuit)
btn2 = wx.Button(panel, label='I am a do nothing button.')
txt1 = wx.TextCtrl(panel, size=(140,-1))
txt2 = wx.TextCtrl(panel, size=(140,-1))
txt3 = wx.TextCtrl(panel, size=(140,-1))
btn3 = wx.Button(panel, label='I am a happy button.')
btn4 = wx.Button(panel, label='I am a bacon button.')
btn5 = wx.Button(panel, label='I am a python button.')
# So many sizers!
vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
hbox3 = wx.BoxSizer(wx.HORIZONTAL)
hbox4 = wx.BoxSizer(wx.HORIZONTAL)
hbox1.Add(btn)
hbox1.Add(btn2)
hbox1.Add(txt1)
hbox2.Add(txt2)
hbox2.Add(txt3)
hbox2.Add(btn3)
hbox3.Add(btn4)
hbox4.Add(btn5)
vbox.Add(hbox1)
vbox.Add(hbox2)
vbox.Add(hbox3)
vbox.Add(hbox4)
panel.SetSizer(vbox)
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
We've added buttons and text widgets to horizontal sizers first, and then to vertical sizers second. We've got sizers in sizers, which is a very common way of doing things in wxPython.
__________________________
|__hbox1_|_______________| \
|_hbox2____|______|____|_| \___VBOX
|___hbox3______|_________| /
|_______|__hbox4_|_______| /
Sort of like that. In each hbox we have a number of widgets. Up to you how many you want. Hope this helps.
wxPython is complex, but so are other GUI toolkits. Let's break it down a bit. To answer the first question, the usual layout of the wxPython GUI is one of the following:
frame -> panel -> sizer -> widgets
frame -> sizer -> panel -> sizer -> widgets
I usually go with the first one. If the layout is complex, I may nest sizers, so I end up with something like this:
frame -> panel -> sizer -> sizer1 -> widgets
-> sizer2 -> widgets
2) The first panel should always be added to the frame as its sole widget:
wx.Frame.__init__(self, None, title="Test")
panel = wx.Panel(self)
3) The boxSizer usually goes into the panel. I usually have a top level boxSizer that I give to the panel and then create nested sizers inside of it.
4) The buttons and other widgets go in BOTH the panel and the sizer! You set the button's parent to the panel, then to layout the widgets inside the panel, you put them in the panel's sizer object. If you were to set the button's parent as the frame, you would have a mess.
5) SetSizer is used to tell wxPython which widget the sizer belongs to. In your code, you give the panel the box sizer instance. The Add() method of the sizer object is used to add widgets (and sizers) to the sizer itself.
I hope that answers all your questions. You might also find the following article useful as it links to the majority of the documentation I use for wx: http://www.blog.pythonlibrary.org/2010/12/05/wxpython-documentation/
I would strongly recommend getting hold of a copy of wxPython in Action by Noel Rappin and Robin Dunn. Since Robin is one of the main authors/architects of wxPython you will get very good insights and clear explanations.
N.B. Before anybody asks I have absolutely no commercial connection with the book, authors or publishers.
I have set up a wxpython GUI that has a menu bar and some items in the menu bar. What I would like to do is select an item in my menu bar (ex. File - Options), and when i select "Options" have a dialog box pop up in which I can set different parameters in my code. Similar behaviors would be wx.FontDialog and wx.FileDialog -- However, I want mine to be custom in that i could have radio buttons and check boxes as selectable options. How do I do this?
Snippets of my code are:
Here is where I set up part of the Main application and GUI (I have layout and box sizers set up in another section):
class TMainForm(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.Splitter = wx.SplitterWindow(self, -1, style=wx.SP_3D|wx.SP_BORDER)
self.PlotPanel = wx.Panel(self.Splitter, -1)
self.FilePanel = wx.Panel(self.Splitter, -1)
#self.SelectionPanel = wx.Panel(self.Splitter,-1)
self.Notebook = wx.Notebook(self.FilePanel, -1)#, style=0)
self.ReportPage = wx.Panel(self.Notebook, -1)
self.FilePage = wx.Panel(self.Notebook, -1)
Here is where I set up part of the Menu Bar:
self.MainMenu = wx.MenuBar()
self.FileMenu = wx.Menu()
self.OptimizeMenu = wx.Menu()
self.HelpMenu = wx.Menu()
self.OptimizeOptions= wx.MenuItem(self.OptimizeMenu, 302, "&Select Parameters","Select Parameters for Optimization",wx.ITEM_NORMAL)
self.OptimizeMenu.AppendItem(self.OptimizeOptions)
self.MainMenu.Append(self.OptimizeMenu, "&Optimization")
Here is where I bind an event to my "options" part of my menu bar. When I click on this, I want a pop up menu dialog to show up
self.Bind(wx.EVT_MENU, self.OnOptimizeOptions, self.OptimizeOptions)
This is the function in which i'm hoping the pop up menu will be defined. I would like to do it in this format if possible (rather than doing separate classes).
def OnOptimizeOptions(self,event):
give me a dialog box (radio buttons, check boxes, etc)
I have only shown snippets, but all of my code does work. My GUI and menu bars are set up correctly - i just don't know how to get a pop up menu like the wx.FileDialog and wx.FontDialog menus. Any help would be great! Thanks
You would want to instantiate a dialog in your handler (OnOptimizeOptions). Basically you would subclass wx.Dialog and put in whatever widgets you want. Then you'd instantiate it in your handler and call ShowModal. Something like this psuedo-code:
myDlg = MyDialog(*args)
myDlg.ShowModal()
See the Custom Dialog part on zetcodes site: http://zetcode.com/wxpython/dialogs/ (near the bottom) for one example.
EDIT - Here's an example:
import wx
########################################################################
class MyDialog(wx.Dialog):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Dialog.__init__(self, None, title="Options")
radio1 = wx.RadioButton( self, -1, " Radio1 ", style = wx.RB_GROUP )
radio2 = wx.RadioButton( self, -1, " Radio2 " )
radio3 = wx.RadioButton( self, -1, " Radio3 " )
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(radio1, 0, wx.ALL, 5)
sizer.Add(radio2, 0, wx.ALL, 5)
sizer.Add(radio3, 0, wx.ALL, 5)
for i in range(3):
chk = wx.CheckBox(self, label="Checkbox #%s" % (i+1))
sizer.Add(chk, 0, wx.ALL, 5)
self.SetSizer(sizer)
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "wx.Menu Tutorial")
# Add a panel so it looks the correct on all platforms
self.panel = wx.Panel(self, wx.ID_ANY)
menuBar = wx.MenuBar()
fileMenu = wx.Menu()
optionsItem = fileMenu.Append(wx.NewId(), "Options",
"Show an Options Dialog")
self.Bind(wx.EVT_MENU, self.onOptions, optionsItem)
exitMenuItem = fileMenu.Append(wx.NewId(), "Exit",
"Exit the application")
self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem)
menuBar.Append(fileMenu, "&File")
self.SetMenuBar(menuBar)
#----------------------------------------------------------------------
def onExit(self, event):
""""""
self.Close()
#----------------------------------------------------------------------
def onOptions(self, event):
""""""
dlg = MyDialog()
dlg.ShowModal()
dlg.Destroy()
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()
I'm building an app that should contain a resizable sidebar area on the left (starting at 200px width) and a main area on the right that should expand to fill the remaining area. I've gone with the SplitterWindow method as it's the only one I think offers manual resize on panels. I'm experiencing some black borders around the individual panels AND the entire frame that I can't seem to get rid of. The borders on the individual panels disappear when I comment out the make_canvas calls, but the border on the frame is still there. Strangely enough if I resize the entire app window the borders flicker on and off. I suspect it's not actually a border issue but a BoxSizing issue, but I'm not sure how to take care of it.
Here's the code:
#! /usr/bin/python
# -*- coding: utf-8 -*-
import wx, random
class TDTaskBarIcon(wx.TaskBarIcon):
def __init__(self, parent):
wx.TaskBarIcon.__init__(self)
self.parentApp = parent
self.icon = wx.Icon("images/icon_glasses.png", wx.BITMAP_TYPE_PNG)
self.SetIconImage()
def SetIconImage(self):
self.SetIcon(self.icon)
class Sidebar(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# tiled background
self.bgimage = wx.Bitmap('images/noise.png')
wx.FutureCall(50, self.make_canvas)
wx.EVT_SIZE(self, self.make_canvas)
self.SetBackgroundColour((229,226,218))
def make_canvas(self, event=None):
dc = wx.ClientDC(self)
brush_bmp = wx.BrushFromBitmap(self.bgimage)
dc.SetBrush(brush_bmp)
w, h = self.GetClientSize()
dc.DrawRectangle(0, 0, w, h)
class Main(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# tiled background
self.bgimage = wx.Bitmap('images/noise.png')
wx.FutureCall(50, self.make_canvas)
wx.EVT_SIZE(self, self.make_canvas)
self.SetBackgroundColour((229,226,218))
self.SetBackgroundColour('WHITE')
def make_canvas(self, event=None):
dc = wx.ClientDC(self)
brush_bmp = wx.BrushFromBitmap(self.bgimage)
dc.SetBrush(brush_bmp)
w, h = self.GetClientSize()
dc.DrawRectangle(0, 0, w, h)
# Create Tapedeck class
class Tapedeck(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.tbicon = TDTaskBarIcon(self)
self.tbicon.Bind(wx.EVT_MENU, self.OnQuit, id=wx.ID_EXIT)
splitter = wx.SplitterWindow(self)
self.Sidebar = Sidebar(splitter)
self.Main = Main(splitter)
splitter.SplitVertically(self.Sidebar, self.Main)
splitter.SetSashPosition(200)
splitter.SetMinimumPaneSize(200)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(splitter, 1, wx.EXPAND)
self.SetSizerAndFit(sizer)
self.SetAutoLayout(True)
self.InitUI()
self.SetSize((800, 600))
self.SetTitle('Tapedeck')
self.Center()
self.Show(True)
def InitUI(self):
panel = wx.Panel(self)
# font styles
header = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD, False, u'Helvetica')
# create a menubar at the top of the user frame
menuBar = wx.MenuBar()
# create menus
fileMenu = wx.Menu()
helpMenu = wx.Menu()
# export
export = fileMenu.Append(wx.NewId(), "&Export", "Export Playlist",
wx.ITEM_NORMAL)
export.SetBitmap(wx.Bitmap('images/men_playlist.png'))
fileMenu.AppendSeparator()
# quit
quit = fileMenu.Append(wx.NewId(), "&Quit\tCtrl+Q", "Quit the program",
wx.ITEM_NORMAL)
quit.SetBitmap(wx.Bitmap('images/men_quit.png'))
self.Bind(wx.EVT_MENU, self.OnQuit, quit)
# put the file menu on the menubar
menuBar.Append(fileMenu, "&File")
# about tapedeck
about = helpMenu.Append(wx.NewId(), "&About TapeDeck",
"About TapeDeck", wx.ITEM_NORMAL)
about.SetBitmap(wx.Bitmap('images/men_skull.png'))
self.Bind(wx.EVT_MENU, self.OnAbout, about)
# put the help menu on the menubar
menuBar.Append(helpMenu, "&Help")
# set menu bar
self.SetMenuBar(menuBar)
# create a status bar at the bottom of the frame
self.CreateStatusBar()
def OnQuit(self, e):
self.tbicon.RemoveIcon()
self.tbicon.Destroy()
self.Close()
def OnAbout(self, e):
self.SetStatusText("Here's your help!")
# Run the application
def main():
deck = wx.App()
Tapedeck(None)
deck.MainLoop()
if __name__ == '__main__':
main()
And screenshots:
Before resize (source):
After resize (source):
Suggestions?
You are drawing those lines with the call to DrawRectangle.
If you want to eliminate the lines and still draw the rectangle you can do:
dc.SetPen(wx.Pen("WHITE",1))
dc.DrawRectangle(0, 0, w, h)
in the two make_canvas methods. It works in windows.
I would like to be able to display Notebook and a TxtCtrl wx widgets in a single frame. Below is an example adapted from the wxpython wiki; is it possible to change their layout (maybe with something like wx.SplitterWindow) to display the text box below the Notebook in the same frame?
import wx
import wx.lib.sheet as sheet
class MySheet(sheet.CSheet):
def __init__(self, parent):
sheet.CSheet.__init__(self, parent)
self.SetLabelBackgroundColour('#CCFF66')
self.SetNumberRows(50)
self.SetNumberCols(50)
class Notebook(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(600, 600))
menubar = wx.MenuBar()
file = wx.Menu()
file.Append(101, 'Quit', '' )
menubar.Append(file, "&File")
self.SetMenuBar(menubar)
wx.EVT_MENU(self, 101, self.OnQuit)
nb = wx.Notebook(self, -1, style=wx.NB_BOTTOM)
self.sheet1 = MySheet(nb)
self.sheet2 = MySheet(nb)
self.sheet3 = MySheet(nb)
nb.AddPage(self.sheet1, "Sheet1")
nb.AddPage(self.sheet2, "Sheet2")
nb.AddPage(self.sheet3, "Sheet3")
self.sheet1.SetFocus()
self.StatusBar()
def StatusBar(self):
self.statusbar = self.CreateStatusBar()
def OnQuit(self, event):
self.Close()
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(450, 400))
self.text = wx.TextCtrl(self, -1, style = wx.TE_MULTILINE)
self.Center()
class MyApp(wx.App):
def OnInit(self):
frame = Notebook(None, -1, 'notebook.py')
frame.Show(True)
frame.Center()
frame2 = MyFrame(None, -1, '')
frame2.Show(True)
self.SetTopWindow(frame2)
return True
app = MyApp(0)
app.MainLoop()
Making two widgets appear on the same frame is easy, actually. You should use sizers to accomplish this.
In your example, you can change your Notebook class implementation to something like this:
class Notebook(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(600, 600))
menubar = wx.MenuBar()
file = wx.Menu()
file.Append(101, 'Quit', '' )
menubar.Append(file, "&File")
self.SetMenuBar(menubar)
wx.EVT_MENU(self, 101, self.OnQuit)
nb = wx.Notebook(self, -1, style=wx.NB_BOTTOM)
self.sheet1 = MySheet(nb)
self.sheet2 = MySheet(nb)
self.sheet3 = MySheet(nb)
nb.AddPage(self.sheet1, "Sheet1")
nb.AddPage(self.sheet2, "Sheet2")
nb.AddPage(self.sheet3, "Sheet3")
self.sheet1.SetFocus()
self.StatusBar()
# new code begins here:
# add your text ctrl:
self.text = wx.TextCtrl(self, -1, style = wx.TE_MULTILINE)
# create a new sizer for both controls:
sizer = wx.BoxSizer(wx.VERTICAL)
# add notebook first, with size factor 2:
sizer.Add(nb, 2)
# then text, size factor 1, maximized
sizer.Add(self.text, 1, wx.EXPAND)
# assign the sizer to Frame:
self.SetSizerAndFit(sizer)
Only the __init__ method is changed. Note that you can manipulate the proportions between the notebook and text control by changing the second argument of the Add method.
You can learn more about sizers from the official Sizer overview article.
You can use a splitter, yes.
Also, it makes sense to create a Panel, place your widgets in it (with sizers), and add this panel to the Frame.