I have a problem with passing textCtrl data from one class to another in wxpython. I tried using the instance method of passing variables but if I use init_function it is only relevant at the start of the program and doesn't take into account any changes to the text control box after the initial start. Tried the Update() or Refresh() and it didn't work either.
Here is the code simplified.
class DropTarget(wx.DropTarget):
def __init__(self,textCtrl, *args, **kwargs):
super(DropTarget, self).__init__( *args, **kwargs)
self.tc2=kwargs["tc2"]
print self.tc2
class Frame(wx.Frame):
def __init__(self, parent, tc2):
self.tc2 = wx.TextCtrl(self, -1, size=(100, -1),pos = (170,60))#part number
def main():
ex = wx.App()
frame = Frame(None, None)
frame.Show()
b = DropTarget(None, kwarg['tc2'])
ex.MainLoop()
if __name__ == '__main__':
main()
The following way of passing the variable gives me a keyerror. Any help is appreciated.
This isn't the most elegant solution to the problem, but I had a similar issue. If you dump your text to a temporary text file, you can pick it back up whenever you want. So it would be something like this:
tmpFile = open("temp.txt",'w')
tmpFile.write(self.tc2.GetValue())
tmpFile.close()
#when you want the string back in the next class
tmpFile = open("temp.txt",'r')
string = tmpFile.read()
tmpFile.close()
os.system("del temp.txt") #This just removes the file to clean it up, you'll need to import os if you want to do this
import wx
class DropTarget(wx.DropTarget):
def __init__(self,textCtrl, *args, **kwargs):
self.tc2 = kwargs.pop('tc2',None) #remove tc2 as it is not a valid keyword for wx.DropTarget
super(DropTarget, self).__init__( *args, **kwargs)
print self.tc2
class Frame(wx.Frame):
def __init__(self, parent, tc2):
#initialize the frame
super(Frame,self).__init__(None,-1,"some title")
self.tc2 = wx.TextCtrl(self, -1, size=(100, -1),pos = (170,60))#part number
def main():
ex = wx.App(redirect=False)
frame = Frame(None, None)
frame.Show()
#this is how you pass a keyword argument
b = DropTarget(frame,tc2="something")
ex.MainLoop()
if __name__ == '__main__':
main()
there were at least a few errors in your code ... it at least makes the frame now
Related
I am currently making a UI in python using wx. I am trying to have multiple tabs active at the same time, but at the same time I am trying to keep either a list or int value active and showing in the bottom right corner on any tab at all times. Unfortunately I seem to have run into a road block. When I run the code below I get the error:
i = parent.GetString(Points.a)
TypeError: CommandEvent.GetString(): too many arguments
Honestly I am only a year into coding practice and I don't really know what this error means. If possible, could someone please explain it to me and possible give me some tips on how to solve the issue?
Thanks in advance.
import wx
class Points:
c = 14
a = [14]
b = "{}\n" .format(a)
class MOC(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.poi = wx.StaticText(self, label=Points.b, pos=(400, 400))
select = wx.Button(self, wx.ID_ANY, '+1', size=(90, 30))
select.Bind(wx.EVT_BUTTON, self.add)
def add(self, parent):
i = parent.GetString(Points.a)
Points.a.remove(Points.c)
Points.c += 1
Points.a.append(Points.c)
self.poi.SetLabel(i)
class TOS(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
wx.StaticText(self, label=Points.b, pos=(400, 400))
class UIFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, size = (500,500), title = "Mind")
p = wx.Panel(self)
nb = wx.Notebook(p)
page1 = MOC(nb)
page2 = TOS(nb)
nb.AddPage(page1, "Means")
nb.AddPage(page2, "Types")
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
if __name__ == "__main__":
app = wx.App()
UIFrame().Show()
app.MainLoop()
In the line i = parent.GetString(Points.a) you are passing the argument Points.a but GetString has no arguments because it is used to get the string from an item i.e. self.Item.GetString().
Points.a is not a wx defined item, it is in fact a python list, to access that you should change the offending line above with
i = str(Points.a[0]) or
i = Points.a[0] or
i = Points.a or
i = str(Points.a) depending on your requirements.
Depending on which access method you choose, you may have to alter the
self.poi.SetLabel(i) as well, as i could be a list or an int rather than the required str
Running with the first option works without further changes
I am creating an application by using the language wxPython.
I have a simple problem in which I cant really find the solution in the internet.
I have a main user interface with a menubar which contain a menu called new file.
By clicking the new file, a new window will appear demanding the user to fill up the necessary information.
The problem is that, by clicking multiple times the menu (new file), the application opens multiple windows.
How can i prevent this?
The following code creates a new sub frame if one doesn't exists already.
If it does exist already, it uses the existing sub frame.
Note the code is tested with latest wxpython phoenix and classic.
import wx
from wx.lib import sized_controls
class MultiMessageFrame(sized_controls.SizedFrame):
def __init__(self, *args, **kwargs):
super(MultiMessageFrame, self).__init__(*args, **kwargs)
pane = self.GetContentsPane()
text_ctrl = wx.TextCtrl(
pane, style=wx.TE_READONLY | wx.TE_CENTRE | wx.TE_MULTILINE)
text_ctrl.SetSizerProps(proportion=1, expand=True)
text_ctrl.SetBackgroundColour('White')
self.text_ctrl = text_ctrl
pane_btns = sized_controls.SizedPanel(pane)
pane_btns.SetSizerType('horizontal')
pane_btns.SetSizerProps(align='center')
button_ok = wx.Button(pane_btns, wx.ID_OK)
button_ok.Bind(wx.EVT_BUTTON, self.on_button_ok)
def append_msg(self, title_text, msg_text):
self.SetTitle(title_text)
self.text_ctrl.AppendText(msg_text)
def on_button_ok(self, event):
self.Close()
class MainFrame(sized_controls.SizedFrame):
def __init__(self, *args, **kwargs):
super(MainFrame, self).__init__(*args, **kwargs)
self.SetInitialSize((800, 600))
self.CreateStatusBar()
menubar = wx.MenuBar()
self.SetMenuBar(menubar)
menu_file = wx.Menu()
menu_file.Append(
wx.ID_NEW, 'Show msg', 'Add a new message to message frame')
menubar.Append(menu_file, '&File')
self.Bind(wx.EVT_MENU, self.on_new, id=wx.ID_NEW)
self.count = 1
self.multi_message_frame = None
def on_new(self, event):
title_text = 'MultiMessageFrame already exists'
if not self.multi_message_frame:
title_text = 'Newly created MultiMessageFrame'
self.multi_message_frame = MultiMessageFrame(
self, style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT)
self.multi_message_frame.Bind(
wx.EVT_CLOSE, self.on_multi_message_frame_close)
self.multi_message_frame.Center()
self.multi_message_frame.Show()
self.multi_message_frame.append_msg(
title_text, 'message no.{}\n'.format(self.count))
self.count += 1
def on_multi_message_frame_close(self, event):
self.multi_message_frame = None
event.Skip()
if __name__ == '__main__':
app = wx.App(False)
main_frame = MainFrame(None)
main_frame.Show()
app.MainLoop()
I am trying to display a grid of images in wxPython. I am using a GridSizer to create a grid to which I add my staticbitmaps. But for some reason I only see one image at the first position in the grid. I am not sure where I am going wrong. Here is my code and the corresponding output.
import wx
import sys
import glob
MAIN_PANEL = wx.NewId()
class CommunicationApp(wx.App):
"""This is the class for the communication tool application.
"""
def __init__(self, config=None, redirect=False):
"""Instantiates an application.
"""
wx.App.__init__(self, redirect=redirect)
self.cfg = config
self.mainframe = CommunicationFrame(config=config,
redirect=redirect)
self.mainframe.Show()
def OnInit(self):
# self.SetTopWindow(self.mainframe)
return True
class CommunicationFrame(wx.Frame):
"""Frame of the Communication Application.
"""
def __init__(self, config, redirect=False):
"""Initialize the frame.
"""
wx.Frame.__init__(self, parent=None,
title="CMC Communication Tool",
style=wx.DEFAULT_FRAME_STYLE)
self.imgs = glob.glob('../img/img*.png')
self.panel = CommuniationPanel(parent=self,
pid=MAIN_PANEL,
config=config)
# # Gridbagsizer.
nrows, ncols = 3, 4
self.grid = wx.GridSizer(rows=nrows, cols=ncols)
# Add images to the grid.
for r in xrange(nrows):
for c in xrange(ncols):
_n = ncols * r + c
_tmp = wx.Image(self.imgs[_n],
wx.BITMAP_TYPE_ANY)
_temp = wx.StaticBitmap(self.panel, wx.ID_ANY,
wx.BitmapFromImage(_tmp))
self.grid.Add(_temp, 0, wx.EXPAND)
self.grid.Fit(self)
# set to full screen.
# self.ShowFullScreen(not self.IsFullScreen(), 0)
class CommuniationPanel(wx.Panel):
"""Panel of the Communication application frame.
"""
def __init__(self, parent, pid, config):
"""Initialize the panel.
"""
wx.Panel.__init__(self, parent=parent, id=pid)
# CALLBACK BINDINGS
# Bind keyboard events.
self.Bind(wx.EVT_KEY_UP, self.on_key_up)
def on_key_up(self, evt):
"""Handles Key UP events.
"""
code = evt.GetKeyCode()
print code, wx.WXK_ESCAPE
if code == wx.WXK_ESCAPE:
sys.exit(0)
def main():
app = CommunicationApp()
app.MainLoop()
if __name__ == '__main__':
main()
Here is the output.
What I would like to see (or expected to see) was 3X4 grid of the different images.
What is the problem with my code? And how do I fix it?
You appear to have forgotten to set a sizer for your panel
Try putting this in the frame's __init__
self.panel.SetSizer(self.grid)
I have researched heavily on how to get the variables from a different class in wxPython without much luck. My problem is that I want to update a combobox in the main window after the user closes the second window. I thought the best way to do this was to try to get the main window combobox variable somehow. Example:
import wx
class oranges(wx.Frame):
#----------Main Window---------#
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Test',size=(1024,768))
self.frame=wx.Panel(self)
self.tickers=['Apples','a','1234']
self.dropdown=wx.ComboBox(self.frame,choices=self.tickers,pos=(750,62),style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.get_stuff,self.dropdown)
apples=wx.Button(self.frame,label='Click here',pos=(300,300),size=(100,100))
self.Bind(wx.EVT_BUTTON, self.plus,apples)
def get_stuff(self,event):
pass
def plus(self,event):
class orange(wx.Frame):
#----------Second Window---------#
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Testing',size=(500,500))
self.frames=wx.Panel(self)
apples=wx.Button(self.frames,label='Collect Info',pos=(300,300),size=(100,100))
self.Bind(wx.EVT_BUTTON, self.click,apples)
self.what=wx.TextCtrl(self.frames,-1,'12',pos=(200,48))
def click(self,event):
asdf=self.what.GetValue()
self.tickers=[]
self.tickers.append(asdf)
self.dropdown.Clear()
self.dropdown.AppendItems(self.tickers)
#Need to update dropdown#
self.Destroy()
if __name__ =='__main__':
apps = wx.PySimpleApp()
windows = orange(parent=None,id=-1)
windows.Show()
apps.MainLoop()
if __name__ =='__main__':
app = wx.PySimpleApp()
window = oranges(parent=None,id=-1)
window.Show()
app.MainLoop()
I am really confused on how to go about fixing this problem. Thanks in advance! I am looking forward to the answers!
in your parent Frame, add a method called UpdateComboBox(self, newVal) that takes in the new string... then since your popup is a child of that, just before you call self.Destroy in the child, call self.GetParent().UpdateComboBox(asdf) (where asdf is from your example, i.e. the string you want to pass back)
import wx
class SomeUserForm(wx.Dialog):
def __init__(self):
wx.Dialog.__init__(self,None,-1,"Enter User Info In this Frame")
self.txt = wx.TextCtrl(self,-1,pos=(50,50))
self.txt2 = wx.TextCtrl(self,-1,pos=(50,100))
self.ok = wx.Button(self,wx.ID_OK,pos=(50,125))
def GetValue(self):
return self.txt.GetValue() + "::"+ self.txt2.GetValue()
class oranges(wx.Frame):
#----------Main Window---------#
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Test',size=(1024,768))
self.frame=wx.Panel(self)
self.tickers=['Apples','a','1234']
self.dropdown=wx.ComboBox(self.frame,choices=self.tickers,pos=(750,62),style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.get_stuff,self.dropdown)
apples=wx.Button(self.frame,label='Click here',pos=(300,300),size=(100,100))
self.Bind(wx.EVT_BUTTON, self.plus,apples)
def get_stuff(self,event):
pass
def plus(self,evt):
dlg = SomeUserForm()
if dlg.ShowModal() != wx.ID_OK:
wx.MessageBox("User Cancelled Add!","Cancelled!")
return
self.dropdown.Append(dlg.GetValue())
if __name__ =='__main__':
app = wx.PySimpleApp()
window = oranges(parent=None,id=-1)
window.Show()
app.MainLoop()
may do what you are asking for ...
I have a Panel with several images on it, each of which is bound to the same event handler. How can I determine which image is being clicked from the event handler? I tried using Event.GetEventObject() but it returns the parent panel instead of the image that was clicked.
Here's some sample code:
import math
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, id=-1,title="",pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE,
name="frame"):
wx.Frame.__init__(self,parent,id,title,pos,size,style,name)
self.panel = wx.ScrolledWindow(self,wx.ID_ANY)
self.panel.SetScrollbars(1,1,1,1)
num = 4
cols = 3
rows = int(math.ceil(num / 3.0))
sizer = wx.GridSizer(rows=rows,cols=cols)
filenames = []
for i in range(num):
filenames.append("img"+str(i)+".png")
for fn in filenames:
img = wx.Image(fn,wx.BITMAP_TYPE_ANY)
img2 = wx.BitmapFromImage(img)
img3 = wx.StaticBitmap(self.panel,wx.ID_ANY,img2)
sizer.Add(img3)
img3.Bind(wx.EVT_LEFT_DCLICK,self.OnDClick)
self.panel.SetSizer(sizer)
self.Fit()
def OnDClick(self, event):
print event.GetEventObject()
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyFrame(None)
frame.Show()
app.MainLoop()
In your loop, give each StaticBitmap widget a unique name. One way to do this would be something like this:
wx.StaticBitmap(self, wx.ID_ANY,
wx.BitmapFromImage(img),
name="bitmap%s" % counter)
And then increment the counter at the end. Then in the event handler, do something like this:
widget = event.GetEventObject()
print widget.GetName()
That's always worked for me.
Call GetId() on your event in the handler and compare the id it returns to the ids of your staticBitmaps. If you need an example let me know and Ill update my answer
You can use GetId(), but make sure you keep it unique across your program. I am posting modified code to show how can you do it. Despite of using filenames as list.
def __init__(self, parent, id=-1,title="",pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE,
name="frame"):
wx.Frame.__init__(self,parent,id,title,pos,size,style,name)
self.panel = wx.ScrolledWindow(self,wx.ID_ANY)
self.panel.SetScrollbars(1,1,1,1)
num = 4
cols = 3
rows = int(math.ceil(num / 3.0))
sizer = wx.GridSizer(rows=rows,cols=cols)
#you should use dict and map all id's to image files
filenames = []
for i in range(num):
filenames.append("img"+str(i)+".png")
for imgid,fn in enumerate(filenames):
img = wx.Image(fn,wx.BITMAP_TYPE_ANY)
img2 = wx.BitmapFromImage(img)
#pass the imgid here
img3 = wx.StaticBitmap(self.panel,imgid,img2)
sizer.Add(img3)
img3.Bind(wx.EVT_LEFT_DCLICK,self.OnDClick)
self.panel.SetSizer(sizer)
self.Fit()
def OnDClick(self, event):
print 'you clicked img%s'%(event.GetId() )
You can use dict and map every file name to id, by this way you will keep track of it all through your programe.