Passing a tuple between two Panels in wxPython - python

I am trying to pass the tuple of the the checked strings in one panel to the textCtrl widget in another panel. I thought that if I polled the panel class containing the checklistbox widget for the checked boxes and set that equal to an attribute of the panel class containing the TextCtrl widget I could do things in the TextCtrl widget based on the boxes that are checked
I also tried using pubsub but I was having difficulty and wasn't sure if this was the case that you would use it or not.
As a disclaimer I am new to object oriented programming and python. I am making progress in learning object oriented programming but there are still things that are a bit fuzzy for me.
Here is my code:
#! /usr/bin/python
# Trying to do things in a separate panel based on
# events that happen in another panel
import wx
# ----- Functions
# ----- Classes
class chkbxPanel(wx.Panel):
# This class defines the panel that will
# contain the checkbox
def __init__(self, parent):
wx.Panel.__init__(self,parent=parent, id=-1)
# Widgets
List = ['one','two','three']
Prompt = 'Please Make a Choice'
self.ChkBx = wx.CheckListBox(self,id=-1,choices=List,size=(-1,200))
self.PromptChkBx = wx.StaticText(self,id=-1,label=Prompt)
# Page Sizers
self.panel_vertSizer=wx.BoxSizer(wx.VERTICAL)
self.panel_vertSizer.Add(self.PromptChkBx,proportion=0,flag=wx.ALIGN_LEFT)
self.panel_vertSizer.Add(self.ChkBx,proportion=0,flag=wx.ALIGN_LEFT)
# Invoke Sizer
self.SetSizer(self.panel_vertSizer)
# Make 'self' (the panel) shrink to the minimum size
# required by the controls
self.Fit()
# end __init__
# ----- Functions
class resultsPanel(wx.Panel):
# This class define the panel that will
# contain the textctrl
def __init__ (self,parent):
wx.Panel.__init__(self,parent=parent,id=-1)
# Widgets
ResultsPanelTitle = 'Results:'
self.ResultsTitle = wx.StaticText(self, id=-1, label= ResultsPanelTitle)
self.Results = wx.TextCtrl(self, id=-1,size=(300,500),style=(wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP))
self.CheckedBxs = ()
lenofcb = len(self.CheckedBxs)
typeofcb = type(self.CheckedBxs)
self.Results.AppendText('How Many Boxes are Checkd:\n')
self.Results.AppendText(str(lenofcb)+'\n')
self.Results.AppendText(str(typeofcb)+'\n')
# Page Sizer
self.panel_vertSizer = wx.BoxSizer(wx.VERTICAL)
self.panel_vertSizer.Add(self.ResultsTitle,proportion=0, flag=wx.ALIGN_LEFT)
self.panel_vertSizer.Add(self.Results, proportion=0, flag=wx.ALIGN_LEFT)
# Invoke Sizer
self.SetSizer(self.panel_vertSizer)
# Make 'self' (the panel) shrink to the minimum size
# required by the controls
self.Fit()
# end __init__
# ----- Functions
# ----- Main Frame
class MainFrame(wx.Frame):
# A 2-Control Class With BoxSizers
def __init__(self):
# Configure the Figure
titleText = 'Wx Question'
wx.Frame.__init__( self, None, title=titleText
,size=(600,300), style=wx.DEFAULT_FRAME_STYLE)
# First Frame Control automatically expands to the
# Frame's client size
frame_panel = wx.Panel(self)
# Create the Controls
LeftPanel = chkbxPanel(frame_panel)
RightPanel = resultsPanel(frame_panel)
RightPanel.CheckedBxs = LeftPanel.ChkBx.GetCheckedStrings()
RightPanel.CheckedBxs = ('one','two')
# Create Sizers and add the controls
panelCtrls_horzSizer = wx.BoxSizer(wx.HORIZONTAL)
panelCtrls_horzSizer.Add(LeftPanel)
panelCtrls_horzSizer.Add(RightPanel)
framePanel_vertSizer = wx.BoxSizer(wx.VERTICAL)
framePanel_vertSizer.Add(panelCtrls_horzSizer)
frame_panel.SetSizer(framePanel_vertSizer)
frame_panel.Fit()
self.SetSize((600,600))
# Main if statement
if __name__ == '__main__':
app = wx.PySimpleApp(redirect=False)
appFrame = MainFrame().Show()
app.MainLoop()
Thank you for any help

