Why do my Dialog Box Classes write to each other? - python

I'm working on a program that is going to be used with a Time Motion study. There are times that the user may have to create add new objects (Observer, Subject, Clinic). In order to accomplish this I have employed the use of a modal dialog box, (since all data is associated to a subject, observer, and clinic).
I have created a general class for the dialog boxes, and then just create an instance of this class for each dialog box. However, when the user creates a new entry with one class, and then the other, the previous classes input is created again, thus causing a duplicate in data.
I'm not exactly sure what's going on and looking for some help:
Here's my general dialog box class:
class NewDataDialog(wx.Dialog):
def __init__(self, parent, id, title, databoxes, pubsubmessage):
wx.Dialog.__init__(self,parent,id, title)
self.databoxes = databoxes
self.pubsubmessage = pubsubmessage
# MainSizer Creation
self.MainSizer = wx.BoxSizer(wx.VERTICAL)
# Top Label Creation and addition to Main Sizer
self.TopLbl = wx.StaticText(self, -1, "Create a " + title)
self.TopLbl.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD))
self.MainSizer.Add(self.TopLbl, 0, wx.ALL|wx.ALIGN_CENTER, 5)
self.SubSizer = wx.BoxSizer(wx.HORIZONTAL)
# Labels
self.LblSizer = wx.BoxSizer(wx.VERTICAL)
for lbl in databoxes:
self.lbl = wx.StaticText(self, -1, lbl+":")
self.LblSizer.Add(self.lbl, 0, wx.ALL|wx.ALIGN_LEFT, 5)
self.SubSizer.Add(self.LblSizer, 0, wx.ALL|wx.ALIGN_LEFT, 5)
# Boxes
self.InputSizer = wx.BoxSizer(wx.VERTICAL)
for lbl in databoxes:
self.box = wx.TextCtrl(self, -1, style=wx.ALIGN_LEFT)
self.InputSizer.Add(self.box, 0, wx.ALL, 1)
self.SubSizer.Add(self.InputSizer, 0, wx.ALL|wx.ALIGN_LEFT, 5)
self.MainSizer.Add(self.SubSizer, 0, wx.ALL|wx.ALIGN_CENTER, 5)
# Save and Cancel Buttons
self.buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
self.saveButton = SaveButton(self, 'Save')
self.cancelButton = CancelButton(self, 'Cancel')
self.buttonSizer.Add(self.saveButton, 0, wx.ALL|wx.ALIGN_CENTER, 5)
self.buttonSizer.Add(self.cancelButton, 0, wx.ALL|wx.ALIGN_CENTER, 5)
self.MainSizer.Add(self.buttonSizer, 0, wx.ALL|wx.ALIGN_CENTER, 5)
self.SetSizerAndFit(self.MainSizer)
pub.subscribe(self.cancelbutton, "mainpanel.CancelButton")
pub.subscribe(self.savebutton, "mainpanel.SaveButton")
def cancelbutton(self, message):
self.Close()
def savebutton(self, message):
results = []
for lbl in self.databoxes:
results.append(self.box.GetValue())
pub.sendMessage(self.pubsubmessage, results)
self.Close()
class CancelButton(wx.Panel):
def __init__(self, parent, title):
wx.Panel.__init__(self, parent)
self.dialogbutton = wx.Button(self, -1, title)
self.Bind(wx.EVT_BUTTON, self.OnButtonActivate, self.dialogbutton)
def OnButtonActivate(self, event):
pub.sendMessage("mainpanel.CancelButton", "")
class SaveButton(CancelButton):
def OnButtonActivate(self, event):
pub.sendMessage("mainpanel.SaveButton", "")
And here's the creation of each instance of the dialog box:
def newsubject(self, message):
titles = ["Full Name", "Initials", "Job Title"]
self.newsubject = NewDataDialog(self, 0, 'New Subject', titles, "MainPanel.NewSubjectDialog.Save")
self.newsubject.ShowModal()
def newobserver(self, message):
titles = ["Full Name", "Initials"]
self.newobserver = NewDataDialog(self, 1, 'New Observer', titles, "MainPanel.NewObserverDialog.Save")
self.newobserver.ShowModal()
def newclinic(self, message):
titles = ["Clinic Name","Location","Initials"]
self.newclinic = NewDataDialog(self, 2, 'New Clinic', titles, "MainPanel.NewClinicDialog.Save")
self.newclinic.ShowModal()
Where each of these are called if the user selects a button labeled for the action that they desire. I.e. "Create a New Observer" will run the function newobserver
For a full view of the code you can look here. Note: Not all comments are correctly annotated, and there are other files as a part of this and so therefore won't run, but will hopefully give you a little more insight to what's going on

