wxpython : How to AppendText one by one (as any key pressed) - python

In this code, I have a wx TextCtrl to show information (info_window), and a function print_info() to receive texts from my main script, append them to TextCtrl. The texts are appended at the same time, but I need them to be appended like this:
hello 1
-press any key
hello 2
-press any key
hello 3
Is there any way to append the strings one by one after pressing any key by keyboard?
I suppose the key should be the function press_any_key(). It may associated with any type of wx event, but I don't know how to write the function properly.
import wx
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size(500,300), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)
bSizer1 = wx.BoxSizer(wx.VERTICAL)
self.info_window = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size(450,250), wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2)
bSizer1.Add(self.info_window, 0, wx.ALL, 5)
self.SetSizer(bSizer1)
self.Layout()
def print_info(self, string):
self.string = string + '\n'
self.info_window.AppendText(self.string)
self.press_any_key()
def press_any_key(self):
pass
def main():
frame.print_info('hello 1')
frame.print_info('hello 2')
frame.print_info('hello 3')
app = wx.App()
frame = Frame(None)
frame.Show()
main()
app.MainLoop()
Thanks Rolf of Saxony. I solved my problem, the key point is wx.Yield(). I modified the code as below
import wx
import time
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size(500,300), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)
bSizer1 = wx.BoxSizer(wx.VERTICAL)
self.info_window = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size(450,250), wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2)
bSizer1.Add(self.info_window, 0, wx.ALL, 5)
self.info_window.Bind(wx.EVT_KEY_DOWN, self.go)
self.SetSizer(bSizer1)
self.Layout()
self.go_status = False
def print_info(self, string):
self.waitkey()
self.string = string + '\n'
self.info_window.AppendText(self.string)
self.go_status = False
def go(self, event):
self.go_status = True
def waitkey(self):
while self.go_status == False:
wx.Yield()
time.sleep(0.1)
def main():
frame.print_info('hello 1')
frame.print_info('hello 2')
frame.print_info('hello 3')
app = wx.App()
frame = Frame(None)
frame.Show()
main()
app.MainLoop()

It's not pretty but I couldn't think of a easier way to do it.
import wx
import time
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size(500,360), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
self.SetSizeHints(500,360)
bSizer1 = wx.BoxSizer(wx.VERTICAL)
self.info_window = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size(450,250), wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2)
self.message = wx.StaticText(self,-1,("Press any key"))
self.keyinput = wx.TextCtrl(self,-1)
bSizer1.Add(self.info_window, 0, wx.ALL, 5)
bSizer1.Add(self.message, 0, wx.ALL, 5)
bSizer1.Add(self.keyinput, 0, wx.ALL, 5)
self.SetSizer(bSizer1)
self.Layout()
self.Show()
self.keyinput.SetFocus()
def print_info(self, string):
self.WaitOnKey()
self.string = string + '\n'
self.info_window.AppendText(self.string)
def WaitOnKey(self):
while self.keyinput.GetValue() == "":
wx.Yield()
time.sleep(0.2)
self.keyinput.SetValue("")
def main():
frame.print_info('hello 1')
frame.print_info('hello 2')
frame.print_info('hello 3')
app = wx.App()
frame = Frame(None)
main()
app.MainLoop()
The code is self explanatory with the exception of wx.Yield(). This returns control back to the MainLoop which means that the program doesn't freeze. Essentially while the program waits for key input, control is passed back to the main loop every 2/10ths of a second, to see if anything else is going on. This allows the program to continue to perform normally.
Note: This will not work with function keys. For that I think you would have to find a way to bind to a key event and use event.GetKeyCode()

Related

wxpython assign variable in an event handler