You could do your event binding in the parent class as it has access to both panels
#! /usr/bin/python
# Trying to do things in a separate panel based on
# events that happen in another panel
import wx
# ----- Functions
# ----- Classes
class ChkbxPanel(wx.Panel):
# This class defines the panel that will
# contain the checkbox
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent, id=-1)
# Widgets
choices = ['one', 'two', 'three']
prompt = 'Please Make a Choice'
self.chkBx = wx.CheckListBox(self, choices=choices, size=(-1, 200))
self.PromptChkBx = wx.StaticText(self, label=prompt)
# Page Sizers
self.panel_vertSizer = wx.BoxSizer(wx.VERTICAL)
self.panel_vertSizer.Add(self.PromptChkBx, proportion=0,
flag=wx.ALIGN_LEFT)
self.panel_vertSizer.Add(self.chkBx, proportion=0, flag=wx.ALIGN_LEFT)
# Invoke Sizer
self.SetSizer(self.panel_vertSizer)
# Make 'self' (the panel) shrink to the minimum size
# required by the controls
self.Fit()
# end __init__
# ----- Functions
class ResultsPanel(wx.Panel):
# This class define the panel that will
# contain the textctrl
def __init__ (self, parent):
wx.Panel.__init__(self, parent=parent, id=-1)
# Widgets
resultsPanelTitle = 'Results:'
self.resultsTitle = wx.StaticText(self, label=resultsPanelTitle)
self.results = wx.TextCtrl(self, size=(300, 500),
style=(wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP))
self.CheckedBxs = ()
lenofcb = len(self.CheckedBxs)
typeofcb = type(self.CheckedBxs)
self.results.AppendText('How Many Boxes are Checkd:\n')
self.results.AppendText(str(lenofcb) + '\n')
self.results.AppendText(str(typeofcb) + '\n')
# Page Sizer
self.panel_vertSizer = wx.BoxSizer(wx.VERTICAL)
self.panel_vertSizer.Add(self.resultsTitle, proportion=0, flag=wx.ALIGN_LEFT)
self.panel_vertSizer.Add(self.results, proportion=0, flag=wx.ALIGN_LEFT)
# Invoke Sizer
self.SetSizer(self.panel_vertSizer)
# Make 'self' (the panel) shrink to the minimum size
# required by the controls
self.Fit()
# end __init__
# ----- Functions
# ----- Main Frame
class MainFrame(wx.Frame):
# A 2-Control Class With BoxSizers
def __init__(self):
# Configure the Figure
titleText = 'Wx Question'
wx.Frame.__init__(self, None, title=titleText
, size=(600, 300), style=wx.DEFAULT_FRAME_STYLE)
# First Frame Control automatically expands to the
# Frame's client size
frame_panel = wx.Panel(self)
# Create the Controls
leftPanel = ChkbxPanel(frame_panel)
self.rightPanel = ResultsPanel(frame_panel)
# Create Sizers and add the controls
panelCtrls_horzSizer = wx.BoxSizer(wx.HORIZONTAL)
panelCtrls_horzSizer.Add(leftPanel)
panelCtrls_horzSizer.Add(self.rightPanel)
framePanel_vertSizer = wx.BoxSizer(wx.VERTICAL)
framePanel_vertSizer.Add(panelCtrls_horzSizer)
frame_panel.SetSizer(framePanel_vertSizer)
frame_panel.Fit()
self.SetSize((600, 600))
leftPanel.chkBx.Bind(wx.EVT_CHECKLISTBOX, self.onCheckBox)
def onCheckBox(self, event):
checked = event.EventObject.CheckedStrings
self.rightPanel.results.AppendText(
'Checked: {0}, Qty checked: {1}\n'.format(checked, len(checked)))
# Main if statement
if __name__ == '__main__':
app = wx.App(redirect=False)
appFrame = MainFrame().Show()
app.MainLoop()

