There is an existing question on this subject: Find text dialog with wxpython, but it's in TextCtrl. So I changed the TextCtrl to StyledTextCtrl, and tested it. But I got this error:
in wxStyledTextCtrl::SetStyle(): not implemented
How do I make the SetStyle a selection instead so that you can click away? Here is my code:
import wx
import wx.stc as stc
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.tc = stc.StyledTextCtrl(self, style=wx.TE_MULTILINE | wx.TE_WORDWRAP)
self.bt_find = wx.Button(self, -1, "find")
self.Bind(wx.EVT_BUTTON, self.on_button, self.bt_find)
self.Bind(wx.EVT_FIND, self.on_find)
self.pos = 0
self.size = 0
#
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.tc, 1, wx.EXPAND, 0)
sizer.Add(self.bt_find, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
self.SetSizer(sizer)
sizer.Fit(self)
self.Layout()
def on_button(self, event):
self.txt = self.tc.GetValue()
self.data = wx.FindReplaceData() # initializes and holds search parameters
self.dlg = wx.FindReplaceDialog(self.tc, self.data, 'Find')
self.dlg.Show()
def on_find(self, event):
fstring = self.data.GetFindString() # also from event.GetFindString()
self.pos = self.txt.find(fstring, self.pos)
self.size = len(fstring)
self.tc.SetStyle(self.pos, self.pos+self.size, wx.TextAttr("red", "black"))
if __name__ == "__main__":
app = wx.PySimpleApp(0)
frame_1 = MyFrame(None, wx.ID_ANY, "")
frame_1.Show()
app.MainLoop()
The StyledTextCtrl looks like a highly complex beast and I can only assume that you will have to read the scintilla documents exhustively http://www.scintilla.org/
The link in my comment was pointing at using SetStyling function not AddSelection.
This is what I managed using that:
import wx
import wx.stc as stc
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.tc = stc.StyledTextCtrl(self, style=wx.TE_MULTILINE | wx.TE_WORDWRAP)
self.bt_find = wx.Button(self, -1, "find")
self.Bind(wx.EVT_BUTTON, self.on_button, self.bt_find)
self.Bind(wx.EVT_FIND, self.on_find)
self.pos = 0
self.size = 0
#
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.tc, 1, wx.EXPAND, 0)
sizer.Add(self.bt_find, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
self.SetSizer(sizer)
sizer.Fit(self)
self.Layout()
def on_button(self, event):
self.txt = self.tc.GetValue()
self.data = wx.FindReplaceData() # initializes and holds search parameters
dlg = wx.FindReplaceDialog(self.tc, self.data, 'Find')
dlg.Show()
def on_find(self, event):
self.tc.StartStyling(pos=0, mask=0xFF)
self.tc.SetStyling(length=len(self.txt), style=0)
fstring = event.GetFindString()
self.size = len(fstring)
while True:
self.pos = self.txt.find(fstring, self.pos)
if self.pos < 0:
break
self.tc.StyleSetSpec(1, "fore:#FF0000,back:#000000")
self.tc.StartStyling(pos=self.pos, mask=0xFF)
self.tc.SetStyling(length=self.size, style=1)
self.pos += 1
self.pos = 0
if __name__ == "__main__":
app = wx.App()
frame_1 = MyFrame(None, wx.ID_ANY, "")
frame_1.Show()
app.MainLoop()
Related
I am trying to get a variable out of wxPython file open dialog. I have 2 button which gets the path to 2 files with .GetPath() ?
this is the code I have so far
'def onclk1(event):
with wx.FileDialog(panel, "OPEN EMG FILE", wildcard="TXT Files(*.txt)|*.txt",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as EmgFile:
if EmgFile.ShowModal() == wx.ID_CANCEL:
return "cancelled"
emg = EmgFile.GetPath()
e1.Bind(wx.EVT_BUTTON, onclk1)
Now I need to pass the path outside def to another variable.
Thanks in advance
In future it might be better to provide a minimal working example of your code.
Don't forget that a GUI is event driven and you must use the event to assign the return value of a dialog to the variable you want.
You've not said what you want to do with the file path, but this code shows how to assign it to a label.
"""Main Frame module for basic wxPython App."""
import wx
class MainFrame(wx.Frame):
"""Create MainFrame class."""
def __init__(self, *args, **kwargs):
super().__init__(None, *args, **kwargs)
self.size = (400, 1000)
self.Title = 'wx App'
self.Bind(wx.EVT_CLOSE, self.on_quit_click)
self.panel = MainPanel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel)
self.SetSizer(sizer)
self.Center()
self.Show()
def onclk1(self, event):
with wx.FileDialog(self.panel, "OPEN EMG FILE", wildcard="TXT Files(*.txt)|*.txt",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as EmgFile:
if EmgFile.ShowModal() == wx.ID_CANCEL:
return "cancelled"
emg = EmgFile.GetPath()
self.panel.lbl_file1.SetLabel(emg)
def on_quit_click(self, event):
"""Handle close event."""
del event
wx.CallAfter(self.Destroy)
class MainPanel(wx.Panel):
"""Create a panel class to contain screen widgets."""
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
e1 = wx.Button(self, label='File1')
e1.Bind(wx.EVT_BUTTON, parent.onclk1)
self.lbl_file1 = wx.StaticText(self, label=' '*100)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(e1)
sizer.Add(self.lbl_file1)
self.SetSizer(sizer)
if __name__ == '__main__':
wx_app = wx.App()
MainFrame()
wx_app.MainLoop()
Just to provide another option, there is also a wx.FilePickerCtrl
import wx
import os
wildcard = "All files (*.*)|*.*"
class MainWindow(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='File Selector')
self.currentDirectory = os.getcwd()
self.panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
ie_box = wx.StaticBox(self.panel, -1, 'Please select the input file')
ie_sizer = wx.StaticBoxSizer(ie_box, wx.VERTICAL)
fl_box = wx.BoxSizer(wx.HORIZONTAL)
self.fl_ctrl = wx.FilePickerCtrl(self.panel, message="Choose a file")
fl_box.Add(self.fl_ctrl, 1, wx.ALL | wx.CENTER | wx.EXPAND, 5)
ie_sizer.Add(fl_box, 1, wx.ALL | wx.CENTER | wx.EXPAND, 10)
self.fl_ctrl.Bind(wx.EVT_FILEPICKER_CHANGED, self.on_open_file)
vbox.Add(ie_sizer, 0, wx.ALL | wx.CENTER | wx.EXPAND, 5)
self.panel.SetSizer(vbox)
self.Center()
self.panel.Fit()
self.Show()
def on_open_file(self, event):
self.fl_ctrl.GetPath()
if __name__ == '__main__':
app = wx.App()
frame = MainWindow()
app.MainLoop()
I have a code. When it runs, you click on add contact button and add some contact. When you press on each contact, it just shows you the last contact information you have added. But when I press on each contact, I want it to instead show me the information for the contact I have clicked. Who can help me to solve this problem?
import wx
from wx._core import RB_GROUP, TE_READONLY
import sys
import os
from _ssl import nid2obj
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(500,500))
self.panel = wx.Panel(self, -1)
self.contactslist =[]
self.path = os.getcwd()+'\\contacts-db'
self.nc = wx.Button(self.panel, label='new contact')
self.nc.Bind(wx.EVT_BUTTON, self.newcontact)
self.displaycontacts()
self.Show(True)
def displaycontacts(self):
for roots, dirs, files in os.walk(self.path):
for filename in files:
#self.contactslist.append(filename)
self.cntct = wx.Button(self.panel, label=filename)
self.cntct.Bind(wx.EVT_BUTTON, self.clickcontacts)
def clickcontacts(self, e):
self.oc =self.path+'\\'+self.cntct.GetLabel()
self.oc2 = open(self.oc, 'r')
prt = wx.TextCtrl(self.panel, value=self.oc2.read())
def newcontact(self, e):
self.val = ''
self.f1 = wx.TextCtrl(self.panel, value='enter your first name', pos=(0,0))
self.f1.SetFocus()
self.f2 = wx.TextCtrl(self.panel, value='enter your last name', pos=(0,50))
self.rbm = wx.RadioButton(self.panel, label='male', style=RB_GROUP, pos=(0,100))
self.rbm.Bind(wx.EVT_RADIOBUTTON, self.male)
self.rbf = wx.RadioButton(self.panel, label='female')
self.rbf.Bind(wx.EVT_RADIOBUTTON, self.female)
self.btn = wx.Button(self.panel, label='show', pos=(0,200))
self.btn.Bind(wx.EVT_BUTTON, self.showform)
self.s = wx.TextCtrl(self.panel, value=self.val, style=wx.TE_MULTILINE, size=(800,800))
self.clrbtn = wx.Button(self.panel, label='clear', pos=(800,800))
self.clrbtn.Bind(wx.EVT_BUTTON, self.onclear)
self.af = wx.Button(self.panel, label='add additional field')
self.af.Bind(wx.EVT_BUTTON, self.additionalfield)
self.sv = wx.Button(self.panel, label='save')
self.sv.Bind(wx.EVT_BUTTON, self.save)
def showform(self, e):
self.s.SetValue('first name: '+self.f1.GetValue()+'\nlast name: '+self.f2.GetValue()+self.val)
def male(self, e):
self.val=''
self.val = '\ngender: male'
def female(self, e):
self.val=''
self.val='\ngender: female'
def onclear(self, e):
self.s.Clear()
self.f1.Clear()
self.f2.Clear()
def additionalfield(self, e):
self.x = wx.TextCtrl(self.panel, value='\nenter field name: ')
self.x.SetFocus()
self.y = wx.TextCtrl(self.panel, value='enter information ')
self.add = wx.Button(self.panel, label='add')
self.add.Bind(wx.EVT_BUTTON, self.additionalfieldappend)
def additionalfieldappend(self, e):
self.s.AppendText('\n'+self.x.GetValue()+': '+self.y.GetValue())
self.x.Destroy()
self.y.Destroy()
def save(self, e):
if not os.path.exists(self.path):
os.makedirs(self.path)
cnt = open(self.path+'\\'+self.f1.GetValue()+self.f2.GetValue()+'.txt', 'x')
cnt.write(self.s.GetValue())
nid2obj
app = wx.App()
frame = MyFrame(None, 'contact form')
app.MainLoop()
Everyone will develop their own style when using wxPython. As Rolf has suggested, you do not just add widgets to a frame, but you need to add a panel. I have added a basic contact add screen below. The 'New' button creates an instance of a wx.Dialog, which captures the details of a contact. These are then available to the MainFrame where you can save them if you want.
Note that I have freely created new classes in the application to handle the different areas of concern. GUI apps can become very complex, and in my opinion, there is no substitute for factoring each bit of functionality into its own method or class.
Not everything needs to be a member of the frame class.
Note also the I have used sizers and not absolute positions.
This code does not do everything that you want to do, but it might help get you started.
import wx
BORDER = 5
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(None, *args, **kwargs)
self.size = (400, 1000)
self.Title = 'Contacts'
self.Bind(wx.EVT_CLOSE, self.on_quit_click)
self.panel = MainPanel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel)
self.SetSizer(sizer)
self.Center()
self.Show()
def new_contact(self, event):
del event
contact_add_screen = NewContact(self)
try:
contact_add_screen.ShowModal()
if contact_add_screen.state == wx.ID_OK:
print(contact_add_screen.first_name)
print(contact_add_screen.last_name)
# This is where you can save your contacts
finally:
contact_add_screen.Destroy()
def on_quit_click(self, event):
del event
wx.CallAfter(self.Destroy)
class MainPanel(wx.Panel):
"""Create a panel class to contain screen widgets."""
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.parent = parent
cmd_new_contact = wx.Button(self, id= wx.ID_NEW)
cmd_new_contact.Bind(wx.EVT_BUTTON, parent.new_contact)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(cmd_new_contact, flag=wx.ALL, border = BORDER)
self.SetSizer(sizer)
class NewContact(wx.Dialog):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.state = None
self.first_name = None
self.last_name = None
self.parent = parent
self.SetTitle('Add Contact')
self.panel = ContactAddPanel(self)
sizer = wx.BoxSizer()
sizer.Add(self.panel)
self.SetSizerAndFit(sizer)
def on_cmd_save_click(self, event):
del event
self.first_name = self.panel.txt_first_name.GetValue()
self.last_name = self.panel.txt_last_name.GetValue()
self.state = wx.ID_OK
self.Destroy()
def on_quit_click(self, event):
del event # unused
self.Destroy()
class ContactAddPanel(wx.Panel):
TEXT_SIZE = (450, -1)
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.parent = parent
contact_sizer = self._contact_sizer()
button_panel = ButtonPanel(self, wx.ID_SAVE,
self.parent.on_cmd_save_click,
self.parent.on_quit_click)
self.txt_first_name.SetFocus()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(contact_sizer)
sizer.Add(button_panel, flag=wx.EXPAND|wx.TOP, border=BORDER)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(sizer, flag=wx.ALL, border=BORDER)
self.SetSizer(main_sizer)
def _contact_sizer(self):
lbl_first_name= wx.StaticText(self, label='First name: ')
self.txt_first_name= wx.TextCtrl(self, size=self.TEXT_SIZE)
lbl_last_name = wx.StaticText(self, label='Last name:')
self.txt_last_name = wx.TextCtrl(self, size=self.TEXT_SIZE)
sizer = wx.GridBagSizer(BORDER, BORDER)
sizer.Add(lbl_first_name, pos=(0, 0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.txt_first_name, pos=(0, 1))
sizer.Add(lbl_last_name, pos=(1, 0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.txt_last_name, pos=(1, 1))
return sizer
class ButtonPanel(wx.Panel):
def __init__(self, parent, ok_id, ok_bind, cancel_bind, *args, **kwargs):
super(ButtonPanel, self).__init__(parent, *args, **kwargs)
self.cmd_action = wx.Button(self, ok_id)
cmd_cancel = wx.Button(self, wx.ID_CANCEL)
self.cmd_action.Bind(wx.EVT_BUTTON, ok_bind)
cmd_cancel.Bind(wx.EVT_BUTTON, cancel_bind)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.cmd_action)
sizer.Add((0, 0), proportion=1)
sizer.Add(cmd_cancel)
self.SetSizer(sizer)
if __name__ == '__main__':
wx_app = wx.App()
MainFrame()
wx_app.MainLoop()
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
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()
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.