You are storing references to the NewDataDialog instances in self.newsubject, self.newobserver and self.newclinic. This means the objects continue to exist, and to listen for "mainpanel.SaveButton" events, even after the newsubject, newobserver, and newclinic methods exit. Once you've opened one of each kind of dialog box, there will always be three such objects hanging around, and each "mainpanel.SaveButton" event will cause all three to try and save their data.
If you did not store these references, then the objects would apparently be garbage collected, and the subscriptions automatically removed. If you do need to store the references, then you should arrange for an unsubscribe to happen after the ShowModal().
def cancelbutton(self, message):
pub.unsubscribe(self.savebutton, "mainpanel.SaveButton")
pub.unsubscribe(self.cancelbutton, "mainpanel.CancelButton")
self.Close()
def savebutton(self, message):
results = []
for lbl in self.databoxes:
results.append(self.box.GetValue())
pub.sendMessage(self.pubsubmessage, results)
pub.unsubscribe(self.savebutton, "mainpanel.SaveButton")
pub.unsubscribe(self.cancelbutton, "mainpanel.CancelButton")
self.Close()

Related

wxPython : Issues on windows using multiple sizers, but works well on linux

I am writing a small app that works very well on linux, but I have some trouble on windows. Here is the code sample:
import wx
#####################################################################
class Main(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="StackOverflow", pos=wx.DefaultPosition, size=(800,600))
self.SetMinSize( self.GetSize() )
p = wx.Panel(self)
nb = wx.Notebook(p)
page1 = AddToCollection(nb)
page2 = CollectionStatistics(nb)
nb.AddPage(page1, "Page 1")
nb.AddPage(page2, "Page 2")
# finally, put the notebook in a sizer for the panel to manage
# the layout
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
#########################################################################
class CollectionStatistics(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
#########################################################################
class AddToCollection(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.v1_qty_list = [str(x) for x in range(9)]
self.v2_qty_list = [str(x) for x in range(9)]
self.sizername = wx.GridBagSizer(5, 5)
self.sizername.AddGrowableCol(0,0)
self.name_txt = wx.StaticText(self, label="Enter Name :")
self.sizername.Add(self.name_txt,(2,0),(1,1),wx.EXPAND)
self.name = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER,value=u"")
self.sizername.Add(self.name,(3,0),(1,1),wx.EXPAND)
self.Bind(wx.EVT_TEXT_ENTER, self.OnPressEnter, self.name)
self.SetSizerAndFit(self.sizername)
self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y )
##########################################################################
def OnPressEnter(self,event):
self.selected_name = self.name.GetValue()
self.AddToCol()
##########################################################################
def AddToCol(self):
self.sizerAdd = wx.GridBagSizer(5, 5)
self.sizerAdd.AddGrowableCol(0, 0)
self.name.Enable(False)
### Expansion
self.expansion = wx.Choice(self, -1, choices=['test 1', 'test 2'])
self.expansion.SetSelection(0)
self.sizerAdd.Add(self.expansion,(5,0),(1,6),wx.EXPAND)
### Quantities txt
self.v1_txt = wx.StaticText(self, label="V1 Quantity :")
self.sizerAdd.Add(self.v1_txt,(7,0),(1,1),wx.EXPAND)
self.v2_txt = wx.StaticText(self, label="V2 Quantity :")
self.sizerAdd.Add(self.v2_txt,(8,0),(1,1),wx.EXPAND)
### Quantities choices
self.v1_qty = wx.Choice(self, -1, choices=self.v1_qty_list)
self.v1_qty.SetSelection(0)
self.sizerAdd.Add(self.v1_qty,(7,5),(1,1),wx.EXPAND)
self.v2_qty = wx.Choice(self, -1, choices=self.v1_qty_list)
self.v2_qty.SetSelection(0)
self.sizerAdd.Add(self.v2_qty,(8,5),(1,1),wx.EXPAND)
### Ok Button
self.Add_btn = wx.Button(self, -1, "Add")
self.Add_btn.Bind(wx.EVT_BUTTON, self.OnAdd)
self.sizerAdd.Add(self.Add_btn,(9,5),(1,1),wx.EXPAND)
### Reset Button
self.Reset_btn = wx.Button(self, -1, "Reset")
self.Reset_btn.Bind(wx.EVT_BUTTON, self.OnResetPanel)
self.sizerAdd.Add(self.Reset_btn,(9,4),(1,1),wx.EXPAND)
self.SetSizerAndFit(self.sizerAdd)
self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y )
######################################################################
def OnResetPanel(self,event):
### Kill all children
self.expansion.Destroy()
self.v1_txt.Destroy()
self.v1_qty.Destroy()
self.v2_txt.Destroy()
self.v2_qty.Destroy()
self.Add_btn.Destroy()
self.Reset_btn.Destroy()
### Reinitialise sizer
self.name.Enable(True)
self.name.SetValue("")
######################################################################
def OnAdd(self,event):
print 'Add'
self.OnResetPanel(self)
######################################################################
######################################################################
if __name__ == "__main__":
app = wx.App()
Main().Show()
app.MainLoop()
Basically, I have a TextCtrl in a first sizer which is waiting for an entry. Once the user hits enter, several objects appear in a second sizer.
The issue on windows seems to come from the use of the two gridbagsizers (sizername and sizerAdd). After pressing enter (waited event in the __init__), the objects defined within the sizerAdd do not appear. When I extend the window where the script is running, these objects appear magically !
Any idea ?
EDIT : The code is now runnable
I think the problem in your code is these two lines at the end of your AddToCol method:
self.SetSizerAndFit(self.sizerAdd)
self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y )
At this point, you're changing the sizer of the AddToCollection panel from self.sizername to self.sizerAdd. The Enter Name: label and the textbox however are still within the self.sizername sizer. However, this sizer isn't the sizer for any window, nor has it been added to any other sizer.
Generally, in wxPython, every sizer should be set as the sizer for a window, or be added to another sizer. This other sizer would then be the sizer for a window, or be contained within another sizer, and so on. In your case, your self.sizername sizer ends up being neither, and in this situation I would expect unpredictable behaviour. If your code works on Linux then I would say that it happens to work by accident.
I can think of a few things you could do here:
Add self.sizerAdd as a child of self.sizername. This can be done by replacing the two lines above with
self.sizername.Add(self.sizerAdd,(4,0),(1,1),wx.EXPAND)
self.sizername.Layout()
In AddToCol, add the widgets directly to the self.sizername sizer instead of adding them to self.sizerAdd.
Create a wx.BoxSizer() with vertical orientation, set that to be the sizer for the AddToCollection panel, and add the self.sizername and self.sizerAdd sizers to your BoxSizer.
In all three cases, after creating the new widgets you will need to call the Layout() method on the top-level sizer, be it either self.sizername or the top-level BoxSizer. The code snippet under option 1 includes this line already.
Additionally, you may need to modify your OnResetPanel() method. If you chose options 1 or 3, you will need to remove the self.sizerAdd sizer from whichever sizer you added it to. For example, in option 1, you would add the line
self.sizername.Remove(self.sizerAdd)
Another approach would be for your AddToCol method to create all the widgets within a Panel and add that to the main panel at the end. Your AddToCol method would then need to create a child panel, add the extra controls as children of this panel instead of the main panel (self), set the sizer of the child panel to self.sizerAdd and finally add this panel to the self.sizername sizer.
def AddToCol(self):
self.sizerAdd = wx.GridBagSizer(5, 5)
self.sizerAdd.AddGrowableCol(0, 0)
self.name.Enable(False)
self.child_panel = wx.Panel(self)
### Expansion
self.expansion = wx.Choice(self.child_panel, -1, choices=['test 1', 'test 2'])
self.expansion.SetSelection(0)
self.sizerAdd.Add(self.expansion,(5,0),(1,6),wx.EXPAND)
# Create other widgets as before but with the parent set to self.child_panel
# instead of self.
self.child_panel.SetSizer(self.sizerAdd)
self.sizername.Add(self.child_panel,(4,0),(1,1),wx.EXPAND)
self.sizername.Layout()
You would then also need to replace the line
self.sizername.Remove(self.sizerAdd)
in OnResetPanel() with the two lines:
self.sizername.Remove(self.child_panel)
self.child_panel.Destroy()
One thing which bugged me about my approach 1 above was that I saw the widgets briefly appear in the top-left corner before appearing in the correct place. This adaptation fixes this problem and so makes the GUI behave itself a bit better. I couldn't reproduce your black area issue you mention in your comment, but hopefully this approach fixes your problem as well.