I removed all comments, whitespace to reduces lines. And added comments where I changed/added code. (1),(2),(3)
import wx
class chkbxPanel(wx.Panel):
def __init__(self, parent, resultsPanel):
wx.Panel.__init__(self,parent=parent, id=-1)
List = ['one','two','three']
Prompt = 'Please Make a Choice'
self.ChkBx = wx.CheckListBox(self,id=-1,choices=List,size=(-1,200))
### (1) Bind CHECKLISTBOX event (which is triggered when checkbox is toggled: checked/unchecked)
self.ChkBx.Bind(wx.EVT_CHECKLISTBOX, lambda e: resultsPanel.changed(self.ChkBx.GetCheckedStrings()))
###
self.PromptChkBx = wx.StaticText(self,id=-1,label=Prompt)
self.panel_vertSizer=wx.BoxSizer(wx.VERTICAL)
self.panel_vertSizer.Add(self.PromptChkBx,proportion=0,flag=wx.ALIGN_LEFT)
self.panel_vertSizer.Add(self.ChkBx,proportion=0,flag=wx.ALIGN_LEFT)
self.SetSizer(self.panel_vertSizer)
self.Fit()
class resultsPanel(wx.Panel):
def __init__ (self,parent):
wx.Panel.__init__(self,parent=parent,id=-1)
ResultsPanelTitle = 'Results:'
self.ResultsTitle = wx.StaticText(self, id=-1, label= ResultsPanelTitle)
self.Results = wx.TextCtrl(self, id=-1,size=(300,500),style=(wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP))
self.panel_vertSizer = wx.BoxSizer(wx.VERTICAL)
self.panel_vertSizer.Add(self.ResultsTitle,proportion=0, flag=wx.ALIGN_LEFT)
self.panel_vertSizer.Add(self.Results, proportion=0, flag=wx.ALIGN_LEFT)
self.SetSizer(self.panel_vertSizer)
self.Fit()
### (2): Called when checkbox is toggled with checkbox strings as parameter. See (1)
def changed(self, checked_strings):
self.Results.AppendText('How Many Boxes are Checkd:\n')
self.Results.AppendText(str(len(checked_strings))+'\n')
self.Results.AppendText(str(checked_strings)+'\n')
###
class MainFrame(wx.Frame):
def __init__(self):
titleText = 'Wx Question'
wx.Frame.__init__(self, None, title=titleText ,size=(600,300), style=wx.DEFAULT_FRAME_STYLE)
frame_panel = wx.Panel(self)
### (3): Changed creation order. Passed resultsPanel instance to chkbxPanel creator
RightPanel = resultsPanel(frame_panel)
LeftPanel = chkbxPanel(frame_panel, RightPanel)
###
RightPanel.CheckedBxs = LeftPanel.ChkBx.GetCheckedStrings()
RightPanel.CheckedBxs = ('one','two')
panelCtrls_horzSizer = wx.BoxSizer(wx.HORIZONTAL)
panelCtrls_horzSizer.Add(LeftPanel)
panelCtrls_horzSizer.Add(RightPanel)
framePanel_vertSizer = wx.BoxSizer(wx.VERTICAL)
framePanel_vertSizer.Add(panelCtrls_horzSizer)
frame_panel.SetSizer(framePanel_vertSizer)
frame_panel.Fit()
self.SetSize((600,600))
if __name__ == '__main__':
app = wx.PySimpleApp(redirect=False)
appFrame = MainFrame().Show()
app.MainLoop()

Related

