Disable wxMenuBar - python

So I'm looking to disable and enable a wxMenuBar in wxPython. Basically, grey out the whole thing.
If you look at the documentation: http://docs.wxwidgets.org/trunk/classwx_menu_bar.html
... you can see that the enable function takes a parameter for the menu item. As in, it doesn't disable/enable the whole menu, just a certain item.
Better yet, there's an EnableTop(size_t pos, bool enable) function to disable a whole menu, but not the whole bar.
Do I have to disable each item or menu individually? There's no function for doing the whole bar?
I made a function to do this manually but there must be a better way?
def enableMenuBar(action): #true or false
for index in range(frame.menuBar.GetMenuCount()):
frame.menuBar.EnableTop(index, action)
Thanks

You can disable the whole Menu by using EnableTop()
Code sample:
import wx
class gui(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, None, id, title, style=wx.DEFAULT_FRAME_STYLE)
menuBar = wx.MenuBar()
file = wx.Menu()
quit = wx.MenuItem(file, 101, '&Quit\tCtrl+Q', 'Quit the Application')
about = wx.MenuItem(file, 102, '&About\tCtrl+A', 'About the Application')
help = wx.MenuItem(file, 103, '&Help\tCtrl+H', 'Help related to the Application')
file.AppendItem(help)
file.AppendSeparator()
file.AppendItem(about)
file.AppendSeparator()
file.AppendItem(quit)
file.AppendSeparator()
menuBar.Append(file, '&File')
self.SetMenuBar(menuBar)
menuBar.EnableTop(0, False)#Comment out this to enable the menu
#self.SetMenuBar(None)#Uncomment this to hide the menu bar
if __name__ == '__main__':
app = wx.App()
frame = gui(parent=None, id=-1, title="My-App")
frame.Show()
app.MainLoop()
Also if you use self.SetMenuBar(None) the whole menu bar is gone as shown below. You can toggle the showing/hiding of the menu bar using this quick and dirty way. To show the menu bar again just set it again like self.SetMenuBar(menuBar) then the menu bar will be visible again. There could be a better approach too.
I hope it was helpful.

Related

How to disable Main Window MenuBar

