I have a python 3 (wxpython phoenix) app which has two TABs, each TAB has a OnDropFiles box, but I just can't get it working. I have a simple stripped down example below, which should print the file URL on each drop, but not working, if someone could show a working example please, or point me in the right direcion, I would be very gratefull.
I'm using Python 3.10.5 and wxpython 4.2.
import wx
class ScrolledWindow(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(510, 330), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER |
wx.MAXIMIZE_BOX))
run_params = {}
self.tabbed = wx.Notebook(self, -1, style=(wx.NB_TOP))
self.filePrep = PrepFile(self.tabbed, self, run_params)
self.fileCheck = CheckFile(self.tabbed, self, run_params)
self.tabbed.AddPage(self.filePrep, "File Prep")
self.tabbed.AddPage(self.fileCheck, "File Check")
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.switchSize)
self.Centre()
self.Show()
def switchSize(self, e):
page = self.tabbed.GetPageText(self.tabbed.GetSelection())
if page == 'File Prep':
self.SetSize((510, 330))
elif page == 'File Check':
self.SetSize((510, 510))
self.fileCheck.setSubmissionDrop(self)
class PrepFile(wx.Panel):
def __init__(self, parent, frame, run_params):
wx.Panel.__init__(self, parent)
self.run_params = run_params
self.parent = parent
self.frame = self
self.selectedFiles = ""
outputtxt3 = '''Drag and Drop files'''
wx.StaticText(self, -1, outputtxt3, pos=(25, 180), style=wx.ALIGN_CENTRE)
self.drop_target = MyFileDropTarget(self)
self.SetDropTarget(self.drop_target)
self.tc_files = wx.TextCtrl(self, wx.ID_ANY, pos=(28, 200), size=(360, 25))
self.tc_files.SetFocus()
self.Show()
def setSubmissionDrop(self, dropFiles):
"""Called by the FileDropTarget when files are dropped"""
print(dropFiles)
self.tc_files.SetValue(','.join(dropFiles))
self.selectedFiles = dropFiles
class CheckFile(wx.Panel):
def __init__(self, parent, frame, run_params):
wx.Panel.__init__(self, parent)
self.run_params = run_params
self.parent = parent
self.frame = self
self.selectedFiles = ""
wx.StaticText(self, -1, '''Drag and Drop files''', pos=(25, 10), style=wx.ALIGN_CENTRE)
self.drop_target = MyFileDropTarget(self)
self.SetDropTarget(self.drop_target)
self.tc_files = wx.TextCtrl(self, wx.ID_ANY, pos=(25, 30), size=(302, 25))
self.tc_files.SetFocus()
self.Show()
def setSubmissionDrop(self, dropFiles):
"""Called by the FileDropTarget when files are dropped"""
print(dropFiles)
self.selectedFiles = dropFiles
class MyFileDropTarget(wx.FileDropTarget):
""""""
def __init__(self, window):
wx.FileDropTarget.__init__(self)
self.window = window
def OnDropFiles(self, x, y, filenames):
print(filenames)
self.window.setSubmissionDrop(filenames)
return True
app = wx.App()
ScrolledWindow(None, -1, 'File Prep ')
app.MainLoop()
We want this to be event driven, so you should define an event, from wx.lib.newevent.
I assume you want the drop zone to be the textctrl not the whole panel, so it's that that needs to be set as the target.
BIND the event.
In the FileDropTarget class we define the event and fire it.
In each drop event callback, we accept the event as a parameter and unpack whatever we packed into the event.
One last thing, in this case, you are getting back a list.
It's simple but every time you decide to use it, it trips you up, I don't know why.
import wx
import wx.lib.newevent
drop_event, EVT_DROP_EVENT = wx.lib.newevent.NewEvent()
class ScrolledWindow(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(510, 330), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER |
wx.MAXIMIZE_BOX))
run_params = {}
self.tabbed = wx.Notebook(self, -1, style=(wx.NB_TOP))
self.filePrep = PrepFile(self.tabbed, self, run_params)
self.fileCheck = CheckFile(self.tabbed, self, run_params)
self.tabbed.AddPage(self.filePrep, "File Prep")
self.tabbed.AddPage(self.fileCheck, "File Check")
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.switchSize)
self.Centre()
self.Show()
def switchSize(self, e):
page = self.tabbed.GetPageText(self.tabbed.GetSelection())
if page == 'File Prep':
self.SetSize((510, 330))
elif page == 'File Check':
self.SetSize((510, 510))
class PrepFile(wx.Panel):
def __init__(self, parent, frame, run_params):
wx.Panel.__init__(self, parent)
self.run_params = run_params
self.parent = parent
self.frame = self
self.selectedFiles = ""
outputtxt3 = '''Drag and Drop files'''
wx.StaticText(self, -1, outputtxt3, pos=(25, 180), style=wx.ALIGN_CENTRE)
self.tc_files = wx.TextCtrl(self, wx.ID_ANY, pos=(28, 200), size=(360, 25))
self.drop_target = MyFileDropTarget(self)
self.tc_files.SetDropTarget(self.drop_target)
self.Bind(EVT_DROP_EVENT, self.setSubmissionDrop)
self.tc_files.SetFocus()
self.Show()
def setSubmissionDrop(self, event):
"""Called by the FileDropTarget when files are dropped"""
files = event.data
print("\nprep event", files)
self.tc_files.SetValue(','.join(files))
self.selectedFiles = files
class CheckFile(wx.Panel):
def __init__(self, parent, frame, run_params):
wx.Panel.__init__(self, parent)
self.run_params = run_params
self.parent = parent
self.frame = self
self.selectedFiles = ""
wx.StaticText(self, -1, '''Drag and Drop files''', pos=(25, 10), style=wx.ALIGN_CENTRE)
self.tc_files = wx.TextCtrl(self, wx.ID_ANY, pos=(25, 30), size=(302, 25))
self.drop_target = MyFileDropTarget(self)
self.tc_files.SetDropTarget(self.drop_target)
self.Bind(EVT_DROP_EVENT, self.setSubmissionDrop)
self.tc_files.SetFocus()
self.Show()
def setSubmissionDrop(self, event):
"""Called by the FileDropTarget when files are dropped"""
files = event.data
print("\ncheck event", files)
self.tc_files.SetValue(','.join(files))
self.selectedFiles = files
class MyFileDropTarget(wx.FileDropTarget):
""""""
def __init__(self, window):
wx.FileDropTarget.__init__(self)
self.obj = window
def OnDropFiles(self, x, y, filenames):
drp_evt = drop_event(data=filenames)
wx.PostEvent(self.obj, drp_evt)
return True
app = wx.App()
ScrolledWindow(None, -1, 'File Prep ')
app.MainLoop()
Related
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
I want to open a TextEntryDialog, when user clicks the button. So if i have a button in the parent frame which i am going to bind this way:
self.Bind(wx.EVT_BUTTON, self.OnAddNew, self.add_new_btn)
Now i have to open a TextEntryDialog when user clicks the button add_new. I want to make textentrydialog somewthing like this
Python, Using wxPython to get multiple input from user
How can i do that? Do i need to just paste that code in ` def OnAddNew(self, event):
Here is the pastebin link to my code: https://pastebin.com/UEYscgFa
I have created class inside a function, so is it possible to do in that way?
NO!
GetData is a class in its own right.
That code already provides you with the method.
The MyFrame is all fluff, to create a standalone working example.
def OnButton(self,event):
dlg = GetData(parent = self.panel)
dlg.ShowModal()
if dlg.result_name:
self.log.AppendText("Name: "+dlg.result_name+"\n")
self.log.AppendText("Surname: "+dlg.result_surname+"\n")
self.log.AppendText("Nickname: "+dlg.result_nickname+"\n")
else:
self.log.AppendText("No Input found\n")
dlg.Destroy()
Edit: I don't understand where the instructions in my comments eluded you but for my sins, here is your code cleaned up and edited as in the comments.
import sqlite3
import wx
import os
class Example(wx.Frame):
def __init__(self, parent, title):
super(Example, self).__init__(parent, title=title, size=(1000,800))
self.inter_list = list()
self.plot_list = list()
self.InitUI()
self.Layout()
self.Centre()
self.Show()
def InitUI(self):
self.p = wx.Panel(self)
bs = wx.BoxSizer(wx.VERTICAL)
gs = wx.GridSizer(10, 18, 5, 5)
bs.Add(gs, 1, wx.EXPAND)
self.search_btn=wx.Button(self.p,-1,"Search!")
self.search_btn.Bind(wx.EVT_BUTTON, self.OnSearch, self.search_btn)
bs.Add(self.search_btn,0,wx.ALIGN_CENTER)
self.p.SetSizer(bs)
def OnSearch(self, event):
dlg = GetData(parent = self.p)
dlg.ShowModal()
if dlg.result_name:
print "Name: "+dlg.result_name+"\n"
print "Surname: "+dlg.result_surname+"\n"
print "Nickname: "+dlg.result_nickname+"\n"
else:
print "No Input found\n"
dlg.Destroy()
class GetData(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, wx.ID_ANY, "Name Input", size= (650,220))
self.p = wx.Panel(self,wx.ID_ANY)
self.lblname = wx.StaticText(self.p, label="Name", pos=(20,20))
self.name = wx.TextCtrl(self.p, value="", pos=(110,20), size=(500,-1))
self.lblsur = wx.StaticText(self.p, label="Surname", pos=(20,60))
self.surname = wx.TextCtrl(self.p, value="", pos=(110,60), size=(500,-1))
self.lblnick = wx.StaticText(self.p, label="Nickname", pos=(20,100))
self.nickname = wx.TextCtrl(self.p, value="", pos=(110,100), size=(500,-1))
self.saveButton =wx.Button(self.p, label="Save", pos=(110,160))
self.closeButton =wx.Button(self.p, label="Cancel", pos=(210,160))
self.saveButton.Bind(wx.EVT_BUTTON, self.SaveConnString)
self.closeButton.Bind(wx.EVT_BUTTON, self.OnQuit)
self.Bind(wx.EVT_CLOSE, self.OnQuit)
self.Show()
def OnQuit(self, event):
self.result_name = None
self.Destroy()
def SaveConnString(self, event):
self.result_name = self.name.GetValue()
self.result_surname = self.surname.GetValue()
self.result_nickname = self.nickname.GetValue()
self.Destroy()
app = wx.App()
Example(None, title = 'Raman Spectroscopy Database')
app.MainLoop()
i am trying to Refresh() a panel which uses the wx.ColourDialog. Once I refresh the panel once, it is unable to refresh again. Try the following to see the problem in action.
By clicking the button, it will ask you what color you would like to change the rectangle to. Once you press OK, it should change the rectangles color. It will not work it will not change the rectangle.
import wx
xcolor_of_font_dia=(0,0,0)
class MyFrame(wx.Frame):
"""a frame with a panel"""
def __init__(self, parent=None, id=wx.ID_ANY, title=None):
global xcolor_of_font_dia
global dc
wx.Frame.__init__(self, parent, wx.ID_ANY, title)
self.panel = wx.Panel(self, size=(350, 200))
self.panel.Bind(wx.EVT_PAINT, self.on_paint)
self.button2 = wx.Button(self.panel, id=wx.ID_ANY, label='Button2',pos=(8, 38), size=(175, 28))
self.button2.Bind(wx.EVT_BUTTON, self.onColorDlg)
self.Fit()
def onColorDlg(self, event):
global xcolor_of_font_dia
global dc
"""
This is mostly from the wxPython Demo!
"""
dlg = wx.ColourDialog(self)
# Ensure the full colour dialog is displayed,
# not the abbreviated version.
dlg.GetColourData().SetChooseFull(True)
if dlg.ShowModal() == wx.ID_OK:
data = dlg.GetColourData()
print 'You selected: %s\n' % str(data.GetColour().Get())
xcolor_of_font_dia='#%02x%02x%02x' % data.GetColour().Get()
dlg.Destroy()
self.panel.Refresh()
def on_paint(self, event):
global xcolor_of_font_dia
global dc
dc = wx.PaintDC(self.panel)
dc.SetPen(wx.Pen(xcolor_of_font_dia, 1))
rect = wx.Rect(50, 50, 100, 100)
dc.DrawRoundedRectangleRect(rect, 8)
# test it ...
app = wx.PySimpleApp()
frame1 = MyFrame(title='rounded-rectangle & circle')
frame1.Center()
frame1.Show()
app.MainLoop()
I cleaned your code a bit. Basically your globals were producing some problems as you were creating (and deleting) different dc instances after every size event.
You should not use globals if it is not strictly necessary (rarely is).
This works:
import wx
class MyFrame(wx.Frame):
"""a frame with a panel"""
def __init__(self, parent=None, id=wx.ID_ANY, title=None):
wx.Frame.__init__(self, parent, wx.ID_ANY, title)
self.xcolor = (0, 0, 0)
self.panel = wx.Panel(self, size=(350, 200))
self.panel.Bind(wx.EVT_PAINT, self.on_paint)
self.button2 = wx.Button(self.panel, id=wx.ID_ANY, label='Button2',
pos=(8, 38), size=(175, 28))
self.button2.Bind(wx.EVT_BUTTON, self.onColorDlg)
self.Fit()
def onColorDlg(self, event):
"""
This is mostly from the wxPython Demo!
"""
dlg = wx.ColourDialog(None)
dlg.GetColourData().SetChooseFull(True)
if dlg.ShowModal() == wx.ID_OK:
data = dlg.GetColourData()
self.xcolor = data.GetColour().Get()
print 'You selected: %s\n' % str(self.xcolor)
dlg.Destroy()
self.panel.Refresh()
def on_paint(self, event):
dc = wx.PaintDC(self.panel)
dc.SetPen(wx.Pen(self.xcolor, 2))
rect = wx.Rect(50, 50, 100, 100)
dc.DrawRoundedRectangleRect(rect, 8)
# test it ...
app = wx.PySimpleApp()
frame1 = MyFrame(title='rounded-rectangle & circle')
frame1.Center()
frame1.Show()
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.