Resolve a problem ComboBox and a TextCtrl [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I want to make that when selecting an element in the ComboBox print a message that is in the tuple in the TextCtrl, depending on the item I chose
When I did it the way I investigated, I throw an error.
import wx
#Mods
Nom_Mods = ["Alca v3", "Barcelone v1", "Anti-Fed (French)", "Elegance v3"]
Info_Mods = ["(ZL + Joystick2) To Open Menu\n(B) To close Menu\nCreate by KillerGamer81"]
#EndMods
class PageOne(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
sz = wx.BoxSizer(wx.VERTICAL)
#Controls
self.Listade_Menus = wx.ComboBox(self, -1, pos=(10,80), size=(173,22), choices = Nom_Mods, style= wx.CB_READONLY)
Cuadro_de_info = wx.TextCtrl(self, -1, "", pos=(200,80), size=(175,80), style = wx.TE_MULTILINE|wx.TE_NO_VSCROLL|wx.TE_READONLY)
class MainFrame(wx.Frame):
def __init__(self):
no_sys_menu = wx.DEFAULT_FRAME_STYLE & (~wx.RESIZE_BORDER) & (~wx.MAXIMIZE_BOX)
wx.Frame.__init__(self, None, title="ProyectoU", style=no_sys_menu, size=(400,225))
ico = wx.Icon('Recursos/icono.ico', wx.BITMAP_TYPE_ICO)
self.SetIcon(ico)
# Here we create a panel and a notebook on the panel
p = wx.Panel(self)
nb = wx.Notebook(p)
# create the page windows as children of the notebook
page1 = PageOne(nb)
# add the pages to the notebook with the label to show on the tab
nb.AddPage(page1, "Inyec/Conec")
# finally, put the notebook in a sizer for the panel to manage
# the layout
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
if __name__ == "__main__":
app = wx.App()
MainFrame().Show()
app.MainLoop()
The first error, would be a indentation error!
The problem is that you are not Binding to the ComboBox event i.e. when you make a selection an event will fire, which must be caught and acted upon.
You need to catch that event and put the currently selected text from the combobox (or whatever) into the textctrl. Currently you are making no attempt to do that.
Here is what I assume you want.
import wx
#Mods
Nom_Mods = ["Alca v3", "Barcelone v1", "Anti-Fed (French)", "Elegance v3"]
Info_Mods = ["(ZL + Joystick2) To Open Menu\n(B) To close Menu\nCreate by KillerGamer81"]
#EndMods
class PageOne(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
sz = wx.BoxSizer(wx.VERTICAL)
#Controls
self.Listade_Menus = wx.ComboBox(self, -1, pos=(10,80), size=(173,22), choices = Nom_Mods, style= wx.CB_READONLY)
#Bind a callback to the event emitted by the Combobox selection
self.Listade_Menus.Bind(wx.EVT_COMBOBOX, self.Nom_Mods_Selected)
self.Cuadro_de_info = wx.TextCtrl(self, -1, "", pos=(200,80), size=(175,80), style = wx.TE_MULTILINE|wx.TE_NO_VSCROLL|wx.TE_READONLY)
# When a selection is made populate the textctrl with the selected text
def Nom_Mods_Selected(self, event):
self.Cuadro_de_info.SetValue(self.Listade_Menus.GetStringSelection())
class MainFrame(wx.Frame):
def __init__(self):
no_sys_menu = wx.DEFAULT_FRAME_STYLE & (~wx.RESIZE_BORDER) & (~wx.MAXIMIZE_BOX)
wx.Frame.__init__(self, None, title="ProyectoU", style=no_sys_menu, size=(400,225))
ico = wx.Icon('Recursos/icono.ico', wx.BITMAP_TYPE_ICO)
self.SetIcon(ico)
# Here we create a panel and a notebook on the panel
p = wx.Panel(self)
nb = wx.Notebook(p)
# create the page windows as children of the notebook
page1 = PageOne(nb)
# add the pages to the notebook with the label to show on the tab
nb.AddPage(page1, "Inyec/Conec")
# finally, put the notebook in a sizer for the panel to manage
# the layout
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
if __name__ == "__main__":
app = wx.App()
MainFrame().Show()
app.MainLoop()

wxPython widgets are one on top of the other

I'm bulding a wxpython GUI.
When I'm running the code all the components are in the left-top corner, on top of each other.
When I resize the window, they align as planned.
The window before resize
The window after resize
How can I fix this?
my code:
class Screen(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(900,500))
self.SetBackgroundColour("#E4F1FE")
self.Show(True)
self.InitUI()
def InitUI(self):
pnlMain = wx.Panel(self, size=(900,500))
# Setup Font
font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
font.SetPointSize(9)
# Setup horizontal box sizer
self.bsMain = wx.BoxSizer(wx.HORIZONTAL)
self.bsMain.SetDimension(0,0,900,500)
# Setup LEFT box sizer
self.bsLeft = wx.BoxSizer(wx.VERTICAL)
self.bsLeft.SetMinSize((3*(self.GetSize()[0]/4),self.GetSize()[1]))
# Make add button
btnAdd = wx.Button(pnlMain, label="+", size=(50,50))
# Add all the components to the LEFT sizer
self.bsLeft.Add(btnAdd, flag = wx.ALIGN_BOTTOM | wx.ALIGN_LEFT )
# Setup RIGHT bsMain sizer
self.bsRight = wx.BoxSizer(wx.VERTICAL)
self.bsRight.SetMinSize((self.GetSize()[0]/4,self.GetSize()[1]))
# Make users headline
stUsers = wx.StaticText(pnlMain, label="USERS")
stUsers.SetFont(font)
# Make users list control
lcUsers = wx.ListCtrl(pnlMain,style=wx.LC_REPORT|wx.SUNKEN_BORDER)
lcUsers.Show(True)
lcUsers.InsertColumn(0,"user")
lcUsers.InsertColumn(1,"status")
# Add all the components to the RIGHT sizer
self.bsRight.Add((-1,10))
self.bsRight.Add(stUsers, flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTRE, border=5)
self.bsRight.Add((-1,10))
self.bsRight.Add(lcUsers, flag=wx.EXPAND)
# Add the vertical sizers to the horizontal sizer
self.bsMain.Add(self.bsLeft)
self.bsMain.Add(self.bsRight)
# Add the vertical sizer to the panel
pnlMain.SetSizer(self.bsMain)
This is a common problem for new wxPython programmers. The solution is almost always a call to the top level sizer's Layout method. Occasionally you'll need to call the top-level parent's Layout instead. In your case, either will work. You can add:
pnlMain.Layout()
or
self.bsMain.Layout()
to the bottom of InitUI method and it should force your widgets to redraw in their correct locations. I've seen some widgets behave badly because they start out with a zero size until their shown. In those cases, I have usually needed to use wx.CallAfter to call Layout. Anyway, here's a complete example using your code:
import wx
class Screen(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(900,500))
self.SetBackgroundColour("#E4F1FE")
self.Show(True)
self.InitUI()
def InitUI(self):
pnlMain = wx.Panel(self, size=(900,500))
# Setup Font
font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
font.SetPointSize(9)
# Setup horizontal box sizer
self.bsMain = wx.BoxSizer(wx.HORIZONTAL)
self.bsMain.SetDimension(0,0,900,500)
# Setup LEFT box sizer
self.bsLeft = wx.BoxSizer(wx.VERTICAL)
self.bsLeft.SetMinSize((3*(self.GetSize()[0]/4),self.GetSize()[1]))
# Make add button
btnAdd = wx.Button(pnlMain, label="+", size=(50,50))
# Add all the components to the LEFT sizer
self.bsLeft.Add(btnAdd, flag = wx.ALIGN_BOTTOM | wx.ALIGN_LEFT )
# Setup RIGHT bsMain sizer
self.bsRight = wx.BoxSizer(wx.VERTICAL)
self.bsRight.SetMinSize((self.GetSize()[0]/4,self.GetSize()[1]))
# Make users headline
stUsers = wx.StaticText(pnlMain, label="USERS")
stUsers.SetFont(font)
# Make users list control
lcUsers = wx.ListCtrl(pnlMain,style=wx.LC_REPORT|wx.SUNKEN_BORDER)
lcUsers.Show(True)
lcUsers.InsertColumn(0,"user")
lcUsers.InsertColumn(1,"status")
# Add all the components to the RIGHT sizer
self.bsRight.Add((-1,10))
self.bsRight.Add(stUsers, flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTRE, border=5)
self.bsRight.Add((-1,10))
self.bsRight.Add(lcUsers, flag=wx.EXPAND)
# Add the vertical sizers to the horizontal sizer
self.bsMain.Add(self.bsLeft)
self.bsMain.Add(self.bsRight)
# Add the vertical sizer to the panel
pnlMain.SetSizer(self.bsMain)
self.bsMain.Layout()
if __name__ == '__main__':
app = wx.App(False)
frame = Screen(None, 'Layout')
app.MainLoop()
Note: I've rarely needed to call Refresh. I think Layout does so automatically.

wxPython : Issues on windows using multiple sizers, but works well on linux

I am writing a small app that works very well on linux, but I have some trouble on windows. Here is the code sample:
import wx
#####################################################################
class Main(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="StackOverflow", pos=wx.DefaultPosition, size=(800,600))
self.SetMinSize( self.GetSize() )
p = wx.Panel(self)
nb = wx.Notebook(p)
page1 = AddToCollection(nb)
page2 = CollectionStatistics(nb)
nb.AddPage(page1, "Page 1")
nb.AddPage(page2, "Page 2")
# finally, put the notebook in a sizer for the panel to manage
# the layout
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
#########################################################################
class CollectionStatistics(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
#########################################################################
class AddToCollection(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.v1_qty_list = [str(x) for x in range(9)]
self.v2_qty_list = [str(x) for x in range(9)]
self.sizername = wx.GridBagSizer(5, 5)
self.sizername.AddGrowableCol(0,0)
self.name_txt = wx.StaticText(self, label="Enter Name :")
self.sizername.Add(self.name_txt,(2,0),(1,1),wx.EXPAND)
self.name = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER,value=u"")
self.sizername.Add(self.name,(3,0),(1,1),wx.EXPAND)
self.Bind(wx.EVT_TEXT_ENTER, self.OnPressEnter, self.name)
self.SetSizerAndFit(self.sizername)
self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y )
##########################################################################
def OnPressEnter(self,event):
self.selected_name = self.name.GetValue()
self.AddToCol()
##########################################################################
def AddToCol(self):
self.sizerAdd = wx.GridBagSizer(5, 5)
self.sizerAdd.AddGrowableCol(0, 0)
self.name.Enable(False)
### Expansion
self.expansion = wx.Choice(self, -1, choices=['test 1', 'test 2'])
self.expansion.SetSelection(0)
self.sizerAdd.Add(self.expansion,(5,0),(1,6),wx.EXPAND)
### Quantities txt
self.v1_txt = wx.StaticText(self, label="V1 Quantity :")
self.sizerAdd.Add(self.v1_txt,(7,0),(1,1),wx.EXPAND)
self.v2_txt = wx.StaticText(self, label="V2 Quantity :")
self.sizerAdd.Add(self.v2_txt,(8,0),(1,1),wx.EXPAND)
### Quantities choices
self.v1_qty = wx.Choice(self, -1, choices=self.v1_qty_list)
self.v1_qty.SetSelection(0)
self.sizerAdd.Add(self.v1_qty,(7,5),(1,1),wx.EXPAND)
self.v2_qty = wx.Choice(self, -1, choices=self.v1_qty_list)
self.v2_qty.SetSelection(0)
self.sizerAdd.Add(self.v2_qty,(8,5),(1,1),wx.EXPAND)
### Ok Button
self.Add_btn = wx.Button(self, -1, "Add")
self.Add_btn.Bind(wx.EVT_BUTTON, self.OnAdd)
self.sizerAdd.Add(self.Add_btn,(9,5),(1,1),wx.EXPAND)
### Reset Button
self.Reset_btn = wx.Button(self, -1, "Reset")
self.Reset_btn.Bind(wx.EVT_BUTTON, self.OnResetPanel)
self.sizerAdd.Add(self.Reset_btn,(9,4),(1,1),wx.EXPAND)
self.SetSizerAndFit(self.sizerAdd)
self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y )
######################################################################
def OnResetPanel(self,event):
### Kill all children
self.expansion.Destroy()
self.v1_txt.Destroy()
self.v1_qty.Destroy()
self.v2_txt.Destroy()
self.v2_qty.Destroy()
self.Add_btn.Destroy()
self.Reset_btn.Destroy()
### Reinitialise sizer
self.name.Enable(True)
self.name.SetValue("")
######################################################################
def OnAdd(self,event):
print 'Add'
self.OnResetPanel(self)
######################################################################
######################################################################
if __name__ == "__main__":
app = wx.App()
Main().Show()
app.MainLoop()
Basically, I have a TextCtrl in a first sizer which is waiting for an entry. Once the user hits enter, several objects appear in a second sizer.
The issue on windows seems to come from the use of the two gridbagsizers (sizername and sizerAdd). After pressing enter (waited event in the __init__), the objects defined within the sizerAdd do not appear. When I extend the window where the script is running, these objects appear magically !
Any idea ?
EDIT : The code is now runnable
I think the problem in your code is these two lines at the end of your AddToCol method:
self.SetSizerAndFit(self.sizerAdd)
self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y )
At this point, you're changing the sizer of the AddToCollection panel from self.sizername to self.sizerAdd. The Enter Name: label and the textbox however are still within the self.sizername sizer. However, this sizer isn't the sizer for any window, nor has it been added to any other sizer.
Generally, in wxPython, every sizer should be set as the sizer for a window, or be added to another sizer. This other sizer would then be the sizer for a window, or be contained within another sizer, and so on. In your case, your self.sizername sizer ends up being neither, and in this situation I would expect unpredictable behaviour. If your code works on Linux then I would say that it happens to work by accident.
I can think of a few things you could do here:
Add self.sizerAdd as a child of self.sizername. This can be done by replacing the two lines above with
self.sizername.Add(self.sizerAdd,(4,0),(1,1),wx.EXPAND)
self.sizername.Layout()
In AddToCol, add the widgets directly to the self.sizername sizer instead of adding them to self.sizerAdd.
Create a wx.BoxSizer() with vertical orientation, set that to be the sizer for the AddToCollection panel, and add the self.sizername and self.sizerAdd sizers to your BoxSizer.
In all three cases, after creating the new widgets you will need to call the Layout() method on the top-level sizer, be it either self.sizername or the top-level BoxSizer. The code snippet under option 1 includes this line already.
Additionally, you may need to modify your OnResetPanel() method. If you chose options 1 or 3, you will need to remove the self.sizerAdd sizer from whichever sizer you added it to. For example, in option 1, you would add the line
self.sizername.Remove(self.sizerAdd)
Another approach would be for your AddToCol method to create all the widgets within a Panel and add that to the main panel at the end. Your AddToCol method would then need to create a child panel, add the extra controls as children of this panel instead of the main panel (self), set the sizer of the child panel to self.sizerAdd and finally add this panel to the self.sizername sizer.
def AddToCol(self):
self.sizerAdd = wx.GridBagSizer(5, 5)
self.sizerAdd.AddGrowableCol(0, 0)
self.name.Enable(False)
self.child_panel = wx.Panel(self)
### Expansion
self.expansion = wx.Choice(self.child_panel, -1, choices=['test 1', 'test 2'])
self.expansion.SetSelection(0)
self.sizerAdd.Add(self.expansion,(5,0),(1,6),wx.EXPAND)
# Create other widgets as before but with the parent set to self.child_panel
# instead of self.
self.child_panel.SetSizer(self.sizerAdd)
self.sizername.Add(self.child_panel,(4,0),(1,1),wx.EXPAND)
self.sizername.Layout()
You would then also need to replace the line
self.sizername.Remove(self.sizerAdd)
in OnResetPanel() with the two lines:
self.sizername.Remove(self.child_panel)
self.child_panel.Destroy()
One thing which bugged me about my approach 1 above was that I saw the widgets briefly appear in the top-left corner before appearing in the correct place. This adaptation fixes this problem and so makes the GUI behave itself a bit better. I couldn't reproduce your black area issue you mention in your comment, but hopefully this approach fixes your problem as well.

wx.CollapsiblePane in a wx.Notebook resizing

I am trying to create a wx.CollapsiblePane on a wx.Notebook page which is successfully done using the minimal code example below. However, when the pane is unfolded, the frame fails to resize. However, if instead of creating a Notebook I make a simple Panel (see the commented line in the code), the frame does resize as expected. Any ideas why it doesn't work on a Notebook?
EDIT: I had a chance to test it on Windows and it works (wx 3.0.0.0 and 2.8). There only seems to be a problem in Linux (Ubuntu 13.10 with wx 2.8.12.1).
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.panel = wx.Panel(self)
# Notebook setup
self.nb = wx.Notebook(self.panel)
#self.nb = wx.Panel(self.panel) # uncomment this for a working example
self.pagepanel = wx.Panel(self.nb)
self.nb.AddPage(self.pagepanel, 'page')
# add something to the Notebook page
checkbox = wx.CheckBox(self.pagepanel, -1, 'box 1')
# add CollapsiblePane to the Notebook page
colpane = wx.CollapsiblePane(self.pagepanel)
colpane.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged)
# add something to the CollapsiblePane
win = colpane.GetPane()
checkbox2 = wx.CheckBox(win, -1, 'box 2')
# Set CollapsiblePane sizer
colpanesizer = wx.BoxSizer(wx.VERTICAL)
colpanesizer.Add(checkbox2, -1)
win.SetSizer(colpanesizer)
colpanesizer.SetSizeHints(win)
colpane.Collapse()
# set Notebook page sizer
pagesizer = wx.BoxSizer(wx.VERTICAL)
pagesizer.Add(checkbox)
pagesizer.Add(colpane)
self.pagepanel.SetSizerAndFit(pagesizer)
# set the whole Panel sizer
panelsizer = wx.BoxSizer()
panelsizer.Add(self.nb)
self.panel.Layout()
self.panel.SetSizerAndFit(panelsizer)
# set Frame size
self.Fit()
def OnPaneChanged(self, event):
# redo the layout
self.pagepanel.Layout()
self.pagepanel.Fit()
self.panel.Layout()
self.panel.Fit()
self.Fit()
app = wx.App()
frame = MyFrame()
frame.Center()
frame.Show()
app.MainLoop()
colpanesizer.Add(checkbox2, -1) should be colpanesizer.Add(checkbox2)
Try:
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.panel = wx.Panel(self)
# Notebook setup
self.nb = wx.Notebook(self.panel)
#self.nb = wx.Panel(self.panel) # uncomment this for a working example
self.pagepanel = wx.Panel(self.nb)
self.nb.AddPage(self.pagepanel, 'page')
# add something to the Notebook page
checkbox = wx.CheckBox(self.pagepanel, -1, 'box 1')
# add CollapsiblePane to the Notebook page
colpane = wx.CollapsiblePane(self.pagepanel)
colpane.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged)
# add something to the CollapsiblePane
win = colpane.GetPane()
checkbox2 = wx.CheckBox(win, -1, 'box 2')
# Set CollapsiblePane sizer
colpanesizer = wx.BoxSizer(wx.VERTICAL)
colpanesizer.Add(checkbox2)
win.SetSizer(colpanesizer)
colpanesizer.SetSizeHints(win)
colpane.Collapse()
# set Notebook page sizer
pagesizer = wx.BoxSizer(wx.VERTICAL)
pagesizer.Add(checkbox)
pagesizer.Add(colpane)
self.pagepanel.SetSizerAndFit(pagesizer)
# set the whole Panel sizer
panelsizer = wx.BoxSizer()
panelsizer.Add(self.nb)
self.panel.Layout()
self.panel.SetSizerAndFit(panelsizer)
# set Frame size
self.Fit()
def OnPaneChanged(self, event):
# redo the layout
self.pagepanel.Layout()
self.pagepanel.Fit()
self.panel.Layout()
self.panel.Fit()
self.Fit()
app = wx.App()
frame = MyFrame()
frame.Center()
frame.Show()
app.MainLoop()

