I have two panels to which I am both adding to a single sizer at the top level, however the elements within those panels are not aligned with each other.
Here is a simple example to demonstrate what I am trying to achieve.
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
super(MyPanel, self).__init__(parent=parent)
mygridsizer = wx.GridBagSizer()
sizer = wx.BoxSizer(orient=wx.HORIZONTAL)
sizer.Add(wx.StaticText(self,label="Hello world"))
sizer.Add(wx.Button(self, label="hello"))
mygridsizer.Add(sizer, pos=(0,0))
mygridsizer.Add(wx.ComboBox(self), pos=(0,1))
self.SetSizer(mygridsizer)
class MyPanel2(wx.Panel):
def __init__(self, parent):
super(MyPanel2, self).__init__(parent=parent)
sizer = wx.BoxSizer(orient=wx.HORIZONTAL)
sizer.Add(wx.Button(self, label="non-aligned button"))
self.SetSizer(sizer)
class MainFrame(wx.Frame):
def __init__(self, parent):
super(MainFrame, self).__init__(None)
sizer = wx.GridSizer(3, 1)
panel1 = MyPanel(parent=self)
panel2 = MyPanel2(parent=self)
sizer.Add(panel1)
sizer.Add(panel2)
self.SetSizer(sizer)
if __name__ == '__main__':
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()
With the example above, what can I do to align the buttons of both the panels?
The problem is the sizer is aligning the Panels, if you want the buttons aligned you should make them part of the same sizer (not part of two Panels with their own sizers). You could also do something like this for a quick hack (essentially adding a spacer the same size as the text):
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
super(MyPanel, self).__init__(parent=parent)
mygridsizer = wx.GridBagSizer()
sizer = wx.BoxSizer(orient=wx.HORIZONTAL)
sizer.Add(wx.StaticText(self,label="Hello world"))
sizer.Add(wx.Button(self, label="hello"))
mygridsizer.Add(sizer, pos=(0,0))
mygridsizer.Add(wx.ComboBox(self), pos=(0,1))
self.SetSizer(mygridsizer)
class MyPanel2(wx.Panel):
def __init__(self, parent):
super(MyPanel2, self).__init__(parent=parent)
sizer = wx.BoxSizer(orient=wx.HORIZONTAL)
t = wx.StaticText(self,label="Hello world")
t.Hide()
t.GetSize()
sizer.Add(t.GetSize())
sizer.Add(wx.Button(self, label="non-aligned button"))
self.SetSizer(sizer)
class MainFrame(wx.Frame):
def __init__(self, parent):
super(MainFrame, self).__init__(None)
sizer = wx.GridSizer(3, 1)
panel1 = MyPanel(parent=self)
panel2 = MyPanel2(parent=self)
sizer.Add(panel1)
sizer.Add(panel2)
self.SetSizer(sizer)
if __name__ == '__main__':
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()
Related
I wrote the following code to make grid in the Pycharm. Unable to make mathematical calculations
import wx
import wx.grid as grid
class MyFrame(wx.Frame):
def __init__(self, parent, title):
super(MyFrame, self).__init__(parent, title=title, size = (600, 800))
#self.panel = wx.Panel (self)
self.panel = MyPanel(self)
class MyPanel(wx.Panel) :
def __init__(self, parent) :
super(MyPanel, self). __init__(parent)
madrid = grid.Grid(self)
madrid.CreateGrid(40, 8)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(madrid, 1 , wx.EXPAND)
self.SetSizer(sizer)
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(parent=None, title="Electrical Sizing File")
self.frame.Show()
return True
app = MyApp()
app.MainLoop()
I am trying to use window splitter to get 6 different subwindows. Three columns and two rows. So far I am trying to use nested splitters, but it is not working.
This is the code I have:
import wx
########################################################################
class RandomPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent, color):
"""Constructor"""
wx.Panel.__init__(self, parent)
self.SetBackgroundColour(color)
########################################################################
class MainPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
topSplitter = wx.SplitterWindow(self)
vSplitter = wx.SplitterWindow(topSplitter)
panelOne = RandomPanel(vSplitter, "blue")
panelTwo = RandomPanel(vSplitter, "red")
vSplitter.SplitVertically(panelOne, panelTwo)
vSplitter.SetSashGravity(0.5)
panelThree = RandomPanel(topSplitter, "green")
topSplitter.SplitHorizontally(vSplitter, panelThree)
topSplitter.SetSashGravity(0.5)
panelFour=RandomPanel(hSplitter, "yellow")
hSplitter.SplitVertically(topSplitter, panelFour)
hSplitter.SetSashGravity(0.5)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(topSplitter, 1, wx.EXPAND)
self.SetSizer(sizer)
#
class MainFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Nested Splitters",
size=(800,600))
panel = MainPanel(self)
self.Show()
----------------------------------------------------------------------
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
app.MainLoop()
For this I am just trying to get 4 subwindows not 6, and I still get an error.
You might want to check out the MultiSplitterWindow widget:
https://wxpython.org/Phoenix/docs/html/wx.lib.splitter.MultiSplitterWindow.html
It allows you to have more than two windows in a splitter window widget. I actually wrote a bit about the various splitter windows that wxPython supports over on my blog, so you might want to check that out too.
Anyway, here is a simple example that uses that widget:
import wx
from wx.lib.splitter import MultiSplitterWindow
class SplitterPanel(wx.Panel):
def __init__(self, parent, color):
"""Constructor"""
wx.Panel.__init__(self, parent)
main_sizer = wx.BoxSizer(wx.VERTICAL)
splitter = MultiSplitterWindow(self, style=wx.SP_LIVE_UPDATE)
for col in range(3):
panel = wx.Panel(splitter, size=(200, 200))
panel.SetBackgroundColour(color)
splitter.AppendWindow(panel)
main_sizer.Add(splitter, 1, wx.ALL|wx.EXPAND)
self.SetSizer(main_sizer)
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='Splitters')
panel = wx.Panel(self)
main_sizer = wx.BoxSizer(wx.VERTICAL)
splitter_panel = SplitterPanel(panel, color='blue')
main_sizer.Add(splitter_panel, 1, wx.ALL|wx.EXPAND)
splitter_panel_two = SplitterPanel(panel, color='red')
main_sizer.Add(splitter_panel_two, 1, wx.ALL|wx.EXPAND)
panel.SetSizer(main_sizer)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MainFrame()
app.MainLoop()
I want to ask is it possible to add wx.Panel with event button in wxpython? There are plenty examples how to switch panels Hide first one and show second, but they are useless for me. I want to create panel with add button. For example I have panel something like this
import wx
import wx.grid as grid
class MainPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent = parent)
class SecondPanel(wx.Panel):
def __init__(self, parent,a,b):
wx.Panel.__init__(self, parent=parent)
MyGrid=grid.Grid(self)
MyGrid.CreateGrid(a, b)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(MyGrid, 0, wx.EXPAND)
self.SetSizer(sizer)
class MainFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="test",
size=(800,600))
self.splitter = wx.SplitterWindow(self)
self.panelOne = MainPanel(self.splitter)
self.panelTwo = SecondPanel(self.splitter, 1, 1)
txtOne = wx.StaticText(self.panelOne, -1, label = "piradoba", pos = (20,10))
self.txtTwo = wx.StaticText(self.panelOne, -1, label = "", pos = (40,80))
self.txtPlace = wx.TextCtrl(self.panelOne, pos = (20,30))
button = wx.Button(self.panelOne, label = "search", pos = (40,100))
button.Bind(wx.EVT_BUTTON, self.Onbutton)
self.splitter.SplitHorizontally(self.panelOne, self.panelTwo)
self.splitter.SetMinimumPaneSize(20)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.splitter, 1, wx.EXPAND)
self.SetSizer(sizer)
def Onbutton(self, event):
var=self.txtPlace.GetValue()
if len(var) == 9 or len(var) == 11:
???????????????????????????????????????????????
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
frame.Show()
app.MainLoop()
for example now I want to add new panel with this event what can I do? and I want to create this panel with event.
I don't know if it is what you need but in this example you have:
panel with button and event
button call function in mainframe
mainframe add next panel (with grid) to boxsizer
Tested on Linux Mint + Python 2.7.4
import wx
import wx.grid as grid
class MainPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent = parent)
self.txtOne = wx.StaticText(self, -1, label = "piradoba", pos = (20,10))
self.txtPlace = wx.TextCtrl(self, pos = (20,30))
self.txtTwo = wx.StaticText(self, -1, label = "", pos = (20,40))
button = wx.Button(self, label = "search", pos = (20,70))
button.Bind(wx.EVT_BUTTON, self.onButton)
def onButton(self, event):
var=self.txtPlace.GetValue()
if len(var) == 9 or len(var) == 11:
print "???"
# MainPanel->SplitterWindow->MainFrame ( 2x GetParent() )
self.GetParent().GetParent().AddPanel()
class SecondPanel(wx.Panel):
def __init__(self, parent,a,b):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
MyGrid=grid.Grid(self)
MyGrid.CreateGrid(a, b)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(MyGrid, 0, wx.EXPAND)
self.SetSizer(sizer)
class MainFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="test", size=(800,600))
self.splitter = wx.SplitterWindow(self)
self.panelOne = MainPanel(self.splitter)
self.panelTwo = SecondPanel(self.splitter, 1, 1)
self.splitter.SplitHorizontally(self.panelOne, self.panelTwo)
self.splitter.SetMinimumPaneSize(20)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.splitter, 2, wx.EXPAND)
self.SetSizer(self.sizer)
def AddPanel(self):
self.newPanel = SecondPanel(self, 1, 1)
self.sizer.Add(self.newPanel, 1, wx.EXPAND)
self.sizer.Layout()
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
frame.Show()
app.MainLoop()
I want to display a button that when I click adds to the main panel a static text that automatic adds to the BoxSizer of the panel. I have this code but dosen't work good. Anyone can help me? I am desperate. Thanks
import wx
class MyApp(wx.App):
def OnInit(self):
self.frame = MainFrame(None,title='')
self.SetTopWindow(self.frame)
self.frame.Show()
return True
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super(MainFrame, self).__init__(*args, **kwargs)
#Atributos
self.panel = MainPanel(self)
self.CreateStatusBar()
#Layout
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.sizer.Add(self.panel,1,wx.EXPAND)
self.SetSizer(self.sizer)
class MainPanel(wx.Panel):
def __init__(self, parent):
super(MainPanel, self).__init__(parent)
#Atributos
bmp = wx.Bitmap('./img.png',wx.BITMAP_TYPE_PNG)
self.boton = wx.BitmapButton(self,bitmap=bmp)
# Layout
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.sizer.Add(self.boton)
self.SetSizer(self.sizer)
self.Bind(wx.EVT_BUTTON,self.add,self.boton)
def add(self,event):
self.sizer.Add(wx.StaticText(self,label='Testing'))
if __name__ == "__main__":
app = MyApp(False)
app.MainLoop()
If your problem is that your text initially shows up behind the button when it is clicked, you can force the sizer to update by adding a call to your Panel's Layout method.
class MainPanel(wx.Panel):
def __init__(self, parent):
super(MainPanel, self).__init__(parent)
#Atributos
bmp = wx.Bitmap('./img.png',wx.BITMAP_TYPE_PNG)
self.boton = wx.BitmapButton(self,bitmap=bmp)
# Layout
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.sizer.Add(self.boton)
self.SetSizer(self.sizer)
self.Bind(wx.EVT_BUTTON,self.add,self.boton)
def add(self,event):
self.sizer.Add(wx.StaticText(self,label='Testing'))
self.Layout()
This is a continuation from this question:
wxPython: Can a wx.PyControl contain a wx.Sizer?
The main topic here is using a wx.Sizer inside a wx.PyControl. I had problems Fit()ting my CustomWidget around its child widgets. That problem was solved by calling Layout() after Fit().
However, as far as I have experienced, the solution only works when the CustomWidget is a direct child of a wx.Frame. It breaks down when it becomes a child of a wx.Panel.
EDIT: Using the code below, the CustomWidget doesn't resize correctly to fit its children. I observed that this only happens when the CustomWidget (as a subclass of wx.PyControl) is a child of a wx.Panel; otherwise, if it is a direct child of a wx.Frame, it Fit()s perfectly.
Here is the code:
import wx
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None)
panel = Panel(parent=self)
custom = CustomWidget(parent=panel)
self.Show()
class Panel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
self.SetSize(parent.GetClientSize())
class CustomWidget(wx.PyControl):
def __init__(self, parent):
wx.PyControl.__init__(self, parent=parent)
# Create the sizer and make it work for the CustomWidget
sizer = wx.GridBagSizer()
self.SetSizer(sizer)
# Create the CustomWidget's children
text = wx.TextCtrl(parent=self)
spin = wx.SpinButton(parent=self, style=wx.SP_VERTICAL)
# Add the children to the sizer
sizer.Add(text, pos=(0, 0), flag=wx.ALIGN_CENTER)
sizer.Add(spin, pos=(0, 1), flag=wx.ALIGN_CENTER)
# Make sure that CustomWidget will auto-Layout() upon resize
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Fit()
def OnSize(self, event):
self.Layout()
app = wx.App(False)
frame = Frame()
app.MainLoop()
.SetSizerAndFit(sizer) does the job. I'm not sure why a .SetSizer(sizer) then a .Fit() won't work. Any ideas?
import wx
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None)
panel = Panel(parent=self)
custom = CustomWidget(parent=panel)
self.Show()
class Panel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
self.SetSize(parent.GetClientSize())
class CustomWidget(wx.PyControl):
def __init__(self, parent):
wx.PyControl.__init__(self, parent=parent)
# Create the sizer and make it work for the CustomWidget
sizer = wx.GridBagSizer()
self.SetSizer(sizer)
# Create the CustomWidget's children
text = wx.TextCtrl(parent=self)
spin = wx.SpinButton(parent=self, style=wx.SP_VERTICAL)
# Add the children to the sizer
sizer.Add(text, pos=(0, 0), flag=wx.ALIGN_CENTER)
sizer.Add(spin, pos=(0, 1), flag=wx.ALIGN_CENTER)
# Set sizer and fit, then layout
self.SetSizerAndFit(sizer)
self.Layout()
# ------------------------------------------------------------
# # Make sure that CustomWidget will auto-Layout() upon resize
# self.Bind(wx.EVT_SIZE, self.OnSize)
# self.Fit()
#
#def OnSize(self, event):
# self.Layout()
# ------------------------------------------------------------
app = wx.App(False)
frame = Frame()
app.MainLoop()