Code Layout guide for multiple frames in wxpython - python

EDITED ~ Now with code.
I’m new to coding, and struggling getting variables input into ‘frameA’ output into ‘frameB’. My question is, how should the layout of the code be written so that a variable entered into FrameA is usable, (and refreshed on user input - either on a button click or deselecting textctrl etc-) in frameB?
I’m using wxpython, and using Wx builder as a guide, but writing the actual UI code used myself to help understand what’s going on underneath. I’ve tried class -> def -> frame UI and the frames are organised as I want them, show and hide as I want and the variables I want are printable on entry/button clicks etc within that frame, but are not accessible from outside of that frame, even though I am returning the variables needed.
In this example I want to take what is written in frameA's textctrl, and save it as a variable accessible (and updated) to other classes, in this case FrameB.
import wx
var = "This Should change to whatever is typed in FrameA"
class FrameA ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = (0,0), size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
self.INPUT = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.INPUT, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
self.SetSizer( bSizer1 )
self.INPUT.Bind( wx.EVT_TEXT, self.InputUpdate)
def InputUpdate(self, Evt):
var = self.INPUT.GetValue()
#print (var)
return var
class FrameB ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = (100,100), size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
self.OUTPUT = wx.StaticText( self, wx.ID_ANY, var, wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer2.Add( self.OUTPUT, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
self.SetSizer( bSizer2 )
if __name__ == '__main__':
app = wx.App()
frmA = FrameA(None)
frmB = FrameB(None)
frmA.Centre()
frmB.Centre()
frmA.Show()
frmB.Show()
app.MainLoop()
As I’m still new I am at the point where I can understand each single line of code, but the larger organisation is still getting messy for me.
My understanding is that the code in its state above the edited 'var' can be accessed from within frameA only, and 'return var' might(?) update the 'global' var, but is not being refreshed into frameB. What am I missing? I've been trying to avoid using global variables as I've heard they're a bad habit to get into this early on...
Thanks, Sundown

If you want the value of var to be accessible to all classes then you need to add the line global var to the method InputUpdate() in Class FrameA before assigning the new value to var.
However, this will make var accessible to all classes in this module, only. If you split the code into two files, then you will have two modules and var will be accessible only in the module that defines it, unless you also import the module defining var in the other module.
Code with some relevant comments:
import wx
var = "This Should change to whatever is typed in FrameA"
class FrameA ( wx.Frame ):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=(0,0), size=(500,300), style=wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
bSizer1 = wx.BoxSizer(wx.HORIZONTAL)
self.INPUT = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
bSizer1.Add(self.INPUT, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
self.SetSizer(bSizer1)
self.INPUT.Bind(wx.EVT_TEXT, self.InputUpdate)
def InputUpdate(self, Evt):
#### You need to add the following line before assigning the new value to
#### var in order to modify the global var variable and not the local
#### var variable
global var
var = self.INPUT.GetValue()
#print (var)
#### The try/except block is placed to avoid having an error if the text
#### in frameA changes but frameB does not exist anymore. The code inside
#### the try statement changes the text in frameB in real time.
try:
frmB.OUTPUT.SetLabel(var)
except Exception:
pass
class FrameB ( wx.Frame ):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=(100,100), size=(500,300), style=wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
bSizer2 = wx.BoxSizer(wx.VERTICAL)
self.OUTPUT = wx.StaticText(self, wx.ID_ANY, var, wx.DefaultPosition, wx.DefaultSize, 0)
bSizer2.Add(self.OUTPUT, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
#### Button to check the value of the global var variable and make sure
#### that the code in InputUpdate actually changes the value of the global
#### variable var
self.button = wx.Button(self, wx.ID_ANY, label='Var Value')
bSizer2.Add(self.button, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
self.SetSizer(bSizer2)
self.button.Bind(wx.EVT_BUTTON, self.varValue)
def varValue(self, event):
#### Print the value of the global variable var
print(var)
if __name__ == '__main__':
app = wx.App()
frmA = FrameA(None)
frmB = FrameB(None)
frmA.Centre()
frmB.Centre()
frmA.Show()
frmB.Show()
app.MainLoop()

Related

wxpython : How to AppendText one by one (as any key pressed)

In this code, I have a wx TextCtrl to show information (info_window), and a function print_info() to receive texts from my main script, append them to TextCtrl. The texts are appended at the same time, but I need them to be appended like this:
hello 1
-press any key
hello 2
-press any key
hello 3
Is there any way to append the strings one by one after pressing any key by keyboard?
I suppose the key should be the function press_any_key(). It may associated with any type of wx event, but I don't know how to write the function properly.
import wx
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size(500,300), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)
bSizer1 = wx.BoxSizer(wx.VERTICAL)
self.info_window = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size(450,250), wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2)
bSizer1.Add(self.info_window, 0, wx.ALL, 5)
self.SetSizer(bSizer1)
self.Layout()
def print_info(self, string):
self.string = string + '\n'
self.info_window.AppendText(self.string)
self.press_any_key()
def press_any_key(self):
pass
def main():
frame.print_info('hello 1')
frame.print_info('hello 2')
frame.print_info('hello 3')
app = wx.App()
frame = Frame(None)
frame.Show()
main()
app.MainLoop()
Thanks Rolf of Saxony. I solved my problem, the key point is wx.Yield(). I modified the code as below
import wx
import time
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size(500,300), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)
bSizer1 = wx.BoxSizer(wx.VERTICAL)
self.info_window = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size(450,250), wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2)
bSizer1.Add(self.info_window, 0, wx.ALL, 5)
self.info_window.Bind(wx.EVT_KEY_DOWN, self.go)
self.SetSizer(bSizer1)
self.Layout()
self.go_status = False
def print_info(self, string):
self.waitkey()
self.string = string + '\n'
self.info_window.AppendText(self.string)
self.go_status = False
def go(self, event):
self.go_status = True
def waitkey(self):
while self.go_status == False:
wx.Yield()
time.sleep(0.1)
def main():
frame.print_info('hello 1')
frame.print_info('hello 2')
frame.print_info('hello 3')
app = wx.App()
frame = Frame(None)
frame.Show()
main()
app.MainLoop()
It's not pretty but I couldn't think of a easier way to do it.
import wx
import time
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size(500,360), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
self.SetSizeHints(500,360)
bSizer1 = wx.BoxSizer(wx.VERTICAL)
self.info_window = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size(450,250), wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2)
self.message = wx.StaticText(self,-1,("Press any key"))
self.keyinput = wx.TextCtrl(self,-1)
bSizer1.Add(self.info_window, 0, wx.ALL, 5)
bSizer1.Add(self.message, 0, wx.ALL, 5)
bSizer1.Add(self.keyinput, 0, wx.ALL, 5)
self.SetSizer(bSizer1)
self.Layout()
self.Show()
self.keyinput.SetFocus()
def print_info(self, string):
self.WaitOnKey()
self.string = string + '\n'
self.info_window.AppendText(self.string)
def WaitOnKey(self):
while self.keyinput.GetValue() == "":
wx.Yield()
time.sleep(0.2)
self.keyinput.SetValue("")
def main():
frame.print_info('hello 1')
frame.print_info('hello 2')
frame.print_info('hello 3')
app = wx.App()
frame = Frame(None)
main()
app.MainLoop()
The code is self explanatory with the exception of wx.Yield(). This returns control back to the MainLoop which means that the program doesn't freeze. Essentially while the program waits for key input, control is passed back to the main loop every 2/10ths of a second, to see if anything else is going on. This allows the program to continue to perform normally.
Note: This will not work with function keys. For that I think you would have to find a way to bind to a key event and use event.GetKeyCode()

