I made a small and simple program using wx.BoxSizer.
Here is the source code:'
import wx
# MAIN PROGRAM...
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "My Frame", size = (600, 600))
mainPanel = wx.Panel(self)
mainBox = wx.BoxSizer(wx.VERTICAL)
header1 = wx.StaticText(mainPanel, label = 'Header1:')
header2 = wx.StaticText(mainPanel, label = 'Header2:')
panel1 = wx.Panel(mainPanel, size = (200, 200), style = wx.SUNKEN_BORDER)
panel2 = wx.Panel(mainPanel, size = (200, 200), style = wx.SUNKEN_BORDER)
box1 = wx.BoxSizer(wx.HORIZONTAL)
box1.AddSpacer(50)
box1.Add(header1, 0, wx.ALL, 5)
box1.AddSpacer(50)
box1.Add(header2, 0, wx.ALL, 5)
box2 = wx.BoxSizer(wx.HORIZONTAL)
box2.Add(panel1, 0, wx.ALL, 5)
box2.Add(panel2, 0, wx.ALL, 5)
mainBox.Add(box1, 0, wx.ALL, 5)
mainBox.Add(box2, 0, wx.ALL, 5)
mainPanel.SetSizer(mainBox)
#self.Center()
if __name__ == '__main__':
app = wx.App()
frame = MyFrame()
frame.Show(True)
app.MainLoop()
print 'Exiting...'
The issue is that when, I add horizontal space to the left of each header, it also adds vertical space between the headers and sunken_border header1 and header2. Is there anyway to just add the horizontal space before the headers without adding the vertical space as a side effect?
Thanks.
---EDIT---
To answer your comment:
here is a picture of the program:
Simple BoxSizer program...
The 'space' in green is wanted space, but the 'space' in red is an unneeded side effect. I basically only want the green space, but I don't want the red space, I want the headers to be flush with the two panels (like right directly on top...).
Right now, I am having to do absolute positioning to get it to work, I just wanted to know if you can make it work with BoxSizer or some other layout manager...
Thanks again.
When you write
Add( ..., 0, wx.ALL, 5)
you are adding 5 pixels ALL AROUND.
So:
box1.Add(header1, 0, wx.ALL, 5)
adds 5 pizels below header 1
box2.Add(panel1, 0, wx.ALL, 5)
adds 5 pixels above panel 1
mainBox.Add(box1, 0, wx.ALL, 5)
adds 5 pixels below header 1 ( contained in box1 )
mainBox.Add(box2, 0, wx.ALL, 5)
adds 5 pixels above panel1 ( contained in box2 )
for a total of 20 extra pixels.
If you do not want white space in the vertical direction, do not write
Add( ..., 0, wx.ALL, 5)
Instead, something like this
mainPanel = wx.Panel(self)
mainBox = wx.BoxSizer(wx.VERTICAL)
header1 = wx.StaticText(mainPanel, label = 'Header1:')
header2 = wx.StaticText(mainPanel, label = 'Header2:')
panel1 = wx.Panel(mainPanel, size = (200, 200), style = wx.SUNKEN_BORDER)
panel2 = wx.Panel(mainPanel, size = (200, 200), style = wx.SUNKEN_BORDER)
box1 = wx.BoxSizer(wx.HORIZONTAL)
box1.AddSpacer(50)
box1.Add(header1)
box1.AddSpacer(50)
box1.Add(header2)
box2 = wx.BoxSizer(wx.HORIZONTAL)
box2.AddSpacer(5)
box2.Add(panel1)
box2.AddSpacer(10)
box2.Add(panel2)
mainBox.AddSpacer(5)
mainBox.Add(box1)
mainBox.Add(box2)
mainPanel.SetSizer(mainBox)
#self.Center()
I found the solution!
instead of this:
box1.AddSpacer(50)
do this...
box1.AddSpacer((50, 0))
It works, yay!
Thanks.
Related
I want to add a white color to the thickness box which is currently appearing as grey as in the image. Any help to solve
Below is the code
sbSizer4 = wx.StaticBoxSizer( wx.StaticBox( self.m_panel_geometry, wx.ID_ANY, u"Thickness" ), wx.VERTICAL )
sbSizer4.Add( ( 0, 0), 1, wx.EXPAND, 5 )
m_thicknessChoices = [ u"0.062 in", u"0.031 in" ]
self.m_thickness = wx.Choice( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_thicknessChoices, 0 )
self.m_thickness.SetSelection( 0 )
#self.m_thickness.SetBackgroundColour(wx.Colour(240, 0, 240))
sbSizer4.Add( self.m_thickness, 0, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 15 )
sbSizer4.Add( ( 0, 0), 1, wx.EXPAND, 5 )
bSizer11.Add( sbSizer4, 1, wx.ALL|wx.EXPAND, 10 )
bSizer9.Add( bSizer11, 1, wx.EXPAND, 5 )
bSizer12 = wx.BoxSizer( wx.HORIZONTAL )
It took a while to realise that:
Your code was not indented properly (not helped by another edit)
You're using a StaticBox within a StaticBoxSizer
You must be using an older version of wxPython
Try removing one of the static boxes, there seems little to be gained from having 2 of them, whilst only labeling one.
You specify white in the question but in the code you attempted a vile puce/pink colour, I've run with that ;).
import wx
class TestFrame(wx.Frame):
def __init__(self, parent, title="Static Box"):
wx.Frame.__init__(self, parent, -1, title)
panel = wx.Panel(self)
panel.SetBackgroundColour("palegreen")
bSizer9 = wx.BoxSizer( wx.VERTICAL )
bSizer11 = wx.BoxSizer( wx.VERTICAL )
sbSizer4 = wx.StaticBoxSizer( wx.VERTICAL, panel, "Thickness")
sbSizer4.Add( ( 0, 0), 1, wx.EXPAND, 5 )
m_thicknessChoices = [ u"0.062 in", u"0.031 in" ]
self.m_thickness = wx.Choice( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_thicknessChoices, 0 )
self.m_thickness.SetSelection( 0 )
self.m_thickness.SetBackgroundColour(wx.Colour(240, 0, 240))
sbSizer4.Add( self.m_thickness, 0, wx.ALL|wx.EXPAND, 15 )
sbSizer4.Add( ( 0, 0), 1, wx.EXPAND, 5 )
bSizer11.Add( sbSizer4, 0, wx.ALL|wx.EXPAND, 10 )
bSizer9.Add( bSizer11, 1, wx.EXPAND, 5 )
panel.SetSizer(bSizer9)
self.Show()
if __name__ == '__main__':
app = wx.App()
TestFrame(None)
app.MainLoop()
Replacing wx.Choice() with BitmapComboBox() and style=wx.CB_READONLY fixed the color issue for me. There's some odd fading in and out when changing the selection though (at least on Win 10). wxPython is really good at making simple things hard.
I have written a program with wxPython. We run that program on many different computers with different display configurations.
Examples:
1920x1080, DPI 100%
3000x2000, DPI 175%
1980x1080, DPI 150% (small 13" Display Laptop)
I code on an Full HD, DPI 100% display - the GUI looks fine! Especially on the 3000x2000. TextCtrls, BitmapButtons, and Images in general change their size (they get much smaller) and the GUI gets messed up for different resolutions. Same for the DPI 150%.
I tried to prevent it by setting the DPI awareness of my process in my main class but this doesn't work consistently.
Here is the how I set my DPI awareness:
import ctypes
# Query DPI Awareness (Windows 10 and 8)
awareness = ctypes.c_int()
errorCode = ctypes.windll.shcore.GetProcessDpiAwareness(0, ctypes.byref(awareness))
# Set DPI Awareness (Windows 10 and 8)
errorCode = ctypes.windll.shcore.SetProcessDpiAwareness(2)
Question:
What do I need to do to make my GUI look at least similar on all DPI and resolution settings?
Are there special considerations for using images?
Do I need to scale widget/font size in my code directly?
Are there any tips with setting the size and distance of widgets in sizers?
I will attach a code example where I try to do as much size and positioning stuff as possible to give you guys a base to maybe fix something.
import wx
import wx.adv
class Mywin(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self, parent, wx.ID_ANY, title,size= (600,-1))
self.SetSize(800,500)
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_1.Add(wx.StaticText(self, size=(125,-1), label='Order ID'), 0, wx.ALL , 5)
sizer_1.Add(wx.StaticText(self, size=(125,-1), label='Status'), 0, wx.ALL , 5)
sizer_1.Add(wx.StaticText(self, size=(125,-1), label='Creator'), 0, wx.ALL , 5)
sizer_1.Add((-1, 5))
sizer_1.Add(wx.StaticText(self, size=(125,-1), label='Comment'), 0, wx.ALL , 5)
sizer_1.Add((-1, 40))
sizer_1.Add(wx.StaticText(self, size=(125,-1), label='Customer ID'), 0, wx.ALL , 5)
sizer_1.Add(wx.StaticText(self, size=(125,-1), label='Customer Name'), 0, wx.ALL , 5)
sizer_1.Add(wx.StaticText(self, size=(125,-1), label='Contact Person'), 0, wx.ALL , 5)
sizer_1.Add((-1, 21))
sizer_1.Add(wx.StaticText(self, size=(125,-1), label='Inquiry Date'), 0, wx.ALL , 5)
ctrl_height = 25
stati = ["Test", "Example"]
tc_order_id = wx.TextCtrl(self, -1, size=(100, ctrl_height),style=wx.TE_PROCESS_ENTER)
cb_status = wx.ComboBox(self,size=(100, ctrl_height), choices=stati, style=wx.CB_READONLY)
cb_creator = wx.ComboBox(self,size=(100, ctrl_height), choices=stati, style=wx.CB_READONLY)
tc_comment = wx.TextCtrl(self, id=-1, value='', size=(300,55), style=wx.TE_MULTILINE|wx.SUNKEN_BORDER)
tc_customer_id = wx.TextCtrl(self, -1, size=(80, ctrl_height),style=wx.TE_PROCESS_ENTER)
tc_customer_name = wx.TextCtrl(self, -1, size=(300, ctrl_height),style=wx.TE_READONLY)
tc_contact_id = wx.TextCtrl(self, -1, size=(80, ctrl_height),style=wx.TE_PROCESS_ENTER)
calender_style = wx.adv.DP_DROPDOWN | wx.adv.DP_SHOWCENTURY | wx.adv.DP_ALLOWNONE
tc_order_date = wx.adv.GenericDatePickerCtrl(self, size=(90,ctrl_height), style = calender_style)
sizer_2 = wx.BoxSizer(wx.VERTICAL)
sizer_2.Add(tc_order_id, 0)
sizer_2.Add(cb_status,0, wx.TOP , 3)
sizer_2.Add(cb_creator, wx.TOP , 2)
sizer_2.Add(tc_comment, 0, wx.TOP, 9)
sizer_2.Add(tc_customer_id, 0, wx.TOP, 4)
sizer_2.Add(tc_customer_name, 0, wx.TOP, 4)
sizer_2.Add(tc_contact_id, 0, wx.TOP, 4)
sizer_2.Add(tc_order_date, 0, wx.TOP, 20)
mainsizer = wx.BoxSizer(wx.HORIZONTAL)
mainsizer.Add(sizer_1)
mainsizer.Add(sizer_2)
self.SetSizer(mainsizer)
self.Centre()
self.Show()
self.Layout()
demo = wx.App()
Mywin(None,'Example Code')
demo.MainLoop()
This is my code:
class TabTwo(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.resetButton = wx.Button(self, label="Reset")
self.contactButton = wx.Button(self, label="Contact")
self.copyrightButton = wx.Button(self, label="Copyright")
v_sizer = wx.BoxSizer(wx.VERTICAL)
h_sizer = wx.BoxSizer(wx.HORIZONTAL)
v_sizer.Add(self.resetButton, 0, wx.EXPAND, 30)
v_sizer.Add(self.contactButton, 0, wx.EXPAND, 30)
v_sizer.Add(self.copyrightButton, 0, wx.EXPAND, 30)
self.SetSizer(v_sizer)
How do I add some space between the buttons (Reset, Contact and Copyright) so that it doesn't look to much like it's been pressed together.
Specify a border when adding to the sizer:
v_sizer.Add( self.resetButton, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 )
v_sizer.Add( self.contactButton, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 )
v_sizer.Add( self.copyrightButton, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 )
Here wx.TOP|wx.BOTTOM specifies to add a border to the top and bottom of the widget. I'm assuming you just want top and bottom; wx.ALL adds on all sides. Also wx.RIGHT and wx.LEFT are available.
The parameter following wx.EXPAND|wx.TOP|wx.BOTTOM (ie 5) is the size of the border.
See here for more information: https://wxpython.org/Phoenix/docs/html/wx.Sizer.html#wx-sizer. In particular the Add function and the flag and border parameters.
I'm trying to hone my Python skills by creating a simple app to organize an itinerary. The basis of the app is that you enter the task to add, then another window pops out to ask for the due date and priority of the task. The second window has a submit button that is supposed to add all the gathered information to a list box with multiple columns.
My issue is where to create an array to hold the information so that it can be added. I can't add it to the add function itself, because it needs to be referenced by other functions.
I've tried adding it to the __init__ of my MainWindow, but that's where I get stuck. I don't know how to reference the array once it's there. Simply referencing the name (toAdd) give me exception
Traceback (most recent call last):
File "Making GUI - First Shot (Development).py", line 60, in AddItem
toAdd.append(appendItem)
NameError: global name 'toAdd' is not defined
Here's my code:
import wx
class mainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(650, 500))
panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
menubar = wx.MenuBar()
topFont = wx.Font(20, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.topLabel = wx.StaticText(panel, size = (-1, -1), label="Itinerary")
font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.topLabel.SetFont(topFont)
vbox.Add(self.topLabel, 0, wx.ALL, 2)
vbox.Add((-1, 10))
self.listBox = wx.ListCtrl(panel, style = wx.LC_REPORT)
self.listBox.InsertColumn(0, "Priority", width = 150)
self.listBox.InsertColumn(0, "Due Date (if applicable)", width = 250)
self.listBox.InsertColumn(0, "Task", width=250)
self.listBox.SetFont(font)
vbox.Add(self.listBox, 1, wx.EXPAND | wx.ALL, 2)
hbox1.Add((5, -1))
self.newItemInput = wx.TextCtrl(panel, size = (400, -1))
hbox2.Add(self.newItemInput, 1, wx.ALIGN_LEFT | wx.ALL, 1)
self.submitButton = wx.Button(panel, size = (100, -1))
self.submitButton.SetLabel("Hello")
self.Bind(wx.EVT_BUTTON, self.AddItem, self.submitButton)
hbox2.Add(self.submitButton, 1, wx.ALIGN_RIGHT | wx.ALL, 2)
vbox.Add(hbox1, 0, wx.ALL, 2)
vbox.Add(hbox2, 0, wx.EXPAND | wx.ALL, 2)
vbox.Add((-1, 35))
panel.SetSizer(vbox)
self.Show(True)
toAdd = []
def AddItem(self, event):
appendItem = self.newItemInput.GetValue()
toAdd.append(appendItem)
confirmBox = wx.Frame(frame, title = "Task Details", size = (300, 150))
confirmVert = wx.BoxSizer(wx.VERTICAL)
confirmHoriz1 = wx.BoxSizer(wx.HORIZONTAL)
confirmHoriz2 = wx.BoxSizer(wx.HORIZONTAL)
confirmHoriz3 = wx.BoxSizer(wx.HORIZONTAL)
confirmHoriz4 = wx.BoxSizer(wx.HORIZONTAL)
confirmPrompt = wx.StaticText(confirmBox, size = (25, -1), label = "Due Date for " + toAdd[0])
confirmHoriz1.Add(confirmPrompt, 1, wx.EXPAND | wx.ALIGN_CENTER)
addingDate = wx.TextCtrl(confirmBox, size = (25, -1))
confirmHoriz2.Add(addingDate, 1, wx.EXPAND | wx.ALIGN_CENTER)
confirmPriority = wx.StaticText(confirmBox, size = (25, -1), label = "Priority")
confirmHoriz3.Add(confirmPriority, 1, wx.EXPAND | wx.ALIGN_CENTER)
addingPriority = wx.TextCtrl(confirmBox, size = (25, -1))
confirmHoriz4.Add(addingPriority, 1, wx.EXPAND | wx.ALIGN_CENTER)
addListButton = wx.Button(confirmBox, size = (-1, 25), label = "Submit")
confirmVert.Add(confirmHoriz1, 0, wx.EXPAND | wx.ALIGN_CENTER)
confirmVert.Add(confirmHoriz2, 0, wx.EXPAND | wx.ALIGN_CENTER)
confirmVert.Add(confirmHoriz3, 0, wx.EXPAND | wx.ALIGN_CENTER)
confirmVert.Add(confirmHoriz4, 0, wx.EXPAND | wx.ALIGN_CENTER)
confirmVert.Add(addListButton, 0, wx.EXPAND | wx.ALIGN_CENTER)
def itemSubmit(self):
date = addingDate.GetValue()
priority = addingPriority.GetValue()
toAdd.append(date)
toAdd.append(priority)
panel.listBox.Append(toAdd)
confirmBox.Bind(wx.EVT_BUTTON, itemSubmit, addListButton)
confirmBox.SetSizer(confirmVert)
confirmBox.Show()
app = wx.App(False)
frame = mainWindow(None, "Itinerary Manager")
app.MainLoop()
How would I go about making AddItem append the information to toAdd so that I can then append toAdd to the ListCtrl on the main window?
Utilise the self reference for your data items, so declare
toAdd = []
as
self.toAdd[]
this should apply to your other variables as well.
The first argument of every class method, including init, is always a reference to the current instance of the class. By convention, this argument is always named self. It isn't a rule just a convention.
I am making a frame with a scrollbar and some images inside. The scrollbar works fine when the frame is empty. However, when I add a picture in, the scrollbars seem to get pushed up into the top left corner of the frame. How can I implement my code so that the scrollbars stay where they are after I add pictures?
Working Code;
import wx
import wx.animate
class ScrollbarFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Scrollbar Example', pos = (100, 50), size=(1000, 1000))
self.scroll = wx.ScrolledWindow(self, -1)
self.scroll.SetScrollbars(1, 1, 1000, 1000)
#self.button = wx.Button(self.scroll, -1, "Scroll Me", pos=(50, 20))
#self.Bind(wx.EVT_BUTTON, self.OnClickTop, self.button)
#self.button2 = wx.Button(self.scroll, -1, "Scroll Back", pos=(500, 350))
#self.Bind(wx.EVT_BUTTON, self.OnClickBottom, self.button2)
self.SetBackgroundColour("gray")
imageName = "01 background.png"
gifName = "Jill.gif"
backgroundImage = wx.Image(imageName, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(self, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight()))
gifImage = wx.animate.GIFAnimationCtrl(self, 0, gifName, pos=(160, 74))
# clears the background
gifImage.GetPlayer().UseBackgroundColour(True)
gifImage.Play()
def update(self, imageName, gifName):
backgroundImage = wx.Image(imageName, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(self, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight()))
gifImage = wx.animate.GIFAnimationCtrl(self, 0, gifName, pos=(100, 100))
# clears the background
gifImage.GetPlayer().UseBackgroundColour(True)
gifImage.Play()
def OnClickTop(self, event):
self.scroll.Scroll(600, 400)
def OnClickBottom(self, event):
self.scroll.Scroll(1, 1)
app = wx.PySimpleApp()
frame = ScrollbarFrame()
frame.Show()
app.MainLoop()
if you comment out this part:
gifName = "Jill.gif"
backgroundImage = wx.Image(imageName, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(self, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight()))
gifImage = wx.animate.GIFAnimationCtrl(self, 0, gifName, pos=(160, 74))
# clears the background
gifImage.GetPlayer().UseBackgroundColour(True)
gifImage.Play()
the window displays properly with the scrollbar. But include either (or both) of the image files, and the problem occurs.
If you want your images inside the scrolled window panel, then you have to put your static bipmap and gifImage inside it. So the parent of your images should not be self (the wx.Frame instance) but self.scroll.
Modify the 4 lines indicated:
...................
wx.StaticBitmap(self.scroll, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight())) # <- this one
gifImage = wx.animate.GIFAnimationCtrl(self.scroll, 0, gifName, pos=(160, 74)) # <- this one
# clears the background
gifImage.GetPlayer().UseBackgroundColour(True)
gifImage.Play()
def update(self, imageName, gifName):
backgroundImage = wx.Image(imageName, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(self.scroll, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight())) # <- this one
gifImage = wx.animate.GIFAnimationCtrl(self.scroll, 0, gifName, pos=(100, 100)) # <- this one
...................
This puts your two images one over the other. If you want to put them separately (column or row), then you should add them to a sizer inserted in your scrolled window