wxPython: Problems with GridBagSizer - python

I'm new to wxpython and it seems to be very powerful tool for building up GUI, but I have a question about GridBagSizer. Could you please tell me how to adjust the size of the items that are placed inside GridBagSizer to the size of the frame they are supposed to be placed in. I attached the sample at the end: the buttons from 8 to 13 go beyond the frame, but what I want is to make the size of the buttons automatically resize to fit the frame. Any advices and suggestions are appreciated.
Best regards,
Nikita
import wx
class Frame ( wx.Frame ):
def __init__( self ):
wx.Frame.__init__ ( self, None, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE & ~ (wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX|wx.RESIZE_BORDER) )
nums = (('1',(0,3)), ('2',(2,3)), ('14', (3,3)), ('15',(4,3)), ('16',(5,3)), ('17',(6,3)), ('18',(7,3)),
('3',(1,0)), ('4',(1,1)), ('5',(1,2)), ('6',(1,3)), ('7',(1,4)), ('8',(1,5)), ('9',(1,6)), ('10',(1,7)),
('11',(1,8)), ('12',(1,9)), ('13',(1,10)))
panel = wx.Panel(self,-1)
panel.SetBackgroundColour("green")
grid = wx.GridBagSizer(2,2)
for num, pos in nums:
button = wx.Button(panel, wx.NewId(), label = num)
grid.Add(button, pos, flag=wx.EXPAND)
bs2 = wx.BoxSizer(wx.VERTICAL)
bs2.Add(grid, 0, wx.EXPAND,0)
panel.SetSizer(bs2)
panel.Layout()
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
self.mainSizer.Add(panel, 0, wx.EXPAND, 0)
self.SetSizer(self.mainSizer)
self.Layout()
if __name__=='__main__':
app=wx.PySimpleApp()
app.frame = Frame()
app.frame.Center()
app.frame.Show(True)
app.MainLoop()

You must allow the columns to grow by calling AddGrowableCol:
for i in range(11):
grid.AddGrowableCol(i)
Now, they can grow, but they won't shrink beyond their initial size! So you should also reduce their starting size:
for num, pos in nums:
button = wx.Button(panel, wx.NewId(), size=(10,-1), label = num)
#original code was: button = wx.Button(panel, wx.NewId(), label = num)
grid.Add(button, pos, flag=wx.EXPAND)
Here is the complete listing:
import wx
class Frame ( wx.Frame ):
def __init__( self ):
wx.Frame.__init__ ( self, None, id = wx.ID_ANY, title = wx.EmptyString, pos =
wx.DefaultPosition, size = wx.Size( 500,300 ),
style = wx.DEFAULT_FRAME_STYLE & ~ (wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX|wx.RESIZE_BORDER) )
nums = (('1',(0,3)), ('2',(2,3)), ('14', (3,3)), ('15',(4,3)), ('16',(5,3)), ('17',(6,3)), ('18',(7,3)),
('3',(1,0)), ('4',(1,1)), ('5',(1,2)), ('6',(1,3)), ('7',(1,4)), ('8',(1,5)), ('9',(1,6)), ('10',(1,7)),
('11',(1,8)), ('12',(1,9)), ('13',(1,10)))
panel = wx.Panel(self,-1)
panel.SetBackgroundColour("green")
grid = wx.GridBagSizer(2,2)
for num, pos in nums:
button = wx.Button(panel, wx.NewId(), size=(10,-1), label = num)
grid.Add(button, pos, flag=wx.EXPAND)
for i in range(11):
grid.AddGrowableCol(i)
bs2 = wx.BoxSizer(wx.VERTICAL)
bs2.Add(grid, 0, wx.EXPAND,0)
panel.SetSizer(bs2)
panel.Layout()
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
self.mainSizer.Add(panel, 0, wx.EXPAND, 0)
self.SetSizer(self.mainSizer)
self.Layout()
if __name__=='__main__':
app=wx.PySimpleApp()
app.frame = Frame()
app.frame.Center()
app.frame.Show(True)
app.MainLoop()