WxPython GUI programming - NameError: name "self" is not defined

I'm creating a program to edit a .txt file.
I have 2 files inside a folder:
gui.py & edit_text.py
Here's the code for gui.py
# -*- coding: utf-8 -*-
import wx
import wx.xrc
class Main ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Editor MAVB", pos = wx.DefaultPosition, size = wx.Size( 250,180 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.Size( 250,180 ), wx.Size( 250,180 ) )
layout_sizer = wx.BoxSizer( wx.VERTICAL )
self.text1 = wx.StaticText( self, wx.ID_ANY, u"Escolha o arquivo que será editado:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.text1.Wrap( -1 )
layout_sizer.Add( self.text1, 1, wx.ALL|wx.EXPAND, 5 )
self.filePicker = wx.FilePickerCtrl( self, wx.ID_ANY, wx.EmptyString, u"Selecione um arquivo", u"*.txt", wx.DefaultPosition, wx.Size( 210,-1 ), wx.FLP_DEFAULT_STYLE|wx.FLP_FILE_MUST_EXIST|wx.FLP_SMALL )
layout_sizer.Add( self.filePicker, 0, wx.ALL|wx.EXPAND, 5 )
self.null_text = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
self.null_text.Wrap( -1 )
layout_sizer.Add( self.null_text, 0, wx.ALL, 5 )
self.edit_button = wx.Button( self, wx.ID_ANY, u"Alterar arquivo", wx.DefaultPosition, wx.DefaultSize, 0 )
layout_sizer.Add( self.edit_button, 0, wx.ALL, 5 )
self.status_text = wx.StaticText( self, wx.ID_ANY, u"Aguardando arquivo...", wx.DefaultPosition, wx.DefaultSize, 0 )
self.status_text.Wrap( -1 )
layout_sizer.Add( self.status_text, 0, wx.ALL|wx.EXPAND, 5 )
self.SetSizer( layout_sizer )
self.Layout()
self.Centre( wx.BOTH )
# Connect Events
self.edit_button.Bind( wx.EVT_BUTTON, self.editar_txt )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def editar_txt( self, event ):
event.Skip()
And here is the code for edit_txt.py
# -*- coding: utf-8 -*-
import gui
import wx
class MyFrame(gui.Main):
def __init__(self, parent):
gui.Main.__init__(self, parent)
infile = self.filePicker.GetTextCtrlValue()
outfile_path = infile[:len(infile)-4] + "_editado.txt"
def editar_txt(self, infile):
outfile = []
with open(infile) as f:
for line in f:
line_ed = line.replace("|VENDAS|0|", "|VENDAS|2|")
outfile.append(line_ed)
with open(outfile_path, "w") as g:
for line in outfile:
g.write(line)
f.close()
g.close()
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None)
self.SetTopWindow(self.frame)
self.frame.Show(True)
print("\n----------------------------------------\nEditor MAVB - inicializado com sucesso. \n----------------------------------------")
return True
if __name__ == "__main__":
app = MyApp(redirect=False)
app.MainLoop()
When I enter into the program folder and run edit_txt.py, I got the following error:
Error in line
infile = self.filePicker.GetTextCtrlValue()
NameError: name 'self' is not defined
I've created a Main class in gui.py
Imported gui.py script into edit_txt.py
Created a inherited MyFrame class from the gui.Main class
Initialized MyFrame class as soon as I open the program
Then I tried to get the infile path using the command: infile = self.filePicker.GetTextCtrlValue()
Questions:
Why isn't this working?
How can I make it work?
You are trying to access an instance property inherited from gui.Main as a class property. Generally speaking, you are trying to statically access a non-static property.
If you define infile and outfile_path as instance properties for MyFrame, you can then access them with self.Property.
(Please note that this way you need to change references to the editar_txt method where it is referenced, because the argument is no longer necessary.)
Below the modified MyFrame class in edit_txt.py :
class MyFrame(gui.Main):
def __init__(self, parent):
gui.Main.__init__(self, parent)
self.infile = self.filePicker.GetTextCtrlValue()
self.outfile_path = self.infile[:len(self.infile)-4] + "_editado.txt"
def editar_txt(self):
outfile = []
with open(self.infile) as f:
for line in f:
line_ed = line.replace("|VENDAS|0|", "|VENDAS|2|")
outfile.append(line_ed)
with open(self.outfile_path, "w") as g:
for line in outfile:
g.write(line)
f.close()
g.close()
Why isn't it working? Because the following line:
infile = self.filePicker.GetTextCtrlValue()
is outside any function, and is in the class definition. It is trying to execute this line as the class is being defined to create an infile attribute on the class, and as self is not defined at this time, it complains about self not being defined.
How can you make it work? Presumably, you intended that line and the one after it to be in your __init__() method. Indent them accordingly.

