Get Position of Button in wxpython - python

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

Related

Can't insert graph in a wxPython GUI

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

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

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.

wxPython and STC Margins - Top and Bottom

Is there any way of implementing padding in the top and bottom of my program for 3 and 4?
Or is there a workaround like adding \n etc....
I feel asif the line numbers and the Styled text are too close to the top and bottom.
How about using panels of the same color nested inside the sizer as a dirty workaround?
import wx
import wx.stc as stc
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self)
self.text = stc.StyledTextCtrl(self.panel)
self.text.SetWindowStyle(self.text.GetWindowStyle() | wx.NO_BORDER)
self.text.StyleSetSpec(stc.STC_STYLE_DEFAULT, "size:15,face:Courier New")
self.text.SetWrapMode(stc.STC_WRAP_WORD)
self.text.SetMarginLeft(50)
self.text.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#FFFFFF")
self.menu = wx.Menu()
self.menu.Append(wx.ID_ABOUT, "&About", "Information about this program")
self.menu_bar = wx.MenuBar()
self.menu_bar.Append(self.menu, "&File")
self.SetMenuBar(self.menu_bar)
self.panel_top = wx.Panel(self.panel, size = (20, -1))
self.panel_top.SetBackgroundColour(wx.WHITE)
self.panel_bottom = wx.Panel(self.panel, size = (20, -1))
self.panel_bottom.SetBackgroundColour(wx.WHITE)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.panel_top, 0, wx.ALL | wx.EXPAND)
self.sizer.Add(self.text, 1, wx.ALL | wx.EXPAND)
self.sizer.Add(self.panel_bottom, 0, wx.ALL | wx.EXPAND)
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, border=20)
self.panel.SetSizerAndFit(self.border)
self.text.Bind(stc.EVT_STC_CHANGE, self.OnChange)
self.Show()
self.text.SetText("Line!\n"*3)
def OnChange(self, e):
lines = self.text.GetLineCount()
width = self.text.TextWidth(stc.STC_STYLE_LINENUMBER, str(lines)+" ")
self.text.SetMarginWidth(0, width)
if __name__ == "__main__":
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
For your code, modify it as follows:
self.panel_top = wx.Panel(self.panel, size = (20, -1))
self.panel_top.SetBackgroundColour(wx.BLACK)
self.panel_bottom = wx.Panel(self.panel, size = (20, -1))
self.panel_bottom.SetBackgroundColour(wx.BLACK)
#### Add the STC to a Sizer. ####
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel_top, 0, wx.EXPAND,border=20)
sizer.Add(self.text, 1, wx.EXPAND,border=20)
sizer.Add(self.panel_bottom, 0, wx.EXPAND,border=20)
self.panel.SetSizer(sizer)
No, I don't think that Scintilla has a property that controls the size of the top and bottom margins.

Destroy() wxpython simple error?

