Can't insert graph in a wxPython GUI - python

I am trying to make a telemetry software for a college project, that's why I'm using wxPython to make a GUI. I'm currently trying to make a function that displays a graph of brake_p and throttle in function of the time after I opened the entry file.
The code looks good to me, however it looks like there is an error inside the module that blocks me from succeeding.
Here is the error I get when I open the entry file :
> PS C:\Users\Adrie\OneDrive\Bureau\telemetry python> &
> 'C:\Users\Adrie\AppData\Local\Microsoft\WindowsApps\python3.10.exe'
> 'c:\Users\Adrie\.vscode\extensions\ms-python.python-2022.20.1\pythonFiles\lib\python\debugpy\adapter/../..\debugpy\launcher' '54993' '--' 'c:\Users\Adrie\OneDrive\Bureau\telemetry
> python\v0601.py' Traceback (most recent call last): File
> "c:\Users\Adrie\OneDrive\Bureau\telemetry python\v0601.py", line 105,
> in OnOpen self.OpenData(file) File
> "c:\Users\Adrie\OneDrive\Bureau\telemetry python\v0601.py", line 144,
> in OpenData self.canvas.Draw(self.drawBrakeThrottlePlot) File
> "C:\Users\Adrie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\wx\lib\plot\plotcanvas.py",
> line 1750, in Drawgraphics.logScale = self.logScale AttributeError:
> 'method' object has no attribute 'logScale' PS
> C:\Users\Adrie\OneDrive\Bureau\telemetry python>
The error I can't understand is the part in bold caracters,as it is nowhere in my code :
Drawgraphics.logScale = self.logScale
AttributeError: 'method' object has no attribute 'logScale'
I 'd like to add I plan to add a bar marker on the graph that would be either automatically move at real-time, or either movable by the user so the time at the marker would be used to display in other widget data corresponding to the exact instant (like in the matlab simulink graph/scopes), which means I can't store the graph as a bitmap but really as a graph/plot.
I tried to switch to another library to import the plot into the wxFrame but I just can't make it work as they look more complicated to me, so I got back to this method.
Here is the code :
import wx
import numpy as np
import matplotlib.pyplot as plt
from wx.lib.plot import PlotCanvas, PlotGraphics, PolyLine, PolyMarker
import wxmplot.interactive as wi
# Variables initialization
time, speed, distance, brake_p, throttle, g_x, g_y, g_z, gps_x, gps_y, omega_fl, omega_fr = ([] for i in range(12))
r=1 # Wheel radius, will implement a feature to make it editable by the user later
class MainWindow(wx.Frame):
def __init__(self, *args, **kw):
super(MainWindow, self).__init__(*args, **kw)
# Create a panel and add it to the main window
panel = wx.Panel(self)
# Set the panel as the main window's sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(panel, 1, wx.EXPAND)
self.SetSizer(sizer)
# Set the window's min size
self.SetMinSize((1280,720))
# create a menu bar
self.makeMenuBar()
# and a status bar
self.CreateStatusBar()
self.SetStatusText("v 0.1")
# put some text with a larger bold font on it
st = wx.StaticText(panel, label="Welcome on the EFT's Telemetry software !")
font = st.GetFont()
font.PointSize += 10
font = font.Bold()
st.SetFont(font)
# and create a sizer to manage the layout of child widgets
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(st, wx.SizerFlags().Border(wx.TOP|wx.LEFT, 25))
panel.SetSizer(sizer)
def makeMenuBar(self):
# Make a file menu with Hello and Exit items
fileMenu = wx.Menu()
# The "\t..." syntax defines an accelerator key that also triggers
# the same event
openItem = fileMenu.Append(-1, "&Open...\tCtrl-O",
"Open a data file")
fileMenu.AppendSeparator()
# When using a stock ID we don't need to specify the menu item's
# label
exitItem = fileMenu.Append(wx.ID_EXIT)
# Now a help menu for the about item
helpMenu = wx.Menu()
aboutItem = helpMenu.Append(wx.ID_ABOUT)
# Now a view menu for the view item
# viewMenu = wx.Menu()
# aboutItem = helpMenu.Append(wx.ID_VIEW)
# Make the menu bar and add the two menus to it. The '&' defines
# that the next letter is the "mnemonic" for the menu item. On the
# platforms that support it those letters are underlined and can be
# triggered from the keyboard.
menuBar = wx.MenuBar()
menuBar.Append(fileMenu, "&File")
menuBar.Append(helpMenu, "&Help")
# menuBar.Append(viewMenu, "&View")
# Give the menu bar to the frame
self.SetMenuBar(menuBar)
# Finally, associate a handler function with the EVT_MENU event for
# each of the menu items. That means that when that menu item is
# activated then the associated handler function will be called.
self.Bind(wx.EVT_MENU, self.OnOpen, openItem)
self.Bind(wx.EVT_MENU, self.OnExit, exitItem)
self.Bind(wx.EVT_MENU, self.OnAbout, aboutItem)
def OnExit(self, event):
self.Close(True)
def OnAbout(self, event):
wx.MessageBox("This is a simple Telemetry software project.",
wx.OK|wx.ICON_INFORMATION)
def drawBrakeThrottlePlot():
data1 = PolyLine([time, brake_p], legend='Brake Pressure (%)', colour='red', width='1')
data2 = PolyLine([time, throttle], legend='Throttle (%)', colour='green', width='1')
return PlotGraphics([data1, data2], "Real Time Brake Pressure and Throttle", "Time (ms)", "Relative Value (%)")
def OnOpen(self, event):
# Create the file dialog
with wx.FileDialog(self, "Open Data file", wildcard="text files (*.txt)|*.txt",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return # the user changed their mind
# Proceed loading the file chosen by the user
pathname = fileDialog.GetPath()
try:
with open(pathname, 'r') as file:
self.OpenData(file)
except IOError:
wx.LogError("Cannot open file '%s'." % pathname)
def OpenData(self, file):
data = file.readlines() # On assigne à L toutes les lignes du fichier
nb_lignes = len(data) # On assigne à nb_lignes la longueur de L
file.close()
for i in range(nb_lignes):
data[i] = data[i].strip('\n')
temp = data[i].split()
time.append(float(temp[0]))
speed.append((float(temp[8])+float(temp[9]))*r/2)
distance.append(speed[i]*1/1000) # Ici 1/1000 correspond à la fréquence d'échantillonage, modifiable en fx du capteur
brake_p.append(float(temp[1]))
throttle.append(float(temp[2]))
g_x.append(float(temp[3]))
g_y.append(float(temp[4]))
g_z.append(float(temp[5]))
gps_x.append(float(temp[6]))
gps_y.append(float(temp[7]))
omega_fl.append(float(temp[8]))
omega_fr.append(float(temp[9]))
# Remove the text on the panel
for child in self.GetChildren():
child.Destroy()
# create a panel and add it to the main window
panel = wx.Panel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(panel, 1, wx.EXPAND)
self.SetSizer(self.sizer)
# Create the plot
self.canvas = PlotCanvas(panel)
self.canvas.Draw(self.drawBrakeThrottlePlot)
self.sizer.Add(self.canvas, 1, wx.EXPAND)
self.sizer.Add(self.createControls(panel), 0, wx.EXPAND)
self.sizer.Add((-1, 10))
self.sizer.Add(self.createButtonBar(panel), 0, wx.EXPAND)
self.SetSizer(self.sizer)
self.sizer.Fit(self)
def createControls(self, panel):
box = wx.StaticBox(panel, -1, 'Data')
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
grid = wx.GridBagSizer(5, 5)
txt1 = wx.StaticText(panel, -1, 'Time (s)')
grid.Add(txt1, (1, 0))
self.tc1 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc1, (1, 1))
txt2 = wx.StaticText(panel, -1, 'Speed (km/h)')
grid.Add(txt2, (2, 0))
self.tc2 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc2, (2, 1))
txt3 = wx.StaticText(panel, -1, 'RPM')
grid.Add(txt3, (3, 0))
self.tc3 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc3, (3, 1))
txt4 = wx.StaticText(panel, -1, 'Brake pressure')
grid.Add(txt4, (4, 0))
self.tc4 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc4, (4, 1))
txt5 = wx.StaticText(panel, -1, 'Throttle position')
grid.Add(txt5, (5, 0))
self.tc5 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc5, (5, 1))
sizer.Add(grid, 0, wx.ALL, 10)
return sizer
def createButtonBar(self, panel):
"""
Create the buttons at the bottom of the panel
"""
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.zoomInButton = wx.Button(panel, -1, "Zoom In")
self.Bind(wx.EVT_BUTTON, self.OnZoomIn, self.zoomInButton)
sizer.Add(self.zoomInButton, 0, wx.LEFT | wx.RIGHT, 10)
self.zoomOutButton = wx.Button(panel, -1, "Zoom Out")
self.Bind(wx.EVT_BUTTON, self.OnZoomOut, self.zoomOutButton)
sizer.Add(self.zoomOutButton, 0, wx.LEFT | wx.RIGHT, 10)
self.panLeftButton = wx.Button(panel, -1, "Pan Left")
self.Bind(wx.EVT_BUTTON, self.OnPanLeft, self.panLeftButton)
sizer.Add(self.panLeftButton, 0, wx.LEFT | wx.RIGHT, 10)
self.panRightButton = wx.Button(panel, -1, "Pan Right")
self.Bind(wx.EVT_BUTTON, self.OnPanRight, self.panRightButton)
sizer.Add(self.panRightButton, 0, wx.LEFT | wx.RIGHT, 10)
self.resetButton = wx.Button(panel, -1, "Reset")
self.Bind(wx.EVT_BUTTON, self.OnReset, self.resetButton)
sizer.Add(self.resetButton, 0, wx.LEFT | wx.RIGHT, 10)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, self.resetButton)
return sizer
def OnZoomIn(self, event):
self.canvas.Zoom(1.2)
event.Skip()
def OnZoomOut(self, event):
self.canvas.Zoom(1/1.2)
event.Skip()
def OnPanLeft(self, event):
self.canvas.Move(-0.1, 0)
event.Skip()
def OnPanRight(self, event):
self.canvas.Move(0.1, 0)
event.Skip()
def OnReset(self, event):
self.canvas.Reset()
event.Skip()
def OnUpdateUI(self, event):
if self.canvas.CanReset():
self.resetButton.Enable(True)
else:
self.resetButton.Enable(False)
if __name__ == '__main__':
app = wx.App()
frame = MainWindow(None, title='Telemetry EFT')
frame.Show()
app.MainLoop()
And here is a link to the example data file : data file

