Related
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()
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.
I am trying to get the result from the SQL Query to show up next to the text "Tickets Closed Last 24 Hours" when the script is executed.
The SQL Query returns a single number.
I am trying to get the number to show in the StaticText box for self.some_text where it changes the label text to the number when ran.
Example: https://s11.postimg.org/jil0kzfqb/tickets.png
In the image there is no number from the SQL query.
(You can ignore the Address, unit number and city text and boxes)
I am going off another program someone else created so some of this code may not be needed.
I am trying to learn SQL and Python on the fly, pretty much a novice right now.
This is my code so far:
import wx
import MySQLdb
db = MySQLdb.connect(host="xxxxxxxxxxxx",port=xxx,user="xx",passwd="xxxxx",db="xxxx")
class Data():
def TicketsClosedLast24Hours(self, event):
cur = db.cursor()
cur.execute("Select COUNT(*) FROM HD_TICKET WHERE HD_STATUS_ID = 12 AND TIME_CLOSED >= NOW() - INTERVAL 1 DAY")
row = cur.fetchone()
print(row[0])
row = cur.fetchone()
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.Centre()
self.Maximize(True)
self.background = wx.Panel(self)
self.background.SetBackgroundColour(wx.Colour(98, 125, 152))
self.some_text = wx.StaticText(self.background, wx.ID_ANY, label="", style=wx.ALIGN_CENTER)
self.Address = wx.TextCtrl(self.background, -1, "", size=(140, -1))
self.UnitNumber = wx.TextCtrl(self.background, -1, "", size=(140, -1))
self.City = wx.TextCtrl(self.background, -1, "", size=(140, -1))
self.horizontalRow0 = wx.BoxSizer()
img1 = wx.Image("logo1.bmp", wx.BITMAP_TYPE_BMP, -1)
self.bitmap1 = wx.StaticBitmap(self.background, -1, wx.BitmapFromImage(img1), (55, 0))
self.horizontalRow0.Add(self.bitmap1, wx.Center, border=10)
self.VerticalRow1 = wx.BoxSizer(wx.VERTICAL)
self.VerticalRow1.Add(wx.StaticText(self.background, -1, "Tickets Closed Last 24 Hours",
style=wx.ALIGN_CENTER), flag=wx.ALL, border=5)
self.VerticalRow1.Add(wx.StaticText(self.background, -1, "Address:",
style=wx.ALIGN_CENTER), flag=wx.ALL, border=9)
self.VerticalRow1.Add(wx.StaticText(self.background, -1, "Unit Number:",
style=wx.ALIGN_CENTER), flag=wx.ALL, border=9)
self.VerticalRow1.Add(wx.StaticText(self.background, -1, "City:",
style=wx.ALIGN_CENTER), flag=wx.ALL, border=9)
# To add labels - H-1 V-2
self.VerticalRow2 = wx.BoxSizer(wx.VERTICAL)
self.VerticalRow2.Add(self.some_text, proportion=1, flag=wx.ALL, border=6)
self.VerticalRow2.Add(self.Address, proportion=1, flag=wx.ALL, border=6)
self.VerticalRow2.Add(self.UnitNumber, proportion=1, flag=wx.ALL, border=6)
self.VerticalRow2.Add(self.City, proportion=1, flag=wx.ALL, border=6)
# Combine V-1 And V-2 to H1
self.horizontalRow1 = wx.BoxSizer()
self.horizontalRow1.Add((30, 30), proportion=0, flag=wx.EXPAND, border=0)
self.horizontalRow1.Add(self.VerticalRow1, proportion=.5)
self.horizontalRow1.Add(self.VerticalRow2, proportion=0)
# To add labels - H-3 V-8
self.VerticalRow1 = wx.BoxSizer(wx.VERTICAL)
# To add labels - H-4 V-9
self.horizontalRow4 = wx.BoxSizer()
self.horizontalRow4.Add((30, 30), proportion=.5, flag=wx.EXPAND, border=0)
self.horizontalRow4.Add((30, 30), proportion=1, flag=wx.EXPAND, border=0)
# Adds horizontal Rows to Main Window in Vertical boxes
self.verticalBox = wx.BoxSizer(wx.VERTICAL)
self.verticalBox.Add(self.horizontalRow0, proportion=0, flag=wx.EXPAND, border=10)
self.verticalBox.Add((10, 10), proportion=0, flag=wx.EXPAND, border=10)
self.verticalBox.Add(self.horizontalRow1, proportion=0, flag=wx.EXPAND, border=0)
self.verticalBox.Add((10, 10), proportion=0, flag=wx.EXPAND, border=10)
self.verticalBox.Add(self.horizontalRow4, proportion=0, flag=wx.EXPAND, border=0)
self.background.SetSizer(self.verticalBox)
self.Show()
def someFunction(self):
mysql_data = databasemodel.returnData() # query your database to return a string
self.some_text.SetLabel(mysql_data)
if __name__ == '__main__':
app = wx.App(redirect=False)
window = MainFrame()
app.MainLoop()
Any help would be appreciated.
Thanks!
The code looks correct to me. I don't see anything that is actually calling someFunction though. My guess is that that is the issue. You should try calling that and printing out mysql_data to stdout to make sure the result you are receiving is what you expect.
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 would like for my TextCtrl field to gain a vertical scroll as I write events out on it.
The code I have so far is;
sizer = wx.BoxSizer(wx.VERTICAL) #Create a vertical sizer
#Create our multiline console area
self.term = wx.TextCtrl(self, -1, '', style=wx.TE_MULTILINE)
#Add our console to the sizer
sizer.Add(self.term, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 0)
gs = wx.GridSizer(1, 3, 0, 0) #Define the grid layout in rows, columns
gs.AddMany([
(wx.Button(self.panel, 3, 'Browse'), 0, wx.EXPAND),
(wx.Button(self.panel, 1, 'RUN'), 0, wx.EXPAND),
(wx.Button(self.panel, 2, 'QUIT'), 0, wx.EXPAND) ])
#Add our defined grid layout above to our sizer
sizer.Add(gs, 1, wx.EXPAND)
self.SetSizer(sizer) #Pass & show our sizer
I get a scoll bar, it however does not respond to mouse clicks. What am I doing wrong?
Those three buttons are children of self.panel, which is just hanging out in your frame, intercepting your mouse events. If you allow resizing, you'll see that the panel is not resized along with the buttons, but you can click on the portion of the TextCtrl that extends beyond it.
You can either get rid of the panel entirely and make everything a child of the frame, or make gs the panel's sizer, and add the panel to your main sizer in place of gs:
sizer.Add(self.term, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 0)
gs = wx.GridSizer(1, 3, 0, 0) #Define the grid layout in rows, columns
gs.AddMany([
(wx.Button(self.panel, 3, 'Browse'), 0, wx.EXPAND),
(wx.Button(self.panel, 1, 'RUN'), 0, wx.EXPAND),
(wx.Button(self.panel, 2, 'QUIT'), 0, wx.EXPAND) ])
self.panel.SetSizer(gs)
sizer.Add(self.panel, 1, wx.EXPAND) #Add our defined grid layout above to our sizer