i am having an interesting problem,
This program is a simple image viewer and it can contain different images in a listbox. The listbox contains the names of the images. You can load an image to an item in the listbox. You can click any item on the listbox to see its image. For some reason Destroy() is not functioning properly. Please run the following code if you are unable to understand me,
IMAGE_NAME=[]
IMAGE_DATA=[]
IMAGE_LISTSEL=[]
import sys
import wx
def deletepic(self,parent):
try:
bitmap1.Destroy()
bmp1.Destroy()
except:
print sys.exc_info()
def sendnewpic(self,parent):
global scroll_img
deletepic(self,parent)
print IMAGE_DATA[IMAGE_LISTSEL[0]]
if IMAGE_DATA[IMAGE_LISTSEL[0]]!='':
try:
print IMAGE_DATA[IMAGE_LISTSEL[0]]
bmp1 = wx.Image(IMAGE_DATA[IMAGE_LISTSEL[0]], wx.BITMAP_TYPE_ANY).ConvertToBitmap()
bitmap1 = wx.StaticBitmap(scroll_img, -1, bmp1, (0, 0))
except:
pass
def areachange(self,pg):
print pg
try:
if IMAGE_DATA[IMAGE_LISTSEL[0]]=='':
deletepic(self,parent)
except:
pass
if pg=="Images":
self.images_area.Show()
else:
self.images_area.Hide()
class imageMax(wx.Panel):
pass
class imageTab(imageMax):
def imagesel(self,parent):
IMAGE_LISTSEL[:] = []
IMAGE_LISTSEL.append(self.listBox.GetSelection())
sendnewpic(self,parent)
def newAddImage(self,parent):
IMAGE_NAME.append('hi');
IMAGE_DATA.append('');
self.listBox.Set(IMAGE_NAME)
self.listBox.SetSelection(len(IMAGE_NAME)-1)
self.imagesel(self) #making it a selected image, globally
def reName(self,parent):
sel = self.listBox.GetSelection()
text = self.listBox.GetString(sel)
renamed = wx.GetTextFromUser('Rename item', 'Rename dialog', text)
if renamed != '':
IMAGE_NAME.pop(sel)
IMAGE_NAME.insert(sel,renamed)
self.listBox.Set(IMAGE_NAME)
self.listBox.SetSelection(sel)
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.listBox = wx.ListBox(self, size=(200, -1), choices=IMAGE_NAME, style=wx.LB_SINGLE)
self.sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.VERTICAL) #change to horizontal for side by side
self.sizerMain = wx.BoxSizer()
self.listBox.Bind(wx.EVT_LISTBOX_DCLICK, self.reName)
self.listBox.Bind(wx.EVT_LISTBOX, self.imagesel)
btn = wx.Button(self, label="Create New",size=(200, 40))
btnTwo = wx.Button(self, label="Test 2",size=(200, 40))
btn.Bind(wx.EVT_BUTTON, self.newAddImage)
self.sizer.Add(self.listBox, proportion=1, flag=wx.TOP | wx.EXPAND | wx.LEFT, border=5)
btnSizer.Add(btn, 0, wx.ALL, 5)
btnSizer.Add(btnTwo, 0, wx.ALL, 5)
self.sizer.Add(btnSizer)
self.sizerMain.Add(self.sizer, proportion=0, flag=wx.BOTTOM | wx.EXPAND, border=0)
self.SetSizer(self.sizerMain)
class MyNotebook(wx.Notebook):
def __init__(self, *args, **kwargs):
wx.Notebook.__init__(self, *args, **kwargs)
class MyPanel(imageTab):
def OnClickTop(self, event):
scroll_img.Scroll(600, 400)
def OnClickBottom(self, event):
scroll_img.Scroll(1, 1)
def OnPageChanged(self, event):
new = event.GetSelection()
areachange(self,self.notebook.GetPageText(new))
event.Skip()
def OnPageChanging(self, event):
event.Skip()
def onOpenFile(self,parent):
""" Open a file"""
filename = wx.FileSelector()
if (filename!=''):
global bitmap1,bmp1,scroll_img
if IMAGE_DATA[IMAGE_LISTSEL[0]]!='':
deletepic(self,parent)
bmp1 = wx.Image(filename, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
bitmap1 = wx.StaticBitmap(scroll_img, -1, bmp1, (0, 0))
scroll_img.SetScrollbars(1, 1, bmp1.GetWidth(), bmp1.GetHeight())
IMAGE_DATA[IMAGE_LISTSEL[0]]=filename
print IMAGE_DATA
def __init__(self, *args, **kwargs):
global bitmap1,bmp1,scroll_img
wx.Panel.__init__(self, *args, **kwargs)
self.notebook = MyNotebook(self, size=(225, -1))
# self.button = wx.Button(self, label="Something else here? Maybe!")
tab_images = imageTab(self.notebook)
# add the pages to the notebook with the label to show on the tab
self.notebook.AddPage(tab_images, "Pics",select=True)
scroll_img = wx.ScrolledWindow(self, -1)
scroll_img.SetScrollbars(1, 1, 600, 400)
#self.button = wx.Button(scroll_img, -1, "Scroll Me", pos=(50, 20))
#self.Bind(wx.EVT_BUTTON, self.OnClickTop, self.button)
#self.button2 = wx.Button(scroll_img, -1, "Scroll Back", pos=(500, 350))
#self.Bind(wx.EVT_BUTTON, self.OnClickBottom, self.button2)
self.images_area=wx.StaticBox(self, -1, '')
self.sizerBox = wx.StaticBoxSizer(self.images_area,wx.HORIZONTAL)
#self.load_file=wx.Button(self, label='Load File')
#self.sizerBox.Add(self.load_file,0,wx.ALL,5)
self.sizerBox2 = wx.BoxSizer()
self.sizerBox.Add(scroll_img, 1, wx.EXPAND|wx.ALL, 10)
self.sizerBox2.Add(self.sizerBox, 1, wx.EXPAND|wx.ALL, 10)
self.sizer = wx.BoxSizer()
self.sizer.Add(self.notebook, proportion=0, flag=wx.EXPAND)
# self.sizer.Add(self.button, proportion=0)
btnSizer = wx.BoxSizer() #change to horizontal for side by side
btnTwo = wx.Button(self, label="Load File",size=(200, 40))
btnTwo.Bind(wx.EVT_BUTTON,self.onOpenFile)
bmp1 = None
bitmap1 = None
btnSizer.Add(btnTwo, 0, wx.TOP, 15)
self.sizerBox2.Add(btnSizer)
#self.sizerBox.Add(self.bitmap1)
self.sizer.Add(self.sizerBox2, proportion=1, flag=wx.EXPAND)
self.SetSizer(self.sizer)
self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
areachange(self,self.notebook.GetPageText(0))
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = MyPanel(self)
self.Show()
app = wx.App(False)
win = MainWindow(None, size=(600, 400))
app.MainLoop()
Try this to see what the error is,
1.you press create new (any amount of times)
2.press, load file
3. click any item on the listbox (except for the one that you are in)
4. Then go back to the orginal item that you were in,
5. Then click any item, other than the one you are currently in
There will be some sort of problem, the image does not destroy itself and returns an error like the following:
(, PyDeadObjectError('The C++ part of the StaticBitmap object has been deleted, attribute access no longer allowed.',), )
I am still able to load images but the previous images do not delete.
It is hard to word this problem, if anyone can help me with this situation, it would be greatly appreciated. If you need further explanation please comment. I thank you greatly for viewing.
Here you have your code fixed to clear your current image when loading another one.
This is done basically using self.parent.bitmap.Destroy().
I modified some few things without changing the structure of your code, in order for you to recognize changes. I eliminated globals calls. Look how I also eliminated the global IMAGE_LISTSEL variable and converted it in a class attribute. That is what Robin and Fenikso were telling you. Try to do the same with IMAGE_NAME and IMAGE_DATA.
Although the code is working, it is still far from being acceptable wxpython code. You can get many examples of correctly written wxpython code in the web. If you can afford it I recommend to you wxPython in Action from Noel Rappin and Robin Dunn.
IMAGE_NAME = []
IMAGE_DATA = []
import sys
import wx
def deletepic(self):
try:
self.parent.bitmap.Destroy()
except:
print sys.exc_info()
def sendnewpic(self):
if self.parent.bitmap: deletepic(self)
if IMAGE_DATA[self.image_listsel] != '':
try:
print IMAGE_DATA[self.image_listsel]
bmp = wx.Image(IMAGE_DATA[self.image_listsel], wx.BITMAP_TYPE_ANY).ConvertToBitmap()
self.parent.scroll_img.SetScrollbars(1, 1, bmp.GetWidth(), bmp.GetHeight())
self.parent.bitmap = wx.StaticBitmap(self.parent.scroll_img, -1, bmp, (0, 0))
self.parent.Refresh()
except:
pass
def areachange(self, pg):
print pg
try:
if IMAGE_DATA[self.image_listsel] == '':
deletepic(self)
except:
pass
if pg == "Images":
self.images_area.Show()
else:
self.images_area.Hide()
class imageTab(wx.Panel):
def __init__(self, parent, grandparent):
wx.Panel.__init__(self, parent)
self.parent = grandparent
self.image_listsel = 0
self.listBox = wx.ListBox(self, size=(200, -1), choices=IMAGE_NAME, style=wx.LB_SINGLE)
self.sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.VERTICAL) #change to horizontal for side by side
self.sizerMain = wx.BoxSizer()
self.listBox.Bind(wx.EVT_LISTBOX_DCLICK, self.reName)
self.listBox.Bind(wx.EVT_LISTBOX, self.imagesel)
btn = wx.Button(self, label="Create New",size=(200, 40))
btnTwo = wx.Button(self, label="Test 2",size=(200, 40))
btn.Bind(wx.EVT_BUTTON, self.newAddImage)
self.sizer.Add(self.listBox, proportion=1, flag=wx.TOP | wx.EXPAND | wx.LEFT, border=5)
btnSizer.Add(btn, 0, wx.ALL, 5)
btnSizer.Add(btnTwo, 0, wx.ALL, 5)
self.sizer.Add(btnSizer)
self.sizerMain.Add(self.sizer, proportion=0, flag=wx.BOTTOM | wx.EXPAND, border=0)
self.SetSizer(self.sizerMain)
def imagesel(self, evt):
self.image_listsel = self.listBox.GetSelection()
sendnewpic(self)
def newAddImage(self, evt):
IMAGE_NAME.append('hi')
IMAGE_DATA.append('')
self.listBox.Set(IMAGE_NAME)
self.listBox.SetSelection(len(IMAGE_NAME)-1)
self.imagesel(None) #making it a selected image, globally
def reName(self,parent):
sel = self.listBox.GetSelection()
text = self.listBox.GetString(sel)
renamed = wx.GetTextFromUser('Rename item', 'Rename dialog', text)
if renamed != '':
IMAGE_NAME.pop(sel)
IMAGE_NAME.insert(sel,renamed)
self.listBox.Set(IMAGE_NAME)
self.listBox.SetSelection(sel)
class MyPanel(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
self.notebook = wx.Notebook(self, size=(225, -1))
#
self.tab_images = imageTab(self.notebook, self)
# add the pages to the notebook with the label to show on the tab
self.notebook.AddPage(self.tab_images, "Pics", select=True)
self.scroll_img = wx.ScrolledWindow(self, -1)
self.scroll_img.SetScrollbars(1, 1, 600, 400)
self.images_area = wx.StaticBox(self, -1, '')
self.sizerBox = wx.StaticBoxSizer(self.images_area, wx.HORIZONTAL)
self.sizerBox2 = wx.BoxSizer()
self.sizerBox.Add(self.scroll_img, 1, wx.EXPAND|wx.ALL, 10)
self.sizerBox2.Add(self.sizerBox, 1, wx.EXPAND|wx.ALL, 10)
self.sizer = wx.BoxSizer()
self.sizer.Add(self.notebook, proportion=0, flag=wx.EXPAND)
#
btnSizer = wx.BoxSizer() #change to horizontal for side by side
btnTwo = wx.Button(self, label="Load File", size=(200, 40))
btnTwo.Bind(wx.EVT_BUTTON, self.onOpenFile)
self.bmp = None
self.bitmap = None
btnSizer.Add(btnTwo, 0, wx.TOP, 15)
self.sizerBox2.Add(btnSizer)
#
self.sizer.Add(self.sizerBox2, proportion=1, flag=wx.EXPAND)
self.SetSizer(self.sizer)
self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
areachange(self, self.notebook.GetPageText(0))
def OnClickTop(self, event):
self.scroll_img.Scroll(600, 400)
def OnClickBottom(self, event):
self.scroll_img.Scroll(1, 1)
def OnPageChanged(self, event):
new = event.GetSelection()
areachange(self, self.notebook.GetPageText(new))
event.Skip()
def OnPageChanging(self, event):
event.Skip()
def onOpenFile(self, evt):
""" Open a file"""
filename = wx.FileSelector()
if filename != '':
IMAGE_DATA[ self.tab_images.image_listsel] = filename
self.tab_images.imagesel(None)
print IMAGE_DATA
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = MyPanel(self)
self.Show()
app = wx.App(False)
win = MainWindow(None, size=(600, 400))
app.MainLoop()
Sometimes you are using bmp1 and bitmap1 as local variables and sometimes as globals. Since you are making multiple instances of them without saving the prior references anywhere then you are losing your references to the already existing objects. When you Destroy() them then you are only destroying the most recently created instances.
Try adding them to some sort of collection (like a list) instead and then you can access any of the items from the list when you need them later. Also try to avoid using global variables. Store your variables in the object instances that they belong to.

Categories