I would like to assign the value of a menu click to a class variable so I can use that value throughout multiple classes. Any help would be greatly appreciated!
import wx
class TrackPanel (wx.Panel):
""""""
def __init__(self, parent, *args, **kwargs):
"""Constructor"""
wx.Panel.__init__(self, parent, *args, **kwargs)
mainSizer =wx.BoxSizer(wx.VERTICAL)
track = MasterPage.track_selected # This is where i would like access the variable
title = wx.StaticText(self, wx.ID_ANY, label = track)
mainSizer.Add(title, 0,wx.ALL | wx.EXPAND | wx.CENTER)
self.SetSizerAndFit(mainSizer)
self.Layout()
class MasterPage (wx.Frame):
track_selected = ' '
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
menubar = wx.MenuBar()
tracksopt = wx.Menu()
track_command = wx.MenuItem(tracksopt, wx.ID_ANY, 'Atlanta')
tracksopt.Append(track_command)
self.Bind(wx.EVT_MENU, self.change_track, track_command)
track_command2 = wx.MenuItem(tracksopt, wx.ID_ANY, 'Texas')
tracksopt.Append(track_command2)
self.Bind(wx.EVT_MENU, self.change_track, track_command2)
menubar.Append(tracksopt, '&Tracks')
self.SetMenuBar(menubar)
def change_track (self, event):
"""Changes the tack_selected variable based on the menu item picked"""
id_selected = event.GetId()
obj = event.GetEventObject()
track_id= obj.GetLabel(id_selected)
MasterPage.track_selected = track_id
You must create a link to the master in the tracker in order for the tracker to access values in the master.
import wx
class Track (wx.Frame):
def __init__(self, link):
wx.Frame.__init__(self, None)
self.link = link
self.tc = wx.TextCtrl(self, style=wx.TE_MULTILINE)
self.bt = wx.Button(self, label="tracker (push to read master)")
self.bt.Bind(wx.EVT_BUTTON, self.on_read_master)
self.Title = 'Tracker'
sz_1 = wx.BoxSizer(wx.HORIZONTAL)
sz_2 = wx.BoxSizer(wx.VERTICAL)
sz_2.Add(self.tc, 1, wx.EXPAND, 0)
sz_2.Add(self.bt, 0, wx.EXPAND, 0)
sz_1.Add(sz_2, 1, wx.EXPAND, 0)
self.SetSizer(sz_1)
self.Layout()
self.SetSize((250, 100))
def on_read_master(self, evt):
self.tc.SetValue(self.link.track_selected) # here you access the variable)
class Master(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.track_selected = '0'
self.tc = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE)
self.bt = wx.Button(self, wx.ID_ANY, "master (push to send)")
self.bt.Bind(wx.EVT_BUTTON, self.change_track)
self.Title = 'Master'
self.tc.SetValue('enter value to be read by the tracker')
sz_1 = wx.BoxSizer(wx.HORIZONTAL)
sz_2 = wx.BoxSizer(wx.VERTICAL)
sz_2.Add(self.tc, 1, wx.EXPAND, 0)
sz_2.Add(self.bt, 0, wx.EXPAND, 0)
sz_1.Add(sz_2, 1, wx.EXPAND, 0)
self.SetSizer(sz_1)
self.Layout()
self.SetSize((250, 100))
def change_track (self, evt):
"""Changes variable based on text entered"""
self.track_selected = self.tc.GetValue()
if __name__ == "__main__":
app = wx.App(0)
master = Master()
track = Track(master)
master.Show()
track.Show()
app.MainLoop()
This is the fast and dirty method I generally use. If you want something more sophisticated, there is a dedicated library to pass messages between frames: pubsub. A good tutorial of how to use it can be found in the Mike Driscoll blog

How can I resize * wx.CheckListBox* automatically in wxPython?

If the text of label for checkboxes is more than width of a wx.CheckListBox one must change its size.
The short answer is to not set the size of the CheckListBox. This will automatically set the size to the largest item. If you do set the size parameter and the text does not fit, set the style=wx.LB_HSCROLL and a horizontal slider will be created, if needed.
Below a demonstration with both versions of self.clb
import wx
class ClbView(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, None, -1, 'CheckListBox', size=(250, 200))
def createWidgets(self, list):
self.panel = wx.Panel(self, -1)
# self.clb = wx.CheckListBox(self.panel, -1, size=(100,150),choices=list,style=wx.LB_HSCROLL)
self.clb = wx.CheckListBox(self.panel, -1, choices = list)
self.btn_exit = wx.Button(self.panel, wx.ID_ANY, 'Exit')
def sizeWidgets(self):
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.vbox.Add(self.clb, 0, wx.ALL|wx.CENTER, 5)
self.vbox.Add(self.btn_exit, 0, wx.CENTER)
self.panel.SetSizer(self.vbox)
self.Centre()
class ClbControl:
def __init__(self):
self.list = ['Quite a long piece of text', 'Short text', 'X']
self.createView()
def createView(self):
self.view = ClbView(None)
self.view.createWidgets(self.list)
self.view.sizeWidgets()
self.view.Show()
self.view.btn_exit.Bind(wx.EVT_BUTTON, self.onExit)
self.view.clb.Bind(wx.EVT_CHECKLISTBOX, self.onCLB )
def onCLB(self, evt):
x = int(evt.GetSelection())
print "Box ",x," Accessed"
def onExit(self, evt):
self.view.Close()
if __name__ == '__main__':
app = wx.App()
controller = ClbControl()
app.MainLoop()

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

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

Update/Refresh Dynamically–Created WxPython Widgets