Related

Is it possible to adapt width wx.StaticBox?

i've made this code :
import wx
import List as li
from ChoiceBook import *
class MainTab(wx.Panel):
def __init__(self, parent, sb, dm):
wx.Panel.__init__(self, parent)
self.parent = parent
self.hardware = []
box = wx.StaticBox(self, wx.ID_ANY, "Appareil")
self.list = li.List(self, sb, dm)
sizerleft = wx.StaticBoxSizer(box,wx.HORIZONTAL)
sizerleft.Add(self.list, 1, wx.ALL|wx.EXPAND, 5)
box = wx.StaticBox(self, wx.ID_ANY, "Mesures")
self.notebook = Choicebook(self,dm)
sizerright = wx.StaticBoxSizer(box,wx.HORIZONTAL)
sizerright.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(sizerleft, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(sizerright, 1, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def update(self):
self.notebook.update()
it made this window, but when i resize it, it dosen't scale the contents. it just crop it, like this.
I think the probleme come from the StaticBox which are static i guess(i'm not sure).
I would like to know if it's possible to make it resize automatically?
or if not is there is another way to make a box whith a title like StaticBox and so make it resizable ?
EDIT: i figure it out with your help. in fact this wasn't this portion of cod fault but my list Class. i just remove all size in that file
before
wx.ListCtrl.__init__(self,
parent,
size=(800, -1),
style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
self.rm = RM.Res_Man()
self.index = 0
self.InsertColumn(0, 'Appareil de mesure', width=125)
self.InsertColumn(1, 'Connecté')
self.InsertColumn(2, 'ID',width=300)
self.InsertColumn(3, 'Type',width=290)
self.sb = sb
after
wx.ListCtrl.__init__(self,
parent,
style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
self.rm = RM.Res_Man()
self.index = 0
self.InsertColumn(0, 'Appareil de mesure')
self.InsertColumn(1, 'Connecté')
self.InsertColumn(2, 'ID')
self.InsertColumn(3, 'Type')
self.sb = sb
thanks you all ;)
I think that what you want, is to force it to Layout() on a RESIZE event.
However, remember that these items will have a minimum size.
Try this:
import wx
class MainTab(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.hardware = []
box = wx.StaticBox(self, wx.ID_ANY, "Appareil")
lc = wx.ListCtrl(self, wx.ID_ANY, style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES)
lc.InsertColumn(1, "Appareil de mesure")
lc.InsertColumn(2, "Connecte")
lc.InsertColumn(3, "ID")
lc.InsertColumn(4, "Type")
sizerleft = wx.StaticBoxSizer(box,wx.HORIZONTAL)
sizerleft.Add(lc, 1, wx.ALL|wx.EXPAND, 5)
box = wx.StaticBox(self, wx.ID_ANY, "Mesures")
cb = wx.Choicebook(self, wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
style=0, name="")
sizerright = wx.StaticBoxSizer(box,wx.HORIZONTAL)
sizerright.Add(cb, 1, wx.ALL|wx.EXPAND, 5)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(sizerleft, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(sizerright, 1, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
self.Bind(wx.EVT_SIZE, self.ReSize)
def ReSize(self,event):
self.Layout()
if __name__ == '__main__':
app = wx.App()
frame = MainTab()
frame.Show(True)
app.MainLoop()
I have had to hack it together as your code is in complete.

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 hide and show panel

I am creating a Python application that requires a login on start up. I want to have a main panel that will hold my login panel and on successful login the login panel will hide and the main wx.Notebook will show. The following code works, but if in the login panel I re-size the application, after I successfully login and go to the main wx.Notebook the wx.Notebook does not fit the size of the screen. If I resize again while in the main wx.Notebook the main wx.Notebook will fit the window. How do I get the main wx.Notebook to automatically re-size to the window?
Main.py
import wx
import os
from titlePanel import titlePanel
from OneLblOneCB_HorzBoxSizer_Panel import OneLblOneCB_HorzBoxSizer_Panel
from OneLblOneMultiTxt_HorzBoxSizer_Panel import OneLblOneMultiTxt_HorzBoxSizer_Panel
from OneLblOneSingleTxt_HorzBoxSizer_Panel import OneLblOneSingleTxt_HorzBoxSizer_Panel
from OneLblTxtFile_HorzBoxSizer_Panel import OneLblTxtFile_HorzBoxSizer_Panel
from OneBtn_HorzBoxSizer_Panel import OneBtn_HorzBoxSizer_Panel
from LoginPanel import LoginPanel
from ProjectsPanel import ProjectsPanel
from EvDB import EvDB
class MyFrame(wx.Frame):
def __init__(self, parent, ID, title):
wx.Frame.__init__(self, parent, ID, title=title, size=(650,725))
# Create Database Tables
self.db = EvDB(self)
self.db.createTbls()
# Setting up the menu.
filemenu= wx.Menu()
ID_LOGIN = wx.NewId()
ID_LOGOUT = wx.NewId()
# wx.ID_ABOUT and wx.ID_EXIT are standard IDs provided by wxWidgets.
menuOpen = filemenu.Append(wx.ID_OPEN, "&Open"," Open and existing file")
menuAbout = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
filemenu.AppendSeparator()
menuLogin = filemenu.Append(ID_LOGIN, 'Login')
menuLogout = filemenu.Append(ID_LOGOUT, 'Logout')
filemenu.AppendSeparator()
menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
# Set events.
self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen )
self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout )
self.Bind(wx.EVT_MENU, self.OnLogin, menuLogin )
self.Bind(wx.EVT_MENU, self.OnLogout, menuLogout )
self.Bind(wx.EVT_MENU, self.OnExit, menuExit )
main = wx.Panel(self)
self.mainLogin = LoginPanel(main,-1,addSpacers=1)
self.mainLogin.Show()
# Create a notebook on the panel
self.nb = wx.Notebook(main)
self.nb.Hide()
# create the page windows as children of the notebook
flowchartPg = wx.Panel(self.nb)
entryPg = wx.ScrolledWindow(self.nb, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, style=wx.VSCROLL)
entryPg.SetScrollRate( 5, 5 )
projectsPg = ProjectsPanel(self.nb, -1)
# add the pages to the notebook with the label to show on the tab
self.nb.AddPage(projectsPg, "Projects")
self.nb.AddPage(entryPg, "Entry")
self.nb.AddPage(flowchartPg, "Flowchart")
self.entTitle = titlePanel(entryPg, -1)
self.entDescr = OneLblOneMultiTxt_HorzBoxSizer_Panel(entryPg,-1,
name="entDescr", lbl="Description")
self.srcTypeList = ['None','Website', 'Youtube', 'PDF', 'Book']
self.entSourceType = OneLblOneCB_HorzBoxSizer_Panel(entryPg,-1,
name="entSourceType", lbl="Source Type: ", cbList=self.srcTypeList, startVal='None')
self.entSource = OneLblTxtFile_HorzBoxSizer_Panel(entryPg,-1,
name="entSource", lbl="Source: ")
self.entSource.singleTxt.SetEditable(False)
self.entSource._filename.Disable()
self.entAuthor = OneLblOneSingleTxt_HorzBoxSizer_Panel(entryPg,-1,
name="entAuthor", lbl="Author: ", addSpacers=0)
self.entAuthorCre = OneLblOneMultiTxt_HorzBoxSizer_Panel(entryPg,-1,
name="entAuthorCre", lbl="Author's Credentials: ")
self.asPrjList = ['None','Project1', 'Project2', 'Project3', 'Project4']
self.entAsProject = OneLblOneCB_HorzBoxSizer_Panel(entryPg,-1,
name="asProject", lbl="Assign to Project: ", cbList=self.asPrjList, startVal='None')
self.saveOrEditList = ['New','Ev1', 'Ev2', 'Ev3', 'Ev4']
self.entSaveOrEdit = OneLblOneCB_HorzBoxSizer_Panel(entryPg,-1,
name="saveOrEdit", lbl="New or Edit: ", cbList=self.saveOrEditList, startVal='New')
self.entRemarks = OneLblOneMultiTxt_HorzBoxSizer_Panel(entryPg,-1,
name="sourceRemarks", lbl="Evidence Remarks: ")
self.entRemarks.multiTxt.SetEditable(False)
self.entAddBtn = OneBtn_HorzBoxSizer_Panel(entryPg, -1, name="entAddBtn", btn="Add")
self.entSaveBtn = OneBtn_HorzBoxSizer_Panel(entryPg, -1, name="entSaveBtn", btn="Save")
#self.loginTest = LoginPanel(entryPg, -1,addSpacers=1)
self.entSaveBtn.button.Hide()
# Bindings
self.Bind(wx.EVT_COMBOBOX, self.SourceTypeEvtComboBox, self.entSourceType.cb)
self.Bind(wx.EVT_COMBOBOX, self.AsProjectEvtComboBox, self.entAsProject.cb)
self.Bind(wx.EVT_COMBOBOX, self.SaveOrEditEvtComboBox, self.entSaveOrEdit.cb)
self.Bind(wx.EVT_BUTTON, self.EvtAddBtn, self.entAddBtn.button)
self.Bind(wx.EVT_BUTTON, self.EvtSaveBtn, self.entSaveBtn.button)
self.Bind(wx.EVT_BUTTON, self.EvtLoginBtn, self.mainLogin.loginBtns.LoginBtn)
self.Bind(wx.EVT_BUTTON, self.EvtLogoutBtn, self.mainLogin.loginBtns.LogoutBtn)
# Creating Sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
entryPgBox = wx.BoxSizer(wx.VERTICAL)
# Adding Panels to BoxSizer entry panel sizer
mainSizer.AddSpacer(10)
mainSizer.Add(self.nb, 1, wx.ALL|wx.EXPAND)
mainSizer.Add(self.mainLogin, 1, wx.ALL|wx.EXPAND)
entryPgBox.AddSpacer(20)
entryPgBox.Add(self.entAsProject, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entSaveOrEdit, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entTitle, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entDescr, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entSourceType, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entSource, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entAuthor, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entAuthorCre, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entRemarks, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
entryPgBox.Add(self.entAddBtn, 0, wx.EXPAND)
entryPgBox.Add(self.entSaveBtn, 0, wx.EXPAND)
entryPgBox.AddSpacer(10)
# Setting Layouts
entryPg.SetAutoLayout(True)
entryPg.SetSizer(entryPgBox)
entryPgBox.Fit(entryPg)
main.SetAutoLayout(True)
main.SetSizer(mainSizer)
mainSizer.Fit(main)
self.Layout()
self.Show()
def OnLogin(self,e):
self.nb.Hide()
self.mainLogin.Show()
self.Layout()
self.mainLogin.Layout()
def OnLogout(self,e):
self.mainLogin.Show()
self.nb.Hide()
self.Layout()
self.mainLogin.Layout()
def EvtLoginBtn(self,e):
self.nb.Show()
self.mainLogin.Hide()
self.Layout()
self.nb.Layout()
LoginPanel.py
class LoginPanel(wx.Panel):
def __init__(self, parent, ID, addSpacers):
wx.Panel.__init__(self, parent, ID)
sizer = wx.BoxSizer(wx.VERTICAL)
self.userNamePnl = OneLblOneSingleTxt_HorzBoxSizer_Panel(self,-1,
name="loginUser", lbl="Username: ", addSpacers=1)
self.passwordPnl = OneLblOneSingleTxt_HorzBoxSizer_Panel(self,-1,
name="loginPass", lbl="Password: ", addSpacers=1)
self.loginBtns = LoginBtnsPanel(self,-1)
if addSpacers == 1:
sizer.AddStretchSpacer()
sizer.Add(self.userNamePnl,0,wx.EXPAND)
sizer.AddSpacer(10)
sizer.Add(self.passwordPnl,0,wx.EXPAND)
sizer.AddSpacer(10)
sizer.Add(self.loginBtns,0,wx.EXPAND)
if addSpacers == 1:
sizer.AddStretchSpacer()
self.SetAutoLayout(True)
self.SetSizer(sizer)
sizer.Fit(self)
Got it! I was trying to redraw the frame with Layout(), but I needed to redraw the BoxSizer with Layout()
I added the following code to the login button:
def EvtLoginBtn(self,e):
self.nb.Show()
self.mainLogin.Hide()
self.mainSizer.Layout()
Call the Layout() method of the Frame and Panel like this
def EvtLoginBtn(self,e):
self.nb.Show()
self.mainLogin.Hide()
self.Layout()
self.nb.Layout()
The last call is probably not needed. Just check the program without it as well. The Layout() method redraws the Frame or Panel or whichever widget it is a method of.
UPDATE
Your code is obviously very big and has several other parts which I do not know. Anyways, here's something that I came up with, along the lines of the code you have provided, to show how you can do this. Hope this helps:
Main.py
import wx
from LoginPanel import LoginPanel
class MyFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Something something", pos = wx.DefaultPosition, size = wx.Size( 300,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
BoxSizer0 = wx.BoxSizer( wx.VERTICAL )
# Add login panel
self.login_panel = LoginPanel(self)
BoxSizer0.Add(self.login_panel, 1, wx.EXPAND | wx.ALL, 0)
# Add notebook panel and its pages
self.nb = wx.Notebook( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
self.nb_subpanel1 = wx.Panel( self.nb, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
self.nb.AddPage( self.nb_subpanel1, u"something", False )
self.nb_subpanel2 = wx.Panel( self.nb, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
self.nb.AddPage( self.nb_subpanel2, u"something else", False )
BoxSizer0.Add( self.nb, 1, wx.EXPAND |wx.ALL, 0 )
# Adds a logout button
self.logout_button = wx.Button( self, wx.ID_ANY, u"Logout", wx.DefaultPosition, wx.DefaultSize, 0 )
BoxSizer0.Add( self.logout_button, 0, wx.ALIGN_CENTER|wx.ALL, 5 )
# Hide nb and logout button
self.nb.Hide()
self.logout_button.Hide()
self.SetSizer( BoxSizer0 )
self.Layout()
self.Centre( wx.BOTH )
self.Show()
# Connect Events
self.logout_button.Bind( wx.EVT_BUTTON, self.on_logout )
# Virtual event handlers, override them in your derived class
def on_logout( self, event ):
self.nb.Hide()
self.logout_button.Hide()
self.login_panel.Show()
self.Layout()
if __name__ == "__main__":
app = wx.App()
MyFrame(None)
app.MainLoop()
LoginPanel.py
import wx
class LoginPanel ( wx.Panel ):
def __init__( self, parent ):
wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( 300,300 ), style = wx.TAB_TRAVERSAL )
BoxSizer01 = wx.BoxSizer( wx.VERTICAL )
self.login_button = wx.Button( self, wx.ID_ANY, u"Login", wx.DefaultPosition, wx.DefaultSize, 0 )
self.login_button.SetDefault()
BoxSizer01.Add( self.login_button, 0, wx.ALIGN_CENTER|wx.ALL, 5 )
self.SetSizer( BoxSizer01 )
self.Layout()
# Connect Events
self.login_button.Bind( wx.EVT_BUTTON, self.on_login )
# Virtual event handlers, overide them in your derived class
def on_login( self, event ):
self.Hide()
self.Parent.nb.Show()
self.Parent.logout_button.Show()
self.Parent.Layout()

WxPython dynamically added sizers mis-behaving

I'm trying to set-up a display to show the gamertag and avatar of users added to a text file, it most of the way there but I can't get them to position properly.
A quick mock-up of what I want: here.
Here is what I currently have on start: here
EDIT: I've switched from using a BoxSizer to using a GridSizer and that seems to have fixed the position issue, they no longer overlap, the shifting problem is still present however.
The sizer containing the users shouldn't be overlapping with the input sizer at the top, I don't know what is causing this.
And what happens when it updates to check for new users: here
Might not be that easy to see but in the second image the lowest user is shifted down, it gets further and further down as the program runs, each time it is moved down by it's own height.
The relevant code areas:
Creating the starting sizers
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.widget_sizer = wx.BoxSizer(wx.VERTICAL)
#Holds input for gamertags and addition
self.input_sizer = wx.BoxSizer(wx.HORIZONTAL)
#Content to be added immediately.
self.gamer_tag_textbox = wx.TextCtrl(self, -1)
self.gamer_tag_textbox.SetFocus()
self.add_gamer_tag = wx.Button(self, -1, 'Add Friend')
#Contains the displayed content
self.user_sizer = wx.BoxSizer(wx.VERTICAL)
#Add objects to sizers
self.input_sizer.Add(self.gamer_tag_textbox, 0)
self.input_sizer.Add(self.add_gamer_tag, 0)
#Set up the sizers
self.widget_sizer.Add(self.input_sizer, 0)
self.widget_sizer.Add(self.user_sizer, 0)
self.main_sizer.Add(self.widget_sizer, 0)
self.SetSizer(self.main_sizer)
Adding sizers created for each user to the main user_sizer.
def display_user_content(self, details):
self.user_sizer.Clear(True)
#This is different to the original code, it originally used boxsizers in the for each loop.
self.single_user_sizer = wx.GridSizer(cols=2)
for each in details:
#Create sizer to contain user information
#Get username
username = each[0]
#Get location of image file
location = each[-1]
#Create static text to contain username
stat = wx.StaticText(self, -1, 'username')
#Load image from location and convert to bitmap.
png = wx.Image(location, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
#Create bitmap
avatar = wx.StaticBitmap(self, -1, png)
#Add to sizer
self.single_user_sizer.Add(avatar, 1)
self.single_user_sizer.Add(stat, 1)
#Add each users sizer to main user sizer
self.user_sizer.Add(self.single_user_sizer, 1)
#Add main user sizer to widget sizer
self.widget_sizer.Add(self.user_sizer, 0)
self.frame.Fit()
Full code (minus classes): here
Maybe this is similar to what you would like to achieve?
import wx
NUMBER = 3
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self)
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
self.sizer = wx.GridBagSizer(vgap=5, hgap=5)
self.text = wx.TextCtrl(self.panel, size=(0, 0))
self.button = wx.Button(self.panel)
self.sizer.Add(self.text, (0, 0), flag=wx.EXPAND)
self.sizer.Add(self.button, (0, 1))
self.icons = []
self.stats = []
for i in range(NUMBER):
icon = wx.Panel(self.panel, size=(50, 50))
icon.SetBackgroundColour(wx.RED)
stat = wx.Panel(self.panel, size=(200, -1))
stat.SetBackgroundColour(wx.BLUE)
self.sizer.Add(icon, (i+1, 0))
self.sizer.Add(stat, (i+1, 1), flag=wx.EXPAND)
self.icons.append(icon)
self.stats.append(stat)
self.sizer.AddGrowableCol(1)
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
self.Show()
app = wx.App(False)
win1 = MainWindow(None)
app.MainLoop()
Or maybe more like this?
import wx
NUMBER = 3
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self)
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
self.sizer = wx.GridBagSizer(vgap=5, hgap=5)
self.toolbar_sizer = wx.BoxSizer()
self.text = wx.TextCtrl(self.panel)
self.button = wx.Button(self.panel)
self.toolbar_sizer.Add(self.text, 0, flag=wx.CENTER)
self.toolbar_sizer.Add(self.button, 0)
self.sizer.Add(self.toolbar_sizer, (0, 0), span=(1, 2), flag=wx.EXPAND)
self.icons = []
self.stats = []
for i in range(NUMBER):
icon = wx.Panel(self.panel, size=(50, 50))
icon.SetBackgroundColour(wx.RED)
stat = wx.Panel(self.panel, size=(200, -1))
stat.SetBackgroundColour(wx.BLUE)
self.sizer.Add(icon, (i+1, 0))
self.sizer.Add(stat, (i+1, 1), flag=wx.EXPAND)
self.icons.append(icon)
self.stats.append(stat)
self.sizer.AddGrowableCol(1)
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
self.Show()
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
At the end of the display_user_content function I was adding the user_sizer to the widget_sizer each time, this was unnecessary and was causing a doubling of the number of results, I have removed that line and my code now works.
The fixed code:
def display_user_content(self, details):
self.user_sizer.Clear(True)
self.single_user_sizer = wx.GridSizer(cols=2, hgap=5, vgap=5)
for each in details:
#Get username
self.username_sizer = wx.BoxSizer(wx.HORIZONTAL)
username = each[0]
#Get location of image file
location = each[-1]
#Create static text to contain username
stat = wx.StaticText(self, -1, 'username')
#Load image from location and convert to bitmap.
png = wx.Image(location, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
#Create bitmap
avatar = wx.StaticBitmap(self, -1, png)
#Add to sizer
self.single_user_sizer.Add(avatar, 0)
self.username_sizer.Add(stat, 0)
self.single_user_sizer.Add(self.username_sizer, 0)
#Add each users sizer to main user sizer
self.user_sizer.Add(self.single_user_sizer, 0)
#Add main user sizer to widget sizer
#self.widget_sizer.Add(self.user_sizer, 0)
self.Fit()

How to add and edit time in a textctrl in wxpython?

I am developing a GUI using wxpython where i need a textctrl which selects the time .I tried with TimePickerCtrl but failed to fetch the time into the textctrl. It would be great if anyone shares a good example code which adds a time to a textctrl and can be edit the textctrl at any time.Thanks in advance.
Did you even look at the wxPython demo? It shows 3 different ways to create the picker control:
import wx
import wx.lib.masked as masked
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
# 12-hour format
text1 = wx.StaticText( self, -1, "12-hour format:", size=(150,-1))
self.time12 = masked.TimeCtrl( self, -1, name="12 hour control" )
h = self.time12.GetSize().height
spin1 = wx.SpinButton(
self, -1, wx.DefaultPosition, (-1,h), wx.SP_VERTICAL )
self.time12.BindSpinButton( spin1 )
self.addWidgets([text1, self.time12, spin1])
# 24-hour format
text2 = wx.StaticText( self, -1, "24-hour format:")
spin2 = wx.SpinButton(
self, -1, wx.DefaultPosition, (-1,h), wx.SP_VERTICAL )
self.time24 = masked.TimeCtrl(
self, -1, name="24 hour control", fmt24hr=True,
spinButton = spin2
)
self.addWidgets([text2, self.time24, spin2])
# No seconds\nor spin button
text3 = wx.StaticText( self, -1, "No seconds\nor spin button:")
self.spinless_ctrl = masked.TimeCtrl(
self, -1, name="spinless control",
display_seconds = False
)
self.addWidgets([text3, self.spinless_ctrl])
# set sizer
self.SetSizer(self.mainSizer)
def addWidgets(self, widgets):
sizer = wx.BoxSizer(wx.HORIZONTAL)
for widget in widgets:
if isinstance(widget, wx.StaticText):
sizer.Add(widget, 0, wx.ALL|wx.CENTER, 5),
else:
sizer.Add(widget, 0, wx.ALL, 5)
self.mainSizer.Add(sizer)
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Spinner Demo")
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
f = MyFrame()
app.MainLoop()

Categories