Problems using pubsub and passing definitions in python - python

I'm having problem when I subscribe message from pubsub in the childframe class. I can't figure out how write correct code which will show selects from the mainframe. I also can't pass definition row in the childframe class. I don't know how I specified my question I know it's hard to understand, but in this code I think you will find exactly what i was asking for. I'm new in python so plizz don't criticize
import wx
from wx.lib.pubsub import Publisher as pub
import pyodbc
cnxn = pyodbc.connect("DRIVER={SQL Server Native Client 11.0};SERVER=10.75.79.215;DATABASE=HUB_DATA;UID=sa;PWD=password")
cursor = cnxn.cursor()
class Mainframe(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.panel = wx.Panel(self)
self.quote1 = wx.StaticText(self.panel, label = "id")
self.test=wx.StaticText(self.panel, label = "")
self.editquote1 = wx.TextCtrl(self.panel, size = (140, -1))
self.button = wx.Button(self.panel, label = "search")
#
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, wx.ID_ANY, wx.ALL | wx.EXPAND)
#
self.sizer = wx.GridBagSizer(6, 6)
self.sizer.Add(self.quote1, (0, 0))
self.sizer.Add(self.editquote1, (0, 1))
self.sizer.Add(self.button, (3, 1))
self.sizer.Add(self.test, (4, 1))
#
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 6)
#
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
#
self.button.Bind(wx.EVT_BUTTON, self.Onbutton and self.afterOnbutton)
def Onbutton(self,e):
var = self.editquote1.GetValue()
if len(var)==9:
self.test.SetLabel('True')
if len(var)==9:
cursor.execute("""SELECT COUNT(DPVLDT) as amount
FROM [HBGE_Reports].[dbo].[hub_DDJPFile] s
where exists (SELECT [ZGDCS]
FROM [HUB_DATA].[dbo].[SSCUSTP] d
where [ZGIDNO]=?
and
s.DPACS=d.ZGDCS)""",str(var))
raw = cursor.fetchone()
a = raw.amount
pub.sendMessage("amount", a)
cursor.execute("""declare #a varchar(20)
set #a=?
SELECT [DPVLDT]
,[DPCPDT]
,[DPACB]
,[DPACS]
,[DPACX]
,[DPCYCD]
,[DPDLCD]
,[RCY_AMOUNT]
,[LCY_AMOUNT]
,[DPBLBL]
,[DPNAR1]
,[DPNAR2]
,[DPNAR3]
,[DPNAR4]
FROM [HBGE_Reports].[dbo].[hub_DDJPFile] s
where exists (SELECT [ZGDCS]
FROM [HUB_DATA].[dbo].[SSCUSTP] d
where [ZGIDNO]=#a
and
s.DPACS=d.ZGDCS)
order by [DPVLDT] desc""", str(var))
rows = cursor.fetchall()
for i in range(a):
pub.sendMessage(i, rows[i].DPVLDT)
else:
self.test.SetLabel('False')
def afterOnbutton(self,e):
wx.CallAfter(self.Onbutton,e)
var = self.editquote1.GetValue()
if len(var)==9:
self.new = Childframe(None)
self.new.Show()
class Childframe(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.panel=wx.Panel(self)
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, wx.ID_ANY, 13, wx.ALL | wx.EXPAND, 13)
pub.subscribe(self.amount, "amount")
for n in range(3):
pub.subscribe(self.row, n)
def amount(self, amount):
for n in range(amount.data):
[].append(wx.StaticText(self.panel, id=n, label='test', pos=(20, 30 * n)))
N = amount.data
return N
#I'm having problem here. I can't get N and I don't know how to SetLabel in the static text above
def row(self, row):
for n in range(N):
[].SetLabel(str(row.data))
if __name__=='__main__':
app=wx.App(False)
frame1=Childframe(None)
frame=Mainframe(None)
frame.Show()
app.MainLoop()

The problem is wrong timing between the Childframe creation and the sending of the message. When Mainframe send the message, the new frame does not exist yet and therefore the message is not received by anybody. Try splitting the events bound to the button, instead of:
self.button.Bind(wx.EVT_BUTTON, self.Onbutton and self.afterOnbutton)
try:
self.button.Bind(wx.EVT_BUTTON, self.afterOnbutton)
and modify the code in afterOnbutton such that the other function Onbutton is called after:
def afterOnbutton(self):
wx.CallAfter(self.Onbutton)
var = self.editquote1.GetValue()
if len(var)==9:
self.new = Childframe(None)
self.new.Show()
def Onbutton(self):
var = self.editquote1.GetValue()
if len(var)==9:
self.test.SetLabel('True')
... same ...

Related

How do I view the users included in the database by viewing in the listctrl?