Related

wxPython C++ part of TextCtrl is being deleted

I am trying to put together a gui in Python for a school project, but I am getting an error and don't really understand why.
self.prompt.addAnswer(i, self.ansControls[i].GetValue()) File
"C:\Python27\lib\site-packages\wx-3.0-msw\wx_core.py", line 16712, in
getattr
raise PyDeadObjectError(self.attrStr % self._name) wx._core.PyDeadObjectError: The C++ part of the TextCtrl object has
been deleted, attribute access no longer allowed.
I understand what the error means, The TextCtrl object no longer exists so I can't access it. I do not understand why the TextCtrl object does not exist anymore. Here is how the flow goes:
The frame appears with labels, TextCtrls, and buttons. The user enters in data and hits next. Everything goes smoothly. A different instance of the same PromptFrame class is then created, and the same thing happens. This time however, when the user hits next, I get the aforementioned error. Here is the code:
The service in the background running the show:
class AppService(object):
prompts = [Prompt_1, Prompt_2, Prompt_3, Prompt_4, Prompt_5, Prompt_6, Prompt_7,
Prompt_8, Prompt_9, Prompt_10, Prompt_11, Prompt_12, Prompt_13, Prompt_14,
Prompt_15, Prompt_16, Prompt_17, Prompt_18, Prompt_19]
skippedPromptIndices = []
def __init__(self):
print "Service Started"
PromptFrame(self, self.prompts[0], 0, len(self.prompts))
def doBack(self, curIndex, curPrompt):
if curIndex >= 0:
self.prompts[curIndex] = curPrompt
PromptFrame(self, self.prompts[curIndex - 1], curIndex - 1, len(self.prompts))
else:
posCurIndex = (curIndex * -1) - 1
self.prompts[posCurIndex] = curPrompt
backIndex = self.skippedPromptIndices.index(curIndex) - 1
nextPromptIndex = 0
if backIndex < 0:
nextPromptIndex = len(self.prompts) - 1
else:
nextPromptIndex = self.skippedPromptIndices[backIndex]
PromptFrame(self, self.prompts[(nextPromptIndex * -1) - 1], nextPromptIndex, len(self.prompts))
def doSkip(self, curIndex, curPrompt):
skipIndex = (curIndex + 1) * -1
if self.skippedPromptIndices.count(skipIndex) > 0:
self.skippedPromptIndices.remove(skipIndex)
self.skippedPromptIndices.append(skipIndex)
self.doNext(curIndex, curPrompt)
def doNext(self, curIndex, curPrompt):
if curIndex >= 0:
self.prompts[curIndex] = curPrompt
else:
self.prompts[(curIndex * -1) - 1] = curPrompt
if (curIndex >= 0 and curIndex < (len(self.prompts) - 1)):
PromptFrame(self, self.prompts[curIndex + 1], curIndex + 1, len(self.prompts))
elif len(self.skippedPromptIndices) > 0:
skipIndex = self.skippedPromptIndices.pop(0)
nextIndex = (skipIndex * -1) - 1
PromptFrame(self, self.prompts[nextIndex], skipIndex, len(self.prompts))
else:
dlg = wx.MessageDialog(self, "Done!", "Message", wx.OK)
dlg.ShowModal() # Shows it
dlg.Destroy() # finally destroy it when finished.
and here is the PromptFrame Class:
class PromptFrame(wx.Frame):
appService = None
prompt = None
promptIndex = 0
numPrompts = 0
ansControls = []
def __init__(self, appService, prompt=testPrompt, promptIndex=0, numPrompts=0):
print "New Prompt Frame!"
self.appService = appService
self.prompt = prompt
self.promptIndex = promptIndex
self.numPrompts = numPrompts
wx.Frame.__init__(self, None, wx.ID_ANY, title=prompt.title)
self.panel = wx.Panel(self, wx.ID_ANY)
self.panel.SetBackgroundColour('#2FC0E0') #0013E3, #66DFFA, #2FC0E0
self.Maximize()
self.CreateStatusBar() # A Statusbar in the bottom of the window
# Setting up the menu.
filemenu= wx.Menu()
menuAbout= filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
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.
# Creating fonts for the controls
titleFont = wx.Font(24, wx.DECORATIVE, wx.ITALIC, wx.BOLD)
qFont = wx.Font(12, wx.FONTFAMILY_DECORATIVE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
#Creating layout
vertSizer = wx.BoxSizer(wx.VERTICAL)
lblTitle = wx.StaticText(self.panel, wx.ID_ANY, prompt.title)
lblTitle.SetFont(titleFont)
vertSizer.Add(lblTitle, 0, wx.ALIGN_CENTER | wx.TOP, border=30)
vertSizer.Add(wx.StaticLine(self.panel, wx.ID_ANY), 0, wx.EXPAND)
vertSizer.AddStretchSpacer(2)
for i in range(len(prompt.questions)):
if prompt.qTypes[i] == 0:
lbl = wx.StaticText(self.panel, wx.ID_ANY, prompt.questions[i], size=(200, -1))
lbl.SetFont(qFont)
lbl.Wrap(200)
ans = wx.TextCtrl(self.panel, wx.ID_ANY, size=(200,-1))
if not prompt.answers[i] == None:
ans.SetValue(prompt.answers[i])
self.ansControls.append(ans)
horizSizer = wx.BoxSizer(wx.HORIZONTAL)
horizSizer.Add((30, -1), 0)
horizSizer.Add(lbl, 0)
horizSizer.Add((20, -1), 0)
horizSizer.Add(self.ansControls[len(self.ansControls) - 1], 0)
vertSizer.Add(horizSizer, 0)
vertSizer.AddStretchSpacer(1)
print self.ansControls
vertSizer.Add(wx.StaticLine(self.panel, wx.ID_ANY), 0, wx.EXPAND)
self.btnBack = wx.Button(self.panel, wx.ID_ANY, "Back")
self.btnSkip = wx.Button(self.panel, wx.ID_ANY, "Skip")
self.btnNext = wx.Button(self.panel, wx.ID_ANY, "Next")
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add(self.btnBack, 0, wx.RIGHT, border=30)
btnSizer.Add(self.btnSkip, 0)
btnSizer.Add(self.btnNext, 0, wx.LEFT, border=30)
btnSizer.AddStretchSpacer(1)
vertSizer.AddStretchSpacer(2)
vertSizer.Add(btnSizer, 0, wx.ALIGN_CENTER)
vertSizer.AddStretchSpacer(2)
lblPage = wx.StaticText(self.panel, wx.ID_ANY, "Page: " + str(self.promptIndex) + "/" + str(self.numPrompts))
vertSizer.Add(lblPage, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, border=20)
self.panel.SetSizer(vertSizer)
# Events.
self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
self.Bind(wx.EVT_BUTTON, self.OnBack, self.btnBack)
self.Bind(wx.EVT_BUTTON, self.OnSkip, self.btnSkip)
self.Bind(wx.EVT_BUTTON, self.OnNext, self.btnNext)
self.Show()
def OnAbout(self,e):
# Create a message dialog box
aboutString = "This program was designed by students of Worcester Polytechnic Institute to aid water supply " \
"officials apply the World Health Organization's Water Safety Plans."
dlg = wx.MessageDialog(self, aboutString, "About Water Safety Plan Helper", wx.OK)
dlg.ShowModal() # Shows it
dlg.Destroy() # finally destroy it when finished.
def OnExit(self,e):
self.Close(True) # Close the frame.
def OnBack(self, e):
if (self.promptIndex > 0):
self.SaveAns()
self.appService.doBack(self.promptIndex, self.prompt)
self.Close(True)
else:
errorString = "There are no previous pages to go back to"
dlg = wx.MessageDialog(self, errorString, "Error", wx.OK)
dlg.ShowModal() # Shows it
dlg.Destroy() # finally destroy it when finished.
def OnSkip(self, e):
self.SaveAns()
self.appService.doSkip(self.promptIndex, self.prompt)
self.Close(True)
def OnNext(self, e):
self.SaveAns()
self.appService.doNext(self.promptIndex, self.prompt)
self.Close(True)
def SaveAns(self):
print self.ansControls
for i in range(len(self.ansControls)):
if self.prompt.qTypes[i] == 0:
self.prompt.addAnswer(i, self.ansControls[i].GetValue())
Thanks for your help guys!
EDIT: Here is my init.py file:
from MainFrame import MainFrame
import wx
app = wx.App(False)
frame = MainFrame(None, "My App")
app.MainLoop()
ansControls is currently defined as a class variable. Which means that any control defined in any window gets added to it.
You create a control in the first instance, it is added to the class, but the window belongs to the instance. So when you destroy the class, the instance gets destroyed, but the python object pointing to it still exists.
Then you open your second window, add more controls, and then hit the loop where you loop over them. The first ones in your loop will not have a valid C++ object below it anymore, and will fail.
Not sure why they were defined as class variables, but you either need to keep a pointer to the root window as well, delete class controls as the parent windows get deleted, or (simpler) just make ansControls an instance variable instead of a class variable...

wxPython: Class attribute shared among several instances accidentally

This bit of code has me scratching my head.
I'm trying to write wxPython GUI, with a frame that contains several 'PulseBox' objects (code below). Each pulse box is basically 4 wx.TextCtrls with 4 wx.StaticTexts positioned next to them as labels. The object has a single attribute called 'data' which is a dictionary that I would like to access later.
I would like the TextCtrls to change the values of 'data' for their own pulse box when text is entered. Unfortunatley, when I enter text into a single pulse box, it is now changing 'data' for all the pulseboxes.
import wx
class MainGUI(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, '')
self.panel = wx.Panel(self)
#Create Controls
#All Contained in a Static Box
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
#A Row of Pulseboxes
self.setpulse = PulseBox(self.panel, 'Set')
self.resetpulse = PulseBox(self.panel, 'Reset')
self.gatepulse = PulseBox(self.panel, 'Gate')
#Generate Layout
#Use a FlexGrid Sizer
self.fgs = wx.FlexGridSizer(rows=1, cols=3, vgap=15, hgap=15)
self.fgs.AddMany([(self.setpulse, 1, wx.EXPAND),
(self.resetpulse, 1, wx.EXPAND),
(self.gatepulse, 1, wx.EXPAND)])
#Add the FlexGridSizer to the StaticBoxSizer
self.sizer.Add(self.fgs, proportion=1, flag=wx.ALL, border=15)
#FitTheSizer
self.panel.SetSizer(self.sizer)
self.sizer.Fit(self)
class PulseBox(wx.Panel):
def __init__(self, parent, name='Set',
data=dict(Leading='1.0e-6', Width='10.0e-6',
Trailing='1.0e-6', Delay='1.0e-3') ):
wx.Panel.__init__(self, parent)
self.data = data
self.name = name
#Create Controls
#All Contained in a Static Box
self.box = wx.StaticBox(self, label=name + ' Pulse (seconds)')
self.sizer = wx.StaticBoxSizer(self.box, wx.VERTICAL)
#A row of labels
self.label_lead = wx.StaticText(self, label='Leading')
self.label_width = wx.StaticText(self, label='Width')
self.label_trail = wx.StaticText(self, label='Trailing')
self.label_delay = wx.StaticText(self, label='Delay')
#A row of textctrls
self.textctrl_lead = wx.TextCtrl(self, value=data['Leading'], style=wx.TE_PROCESS_ENTER, name='Leading')
self.textctrl_width = wx.TextCtrl(self, value=data['Width'], style=wx.TE_PROCESS_ENTER, name='Width')
self.textctrl_trail = wx.TextCtrl(self, value=data['Trailing'], style=wx.TE_PROCESS_ENTER, name='Trailing')
self.textctrl_delay = wx.TextCtrl(self, value=data['Delay'], style=wx.TE_PROCESS_ENTER, name='Delay')
#Send back their data
self.Bind(wx.EVT_TEXT_ENTER, self.on_change_pulses, self.textctrl_width)
self.Bind(wx.EVT_TEXT_ENTER, self.on_change_pulses, self.textctrl_lead)
self.Bind(wx.EVT_TEXT_ENTER, self.on_change_pulses, self.textctrl_trail)
self.Bind(wx.EVT_TEXT_ENTER, self.on_change_pulses, self.textctrl_delay)
#Generate Layout
#Use a FlexGrid Sizer
self.fgs = wx.FlexGridSizer(rows=4, cols=2, vgap=9, hgap=25)
self.fgs.AddMany([(self.label_lead), (self.textctrl_lead, 1, wx.EXPAND),
(self.label_width), (self.textctrl_width, 1, wx.EXPAND),
(self.label_trail), (self.textctrl_trail, 1, wx.EXPAND),
(self.label_delay), (self.textctrl_delay, 1, wx.EXPAND)])
#Expand the TextCtrl boxes to fill panel
self.fgs.AddGrowableCol(1, 1)
#Add the FlexGridSizer to the StaticBoxSizer
self.sizer.Add(self.fgs, proportion=1, flag=wx.ALL|wx.EXPAND, border=15)
#FitTheSizer
self.SetSizer(self.sizer)
self.sizer.Fit(self)
def on_change_pulses(self, event):
textctrl = event.GetEventObject()
name = textctrl.GetName()
value = textctrl.GetValue()
self.data[name] = value
print self.name, self.data
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = MainGUI()
app.frame.Show()
app.MainLoop()
As an example, when I change the 'Leading' TextCtrl of the 'Set' box
to 1, I get printed: Set {'Delay': '1.0e-3', 'Width': '10.0e-6',
'Trailing': '1.0e-6', 'Leading': u'1'}
And then when I change the 'Width' TextCtrl of the 'Reset' box to 2, I get printed:
Reset {'Delay': '1.0e-3', 'Width': u'2', 'Trailing': '1.0e-6',
'Leading': u'1'}
Even though I never set the 'Leading' for the Reset box.
You are processing the message EVT_TEXT_ENTER and on_change_pulses is only updating self.data with the value of TextCtrl that revised the event.
You can fix it either by processing EVT_TEXT so the values are updated as soon as the user modifies some TextCtrl, you can add:
....
#Send back their data
self.Bind(wx.EVT_TEXT_ENTER, self.on_change_pulses, self.textctrl_width)
self.Bind(wx.EVT_TEXT_ENTER, self.on_change_pulses, self.textctrl_lead)
self.Bind(wx.EVT_TEXT_ENTER, self.on_change_pulses, self.textctrl_trail)
self.Bind(wx.EVT_TEXT_ENTER, self.on_change_pulses, self.textctrl_delay)
# ADDED: listen for EVT_TEXT event
self.Bind(wx.EVT_TEXT, self.on_change_pulses_update, self.textctrl_width)
self.Bind(wx.EVT_TEXT, self.on_change_pulses_update, self.textctrl_lead)
self.Bind(wx.EVT_TEXT, self.on_change_pulses_update, self.textctrl_trail)
self.Bind(wx.EVT_TEXT, self.on_change_pulses_update, self.textctrl_delay)
#Generate Layout
#Use a FlexGrid Sizer
self.fgs = wx.FlexGridSizer(rows=4, cols=2, vgap=9, hgap=25)
....
and add a handler to the event:
def on_change_pulses_update(self, event):
textctrl = event.GetEventObject()
name = textctrl.GetName()
value = textctrl.GetValue()
self.data[name] = value
or you can re-read the values of all TextCtrl if anyone of them revised EVT_TEXT_ENTER:
def on_change_pulses(self, event):
textctrl = event.GetEventObject()
name = textctrl.GetName()
#value = textctrl.GetValue()
self.data['Width'] = self.textctrl_width.GetValue()
self.data['Leading'] = self.textctrl_lead.GetValue()
self.data['Trailing'] = self.textctrl_trail.GetValue()
self.data['Delay'] = self.textctrl_delay.GetValue()
print self.name, self.data

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()

Get Position of Button in wxpython

I am trying to figure out the position of two buttons in wxpython. I have a gui with a small vertical panel on the left and large panel on the right.
wx.Frame.__init__(self, *args, **kwds)
self.Splitter = wx.SplitterWindow(self, -1)#, style=wx.SP_NOSASH)
self.Panel1 = wx.Panel(self.Splitter, -1)
self.Panel3 = wx.Panel(self.Splitter, -1)
self.Splitter.SplitVertically(self.Panel1,self.Panel3,350)
In in the right panel (a notebook) I use a Vertical Sizer to stack three panels:
self.Notebook3 = wx.Notebook(self.Panel3, -1)
self.OptPane = scrolled.ScrolledPanel(self.Notebook3, -1)
self.pane1 = wx.Panel(self.OptPane,-1, style=wx.NO_BORDER)
self.pane2 = wx.Panel(self.OptPane,-1, style=wx.RAISED_BORDER)
self.pane3= wx.Panel(self.OptPane,-1, style=wx.NO_BORDER)
My pane 3 contains three buttons that are organized using a gridsizer (one row, three columns). It all looks great. Now, I want to be able to get the screen position of the three buttons (they change based on resolution of screen, person adjusting the size of the gui, etc.).
My screen size is (1920,1080) which is derived from wx.GetDisplaySize(). I have tried self.button1.GetScreenPosition() and self.pane3.GetScreenPosition and self.button1.GetPosition(). The first returns the position (77,93), second returns (61,95) and the last one gives me (0,0). After testing with testtext = wx.StaticText(self.Notebook3, -1, 'X marks spot',pos=(240,820)), I figured out the position of the button I want returned is (240,820) -- approximately. This is the number I want to return.
Does anyone know what I am doing wrong? Thanks!
*EDIT*
My Full Code - should be runnable -- I am running this on a 1920x1080 (for the text 'x marks the spot').
import wx
import wx.lib.scrolledpanel as scrolled
class TMainForm(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.Splitter = wx.SplitterWindow(self, -1)
self.Panel1 = wx.Panel(self.Splitter, -1)
self.Panel3 = wx.Panel(self.Splitter, -1)
self.Splitter.SplitVertically(self.Panel1,self.Panel3,350)
self.Notebook2 = wx.Notebook(self.Panel1, -1)
self.Notebook3 = wx.Notebook(self.Panel3, -1)
self.OptPane = scrolled.ScrolledPanel(self.Notebook3, -1)
self.OptPane.SetupScrolling()
self.Opt_Info = wx.Panel(self.OptPane,-1, style=wx.NO_BORDER)
self.Opt_Middle = wx.Panel(self.OptPane,-1, style=wx.RAISED_BORDER)
self.Opt_Buttons = wx.Panel(self.OptPane,-1, style=wx.NO_BORDER)
self.Button1 = wx.Button(self.Opt_Buttons,-1,'Button1',size=(-1,-1))
self.Button2 = wx.Button(self.Opt_Buttons,-1,'Button2',size=(-1,-1))
self.Button3 = wx.Button(self.Opt_Buttons,-1,'Button3',size=(-1,-1))
self.MainMenu = wx.MenuBar()
self.FileMenu = wx.Menu()
self.FileOpenItem = wx.MenuItem(self.FileMenu, 103, "&Open\tCtrl+O", "Open a Previous Session", wx.ITEM_NORMAL)
self.FileMenu.AppendItem(self.FileOpenItem)
self.FileSaveItem = wx.MenuItem(self.FileMenu, 102, "&Save\tCtrl+S", "Save the data", wx.ITEM_NORMAL)
self.FileMenu.AppendItem(self.FileSaveItem)
self.FileQuitItem = wx.MenuItem(self.FileMenu, wx.ID_EXIT, "&Quit\tCtrl+Q", "Quit the program", wx.ITEM_NORMAL)
self.FileMenu.AppendItem(self.FileQuitItem)
self.MainMenu.Append(self.FileMenu, "&File")
self.SetMenuBar(self.MainMenu)
self.__set_properties()
self.__do_layout()
print self.Button1.GetScreenPosition()
testtext = wx.StaticText(self.Notebook3, -1, 'X marks spot',pos=(240,840))
def __set_properties(self):
self.SetTitle("My Program")
screen_x = 95 * wx.GetDisplaySize()[0]/100
screen_y = 90 * wx.GetDisplaySize()[1]/100
self.SetSize((screen_x, screen_y))
self.SetFocus()
def __do_layout(self , call_fit = True, set_sizer = True):
vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
hbox3 = wx.BoxSizer(wx.HORIZONTAL)
hbox1.Add(self.Opt_Info, 1, wx.EXPAND|wx.ALL, 3)
hbox2.Add(self.Opt_Middle, 1, wx.EXPAND|wx.ALL, 3)
hbox3.Add(self.Opt_Buttons, 1, wx.EXPAND|wx.ALL, 3)
box_bot = wx.GridSizer(1,3,2,2)
box_bot.Add(self.Button1, 1, wx.ALIGN_CENTER| wx.LEFT | wx.RIGHT, 55)
box_bot.Add(self.Button2, 1, wx.ALIGN_CENTER| wx.LEFT | wx.RIGHT, 55)
box_bot.Add(self.Button3, 1, wx.ALIGN_CENTER| wx.LEFT | wx.RIGHT, 55)
self.Opt_Buttons.SetSizer(box_bot)
vbox.Add(hbox1, 0, wx.EXPAND|wx.TOP, 20)
vbox.Add(hbox2, 1, wx.EXPAND|wx.TOP, 50)
vbox.Add(hbox3, 0, wx.EXPAND|wx.ALL, 20)
self.OptPane.SetSizer(vbox)
self.Notebook3.AddPage(self.OptPane,"Page1")
#Sizer for Panel 2
sizer_P2 = wx.BoxSizer(wx.VERTICAL)
sizer_P2.Add(self.Notebook2, 1, wx.EXPAND, 0)
self.Panel1.SetSizer(sizer_P2)
#Sizer for Panel 3
sizer_P3 = wx.BoxSizer(wx.VERTICAL)
sizer_P3.Add(self.Notebook3, 1, wx.EXPAND, 0)
self.Panel3.SetSizer(sizer_P3)
# Split Panel Sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.Splitter,1,wx.EXPAND)
self.SetSizer(sizer)
self.Layout()
self.Centre()
# Code to Execute File
class TApplication(wx.App):
def OnInit(self):
wx.InitAllImageHandlers()
MainForm = TMainForm(None, -1,"")
self.SetTopWindow(MainForm)
MainForm.Show()
return 1
if __name__ == "__main__":
Application = TApplication(0)
Application.MainLoop()
I think you're asking for the position too soon. You'll want to get the position after everything is rendered to the screen, so you'll probably need to use wxPython's CallAfter. Create a method that looks something like this:
def printLocation(self):
""""""
print self.Button1.GetScreenPosition()
Then at the end of your init, add the following line:
wx.CallAfter(self.printLocation)
When I ran it on my system, I got (155, 211), which is probably closer to what you're looking for. I have a rather weird resolution here.
You might also want to look at this thread which talks about the scrolled window's CalcUnscrolledPosition method.
https://groups.google.com/forum/#!topic/wxpython-users/0VlpIcBYs04

wxpython listctrl and fix column widths

I am trying to make a "table" look good within my panel. This issue I'm having is that the table fills up the panel but everything is to the left. I would like to have each column be the same size and span the entire width of the panel. I have seen the ListCtrlAutoWidthMixin but am not sure how I could utilize this. Here is what I have in code:
self.Analysis = scrolled.ScrolledPanel(self.Notebook3, -1)
# Set Up Analysis Page (Page has four panels -- I care about Top left one)
self.AnalysisUL = wx.Panel(self.Analysis,-1, style=wx.BORDER_NONE)
self.AnalysisUR = wx.Panel(self.Analysis,-1, style=wx.BORDER_NONE)
self.AnalysisLL = wx.Panel(self.Analysis,-1, style=wx.BORDER_NONE)
self.AnalysisLR = wx.Panel(self.Analysis,-1, style=wx.BORDER_NONE)
# Top Left Box (Analyze Button and Projected Points Total)
self.Picks_Left = wx.ListCtrl(self.AnalysisUL,-1,style=wx.LC_REPORT | wx.BORDER_NONE)
self.Picks_Left.InsertColumn(1,'col1')
self.Picks_Left.InsertColumn(2,'col2',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(3,'col3',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(4,'col4',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.SetColumnWidth(0,-2)
self.Picks_Left.SetColumnWidth(1,-2)
self.Picks_Left.SetColumnWidth(2,-2)
self.Picks_Left.SetColumnWidth(3,-2)
# Sizer
vbox_UL = wx.BoxSizer(wx.VERTICAL)
#Title for Table
fontUL = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD)
self.UL_text = wx.StaticText(self.AnalysisUL, -1, 'Title')
self.UL_text.SetFont(fontUL)
vbox_UL.Add(self.UL_text, 0, wx.CENTER|wx.ALL,20)
vbox_UL.Add(self.Picks_Left,1,wx.EXPAND|wx.ALL,3)
self.AnalysisUL.SetSizer(vbox_UL)
Again, the table spans the panel, but all my columns are shifted to the left. Also, I do not want to set the column size manually (unless I can grab the panel size and then divide by the number of columns I have -- since the program will be used on computers with different resolutions). I have tried this approach but cannot seem to get the correct size of the panels. The numbers I get with GetSize() and GetClientSize() are all too small.
Thanks for any help!
EDIT: Code Added:
import wx
import wx.lib.mixins.listctrl as listmix
import wx.lib.scrolledpanel as scrolled
import wx.lib.agw.pybusyinfo as PBI
class TMainForm(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER
wx.Frame.__init__(self, *args, **kwds)
self.Splitter1 = wx.SplitterWindow(self, -1)#, style=wx.SP_NOSASH)
self.Splitter2 = wx.SplitterWindow(self.Splitter1)
self.Panel1 = wx.Panel(self.Splitter2, -1)
self.Panel2 = wx.Panel(self.Splitter2, -1)
self.Splitter2.SplitHorizontally(self.Panel1,self.Panel2)
self.Panel3 = wx.Panel(self.Splitter1, -1)
self.Splitter1.SplitVertically(self.Splitter2,self.Panel3,400)
self.Notebook = wx.Notebook(self.Panel1, -1)
self.MyTeam = scrolled.ScrolledPanel(self.Notebook, -1)
self.TeamComparison = scrolled.ScrolledPanel(self.Notebook, -1)
self.MyTeam.SetupScrolling()
self.TeamComparison.SetupScrolling()
self.Notebook3 = wx.Notebook(self.Panel3, -1)
self.Analysis = scrolled.ScrolledPanel(self.Notebook3, -1)
self.Analysis.SetupScrolling()
self.AnalysisUL = wx.Panel(self.Analysis,-1, style=wx.BORDER_NONE)
self.AnalysisUR = wx.Panel(self.Analysis,-1, style=wx.BORDER_NONE)
self.AnalysisLL = wx.Panel(self.Analysis,-1, style=wx.BORDER_NONE)
self.AnalysisLR = wx.Panel(self.Analysis,-1, style=wx.BORDER_NONE)
# Top Left Box (To Fix!)
self.Picks_Left = wx.ListCtrl(self.AnalysisUL,-1,style=wx.LC_REPORT | wx.BORDER_NONE)
self.Picks_Left.InsertColumn(1,' ')
self.Picks_Left.InsertColumn(2,' ',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(3,'H1',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(4,'H2',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(5,'H#',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(6,'H4',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(7,'H5',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(8,'H6',format=wx.LIST_FORMAT_CENTRE)
self.Picks_Left.InsertColumn(9,'H7',format=wx.LIST_FORMAT_CENTRE)
## table_width = self.Picks_Left.GetSize()[0] #GetSize returns (width, height) tuple
## print table_width
## num_col = self.Picks_Left.GetColumnCount()
## col_width = table_width/num_col
## for i in range(0, num_col):
## self.Picks_Left.SetColumnWidth(i, col_width)
self.Picks_Left.SetColumnWidth(0,-2)
self.Picks_Left.SetColumnWidth(1,-2)
self.Picks_Left.SetColumnWidth(2,-2)
self.Picks_Left.SetColumnWidth(3,-2)
self.Picks_Left.SetColumnWidth(4,-2)
self.Picks_Left.SetColumnWidth(5,-2)
self.Picks_Left.SetColumnWidth(6,-2)
self.Picks_Left.SetColumnWidth(7,-2)
self.Picks_Left.SetColumnWidth(8,-2)
# Bottom Left Box (Suggested Optimal Teams)
self.Notebook_AltTeams = wx.Notebook(self.AnalysisLL, -1)
self.Alt_Team_1 = scrolled.ScrolledPanel(self.Notebook_AltTeams, -1)
self.Alt_Team_2 = scrolled.ScrolledPanel(self.Notebook_AltTeams, -1)
self.Alt_Team_3 = scrolled.ScrolledPanel(self.Notebook_AltTeams, -1)
self.Alt_Team_4 = scrolled.ScrolledPanel(self.Notebook_AltTeams, -1)
self.Alt_Team_5 = scrolled.ScrolledPanel(self.Notebook_AltTeams, -1)
self.Alt_Team_1.SetupScrolling()
self.Alt_Team_2.SetupScrolling()
self.Alt_Team_3.SetupScrolling()
self.Alt_Team_4.SetupScrolling()
self.Alt_Team_5.SetupScrolling()
# Menu Bar
self.MainMenu = wx.MenuBar()
self.FileMenu = wx.Menu()
self.FileOpenItem = wx.MenuItem(self.FileMenu, 103, "&Open\tCtrl+O", "Open a Previous Session", wx.ITEM_NORMAL)
self.FileMenu.AppendItem(self.FileOpenItem)
self.FileReloadItem = wx.MenuItem(self.FileMenu, 104, "&Reload Defaults", "Reload Default Files", wx.ITEM_NORMAL)
self.FileMenu.AppendItem(self.FileReloadItem)
self.FileSaveItem = wx.MenuItem(self.FileMenu, 102, "&Save\tCtrl+S", "Save the data", wx.ITEM_NORMAL)
self.FileMenu.AppendItem(self.FileSaveItem)
self.FileQuitItem = wx.MenuItem(self.FileMenu, wx.ID_EXIT, "&Quit\tCtrl+Q", "Quit the program", wx.ITEM_NORMAL)
self.FileMenu.AppendItem(self.FileQuitItem)
self.MainMenu.Append(self.FileMenu, "&File")
self.SetMenuBar(self.MainMenu)
# Menu Bar end
self.StatusBar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
self.__set_properties()
self.__do_layout()
self.Bind(wx.EVT_MENU, self.OnFileQuit, self.FileQuitItem)
self.Bind(wx.EVT_MENU, self.OnFileSave, self.FileSaveItem)
self.Bind(wx.EVT_MENU, self.OnFileOpen, self.FileOpenItem)
self.Bind(wx.EVT_MENU, self.OnFileReload, self.FileReloadItem)
self.OnAnalyze()
def __set_properties(self): #Set up GUI Title and Map Window
self.SetTitle("Test")
screen_x = 95 * wx.GetDisplaySize()[0]/100
screen_y = 90 * wx.GetDisplaySize()[1]/100
self.SetSize((screen_x, screen_y))
self.SetFocus()
def __do_layout(self , call_fit = True, set_sizer = True): #Create Lay-Out of GUI
# Sizer for Panel 3 (Analysis Page)
hbox = wx.BoxSizer(wx.HORIZONTAL)
vbox1 = wx.BoxSizer(wx.VERTICAL)
vbox2 = wx.BoxSizer(wx.VERTICAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
vbox1.Add(self.AnalysisUL, 1, wx.EXPAND | wx.ALL, 3)
vbox1.Add(self.AnalysisLL, 1, wx.EXPAND | wx.ALL, 3)
vbox2.Add(self.AnalysisUR, 1, wx.EXPAND | wx.ALL, 3)
vbox2.Add(self.AnalysisLR, 1, wx.EXPAND | wx.ALL, 3)
# Analysis Button Panel
vbox_UL = wx.BoxSizer(wx.VERTICAL)
vbox_UL3 = wx.BoxSizer(wx.HORIZONTAL)
fontUL = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD)
self.UL_text = wx.StaticText(self.AnalysisUL, -1, 'Title 1')
self.UL_text.SetFont(fontUL)
Exp_Pts = ' '
fontUL = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD)
self.ULText1 = wx.StaticText(self.AnalysisUL, -1, 'Title 2')
self.ULText2 = wx.StaticText(self.AnalysisUL, -1, Exp_Pts)
self.ULText1.SetFont(fontUL)
self.ULText2.SetFont(fontUL)
self.ULText2.SetForegroundColour((0,0,255))
self.ULText1.SetForegroundColour((0,0,255))
hbox2.Add(self.ULText1, 0)
hbox2.Add(self.ULText2, 0)
vbox_UL.Add(self.UL_text, 0, wx.CENTER|wx.ALL,20)
vbox_UL.Add(self.Picks_Left,1,wx.EXPAND|wx.ALL,3)
vbox_UL.Add(hbox2, 0, wx.CENTER|wx.BOTTOM,50)
self.AnalysisUL.SetSizer(vbox_UL)
# Suggested Pick Panel
vbox_LR = wx.BoxSizer(wx.HORIZONTAL)
vbox_LR2 = wx.BoxSizer(wx.VERTICAL)
font2 = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD)
SuggestedSelection = ' '
self.SuggestedText1 = wx.StaticText(self.AnalysisLR, -1, ' ')
self.SuggestedText2 = wx.StaticText(self.AnalysisLR, -1, SuggestedSelection)
self.SuggestedText1.SetFont(font2)
self.SuggestedText2.SetFont(font2)
self.SuggestedText2.SetForegroundColour((0,0,255))
vbox_LR2.Add(self.SuggestedText1,0,wx.ALIGN_CENTRE)
vbox_LR2.Add(wx.StaticText(self.AnalysisLR, -1, ''),0,wx.CENTER)
vbox_LR2.Add(wx.StaticText(self.AnalysisLR, -1, ''),0,wx.CENTER)
vbox_LR2.Add(self.SuggestedText2,0,wx.ALIGN_CENTRE)
vbox_LR.Add(vbox_LR2,1,wx.CENTER)
self.AnalysisLR.SetSizer(vbox_LR)
# Projected Team Panel
sizer_LL = wx.BoxSizer(wx.VERTICAL)
self.Alt_Team_1.SetSizer(sizer_LL)
sizer_LL = wx.BoxSizer(wx.VERTICAL)
self.Alt_Team_2.SetSizer(sizer_LL)
sizer_LL = wx.BoxSizer(wx.VERTICAL)
self.Alt_Team_3.SetSizer(sizer_LL)
sizer_LL = wx.BoxSizer(wx.VERTICAL)
self.Alt_Team_4.SetSizer(sizer_LL)
sizer_LL = wx.BoxSizer(wx.VERTICAL)
self.Alt_Team_5.SetSizer(sizer_LL)
# Picks Remaining Panel
vbox_UR = wx.BoxSizer(wx.VERTICAL)
fontUR = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD)
self.UR_text = wx.StaticText(self.AnalysisUR, -1, 'Title')
self.UR_text.SetFont(fontUR)
vbox_UR.Add(self.UR_text, 0, wx.CENTER)
self.AnalysisUR.SetSizer(vbox_UR)
# Finish Analysis Sizers
hbox.Add(vbox1, 1, wx.EXPAND)
hbox.Add(vbox2, 1, wx.EXPAND)
self.Analysis.SetSizer(hbox)
# Add Notebook Pages
self.Notebook.AddPage(self.MyTeam,"A")
self.Notebook.AddPage(self.TeamComparison,"B")
self.Notebook3.AddPage(self.Analysis,"CHECK ME")
self.Notebook_AltTeams.AddPage(self.Alt_Team_1,"1")
self.Notebook_AltTeams.AddPage(self.Alt_Team_2,"2")
self.Notebook_AltTeams.AddPage(self.Alt_Team_3,"3")
self.Notebook_AltTeams.AddPage(self.Alt_Team_4,"4")
self.Notebook_AltTeams.AddPage(self.Alt_Team_5,"5")
#Sizer for Panel 1
sizer_P1 = wx.BoxSizer(wx.VERTICAL)
sizer_P1.Add(self.Notebook, 1, wx.EXPAND, 0)
self.Panel1.SetSizer(sizer_P1)
#Sizer for Panel 3
sizer_P3 = wx.BoxSizer(wx.VERTICAL)
sizer_P3.Add(self.Notebook3, 1, wx.EXPAND, 0)
self.Panel3.SetSizer(sizer_P3)
#Sizer for Panel (Alt_Teams)
fontLL = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD)
self.LL_text = wx.StaticText(self.AnalysisLL, -1, 'Title')
self.LL_text.SetFont(fontLL)
vbox_LL = wx.BoxSizer(wx.VERTICAL)
vbox_LL.Add(self.LL_text, 0, wx.CENTER)
#vbox_LL.Add(self.Notebook_AltTeams,1,wx.EXPAND,0)
self.AnalysisLL.SetSizer(vbox_LL)
# Split Panel Sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.Splitter1,1,wx.EXPAND)
self.SetSizer(sizer)
self.Layout()
self.Centre()
# Function closes GUI
def OnFileQuit(self,event):
self.Close()
# Function reloads default parameters/lists
def OnFileReload(self,event):
self.Close()
# Function loads previously saved files
def OnFileOpen(self,event):
self.Close()
# Function saves current work
def OnFileSave(self,event):
self.Close()
# Function analyzes draft, points, adp to suggest an optimal team and the next selection
def OnAnalyze(self):
self.Picks_Left.DeleteAllItems()
self.Picks_Left.InsertStringItem(0, ' ')
self.Picks_Left.InsertStringItem(1, 'Line 1')
self.Picks_Left.InsertStringItem(2, ' ')
self.Picks_Left.InsertStringItem(3, 'Line 2')
self.Picks_Left.InsertStringItem(4, ' ')
self.Picks_Left.InsertStringItem(5, 'Line 3')
self.Picks_Left.SetStringItem(1,2, '1')
self.Picks_Left.SetStringItem(1,3, '2')
self.Picks_Left.SetStringItem(1,4, '3')
self.Picks_Left.SetStringItem(1,5, '4')
self.Picks_Left.SetStringItem(1,6, '5')
self.Picks_Left.SetStringItem(1,7, '6')
self.Picks_Left.SetStringItem(1,8, '7')
self.Picks_Left.SetStringItem(3,2, '1')
self.Picks_Left.SetStringItem(3,3, '1')
self.Picks_Left.SetStringItem(3,4, '1')
self.Picks_Left.SetStringItem(3,5, '1')
self.Picks_Left.SetStringItem(3,6, '1')
self.Picks_Left.SetStringItem(3,7, '1')
self.Picks_Left.SetStringItem(3,8, '1')
self.Picks_Left.SetStringItem(5,2, '2')
self.Picks_Left.SetStringItem(5,3, '2')
self.Picks_Left.SetStringItem(5,4, '2')
self.Picks_Left.SetStringItem(5,5, '2')
self.Picks_Left.SetStringItem(5,6, '2')
self.Picks_Left.SetStringItem(5,7, '2')
self.Picks_Left.SetStringItem(5,8, '2')
self.AnalysisUL.Layout()
app = wx.App(0)
# Code to Execute File
class TApplication(wx.App):
def OnInit(self):
wx.InitAllImageHandlers()
MainForm = TMainForm(None, -1,"")
self.SetTopWindow(MainForm)
MainForm.Show()
return 1
if __name__ == "__main__":
Application = TApplication(0)
Application.MainLoop()
I think the trouble with the GetSize() approach might have been that you were calling it before the effects of the sizer took place, so it was returning the original size of the ListCtrl before the sizer resized it to fit the panel. Try this code after the last line of your code:
table_width = self.Picks_Left.GetSize()[0] #GetSize returns (width, height) tuple
num_col = self.Picks_Left.GetColumnCount()
col_width = table_width/num_col
for i in range(0, num_col):
self.Picks_Left.SetColumnWidth(i, col_width)
You should use the RowColSizer, which is quite fit for your request. Here is a small demo how to use it:
import wx
import wx.lib.rcsizer as rcs
class TestPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
sizer = rcs.RowColSizer()
text = "This sizer lays out it's items by row and column "\
"that are specified explicitly when the item is \n"\
"added to the sizer. Grid cells with nothing in "\
"them are supported and column- or row-spanning is \n"\
"handled as well. Growable rows and columns are "\
"specified just like the wxFlexGridSizer."
sizer.Add(wx.StaticText(self, -1, text), row=1, col=1, colspan=5)
sizer.Add(wx.TextCtrl(self, -1, "(3,1)"), flag=wx.EXPAND, row=3, col=1)
sizer.Add(wx.TextCtrl(self, -1, "(3,2)"), row=3, col=2)
sizer.Add(wx.TextCtrl(self, -1, "(3,3)"), row=3, col=3)
sizer.Add(wx.TextCtrl(self, -1, "(3,4)"), row=3, col=4)
sizer.Add(
wx.TextCtrl(self, -1, "(4,2) span:(2,2)"),
flag=wx.EXPAND, row=4, col=2, rowspan=2, colspan=2
)
sizer.Add(wx.TextCtrl(self, -1, "(6,4)"), row=6, col=4)
sizer.Add(wx.TextCtrl(self, -1, "(7,2)"), row=7, col=2)
sizer.Add(wx.TextCtrl(self, -1, "(8,3)"), row=8, col=3)
sizer.Add(
wx.TextCtrl(self, -1, "(10,1) colspan: 4"),
flag=wx.EXPAND, pos=(10,1), colspan=4
)
sizer.Add(
wx.TextCtrl(self, -1, "(3,5) rowspan: 8, growable col", style=wx.TE_MULTILINE),
flag=wx.EXPAND, pos=(3,5), size=(8,1)
)
box = wx.BoxSizer(wx.VERTICAL)
box.Add(wx.Button(self, -1, "A vertical box"), flag=wx.EXPAND)
box.Add(wx.Button(self, -1, "sizer put in the"), flag=wx.EXPAND)
box.Add(wx.Button(self, -1, "RowColSizer at (12,1)"), flag=wx.EXPAND)
sizer.Add(box, pos=(12,1))
sizer.Add(
wx.TextCtrl(self, -1, "(12,2) align bottom"),
flag=wx.ALIGN_BOTTOM, pos=(12,2)
)
sizer.Add(
wx.TextCtrl(self, -1, "(12,3) align center"),
flag=wx.ALIGN_CENTER_VERTICAL, pos=(12,3)
)
sizer.Add(wx.TextCtrl(self, -1, "(12,4)"),pos=(12,4))
sizer.Add(
wx.TextCtrl(self, -1, "(12,5) full border"),
flag=wx.EXPAND|wx.ALL, border=15, pos=(12,5)
)
sizer.AddGrowableCol(5)
sizer.AddGrowableRow(9)
sizer.AddSpacer(10,10, pos=(1,6))
sizer.AddSpacer(10,10, pos=(13,1))
self.SetSizer(sizer)
self.SetAutoLayout(True)
app = wx.App()
frame = wx.Frame(None, -1)
pn = TestPanel(frame)
frame.Show()
frame.Maximize()
app.MainLoop()
The same request also could be achieved by a more fancy way use the aui
Hope it helps you out.

Categories