wxPython: disable multiple buttons

I have a wxPython GUI which looks like this:
As you can see there are three "columns", each enclosed in a wx.StaticBox. I want to disable all the buttons, text box, and radio buttons within a column. I tried using .Disable on the static box but it had no effect. Is there an easy way to disable everything within a static box?
A wx.StaticBox is not actually a container, it's just:
a rectangle drawn around other panel items to denote a logical grouping of items.
So, the only way you can do this with StaticBox is to keep track of the widgets you've logically grouped together, and call Disable on all of them.
Or, alternatively, you can put the widgets into any of the actual container widgets (like windows and sizers) instead, and then just Disable the container.
Make the StaticBoxSizer into a class attribute if you haven't already (i.e. self.mySizer instead of just mySizer). Then you can use its GetChildren() method to return the widgets. Next you just loop through the widgets and Disable them. Something like this should do it:
children = self.mySizer.GetChildren()
for child in children:
child.Disable()
You might have to add a check in the loop to make sure it's a button or a text control. I recommend using Python's isinstance for that.
Here is a working example:
"""
Demonstration on how to disable / enable all objects within a sizer
Reinhard Daemon / Austria
08.10.2019
"""
import wx
class MainWindow(wx.Frame):
def __init__(self, parent=None):
wx.Frame.__init__(self, parent, -1,
title='Disable / Enable all Widgets within a Sizer',size=(500,200))
self.Move((50,50))
panel = wx.Panel(self)
# layout (sizers, boxes,...):
top_sizer = wx.BoxSizer(wx.VERTICAL)
widget_box = wx.StaticBox(panel, id=-1,
label='Widgets, which are controlled')
widget_box.SetBackgroundColour("yellow")
control_box = wx.StaticBox(panel, -1,
label='Widgets, which controll')
control_box.SetBackgroundColour("yellow")
self.widget_sizer = wx.StaticBoxSizer(widget_box, wx.HORIZONTAL)
control_sizer = wx.StaticBoxSizer(control_box, wx.HORIZONTAL)
# create the widgets:
widget_1 = wx.TextCtrl(panel, value='Text 1')
widget_2 = wx.RadioButton(panel, label='Radio 1')
widget_3 = wx.RadioButton(panel, label='Radio 2')
widget_4 = wx.Button(panel, label='Button 1')
widget_disable = wx.Button(panel, label='DISABLE')
self.widget_enable = wx.Button(panel, label='ENABLE', pos = (100,50))
# add the widgets to the layout:
self.widget_sizer.Add(widget_1)
self.widget_sizer.Add(widget_2)
self.widget_sizer.Add(widget_3)
self.widget_sizer.Add(widget_4)
control_sizer.Add(widget_disable)
control_sizer.Add(self.widget_enable)
# finalize the layout:
top_sizer.Add(sizer=self.widget_sizer, flag=wx.CENTER | wx.EXPAND)
top_sizer.AddSpacer(30)
top_sizer.Add(control_sizer, 0, wx.CENTER | wx.EXPAND)
panel.SetSizer(top_sizer)
panel.Fit()
# bindings:
widget_disable.Bind(wx.EVT_BUTTON, self.on_button_disable)
self.widget_enable.Bind(wx.EVT_BUTTON, self.on_button_enable)
def on_button_disable(self, evt):
children = self.widget_sizer.GetChildren()
for child in children:
print(child.GetWindow(),end='')
try:
child.GetWindow().Enable(False)
print(' DISABLED')
except:
print(' ERROR')
def on_button_enable(self, evt):
children = self.widget_sizer.GetChildren()
for child in children:
print(child.GetWindow(),end='')
try:
child.GetWindow().Enable(True)
print(' ENABLED')
except:
print(' ERROR')
if __name__ == "__main__":
app = wx.App()
view1 = MainWindow()
view1.Show()
app.MainLoop()

Categories

Resources