I do not know how to list the included users of the database in listcrtl.
I have not tried anything because I do not know at most the table code created.
import wx
import sqlite3
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "List Control Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
self.index = 0
self.list_ctrl = wx.ListCtrl(panel, size=(-1,100),
style=wx.LC_REPORT
|wx.BORDER_SUNKEN
)
self.list_ctrl.InsertColumn(0, 'Subject')
self.list_ctrl.InsertColumn(1, 'Due')
self.list_ctrl.InsertColumn(2, 'Location', width=125)
sizer = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(sizer)
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
I hope someone can help me, because it's for a course job and i'm having a lot of trouble.
Here is a simple example.
I have included the core methods of creation, insertion and retrieval. I leave updating and deletion to your own research.
import wx
import sqlite3
import datetime
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Sqlite3 List Control Tutorial")
self.today = datetime.date.today().strftime("%Y%m%d")
self.init_db()
panel = wx.Panel(self, wx.ID_ANY)
self.index = 0
self.list_ctrl = wx.ListCtrl(panel, size=(-1,200),
style=wx.LC_REPORT
|wx.BORDER_SUNKEN
)
self.list_ctrl.InsertColumn(0, 'User')
self.list_ctrl.InsertColumn(1, 'Due')
self.list_ctrl.InsertColumn(2, 'Location', width=125)
btn = wx.Button(panel, label="Add Line")
btn2 = wx.Button(panel, label="Get Data")
btn.Bind(wx.EVT_BUTTON, self.add_line)
btn2.Bind(wx.EVT_BUTTON, self.get_data)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
sizer.Add(btn2, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
self.Bind(wx.EVT_CLOSE, self.OnExit)
def add_line(self, event):
return
def get_data(self, event):
self.cursor.execute("select * from Users")
user_data = self.cursor.fetchall()
if user_data:
for row in user_data:
self.list_ctrl.InsertItem(self.index, str(row['User_id']))
self.list_ctrl.SetItem(self.index, 1, str(row['Start_date']))
self.list_ctrl.SetItem(self.index, 2, row['Location'])
self.index += 1
# Open the database, if necessary create it
# isolation_level None is a convenience that means we don't have to manually commit transactions to the database
# it should be treated with caution other than for test purposes
# row_factory allows us to access the data by column name rather than column position i.e. row['User_id'] vs row[0]
def init_db(self):
self.db_name = "mydb.db"
self.db = sqlite3.connect(self.db_name, isolation_level=None)
self.db.row_factory = sqlite3.Row
self.cursor = self.db.cursor()
result = self.cursor.execute("create table if not exists Users (User_id INT PRIMARY KEY NOT NULL, \
Start_date INT DEFAULT CURRENT_DATE, \
Location TEXT DEFAULT '')")
self.cursor.execute("select * from Users")
data_test = self.cursor.fetchone()
if data_test:
return
#If there is no data in the database, create some
locations = ["Ecuador","France","Chad","Burma","Panama"]
import random
try:
print("Inserting test data")
for idx in range(1,11):
self.db.execute("insert into Users(User_id,Start_date,Location) values (?,?,?)",(idx,str(self.today),random.choice(locations)));
except sqlite3.Error as e:
print(str(e))
def OnExit(self, evt):
self.db.close()
self.Destroy()
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()

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

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

wxpython: closing application does not close the progress bar

I have an app that retrieves data from a SQL server. I include a progress bar to show the progress.
However, the problem is that when I try to close the application by clicking the "x" at the top right corner of the application window, the application's main window will close, but the progress bar will continue to run, until all the work with the SQL server is finished.
I wonder if there is a way to terminate everything when clicking "x". A sample code (minus the part that does the data retrieval from SQL server) is below:
import wx, pyodbc
class App(wx.Frame):
def __init__(self, parent, title):
super(App, self).__init__(parent, title=title, size=(600, 400))
#-----------------------------------------------------------
self.Bind(wx.EVT_CLOSE, self.OnExit) # ADDED
#-----------------------------------------------------------
p = wx.Panel(self)
nb = wx.Notebook(p)
self.Panel1 = PanelMaker(nb, 'Foo')
nb.AddPage(self.Panel1, "Foo")
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
self.Centre()
#-----------------------------------------------------------
def OnExit(self, evt): #ADDED
self.Destroy()
#self.Close() #I tried self.Close(), but I could not even
#close the application window when using it.
#-----------------------------------------------------------
class ProgressBar(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, title="In progress...", size=(300, 90), style = wx.FRAME_FLOAT_ON_PARENT)
GridBagSizer = wx.GridBagSizer()
self.gauge = wx.Gauge(self, range = 100, size = (-1, 30), style = wx.GA_HORIZONTAL, name = 'In Progress')
self.gauge.SetValue(0)
txt = wx.StaticText(self, label = 'Hamsters are working very hard to move data', style = wx.ALIGN_CENTER)
GridBagSizer.Add(self.gauge, pos = (0, 0), span = (1, 1), flag = wx.EXPAND|wx.ALL, border = 15)
GridBagSizer.Add(txt, pos = (1, 0), span = (1, 1), flag = wx.ALL, border = 15)
self.SetSizer(GridBagSizer)
self.Layout()
def Update(self, step):
self.gauge.SetValue(step)
if step == 100:
self.Close()
class PanelMaker(wx.Panel):
def __init__(self, parent, tool):
wx.Panel.__init__(self, parent = parent)
Panel1Sizer = wx.GridBagSizer(0, 10)
ProceedButton = wx.Button(self, label = tool, size = (-1, -1))
ProceedButton.Bind(wx.EVT_BUTTON, self.OnProceedButton)
Panel1Sizer.Add(ProceedButton, pos = (7, 0), span = (1, 1), flag = wx.EXPAND|wx.LEFT, border = 12)
Panel1Sizer.Layout()
self.SetSizer(Panel1Sizer)
def OnProceedButton(self, evt):
Progbar = ProgressBar(self.GetParent())
Progbar.Show()
connection = pyodbc.connect(DRIVER = '{SQL Server}',
SERVER = ServerName,
DATABASE = DatabaseName,
Trusted_Connection = True)
cursor = connection.cursor()
for i in range(100):
#retrieve data from the SQL server.......
wx.Yield()
Progbar.Update(i+1)
#Closing SQL connection
cursor.close()
del cursor
connection.close()
Yes, bind the close event.
self.Bind(wx.EVT_CLOSE, self.OnExit)
Also, I don't see you closing the database connection or a self.Destroy()

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