New python programmer here and trying to learn how to dynamically update widgets. To start, I have the following code. What I would like to do is change my variable "self.dynamiclength" to any integer, and have WxPython update the number of widgets appropriately. I have tried putting self.Refresh() and self.Update() in my TestFrame after updating self.dynamiclength to no avail.
I have done as much reading as possible on this before resorting to asking for help, but I am just too new at Wx to solve this one on my own. Thank you much!
import wx
import wx.lib.scrolledpanel as scrolled
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, size=(1000, 550))
panel = wx.Panel(self)
mainSizer = wx.BoxSizer(wx.VERTICAL)
pbox0 = wx.BoxSizer(wx.VERTICAL)
controlback0 = wx.Button(panel, label="Back0")
controlforward0 = wx.Button(panel, label="Forward0")
pbox0.Add(controlback0, 0, wx.ALL)
pbox0.Add(controlforward0, 0, wx.ALL)
mainSizer.Add(pbox0)
self.scrolling_window = scrolled.ScrolledPanel( panel )
self.scrolling_window.SetAutoLayout(1)
self.scrolling_window.SetupScrolling()
self.sizer = wx.BoxSizer( wx.VERTICAL )
self.child_windows = []
##############################################
#this is the variable that I want to change,
#and I don't know how to get the 'for loop'
#below to update as well.
self.eedictionary = {}
self.dynamiclength = 5
for i in range(0,self.dynamiclength):
wind = self.addBox(i)
self.sizer.Add(wind, 0, wx.CENTER|wx.ALL, 5)
###############################################
#the following code binds all appropriate buttons to a pedigree variable updater
button_binding_list = ['controlback','controlforward']
for j in button_binding_list:
eid = self.eedictionary[str(i)+j]
self.scrolling_window.Bind(wx.EVT_BUTTON, lambda evt: self.onclick(evt, id), id=eid)
self.scrolling_window.SetSizer(self.sizer)
mainSizer.Add(self.scrolling_window, 1, wx.EXPAND)
panel.SetSizer(mainSizer)
def addBox(self, i):
pbox = wx.BoxSizer(wx.VERTICAL)
controlback = wx.Button(self.scrolling_window, label="Back")
controlforward = wx.Button(self.scrolling_window, label="Forward")
pbox.AddMany([(controlback, 0, wx.ALL), (controlforward, 0, wx.ALL)])
#for each object created in the addBox module, its id is added to the dictionary
self.eedictionary[str(i)+'controlback'] = controlback.GetId()
self.eedictionary[str(i)+'controlforward'] = controlforward.GetId()
return pbox
def onclick(self, event):
self.dynamiclength +=1
print 'added one to self.dynamiclength', self.dynamiclength
if __name__=='__main__':
app = wx.App(False)
f = TestFrame()
f.Show()
app.MainLoop()
I have similar test code which I have written some time ago. Maybe you will find it useful.
import wx
#===================================================================================================
class UpperPanel(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
self.combo = wx.ComboBox(self, choices=["0", "1", "2", "3", "4"], size=(200, -1))
self.combo.Bind(wx.EVT_COMBOBOX, self.GetParent().middlePanel.Change)
self.logo = wx.Button(self, size=(300, 100))
self.sizer = wx.BoxSizer()
self.sizer.Add(self.combo, 0, wx.EXPAND)
self.sizer.Add(self.logo, 0, wx.EXPAND)
self.SetSizerAndFit(self.sizer)
#===================================================================================================
class MiddlePanel(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
self.subs = []
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizerAndFit(self.sizer)
def Change(self, e):
self.sizer = wx.BoxSizer(wx.VERTICAL)
for a in self.subs:
a.Destroy()
self.subs = []
for a in range(int(e.GetString())):
b = wx.Button(self, size=(-1, 50))
self.subs.append(b)
self.sizer.Add(b, 1, wx.EXPAND)
self.SetSizerAndFit(self.sizer)
self.GetParent().Fit()
#===================================================================================================
class MainWin(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.middlePanel = MiddlePanel(self)
self.upperPanel = UpperPanel(self)
self.textArea = wx.TextCtrl(self, size=(-1, 300), style=wx.TE_MULTILINE)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.upperPanel, 0, wx.EXPAND)
self.sizer.Add(self.middlePanel, 0, wx.EXPAND)
self.sizer.Add(self.textArea, 1, wx.EXPAND)
self.SetSizerAndFit(self.sizer)
#===================================================================================================
if __name__ == '__main__':
app = wx.PySimpleApp()
main_win = MainWin()
main_win.Show()
app.MainLoop()
If you need to update the number of widgets AFTER you've already created and shown the application, the you'll need to do it in a method, NOT in the init. The init only runs the first time the application is instantiated. Whenever you add or remove widgets after the frame is shown, you'll need to call Layout() on the parent widget or its sizer. See also
http://wxpython-users.1045709.n5.nabble.com/dynamically-adding-amp-removing-widgets-td2342432.html
https://groups.google.com/forum/?fromgroups#!topic/wxPython-users/eQjlYlsw4qs
Adding a widget with a button - wxPython

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