In my wxpython APP, I want to disable Main window MenuBar (I actually don't know what it is called).
If I click that icon, this options are poped up. I want to stop this coming up, not disable items like Move, Minimize, Close. but the whole part.
That is known as the System Menu. You can't actually remove the menu without removing all the buttons too. To do that, you'll have to use a series of style flags during your initialization of the wx.Frame:
import wx
########################################################################
class NoSystemMenuFrame(wx.Frame):
"""
There is no system menu, which means the title bar is there, but
no buttons and no menu when clicking the top left hand corner
of the frame
"""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
no_sys_menu = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.CAPTION | wx.CLIP_CHILDREN | wx.CLOSE_BOX
wx.Frame.__init__(self, None, title="No System Menu", style=no_sys_menu)
panel = wx.Panel(self)
self.Show()
#----------------------------------------------------------------------
if __name__ == "__main__":
app = wx.App(False)
frame = NoSystemMenuFrame()
app.MainLoop()
You can disable some of the settings in the menu, but those settings will also apply to the buttons too. Check out the following article which goes over the majority of the options:
http://www.blog.pythonlibrary.org/2013/11/06/wxpython-101-using-frame-styles/
You might also find the documentation itself useful:
http://wxpython.org/Phoenix/docs/html/Frame.html#frame
My method of working in such situations will be to create an Empty Menubar and set it as the menu bar like this:
empty_menu_bar = MenuBar()
frame.SetMenuBar(empty_menu_bar)
Since there are no menu items in the menu bar, it is not shown in the window.

Adding a text control window to a wxMessageDialog box/AboutDialogInfo in wxPython

I am working with python v2.7 and wxPython v3.0 on Windows 7 OS.
In my app I have a about menu. Upon clicking the about menu I want to display some information about my app. I am trying to create a dialog box/AboutBox exactly as shown in the image below.(This is the about dialog of notepad++. Click on ? in the menu bar of notepad++.)
The special thing about the dialog box of notepad++ is that I need a text control window too. One can copy the info.
I tried to do the same in wxPython, but unfortunately I failed. I tried two different hit and trial approaches.
1. I tried to add the text control window to the dialog box wxMessageDialog but it doesn't shows up at all.
2. I tried to use the AboutBox in wxPython, and tried to add the text control to it but it failed because the AboutDialogInfo is not a window and the parent of the text control should be of a window type.
Error:
aboutPanel = wx.TextCtrl(info, -1, style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
File "C:\Python27\lib\site-packages\wx-3.0-msw\wx\_controls.py", line 2019, in __init__
_controls_.TextCtrl_swiginit(self,_controls_.new_TextCtrl(*args, **kwargs))
TypeError: in method 'new_TextCtrl', expected argument 1 of type 'wxWindow *'
It would be great if someone could provide some idea on how to add a text control windows to a dialog box/AboutBox?
Code: Here is my code sample for playing around:
import wx
from wx.lib.wordwrap import wordwrap
class gui(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self,None, id, title, style=wx.DEFAULT_FRAME_STYLE)
panel1 = wx.Panel(self, -1)
panel1.SetBackgroundColour('#fffaaa')
menuBar = wx.MenuBar()
file = wx.Menu()
file.Append(101, '&About1', 'About1')
file.Append(102, '&About2', 'About2')
menuBar.Append(file, '&File')
self.SetMenuBar(menuBar)
wx.EVT_MENU(self, 101, self.onAbout)# Event for the About1 menu
wx.EVT_MENU(self, 102, self.onAboutDlg)# Event for the About2 menu
def onAbout(self, event):
message = 'This fantastic app was developed using wxPython.\nwxPython is c00l :)'
dlg = wx.MessageDialog(self, message, 'My APP', wx.OK|wx.ICON_INFORMATION)
aboutPanel = wx.TextCtrl(dlg, -1, style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
aboutPanel.WriteText('Experimentation is the part of our life.\n')
dlg.ShowModal()
dlg.Destroy()
def onAboutDlg(self, event):
self.panel = wx.Panel(self, -1)
info = wx.AboutDialogInfo()
info.Name = "My About Box"
info.Version = "0.1"
info.Copyright = "(C) 2014 xxx"
info.Description = wordwrap(
"This is an example application that shows the problem "
"that I am facing :)",
350, wx.ClientDC(self.panel))
info.WebSite = ("http://stackoverflow.com/users/2382792/pss", "My Home Page")
info.Developers = ["PSS"]
info.License = wordwrap("Driving license and a AK-47 too :P ", 500,wx.ClientDC(self.panel))
# Uncomment the following line to get the error!
#aboutPanel = wx.TextCtrl(info, -1, style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
#aboutPanel.WriteText('Experimentation is the part of our life.\n')
wx.AboutBox(info)
if __name__ == '__main__':
app = wx.App()
frame = gui(parent=None, id=-1, title="My-App")
frame.Show()
app.MainLoop()
Thank you for your time!
wxAboutBox() uses the standard about dialog for the current platform so it won't help you to achieve your goal. Similarly, wxMessageDialog is the native message box dialog which, again, can't have your custom text box. OTOH there is absolutely no problem with building any dialog you want using wxDialog and adding elements to it (and using sizers to lay them out).
IOW your mistake is to think that the class you need to use is wxMessageDialog: it isn't, you need wxDialog.

How to add hyperlinks in the help of a wxpython app?

I'm implementing the help menu of an App done in wxPython. By now, I'm using a txt file opened in a frame. I would like to have hyperlinks in the help text in order to open other txt files in the same frame. However, I don't know how to do this. I don't even know if this is the most elegant way to implement a help menu. Any suggestion will be very useful.
Below you can find part of the code I'm using (you will need a txt file called "Help_Main_App.txt"):
import wx
class Help_Frame(wx.Frame):
title = "Help, I need somebody, help..."
def __init__(self):
wx.Frame.__init__(self, wx.GetApp().TopWindow, title=self.title, size=(450,500))
self.CreateStatusBar()
panel = wx.Panel(self, wx.ID_ANY)
panel.SetBackgroundColour('#ededed')
self.Centre()
vBox = wx.BoxSizer(wx.VERTICAL)
hBox = wx.BoxSizer(wx.HORIZONTAL)
self.textbox = wx.TextCtrl(panel, style=wx.TE_MULTILINE, size=(-1, 295))
hBox.Add(self.textbox, 1, flag=wx.EXPAND)
vBox.Add(hBox, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=10)
panel.SetSizer(hBox)
defaultdir, filename = './', 'Help_Main_App.txt'
self.filePath = '/'.join((defaultdir, filename))
self.textbox.LoadFile(self.filePath)
self.textbox.Disable()
class Main_Window(wx.Frame):
def __init__(self, parent, title):
#wx.Frame.__init__(self, parent, title = title, pos = (0, 0), size = wx.DisplaySize())
wx.Frame.__init__(self, parent, title=title, size=(1000,780))
self.Center()
# Setting up the menu.
filemenu = wx.Menu()
helpmenu = wx.Menu()
menuExit = filemenu.Append(wx.ID_EXIT,"&Exit"," Close window and exit program")
menuHelp = helpmenu.Append(wx.ID_HELP, "&Help"," Help of this program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
menuBar.Append(helpmenu,"&Help") # Adding the "helpmenu" to the MenuBar
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
# Set event handlers
self.Bind(wx.EVT_MENU, self.OnHelp, menuHelp)
self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
def OnHelp(self,e):
Help_Frame().Show()
def OnExit(self,e):
self.Close(True) # Close the frame.
def main():
app = wx.App(False)
frame = Main_Window(None, "Main App")
frame.Show()
app.MainLoop()
if __name__ == "__main__" :
main()
I recommend using an HTMLWindow for something simple like that. It can handle only simple HTML, so don't try to make a website with it as HTMLWindow doesn't support CSS or javascript.
I wrote a simple About box using it. You can read about it here:
http://www.blog.pythonlibrary.org/2008/06/11/wxpython-creating-an-about-box/
The basic idea is to subclass HTMLWindow and override its OnLinkClicked method. Then you can use Python's webbrowser to open the user's default browser. Or you can try using subprocess, although that will be a lot less likely to work unless you always know what is installed on your target machines.
Further to Mikes answer if you are able to use wxPython 2.9.4 or above you can consider using the more advanced html2 webview which does support CSS and javascript. Using this you could make the help as a simple website that can be viewed in program.
http://wxpython.org/Phoenix/docs/html/html2.WebView.html
Its also worth mentioning that if (for some strange reason) you don't want to work with you could achieve a similar outcome with a StyledTxtCtrl.
Late to the party but just for the sake of completeness (seeing that the OP's code was using wx.TextCtrl to show the help text), here is an example on how to add and launch hyperlinks using wx.TextCtrl (I have attached any explanations on the code comments):
class HelpDialog(wx.Dialog):
"""Help Dialog."""
def __init__(self, parent, title, style):
"""Init."""
wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY,
title=title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=style)
# We need the 'wx.TE_AUTO_URL' style set.
self.help = wx.TextCtrl(self, wx.ID_ANY, '', DPOS, DSIZE,
wx.TE_AUTO_URL|wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2|wx.TE_WORDWRAP)
# Events - this is the interesting part,
# we catch the mouse on hovering the hyperlink:
self.help.Bind(wx.EVT_TEXT_URL, self.openHlpUrl)
# Show dialog
self.ShowModal()
def openHlpUrl(self, event):
"""Open help URL."""
# We get the starting and ending points on
# the text stored in our ctrl from this event
# and we slice it:
url = self.help.GetValue()[event.GetURLStart():event.GetURLEnd()]
# We want to capture the left up mouse event
# when hovering on the hyperlink:
if event.MouseEvent.LeftDown():
# Let's be wxpythion native and launch the browser this way:
wx.LaunchDefaultBrowser(url)

Sizing a wx.TextCtrl widget?

I'm in the process of learning to use wxWidgets and Python, but I'm having some trouble figuring out how to size widgets within a frame.
I am under the impression that I can set the size of various widgets by giving them a custom size=(x,y) value when calling the constructor. This code is copied and pasted out of the examples for wxPython and I have added the value="example",pos=(0,0) and size=(100,100) values to the wx.TextCtrl() constructor, but when I run this program, the text control takes up the entirety of the 500x500 frame. I'm not sure why, and I'd appreciate any help you could give me to get it to work.
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(500,500))
self.control = wx.TextCtrl(self,-1,value="example",pos=(0,0),size=(100,100))
self.CreateStatusBar() # A Statusbar in the bottom of the window
# Setting up the menu.
filemenu= wx.Menu()
# wx.ID_ABOUT and wx.ID_EXIT are standard IDs provided by wxWidgets.
filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
filemenu.AppendSeparator()
filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
self.Show(True)
app = wx.App(False)
frame = MainWindow(None, "Sample editor")
app.MainLoop()
Please read the sizers overview in the manual to know about how to size widgets correctly.
As for your particular example, it's an exception due to the fact that wxFrame always resizes its only window to fill its entire client area -- just because this is what you almost always want. However typically this only window is a wxPanel which, in turn, contains other controls and uses sizers to position them.
TL;DR: You should never use absolute positioning, i.e. specifying positions in pixels.
For sure you need to read from this book: wxPython 2.8 Application Development Cookbook
Read -> Chapter 7: Window Layout and Design
In your code, add widgets holder: panel.
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(500,500))
panel = wx.Panel(self)
self.control = wx.TextCtrl(panel,-1,value="example",pos=(0,0),size=(100,100))
self.CreateStatusBar() # A Statusbar in the bottom of the window
# Setting up the menu.
filemenu= wx.Menu()
# wx.ID_ABOUT and wx.ID_EXIT are standard IDs provided by wxWidgets.
filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
filemenu.AppendSeparator()
filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
self.Show(True)
app = wx.App(False)
frame = MainWindow(None, "Sample editor")
app.MainLoop()

Bind event to wx.Menu() instead of to the menu item in wxPython

My problem can be easily defined with the following code:
self.Bind(wx.EVT_MENU_OPEN, self.OnAbout)
This will mean that when I click on any wx.Menu() in the MenuBar, the function 'onAbout()' is called. How do I bind this event to a specific wx.Menu() which is called wx.MenuAbout() ?
If you are feeling extra helpful, perhaps you could provide me with a link to the documentation for event handlers. I could find documentation for the event handler function but not for the actual event handlers (such as wx.EVT_MENU).
Similar question but I am not looking to bind a range of wx.Menu()'s to the event: Is it possible to bind an event against a menu instead of a menu item in wxPython?
Edit: Ideally, this is what I'd like to be able to do:
menuAbout = wx.Menu()
self.Bind(wx.EVT_MENU, self.OnAbout, id=menuAbout.GetId())
The result would be that any other items in the .menuBar() (such as: File, Edit, Tools) work as normal menu's, but 'About' works like a clickable link.
Using the wx.EVT_MENU_OPEN means that the File menu can be opened, then when the mouse hovers over 'about', the self.OnAbout function get's called which I only what to happen when the user clicks specifically on the 'About' menu.
Why don't you just bind to the menu items using EVT_MENU instead?
EVT_MENU_OPEN will fire as soon as any menu is opened. That being said, if that's what you really want, you can always do this:
Where you define your menu:
self.about_menu = wx.Menu() # or whatever inherited class you have
self.Bind(wx.EVT_MENU_OPEN, self.on_menu_open)
Then your callback:
def on_menu_open(self, event):
if event.GetMenu()==self.about_menu:
#do something
This works for me:
class myFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "my frame")
#give the Frame a menu bar
self.frame_menubar = wx.MenuBar()
fileMenu = wx.Menu()
self.frame_menubar.Append(fileMenu, "File")
self.rotMenu = wx.Menu()
self.frame_menubar.Append(self.rotMenu, "Rotate")
self.SetMenuBar(self.frame_menubar)
self.Bind(wx.EVT_MENU_OPEN, self.rot)
def rot(self, event):
if event.GetMenu() == self.rotMenu:
print 'rotate clicked'

Categories