How to programmatically generate an event in wxPython

I have a wxPython gui and I want to programmatically generate an event.
I've tried a syntax like this:
e = wx.Event.__init__(grid, eventType=wx.EVT_LEFT_DOWN)
which results in:
TypeError: unbound method __init__() must be called with Event instance as first argument (got Grid instance instead)
or:
e = wx.CommandEvent(commandType=wx.EVT_BUTTON)
TypeError: in method 'new_CommandEvent', expected argument 1 of type 'wxEventType'
So question is simply, what is the exact, literal syntax that I need to use to create an event object? Or, can someone point me to a good resource for making sense of events? I don't know if I'm just missing something simple in my understanding. I haven't been able to find a direct answer to this question yet online. I checked out this question: Generate a custom CommandEvent in wxPython , but I don't want to make a custom event.
Thanks in advance!
You would want to use wx.PostEvent
To programatically generate an event:
wx.PostEvent(self.GetEventHandler(), wx.PyCommandEvent(wx.EVT_BUTTON.typeId, self.GetId()))
if you want to post a wx.EVT_BUTTON event. Making it a PyCommandEvent means it will propagate upwards; other event types don't propagate by default.
The general form of wx.PostEvent(): http://www.wxpython.org/docs/api/wx-module.html#PostEvent
Here's a small example code:
import wx
class MyFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Test", pos = wx.DefaultPosition, size = wx.Size( 200,200 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
sizer_inside = wx.BoxSizer( wx.VERTICAL )
# Adding a button and a textCtrl widget
self.button = wx.Button( self, wx.ID_ANY, u"Click Me", wx.DefaultPosition, wx.DefaultSize, 0 )
sizer_inside.Add( self.button, 0, wx.ALIGN_CENTER|wx.ALL, 5 )
self.textCtrl = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_NO_VSCROLL )
sizer_inside.Add( self.textCtrl, 0, wx.ALIGN_CENTER|wx.ALL, 5 )
self.SetSizer( sizer_inside )
self.Layout()
self.Centre( wx.BOTH )
self.Show()
self.counter = 0
# Binding Events
self.Bind( wx.EVT_BUTTON, self.on_click )
self.Bind( wx.EVT_CHOICE, self.test_dummy)
#Event handlers
def on_click( self, event ):
self.counter += 1
wx.PostEvent(self.GetEventHandler(), wx.PyCommandEvent(wx.EVT_CHOICE.typeId, self.GetId()))
def test_dummy(self, event):
self.counter += 1
self.textCtrl.SetValue(str(self.counter))
if __name__ == "__main__":
app = wx.App(False)
MyFrame(None)
app.MainLoop()
If you run this, notice that the textCtrl will display 2 after clicking the button. The first event handler manually fires the second event which is handled by test_dummy.
I think you'd better using win32gui.PostMessage().
This would help you.
http://markmail.org/message/epiclzlaph44f3kk
Use wx.PostEvent... like so:
class launcherWindow(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title='New Window')
#now add the main body, start with a panel
panel = wx.Panel(self)
#instantiate a new dropdown
self.productDropDown = wx.ComboBox(panel, size=wx.DefaultSize, style = wx.CB_READONLY)
#get the products and product subtypes
self.productDict = self.getProductsAndSubtypes()
#setup subtypes first, just in case, since onProductSelection will reference this
self.productSubtypeDropDown = wx.ComboBox(panel, size=wx.DefaultSize, style = wx.CB_READONLY)
#add products
for product in self.productDict.keys():
self.productDropDown.Append(product)
#bind selection event
self.productDropDown.Bind(wx.EVT_COMBOBOX, self.onProductSelection)
#set default selection
self.productDropDown.SetSelection(0)
#pretend that we clicked the product selection, so it's event gets called
wx.PostEvent(self.productDropDown, wx.CommandEvent(wx.wxEVT_COMMAND_COMBOBOX_SELECTED))
#now add the dropdown to a sizer, set the sizer for the panel, fit the panel, etc...
def onProductSelection(self, event):
productSelected = self.productDropDown.GetStringSelection()
productSubtypes = self.productDict[productSelected]
#clear any existing product subtypes, since each product may have different ones
self.productSubtypeDropDown.Clear()
for productSubtype in productSubtypes:
self.productSubtypeDropDown.Append(productSubtype)
#select the first item by default
self.productSubtypeDropDown.SetSelection(0)
thanks. #i5on9i comment saved me.
I was trying to call the Next button on WxPython under Windows.
When I did try to use a pythonic event my wizard would just end without going through the pages as if I pressed the "Finish" button even though it was not visible on the page.
If I understand correctly, since this is a Windows class (and not a pythonic class) I could not use a pythonic event. I therefore had to call the windows event.
Perhaps a different strategy would have been to switch from a windows Wizard class to a pythonic wizard class but I didn't try it.
BTW the message I ended up sending was:
win32gui.PostMessage(wizard.GetHandle(),0x0111,wx.ID_FORWARD,self.wizard.FindWindowById(wx.ID_FORWARD).GetHandle())