Issue with .Hide() on individual widgets in wxpython

As someone pretty new to wxpython, I'm attempting to write a login script for an imaginary program. On startup, buttons ask if you want to create a new account or register a new one. When either one is clicked, I want all the widgets on the page to disappear, leaving a blank frame for other widgets to be imposed on. However I'm not sure how to .Hide() specific widgets -- my existing widgets are not being recognized as variables. Here's my relevant code:
class Welcome(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, "ImageViewer", size=(500,350))
panel = wx.Panel(self)
text = wx.StaticText(panel, -1, "Welcome to ImageViewer. Do you have an account?", (50,10))
font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
text.SetFont(font)
yesbutton = wx.Button(panel, label="Yes, I wish to log in", pos=(50,150), size=(150,60))
self.Bind(wx.EVT_BUTTON, self.loginwindow, yesbutton)
nobutton = wx.Button(panel, label="No, I wish to register", pos=(270,150), size=(150,60))
self.Bind(wx.EVT_BUTTON, self.registerwindow, nobutton)
def loginwindow(self, event):
self.Hide(self.text) #Error occurs here
AttributeError: 'Welcome' object has no attribute 'text'
I'm not sure if there is a better way of doing this (if there is please let me know) but for now I'm just not sure why I can't access these variables.
text isn't made an attribute of of the Welcome class, so when you try and call it in your loginwindow function it's out of scope.
When you declare it in your init method make it self.text
Edit: This code works.
class Welcome(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, None, id, "ImageViewer", size=(500,350))
panel = wx.Panel(self)
self.text = wx.StaticText(panel, -1, "Welcome to ImageViewer. Do you have an account?", (50,10))
font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
self.text.SetFont(font)
yesbutton = wx.Button(panel, label="Yes, I wish to log in", pos=(50,150), size=(150,60))
self.Bind(wx.EVT_BUTTON, self.loginwindow, yesbutton)
def loginwindow(self, event):
self.text.Hide() #Error occurs here

