I am new to this site and fairly new to Python. I am working on a program using wxPython for the GUI. This is being developed and will be used on Windows OS machines. The GUI uses a number of buttons that trigger different processes in my script. I decided to try using the AGW AquaButtons for visual interest. I am finding that an "AquaButton" with focus will not respond to pressing the "Enter" key while the standard "wx.Button" does. Below are examples (mostly borrowed from similar questions, thanks "Rolf of Saxony" and "Mike Driscoll") of the working and non-working code.
Is there a way to get an "AquaButton" (with Focus) have it's event triggered by the "Enter" key?
This works:
import wx
class Example(wx.Frame):
def __init__(self, parent, title):
frame = wx.Frame.__init__(self, parent, title=title, )
self.panel = wx.Panel(self, -1, size=(200,100))
self.btn1 = wx.Button(self.panel, label='Button 1', id=1)
self.btn1.SetForegroundColour("black")
self.btn2 = wx.Button(self.panel, label='Button 2', id=2)
self.btn2.SetForegroundColour("black")
self.sizer = wx.GridBagSizer(0, 0)
self.sizer.Add(self.btn1, pos=(0, 0), flag=wx.ALIGN_CENTER)
self.sizer.Add(self.btn2, pos=(1, 0), flag=wx.ALIGN_CENTER)
self.text_box = wx.StaticText(self.panel, style = wx.NO_BORDER)
self.text_box.SetFont(wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
self.text_box.SetForegroundColour((40,115,180))
self.sizer.Add(self.text_box, pos=(2,0), flag=wx.ALIGN_CENTER)
self.Bind(wx.EVT_BUTTON, self.button_press)
self.panel.SetSizer(self.sizer)
self.Show()
def button_press(self, event):
Id = event.GetId()
print ('Click Button',str(Id))
retVal = F"Click Button {Id}"
self.text_box.SetLabel(str(retVal))
class AppMenu(wx.App):
def OnInit(self):
'Create the main window and insert the custom frame'
frame = Example(None, 'Example')
frame.Show(True)
return True
app = AppMenu()
app.MainLoop()
This doesn't:
import wx
import wx.lib.agw.aquabutton as AB
class Example(wx.Frame):
def __init__(self, parent, title):
frame = wx.Frame.__init__(self, parent, title=title, )
self.panel = wx.Panel(self, -1, size=(200,100))
self.btn1 = AB.AquaButton(self.panel, label='Button 1', id=1)
self.btn1.SetForegroundColour("black")
self.btn2 = AB.AquaButton(self.panel, label='Button 2', id=2)
self.btn2.SetForegroundColour("black")
self.sizer = wx.GridBagSizer(0, 0)
self.sizer.Add(self.btn1, pos=(0, 0), flag=wx.ALIGN_CENTER)
self.sizer.Add(self.btn2, pos=(1, 0), flag=wx.ALIGN_CENTER)
self.text_box = wx.StaticText(self.panel, style = wx.NO_BORDER)
self.text_box.SetFont(wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
self.text_box.SetForegroundColour((40,115,180))
self.sizer.Add(self.text_box, pos=(2,0), flag=wx.ALIGN_CENTER)
self.Bind(wx.EVT_BUTTON, self.button_press)
self.panel.SetSizer(self.sizer)
self.Show()
def button_press(self, event):
Id = event.GetId()
print ('Click Button',str(Id))
retVal = F"Click Button {Id}"
self.text_box.SetLabel(str(retVal))
class AppMenu(wx.App):
def OnInit(self):
'Create the main window and insert the custom frame'
frame = Example(None, 'Example')
frame.Show(True)
return True
app = AppMenu()
app.MainLoop()
Bizarrely, the AquaButton is pressed using the Spacebar and not the Enter key.
Navigating appears to be via Arrow keys and/or Tab and Shift Tab.
If in doubt the source code is in:
your_python_location/dist-packages/wx/lib/agw/aquabutton.py
I hope that clears that up for you, if not for your users. :)
Related
I've just gotten into wxpython for Python 3.6 and I've hit a roadblock. I just can't work out how to make elements/widgets scale with the screen! I know you have to use sizers but that's about it, I'm still fairly new to programming so just reading the documentation didn't help. If someone could just sample some code that works I'd be very thankful as I could then read through it and work out what I was doing wrong. The code that draws out the GUI I want to scale with window size is below, the key idea is that the TextCtrl scales, other elements don't really need scaling.
def createGUI(self):
panel = wx.Panel(self)
menuBar = wx.MenuBar()
menuButton = wx.Menu()
newItem = wx.MenuItem(menuButton, wx.ID_NEW, 'New Note\tCtrl+N')
delItem = wx.MenuItem(menuButton, wx.ID_DELETE, 'Delete Note\tCtrl+Backspace')
saveItem = wx.MenuItem(menuButton, wx.ID_SAVE, 'Save\tCtrl+S')
exitItem = wx.MenuItem(menuButton, wx.ID_EXIT, 'Quit\tCtrl+Q')
menuButton.Append(newItem)
menuButton.Append(saveItem)
menuButton.Append(delItem)
menuButton.Append(exitItem)
menuBar.Append(menuButton, 'Menu')
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self.new, newItem)
self.Bind(wx.EVT_MENU, self.delete, delItem)
self.Bind(wx.EVT_MENU, self.save, saveItem)
self.Bind(wx.EVT_MENU, self.onExit, exitItem)
self.noteText = wx.TextCtrl(panel)
self.noteText.AppendText(self.notecontent)
self.Bind(wx.EVT_CLOSE, self.onExit)
self.SetTitle(f'Welcome {self.username}! You are working on {self.notepath}')
self.Centre()
self.Show(True)
To begin with it's best to equate sizers to something familiar and I usually think of storage boxes or a chest of drawers.
When we define widgets, they are all dumped into a container, the parent object, often the ubiquitous self or self.panel.
If we do not assign a size and pos to each item, it's just a jumbled mess, a pile of widgets.
The sizer, there are many types, are the virtual drawers in our chest of drawers, that herds this pile of widgets into order.
The widgets are assigned to the appropriate sizer, note sizers can go into other sizers, and eventually when everything has been assigned a place or drawer in our chest of drawers, the sizers do their magic, arranging and sizing all of widgets into a coherent screen for display or arranging the drawers contents and relative positions in the chest of drawers.
Below, I've used the simplest sizer a boxsizer.
One will arrange things vertically and the other horizontally.
The horizontal sizer is for the buttons and the vertical sizer, will be the main sizer, into which I place not only the TectCtrl but also the buttons, prearranged in their horizontal sizer.
For a better and more comprehensive description of sizers and their controls see: https://docs.wxpython.org/sizers_overview.html and for details on the actual sizers available see the detailed documenation on each.
A loose approximation of your code:
#!/usr/bin/python
import wx
class Example(wx.Frame):
def __init__(self, parent, title):
super(Example, self).__init__(parent, title=title,
size=(450, 350))
self.panel = wx.Panel(self, -1)
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.noteText = wx.TextCtrl(self.panel, -1, style=wx.TE_MULTILINE)
self.Button_close = wx.Button(self.panel, -1, label="Quit")
self.Button_1 = wx.Button(self.panel, -1, label="Btn1")
self.Button_2 = wx.Button(self.panel, -1, label="Btn2")
self.Bind(wx.EVT_CLOSE, self.onExit)
self.Button_close.Bind(wx.EVT_BUTTON, self.onExit)
self.Button_1.Bind(wx.EVT_BUTTON, self.onButton)
self.Button_2.Bind(wx.EVT_BUTTON, self.onButton)
# Place buttons within their own horizontal sizer
self.button_sizer.Add(self.Button_close,proportion=0, flag=wx.ALL, border=10)
self.button_sizer.Add(self.Button_1,proportion=0, flag=wx.ALL, border=10)
self.button_sizer.Add(self.Button_2,proportion=0, flag=wx.ALL, border=10)
# Add textctrl and the button sizer to the main sizer (vertical)
self.main_sizer.Add(self.noteText,proportion=1, flag=wx.EXPAND|wx.ALL, border=10)
self.main_sizer.Add(self.button_sizer, 0, 0, 0)
self.panel.SetSizer(self.main_sizer)
self.Show()
def onExit(self, event):
self.Destroy()
def onButton(self, event):
print("A button was pressed")
if __name__ == '__main__':
app = wx.App()
Example(None, title="Example")
app.MainLoop()
Edit:
Here's the same code without using sizers, although they are recommended.
#!/usr/bin/python
import wx
class Example(wx.Frame):
def __init__(self, parent, title):
super(Example, self).__init__(parent, title=title,
size=(450, 350))
self.panel = wx.Panel(self, -1)
self.noteText = wx.TextCtrl(self.panel, -1, pos=(10,10), size=(400,280), style=wx.TE_MULTILINE)
self.Button_close = wx.Button(self.panel, -1, label="Quit", pos=(10,290), size=(50,30))
self.Button_1 = wx.Button(self.panel, -1, label="Btn1", pos=(70,290), size=(50,30))
self.Button_2 = wx.Button(self.panel, -1, label="Btn2", pos=(130,290), size=(50,30))
self.Bind(wx.EVT_CLOSE, self.onExit)
self.Button_close.Bind(wx.EVT_BUTTON, self.onExit)
self.Button_1.Bind(wx.EVT_BUTTON, self.onButton)
self.Button_2.Bind(wx.EVT_BUTTON, self.onButton)
self.Show()
def onExit(self, event):
self.Destroy()
def onButton(self, event):
print("A button was pressed")
if __name__ == '__main__':
app = wx.App()
Example(None, title="Example")
app.MainLoop()
I'm trying to make a form that has several input fields. Underneath these fields I want to have a wxpython Ultimate List Control (for all intents and purposes it's the same thing as a List Control). My issue is with sizers. To give some context, my form looks like this
Name [TextCtrl]
Blah [TextCtrl]
ListControl
I want it to look like
Name [TextCtrl]
Blah [TextCtrl]
ListCtrl (this spans to the end of the row)
My problem is when I try to add the List Control. I want the list control to Stretch from The Static Text to the Text Control, but it pushes the TextControl over. Can someone please point me in the right direction? I have attached the relevant code below.
class UserField(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent=parent, title="Info", size=(350, 400),
style=wx.DEFAULT_FRAME_STYLE)
self.init_ui()
self.Center()
self.ShowModal()
def init_ui(self):
panel = wx.Panel(self, wx.ID_ANY)
hbox = wx.BoxSizer(wx.VERTICAL)
flex_grid = wx.FlexGridSizer(5, 2, 5, 10) # row, col, vgap, hgap
info_text = wx.StaticText(parent=panel, label="Enter information")
self.search_button = wx.Button(parent=panel, label="Search")
self.list_control = UltimateListCtrl(panel,
agwStyle=wx.LC_REPORT | wx.BORDER_SUNKEN | ULC_HAS_VARIABLE_ROW_HEIGHT, )
flex_grid.AddMany(
[
info_text, self.search_button
]
)
lbox = wx.BoxSizer(wx.HORIZONTAL)
lbox.Add(self.list_control
hbox.Add(flex_grid, wx.EXPAND|wx.ALL)
hbox.Add(lbox, proportion=1, flag=wx.ALL|wx.EXPAND)
panel.SetSizer(hbox)
Here's a quick demonstration of wx.GridBagSizer. The program opens a simple frame with a single button that spawns a dialog with a GridBagSizer. You can place items in the sizer according to a position (pos) and optionally allow a widget to span multiple rows and/or columns (span).
import wx
class Example(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.SetSize((300, 200))
self.Centre()
self.Show(True)
self.InitUI()
def InitUI(self):
panel = wx.Panel(self)
sizer = wx.BoxSizer()
btn = wx.Button(panel, label="Spawn Window")
btn.Bind(wx.EVT_BUTTON, self.spawn_window)
sizer.Add(btn)
panel.SetSizerAndFit(sizer)
def spawn_window(self, evt):
UserField(self)
def OnQuit(self, e):
self.Close()
class UserField(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent=parent, title="Info", size=(350, 400),
style=wx.DEFAULT_FRAME_STYLE)
self.init_ui()
self.Center()
self.ShowModal()
def init_ui(self):
panel = wx.Panel(self)
sizer = wx.GridBagSizer(10, 10)
field1Label = wx.StaticText(panel, label="Field 1")
field2Label = wx.StaticText(panel, label="Field 2")
field1Ctrl = wx.TextCtrl(panel)
field2Ctrl = wx.TextCtrl(panel)
listCtrl = wx.ListCtrl(panel)
sizer.Add(field1Label, pos=(0, 0))
sizer.Add(field2Label, pos=(1, 0))
sizer.Add(field1Ctrl, pos=(0, 1))
sizer.Add(field2Ctrl, pos=(1, 1))
# HERE'S THE IMPORTANT LINE. NOTE THE 'span' ARGUMENT:
sizer.Add(listCtrl, pos=(2, 0), span=(1, 2), flag=wx.EXPAND)
panel.SetSizerAndFit(sizer)
if __name__ == '__main__':
ex = wx.App()
mainFrame = Example(None)
ex.MainLoop()
I am trying to create a simple invoice program for a school project. I have the basic layout of my program.
The large text boxes on the left are for the invoice, and the ones on the right are for the price of that input.
I want the text boxes to return the input into them, and assign it to say JobOne. The next step is that I need these values to be send to a file in Notepad when the 'Send To Invoice' button is clicked.
I am really stuck here, I've tried so many different combinations of things, and I'm forever getting "TextCtrl" object is not callable.
Any help would be greatly appreciated.
I've taken out my messy attempts to get the problem working and stripped it down to its barebones.
import wx
class windowClass(wx.Frame):
def __init__(self, *args, **kwargs):
super(windowClass, self).__init__(*args, **kwargs)
self.basicGUI()
def basicGUI(self):
panel = wx.Panel(self)
self.SetSizeWH(1200, 800)
menuBar = wx.MenuBar()
fileButton = wx.Menu()
exitItem = fileButton.Append(wx.ID_EXIT, 'Exit', 'status msg...')
menuBar.Append(fileButton, 'File')
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self.Quit, exitItem)
yesNoBox = wx.MessageDialog(None, 'Do you wish to create a new invoice?',
'Create New Invoice?', wx.YES_NO)
yesNoAnswer = yesNoBox.ShowModal()
yesNoBox.Destroy()
nameBox = wx.TextEntryDialog(None, 'What is the name of the customer?', 'Customer Name'
, 'Customer Name')
if nameBox.ShowModal() ==wx.ID_OK:
CustomerName = nameBox.GetValue()
wx.TextCtrl(panel, pos=(10, 10), size=(500,100))
wx.TextCtrl(panel, pos=(550, 10), size=(60,20))
wx.TextCtrl(panel, pos=(10, 200), size=(500,100))
wx.TextCtrl(panel, pos=(550, 200), size=(60,20))
wx.TextCtrl(panel, pos=(10, 400), size=(500,100))
wx.TextCtrl(panel, pos=(550, 400), size=(60,20))
self.SetTitle('Invoice For ' +CustomerName)
SendToNotepadButton = wx.Button(panel, label='Convert to invoice',pos=(650, 600), size=(120, 80))
def SendToNotepad(e):
f = open("Notepad.exe", 'w')
f.write(())
call(["Notepad.exe", "CustomerInvoice"])
self.Bind(wx.EVT_BUTTON, SendToNotepad)
self.Show(True)
def Quit(self, e):
self.Close()
def main():
app = wx.App()
windowClass(None)
app.MainLoop()
main()
If you manage to help me, I thank you!
This is actually fairly easy. I skipped the MessageDialog stuff and just put together a proof of concept. This worked for me on my Windows 7 box with Python 2.7 and wxPython 3.0.2:
import subprocess
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
self.txt = wx.TextCtrl(self)
notepad_btn = wx.Button(self, label="Send to Invoice")
notepad_btn.Bind(wx.EVT_BUTTON, self.onSendInvoice)
my_sizer = wx.BoxSizer(wx.VERTICAL)
my_sizer.Add(self.txt, 0, wx.EXPAND|wx.ALL, 5)
my_sizer.Add(notepad_btn, 0, wx.CENTER|wx.ALL, 5)
self.SetSizer(my_sizer)
#----------------------------------------------------------------------
def onSendInvoice(self, event):
""""""
txt = self.txt.GetValue()
print txt
# write to file
with open("invoice.txt", 'w') as fobj:
fobj.write(txt)
# open Notepad
subprocess.Popen(['notepad.exe', 'invoice.txt'])
########################################################################
class MainWindow(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Jobs")
panel = MyPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MainWindow()
app.MainLoop()
Hopefully this code will help you see how to put it all together.
How would I add a link to my menu item in wxpython? What I want is when the user clicks the menu item it will go to my website. Is this even possible?
Thanks in advance!! Oh and I am fairly new to programming and to python so if you could dumb it down alittle that would be appreciated!! Thanks
THIS IS MY CODE:
import wx
class MainWindow(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Python Test App',size=(600,400))
panel=wx.Panel(self)
wx.Frame.CenterOnScreen(self)
self.SetBackgroundColour(wx.BLACK)
##MENU AND STATUS BAR
status=self.CreateStatusBar()
menubar=wx.MenuBar()
file_menu=wx.Menu()
help_menu=wx.Menu()
ID_FILE_NEW = 1
ID_FILE_EXIT = 2
ID_HELP_ABOUT = 3
ID_HELP_WEB = 4
file_menu.Append(ID_FILE_NEW,"New Window","This will open a new window")
file_menu.Append(ID_FILE_EXIT,"Exit","This will exit the program")
help_menu.Append(ID_HELP_ABOUT,"About","This will tell you about %name%")
help_menu.Append(ID_HELP_WEB,"Visit Website","This will take you to worm-media.host56.com")
menubar.Append(file_menu,"File")
menubar.Append(help_menu,"Help")
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.newWin, None, 1)
self.Bind(wx.EVT_MENU, self.close, None, 2)
self.Bind(wx.EVT_MENU, self.about, None, 3)
##self.Bind(wx.EVT_MENU, self.web, None, 4)
heading = wx.StaticText(panel, -1, 'Welcome to My App', (144,10))
heading.SetForegroundColour(wx.RED)
font1 = wx.Font(20, wx.DEFAULT, wx.NORMAL, wx.BOLD)
heading.SetFont(font1)
def newWin(self, event):
self.new = NewWindow(parent=None, id=-1)
self.new.Show()
def close(self, event):
box=wx.MessageDialog(None, 'Are you sure you want to exit?', 'Exit program?', wx.YES_NO)
answer=box.ShowModal()
if answer==wx.ID_YES:
self.Destroy()
def about(self, event):
self.new = AboutWindow(parent=None, id=-1)
self.new.Show()
##def web(self, event):
class NewWindow(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self, parent, id, 'New Window', size=(400,300))
wx.Frame.CenterOnScreen(self)
##panel2=wx.Panel(self)
name_text = wx.StaticText(self, -1, 'What is your name?')
name = wx.TextCtrl(self, -1, '', (100,0))
font2 = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
name_text.SetFont(font2)
class AboutWindow(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self, parent, id, 'About', size=(300,190))
wx.Frame.CenterOnScreen(self)
self.SetBackgroundColour(wx.WHITE)
about_bg = 'about_bg.jpg'
bmp1 = wx.Image(about_bg, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
self.bitmap1 = wx.StaticBitmap(self, -1, bmp1, (0,0))
##ABOUT_TEXT
by_text = wx.StaticText(self, -1, 'Made By: Worm', (50,70))
version_text = wx.StaticText(self, -1, 'Version: 1.0', (50,90))
website_text = wx.StaticText(self, -1, 'Website: worm-media.host56.com', (50,110))
##ABOUT_FONTS
by_font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
version_font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
website_font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
by_text.SetFont(by_font)
version_text.SetFont(version_font)
website_text.SetFont(website_font)
##ABOUT_COLORS
by_text.SetBackgroundColour(wx.WHITE)
version_text.SetBackgroundColour(wx.WHITE)
website_text.SetBackgroundColour(wx.WHITE)
##RUN##
if __name__=='__main__':
app=wx.PySimpleApp()
frame=MainWindow(parent=None,id=-1)
frame.Show()
app.MainLoop()
This is my code so far. I really haven't tried anything with this because I'm not even sure where to start. I tried looking how to do this online and came up empty. I guess all I'm asking is how to make a link in python to my website from the menu bar under about/Visit Website.
The functionality you want is actually built into Python. Check the webbrowser API. Specifically, look at the webbrowser.open() function.
In the event handler for the specific menu, you can use Python's own webbrowser,open() method. Or you can use subprocess to open a specific browser (assuming there's more than one installed). The latter would give you more control. There's also os.startfile(), but I'm not sure that would work in this case.
I have three panes with the InfoPane center option.
I want to know how to set their size.
Using this code:
import wx
import wx.aui
class MyFrame(wx.Frame):
def __init__(self, parent, id=-1, title='wx.aui Test',
pos=wx.DefaultPosition, size=(800, 600),
style=wx.DEFAULT_FRAME_STYLE):
wx.Frame.__init__(self, parent, id, title, pos, size, style)
self._mgr = wx.aui.AuiManager(self)
# create several text controls
text1 = wx.TextCtrl(self, -1, 'Pane 1 - sample text',
wx.DefaultPosition, wx.Size(200,150),
wx.NO_BORDER | wx.TE_MULTILINE)
text2 = wx.TextCtrl(self, -1, 'Pane 2 - sample text',
wx.DefaultPosition, wx.Size(200,150),
wx.NO_BORDER | wx.TE_MULTILINE)
text3 = wx.TextCtrl(self, -1, 'Main content window',
wx.DefaultPosition, wx.Size(200,150),
wx.NO_BORDER | wx.TE_MULTILINE)
# add the panes to the manager
self._mgr.AddPane(text1, wx.CENTER)
self._mgr.AddPane(text2, wx.CENTER)
self._mgr.AddPane(text3, wx.CENTER)
# tell the manager to 'commit' all the changes just made
self._mgr.Update()
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, event):
# deinitialize the frame manager
self._mgr.UnInit()
# delete the frame
self.Destroy()
app = wx.App()
frame = MyFrame(None)
frame.Show()
app.MainLoop()
I want to know what is called when we change the size of the panes.
If you tell me that, I can do the rest by myself :)
I've discovered what I want.
It was the wx.aui.AuiPaneInfo.dock_proportion property :)