How to make text fit in cells in a wxPython grid?

Basically if I drag a cell I can size it to whatever size I want. Is there functionality in wxPython where cells expand automatically to fit the size of the text inside of them?
The Grid class has AutoSizeColumn/AutoSizeRow and AutoSizeColumns/AutoSizeRows methods that do a fairly good job of generically resizing rows or cols to be large enough for the contents of the row or col. They can be fairly expensive operations for large grids however, so they should be used with care.
One way to do it would be to catch any data entry into the cell event, get the size of the entered data, check if its greater than the column size -> if yes then set the text width as the column size.
Here's an example code I wrote:
import wx.grid
import wx
class Frame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Test", pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
sizer_main = wx.BoxSizer( wx.VERTICAL )
self.panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
sizer_inner = wx.BoxSizer( wx.VERTICAL )
self.grid = wx.grid.Grid( self.panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
# Grid
self.grid.CreateGrid( 5, 5 )
self.grid.EnableEditing( True )
self.grid.EnableGridLines( True )
self.grid.SetGridLineColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BACKGROUND ) )
self.grid.EnableDragGridSize( False )
self.grid.SetMargins( 0, 0 )
# Columns
self.grid.EnableDragColMove( False )
self.grid.EnableDragColSize( True )
self.grid.SetColLabelSize( 30 )
self.grid.SetColLabelAlignment( wx.ALIGN_CENTRE, wx.ALIGN_CENTRE )
# Rows
self.grid.EnableDragRowSize( True )
self.grid.SetRowLabelSize( 80 )
self.grid.SetRowLabelAlignment( wx.ALIGN_CENTRE, wx.ALIGN_CENTRE )
# Label Appearance
# Cell Defaults
self.grid.SetDefaultCellAlignment( wx.ALIGN_LEFT, wx.ALIGN_TOP )
sizer_inner.Add( self.grid, 1, wx.ALL, 0 )
self.panel.SetSizer( sizer_inner )
self.panel.Layout()
sizer_inner.Fit( self.panel )
sizer_main.Add( self.panel, 1, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( sizer_main )
self.Layout()
self.Centre( wx.BOTH )
self.Show()
# Connect Events
self.grid.Bind( wx.grid.EVT_GRID_CELL_CHANGE, self.on_edit )
# Some essential stuff for resizing
font = wx.Font(pointSize = 10, family = wx.DEFAULT, style = wx.NORMAL, weight = wx.NORMAL, faceName = 'Consolas')
self.dc = wx.ScreenDC()
self.dc.SetFont(font)
def on_edit( self, event ):
row = event.GetRow()
col = event.GetCol()
size = self.dc.GetTextExtent(self.grid.GetCellValue(row, col))
if size[0] > self.grid.GetColSize(col): self.grid.SetColSize(col, size[0])
self.panel.Layout()
if __name__ == "__main__":
app = wx.App()
Frame(None)
app.MainLoop()
The self.panel.Layout() is probably not needed.
You might be able to use wxPython's wordwrap module or a custom renderer or a combination of the two. This other Stack Answer actually uses both:
Auto wrap and newlines in wxPython grid
Looking at the source code in the wxPython demo leads me to believe that you can probably do this with just wordwrap as the examples in GridStdEdRend.py are just using strings that are enclosed with triple quotes. You might want to take a look at that as well.

wxpython - One Frame, Multiple Panels, Modularized Code

I'm working on a fairly large GUI project and am thus using wxpython to build it. I have one frame, multiple frames with their own functions and a main file that imports the gui components as well as other, external functions. I've decided to keep the gui/wxpython code different to better modularize the code.
The main question I have is how to execute the functions in the separate panels and how to make them work from my main python file.
Below is a sample of my wxpython code:
import wx
class MainFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 800,600 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.SetSizer( bSizer1 )
self.Layout()
self.panelOne = panel_one(self)
self.panelTwo = panel_two(self)
self.panelTwo.Hide()
self.Centre( wx.BOTH )
def __del__( self ):
pass
class panel_one ( wx.Panel ):
def __init__( self, parent ):
wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( 800,600 ), style = wx.TAB_TRAVERSAL )
bSizer5 = wx.BoxSizer( wx.VERTICAL )
self.m_button2 = wx.Button( self, wx.ID_ANY, u"MyButton", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer5.Add( self.m_button2, 0, wx.ALL, 5 )
self.SetSizer( bSizer5 )
self.Layout()
# Connect Events
self.m_button2.Bind( wx.EVT_BUTTON, self.changeIntroPanel )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def changeIntroPanel( self, event ):
event.Skip()
class panel_two ( wx.Panel ):
def __init__( self, parent ):
wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( 800,600 ), style = wx.TAB_TRAVERSAL )
... some code in here ...
def __del__( self ):
pass
So those are my gui components. Then, in my main file, I import it and run the gui:
import gui
class MainApp(gui.MainFrame):
def __init__(self, parent):
gui.MainFrame.__init__(self, parent)
self.panelOne = Panel1(self)
self.panelTwo = Panel2(self)
self.panelTwo.Hide()
class Panel1(gui.panel_one):
def __init__(self, parent):
gui.panel_one.__init__(self, parent)
def changeIntroPanel( self, event ):
if self.panelOne.IsShown():
self.SetTitle("Panel Two Showing")
self.PanelOne.Hide()
self.PanelTwo.Show()
else:
self.SetTitle("Panel One Showing")
self.PanelOne.Show()
self.PanelTwo.Hide()
self.Layout()
class Panel2(gui.panel_two):
def __init__(self, parent):
gui.panel_two.__init__(self, parent)
def main():
app = wx.App()
window = MainApp(None)
window.Show(True)
app.MainLoop()
if __name__ == '__main__':
main()
As you can tell, the idea is that I want to do all my implementation in my main file. How would I go about defining the functionality of my changeIntroPanel function that was first defined in panel_one? For now, the idea is to hide panelOne and show panelTwo.
I have done something similar before, but only with one frame. In that case, it was trivial since all the functions are in the MainFrame class to begin with. In that case, the code I posted would work perfectly.
Any help is appreciated. Thank you.
def OnInit(self, parent): is used for wx.App, you need def _ _init_ _(self, parent) instead.
About __init__ please check: Using inheritance in python
About difference between __init__ and OnInit please check this link
Edit:
gui.py
import wx
class MainFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 800,600 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.SetSizer( bSizer1 )
self.Layout()
# self.panelOne = panel_one(self)
# self.panelTwo = panel_two(self)
# self.panelTwo.Hide()
self.Centre( wx.BOTH )
def __del__( self ):
pass
class panel_one ( wx.Panel ):
def __init__( self, parent ):
wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( 800,600 ), style = wx.TAB_TRAVERSAL )
bSizer5 = wx.BoxSizer( wx.VERTICAL )
self.m_button2 = wx.Button( self, wx.ID_ANY, u"panel 1 button", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer5.Add( self.m_button2, 0, wx.ALL, 5 )
self.SetSizer( bSizer5 )
self.Layout()
# Connect Events
self.m_button2.Bind( wx.EVT_BUTTON, self.changeIntroPanel )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def changeIntroPanel( self, event ):
event.Skip()
class panel_two ( wx.Panel ):
def __init__( self, parent ):
wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( 800,600 ), style = wx.TAB_TRAVERSAL )
bSizer5 = wx.BoxSizer( wx.VERTICAL )
self.m_button2 = wx.Button( self, wx.ID_ANY, u"panel 2 button ", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer5.Add( self.m_button2, 0, wx.ALL, 5 )
self.SetSizer( bSizer5 )
self.Layout()
# Connect Events
self.m_button2.Bind( wx.EVT_BUTTON, self.changeIntroPanel )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def changeIntroPanel( self, event ):
event.Skip()
mainapp.py
import wx
import gui
class MainApp(gui.MainFrame):
def __init__(self, parent):
gui.MainFrame.__init__(self, parent)
self.panelOne = Panel1(self)
self.panelTwo = Panel2(self)
self.panelTwo.Hide()
class Panel1(gui.panel_one):
def __init__(self, parent):
gui.panel_one.__init__(self, parent)
self.parent = parent
def changeIntroPanel( self, event ):
if self.IsShown():
self.parent.SetTitle("Panel Two Showing")
self.Hide()
self.parent.panelTwo.Show()
class Panel2(gui.panel_two):
def __init__(self, parent):
gui.panel_two.__init__(self, parent)
self.parent = parent
def changeIntroPanel( self, event ):
if self.IsShown():
self.parent.SetTitle("Panel One Showing")
self.parent.panelOne.Show()
self.Hide()
def main():
app = wx.App()
window = MainApp(None)
window.Show(True)
app.MainLoop()
if __name__ == '__main__':
main()

Categories