Can't go back to wxpython main frame after creating and destroying Dialogue using ShowModal via Pubsub

I am programming an application using wxpython and wx.lib.pubsub. in python 2.7.3
1- There is a Frame with a menu item. When this menu is clicked, a message is published by pubsub.
2- This message destroys (if possible) and creates a "first level" dialogue.
3- "First Level" dialogue has an list of valules and an "add value" button. (NOTE: Such list of variables can be modified so I am trying to update this list)
4- When the "add value" button is clicked, another message is published by pubsub.
5- This message creates a "Second Level" dialogue, so a new name for the new variable can be written.
6- There is a "continue" button in this "second level" dialogue which has two consequences:
First one: Self.Destroy();
Second one: goes to step 2, i.e. destroys the "first level" dialogue and creates it again.
To that point the program seems to work fine, however, when I finish "adding" variables to the "first level" dialogue I Destroy it and then I cannot go back to the main Frame stated in step 1.
Why is this happening?
All the Dialogues are shown via ShowModal(). However if I use only Show() it seems to work fine but, since the program has many menus and items, ShowModal() is preferred.
Any idea why it works with Show() but not with ShowModal()?
If there is a simpler way to perform the task I want to do, it would be appreciated.
import wx
from wx.lib.pubsub import Publisher as pub
class itemReceiver(object):
def __init__(self):
pub.subscribe(self.__OnShowDialog, 'show.dialog')
def __OnShowDialog(self, message):
self.dlgParent = message.data[0]
print str(self.dlgParent)
self.valuesToShow = message.data[1]
print self.valuesToShow
#try to destroy dialog before creating a new one
try:
self.manageParametersDialog.Destroy()
except:
pass
self.manageParametersDialog = manageParamsDialog(self.dlgParent, self.valuesToShow)
print "ready to show first level dialogue"
self.manageParametersDialog.ShowModal() #if .Show() instead, there is no problem
class secondaryReceiver(object):
def __init__(self):
pub.subscribe(self.__OnShowDialog, 'add.item')
def __OnShowDialog(self, message):
dlgParent = message.data[0]
dlgGrandParent = message.data[1]
self.variableList = message.data[2]
editParameterDialog = editParamDlg(dlgParent, dlgGrandParent, self.variableList)
editParameterDialog.ShowModal()
class manageParamsDialog (wx.Dialog):
def __init__(self, parent, valueList):
self.valueList = valueList
self.parent = parent
wx.Dialog.__init__(self, parent, -1, "first level dialogue", style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
sizer=wx.BoxSizer(wx.VERTICAL)
self.optionList = wx.ListBox(self, -1, size=(200, 70), choices = valueList)
sizer.Add(self.optionList)
addButton = wx.Button(self, -1, 'Add New')
self.Bind(wx.EVT_BUTTON, self.OnButton, addButton)
sizer.Add(addButton)
cancelButton = wx.Button(self, -1, 'Cancel')
self.Bind(wx.EVT_BUTTON, self.OnCancel, cancelButton)
sizer.Add(cancelButton)
self.SetSizer(sizer)
self.Fit()
def OnButton (self, e):
pub.sendMessage('add.item', [self, self.parent, self.valueList])
def OnCancel(self,e):
self.Destroy()
class editParamDlg(wx.Dialog):
def __init__(self, parent, grandParent, variableList):
self.variableList = variableList
self.grandParent = grandParent
wx.Dialog.__init__(self, parent, -1, "second level dialogue", style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
hboxSizer = wx.BoxSizer(wx.HORIZONTAL)
self.textInput = wx.TextCtrl(self, -1)
hboxSizer.Add(self.textInput)
addButton = wx.Button(self, -1, 'Continue')
self.Bind(wx.EVT_BUTTON, self.OnAdd, addButton)
hboxSizer.Add(addButton)
cancelButton = wx.Button(self, -1, 'Cancel')
self.Bind(wx.EVT_BUTTON, self.OnCancel, cancelButton)
hboxSizer.Add(cancelButton)
self.SetSizer(hboxSizer)
self.Fit()
def OnAdd(self, e):
self.variableList.append(self.textInput.GetValue())
self.Destroy()
pub.sendMessage('show.dialog',[self.grandParent, self.variableList])
def OnCancel(self,e):
self.Destroy()
class ToolbarFrame(wx.Frame):
#this ToolbarFrame is the main window, with a Toolbar and a white panel below.
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, "this is a frame", size=(480, 320))
myPanel = wx.Panel(self)
myPanel.SetBackgroundColour("White")
menuBar = wx.MenuBar()
fileMenu = wx.Menu()
menuItem = wx.MenuItem(fileMenu, -1, "menu item", "opens dialog via pubsub")
self.Bind(wx.EVT_MENU, self.OnMenuItem, menuItem)
fileMenu.AppendItem(menuItem)
menuBar.Append(fileMenu, "File")
self.SetMenuBar(menuBar)
def OnMenuItem(self, e):
pub.sendMessage('show.dialog', [self, ["one", "two", "three"]])
app = wx.PySimpleApp()
frame = ToolbarFrame(parent=None, id=-1)
frame.Show()
newItemListener = itemReceiver()
editParameterListener = secondaryReceiver()
app.MainLoop()
try changing secondaryReciever as follows
class secondaryReceiver(object):
def __init__(self):
pub.subscribe(self.__OnShowDialog, 'add.item')
def __OnShowDialog(self, message):
dlgParent = message.data[0]
dlgGrandParent = message.data[1]
self.variableList = message.data[2]
editParameterDialog = editParamDlg(dlgParent, dlgGrandParent, self.variableList)
editParameterDialog.ShowModal()
#this line will not execute till the dialog closes
self.dlgParent.optionList.SetItems(editParameterDialog.variableList)
editParameterDialog.Destroy()
and also change editParamDlg
def OnAdd(self, e):
self.variableList.append(self.textInput.GetValue())
self.Close()
the problem was that you would call the show.modal from that OnAdd ... which would try to destroy the existing window and then open a new one... but the old one wasnt destroyed ... this left weird remnants that caused you errors ... and really all you want to do is update the item list ...

How to find an item in a panel

I am using Python WX to make a large GUI containing maybe 100 CheckBoxes. I want to read the value of each checkbox and append these values to a list. I can do this with 100 lines of code but prefer to use a loop. In the loop, how can I identify or select the specific checkbox I want to get the value from?
self.Box1 = wx.CheckBox(self.panel, id = 1, label='first box', pos=(10, 25), size=(30,22))
self.Box2 = wx.CheckBox(self.panel, id = 2, label='second box', pos=(20, 25), size=(30,22))
.
.
.
self.Box100 = wx.CheckBox(self.panel, id = 100, label='100th box', pos=(100, 25), size=(30,22))
Looking for something like:
MyList = []
for N in range (1, 101):
MyList.append(self.Box + N.Value)
The more generic question here is "how to select an object name in a loop"
I have searched all day with no luck. I am not a programming expert and hope this is worthy of someone's answer.
Rather than having 100 almost-identical lines of code, which is error-prone, inefficient and unattractive, actually build the CheckBoxes in a loop and hold them in a list:
self.boxes = []
for i in range(1, 101):
self.boxes.append(wx.CheckBox(self.panel, id=i,
label="Box {0}".format(i)
pos=(10, 25), size=(30,22)))
Then getting all of the values is similarly simple:
for i, box in enumerate(self.boxes, 1):
...
as is accessing a single one:
box = self.boxes[i-1]
If you really want "first", "second", "100th" write a helper function to process i into a string representation.
I personally like to use widget names. For example:
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
self.sizer = wx.BoxSizer(wx.VERTICAL)
for i in range(5):
txt = "Checkbox #%s" % i
chk = wx.CheckBox(self, label=txt, name=txt)
self.sizer.Add(chk, 0, wx.ALL|wx.CENTER, 5)
button = wx.Button(self, label="Get check")
button.Bind(wx.EVT_BUTTON, self.onButton)
self.sizer.Add(button, 0, wx.ALL|wx.CENTER, 5)
self.SetSizer(self.sizer)
#----------------------------------------------------------------------
def onButton(self, event):
""""""
widget = self.FindWindowByName("Checkbox #0")
print widget
print widget.GetValue()
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Checkboxes")
panel = MyPanel(self)
self.Show()
#----------------------------------------------------------------------
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
This code will create a set of 5 wx.Checkboxes that each have a unique name. Then you can look them up by name using wx.FindWindowByName.
You could also create a dictionary using the names as the keys and the values as the CheckBox widgets which gives the advantage of being a faster lookup.

how to make multiline wx.ListBox

I need a ListBox to show a phone book.Then i need to show name in top and number in bottom in each list item like phone.how to bind the datas into listbox.
now i made a listbox with singleline as shown below
cur.execute("select fname from tblsample1 order by fname")
names = [str(item[0]) for item in cur.fetchall()]
lvnames=wx.ListBox(panel,-1,(10,40),(210,180),names, wx.LB_SINGLE)
how to bind sqlite3 cursor with two columns to the listview
i need a wx.ListBox mouse click event(not EVT_LISTBOX
because i need only mouse click event)
Use the HtmlListBox, here is a little example to get you started.
import wx
class PhoneNumbers(wx.HtmlListBox):
def __init__(self, parent):
wx.HtmlListBox.__init__(self, parent)
self.data = [
("Foo", "3452-453"),
("Bar", "5672-346"),
]
self.SetItemCount(len(self.data))
def OnGetItem(self, n):
return "<b>%s</b><br>%s" % self.data[n]
def add_number(self, name, number):
self.data.append((name, number))
self.SetItemCount(len(self.data))
self.Refresh()
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, size=(200, 400))
self.numbers = PhoneNumbers(self)
self.contact_name = wx.TextCtrl(self)
self.contact_number = wx.TextCtrl(self)
self.add_btn = wx.Button(self, label="Add contact")
self.Sizer = wx.BoxSizer(wx.VERTICAL)
self.Sizer.Add(self.numbers, 1, wx.EXPAND)
self.Sizer.Add(wx.SearchCtrl(self), 0, wx.EXPAND)
self.Sizer.Add(wx.StaticText(self, label="Name"), 0, wx.TOP, 10)
self.Sizer.Add(self.contact_name)
self.Sizer.Add(wx.StaticText(self, label="Number"), 0, wx.TOP, 5)
self.Sizer.Add(self.contact_number)
self.Sizer.Add(self.add_btn, 0, wx.ALL, 10)
self.numbers.Bind(wx.EVT_LISTBOX, self.OnSelectNumber)
self.add_btn.Bind(wx.EVT_BUTTON, self.OnAddNumber)
def OnSelectNumber(self, event):
name, number = self.numbers.data[event.Selection]
self.contact_name.Value = name
self.contact_number.Value = number
def OnAddNumber(self, event):
self.numbers.add_number(
self.contact_name.Value,
self.contact_number.Value
)
app = wx.PySimpleApp()
app.TopWindow = f = Frame()
f.Show()
app.MainLoop()
You should rephrase your question, I don't know if I got this right.
If you only need to display the two lines in your ListBox, you could simply use a \n:
cur.execute("select fname,number from tblsample1 order by fname")
entries = [str(item[0])+'\n'+str(item[1]) for item in cur.fetchall()]
To get a 'click' Event, you cant set the style of your wx.ListBox to wx.LC_SINGLE_SEL and catch the selection event wx.EVT_LIST_ITEM_SELECTED

Categories

Resources