I'm new to Python (and programming in general) so forgive me if this is a dumb question.
I'm following a tutorial in a book for creating a GUI in Python. Right now I'm learning about how to make a Spin Control increment some static text. When I run it, the spin control shows up but the console says "value = event.GetPosition()
AttributeError: 'CommandEvent' object has no attribute 'GetPosition'"
The code is:
import wx
class Frame(wx.Frame):
def __init__(self, title):
wx.Frame.__init__(self, None,\
title=title, size=(300,250))
panel = wx.Panel(self)
sc = wx.SpinCtrl(panel, value='0', pos=(130, 50), size=(70, 25))
self.valueText = wx.StaticText(panel, label='', pos=(130,80))
sc.Bind(wx.EVT_SPINCTRL, self.spinControl)
def spinControl(self, event):
# Get spin control value
value = event.GetPosition()
# Update static text
self.valueText.SetLabel(str(value))
app = wx.App()
frame = Frame("wxPython Widgets!")
frame.Show()
app.MainLoop()
That code is literally copy/pasted from the book's website. I have wxPython installed and everything works perfectly up to that point.
Halp!
I've been working through that same book Python in a Day 2. I believe the content is already outdated.
If you change the line with GetPosition() to
value = event.GetEventObject().GetValue()
is correct. I can confirm that it works for Python 2.7.11.
Jeremiah
If you change the line with GetPosition() to
value = event.GetEventObject().GetValue()
it will work. The event just doesnt have the GetPosition attribute, so it cannot eb executed.
If you want to check which functions and attributes are available, you can use
print(dir(event))
This will show you everything which is available inside the event.
Michael
Related
As the title says when I implement code to clear hinted text and it is run the application crashes.
As far as I know this is only on Mac OS X 10.8 but that is also all I have been able to run it on.
On other code it does run and only once I enter text into it (After giving focus) does it crash. But this app crashes immediately (I think something to do with no other widgets and so it get focus right away). Updated example so it no longer crashes right away now you have to click on the combo box and try to type in it for it to crash.
This however does not occur if the text is anything but "" it seems.
Code
import wx
class MyCrashyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
# another widget to take focus at first otherwise it crashes instantly!
sizer = wx.BoxSizer(wx.VERTICAL)
self.text_ctrl = wx.TextCtrl(self, -1, value = "There are major problems here.\nWithout this to auto take focus this will crash immediatly just by trying to clear the hint.\nNow you have to click on the combo ctrl and try to type.", style = wx.TE_MULTILINE)
self.search_ctrl = wx.ComboBox(self, -1)
self.search_ctrl.SetMinSize((650, -1))
self.search_ctrl.SetSize((650, -1))
self.search_ctrl.SetHint("This is are hint text; once it is clear and you try to type something in it it will crash on Mac OS X")
sizer.Add(self.text_ctrl, flag = wx.EXPAND)
sizer.Add(self.search_ctrl)
self.SetSizer(sizer)
self.FirstTimeSearchGetsFocus = True
self.Bind(wx.EVT_BUTTON, lambda e: e.Skip(), self.text_ctrl)
self.search_ctrl.Bind(wx.EVT_SET_FOCUS, self.OnSearchFocus)
self.text_ctrl.SetFocus()
def OnSearchFocus(self, event):
print "Search Focus"
if 1==1:
print "First time"
# clear the hinted text
self.search_ctrl.SetHint("")
self.search_ctrl.Clear()
self.search_ctrl.Refresh()
self.FirstTimeSearchGetsFocus = False
event.Skip()
if __name__ == "__main__":
app = wx.App(False)
f = wx.Frame(None, -1)
MyCrashyPanel(f)
f.Show()
app.MainLoop()
Crash Report
[Too big get here http://pastebin.com/9B1Sgh3P ]
If it crashes, it's a bug in wxWidgets, so the only things to do are to:
Try with a later version, i.e. 2.9.5 or svn/git if you can build it yourself.
Report the bug if it still persists there, following the usual guidelines.
I need to bind the EVT_CHAR event for a GUI application I am developing using wxPython. I tried the following and I cann understand the beahviour of the code.
import wx
import wx.lib.agw.flatnotebook as fnb
class DemoApp(wx.App):
def __init__(self):
wx.App.__init__(self, redirect=False)
self.mainFrame = DemoFrame()
self.mainFrame.Show()
def OnInit(self):
return True
class DemoFrame(wx.Frame):
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, wx.ID_ANY,
"FlatNotebook Tutorial",
size=(600,400)
)
panel = wx.Panel(self)
button = wx.Button(panel, label="Close", pos=(125, 10), size=(50, 50))
self.Bind(wx.EVT_CHAR, self.character)
def character(self, event):
print "Char keycode : {0}".format(event.GetKeyCode())
if __name__ == "__main__":
app = DemoApp()
app.MainLoop()
The character function never gets called. However, when I comment out the two lines call to the Frame constructor, I character function is called. Adding a panel to the frame seems to interfere with the binding of the frame's EVT_CHAR.
How do I address this problem? Am I doing something wrong in my code?
The problem is that you are catching events that happen to the frame, but the frame is not in focus. The button is. In wxPython, events are sent to the widget in focus. If you add this to the end of your init, it works:
self.SetFocus()
However, if you change the focus to the button, then it will stop working again. See also:
wxpython capture keyboard events in a wx.Frame
http://www.blog.pythonlibrary.org/2009/08/29/wxpython-catching-key-and-char-events/
http://wxpython-users.1045709.n5.nabble.com/Catching-key-events-from-a-panel-and-follow-up-to-stacked-panels-td2360109.html
I appreciate that this question was answered 2 years ago but this issue catches us all out at some point or other.
It is the classic binding to wx.Event or wx.CommandEvent problem.
In this case simply changing the self.Bind(wx.EVT_CHAR, self.character) line to read button.Bind(wx.EVT_CHAR, self.character) will solve the problem, detailed above.
The issue of wx.Event - wx.CommandEvent is covered in full here:
http://wiki.wxpython.org/EventPropagation
and here:
http://wiki.wxpython.org/self.Bind%20vs.%20self.button.Bind
I am designing a windows utility software for Windows 7 coded in Python with Wxpython for GUI works.I dont want to open my software if it is already opened.
I want a function like this if user opens that software a message box is to be displayed on windows screen showing that "Your application is already running".
Plz help.
Thanks in advance...
There's already existing wxPython facility that implements wanted logic, called wx.SingleInstanceChecker. Here's and example of code (shamelessly borrowed from wxPython wiki):
import wx
class SingleAppFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(300, 300))
self.Centre()
class SingleApp(wx.App):
def OnInit(self):
self.name = "SingleApp-%s" % wx.GetUserId()
self.instance = wx.SingleInstanceChecker(self.name)
if self.instance.IsAnotherRunning():
wx.MessageBox("Another instance is running", "ERROR")
return False
frame = SingleAppFrame(None, "SingleApp")
frame.Show()
return True
app = SingleApp(redirect=False)
app.MainLoop()
This cannonical example (for a matter of luck) makes exatly what you've asked.
In my application i have text control.
I want my text ctrl should be read only but when some one right click on this he is able to copy the value from that ctrl and he can paste that value in other text control.
If i made my text control read only with wx.TE_READONLY then copy/paste is not working.
Is there any requirement to handle other type of wx event or i have to set more type of wx style flags while creating the text control object.
Thanks in advance.
Hmm Im on windows 7 and don't have any problem copying from a textCtrl that has the wx.READ_ONLY style flag set.
You said you wanted to paste into another textCtrl -obviously you can't have the wx.READ_ONLY style flag set in the textCtrl you want to be able to paste into.
Try out the demo below, you should be able to copy from the textCtrl on the left(which is read only) to the one on the right(which doesn't have the read only style set).
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, id=-1):
wx.Frame.__init__(self,parent,id, size=(200,200))
self.panel = wx.Panel(self,wx.ID_ANY)
bsizer = wx.BoxSizer()
read_only_txtCtrl = wx.TextCtrl(self,-1,
"This textCtrl is read only",
style=wx.TE_MULTILINE|wx.TE_READONLY)
editable_txtCtrl = wx.TextCtrl(self,-1,
"This textCtrl is editable",
style=wx.TE_MULTILINE)
bsizer.Add(read_only_txtCtrl, 1, wx.EXPAND)
bsizer.Add(editable_txtCtrl, 1, wx.EXPAND)
self.SetSizerAndFit(bsizer)
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MainWindow(None)
frame.SetSize((200,200))
frame.Show()
app.MainLoop()
We should bind wx.EVT_TEXT_COPY and wx.EVT_TEXT_PASTE with text control.
one can copy and paste data from text ctrl although text ctrl is read only mode.
Actually I had the same challenge. I needed a textbox where users could paste information (or open -> read file via a menu). The app would then analyze the info for correctness. But I didn't want to allow editing in the textbox - it would suggest that you could correct in the same textbox, while the app was for analysis only. Yeah, requirements, I know.
Weird thing was, I could make a readonly TextCtrl under MacOSX that would allow pasting (but not editing), but not on Windows.
In order to support both, I ended up creating a read/writesuper(MyWin, self).init(None, size=(800,600)) textbox (to allow pasting under windows) and binding wx.EVT_TEXT events to it (apart from wx.EVT_TEXT_PASTE for the obvious pasting). The EVT_TEXT handler that's triggered when the textctrl's contents change, simply shows a dialog that you aren't allowed to do this.
In the app a boolean this.painted plays the following role: when this.painted is true, then modifications of the textctrl aren't allowed. So, the onpaste handler first sets this.painted to false, then modifies the TextCtrl's contents, then sets this.painted to true (otherwise the dialog alert would also go off during the paste event, which I wanted to allow). Unfortunately when the EVT_TEXT handler goes off, the window's contents have already been modified by a user hitting some key. Therefore the app also needs a backup buffer to put back into the TextCtrl when such editing has been detected.
According to the Python docs, TextCtrl.ChangeValue() instead of SetValue() should not trigger the EVT_TEXT event (which would be handy) but I couldn't get that to work, might be my mistake due to not-enough-time-to-investigate-because-it-should-have-been-done-yesterday.
Not an elegant solution, but works.
import wx
class MyWin(wx.Frame):
def __init__(self):
super(MyWin, self).__init__(None, size=(800,600))
self.painted = True
self.backup = ''
self.text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.HSCROLL)
self.text.Bind(wx.EVT_TEXT_PASTE, self.onpaste)
self.text.Bind(wx.EVT_TEXT, self.ontextchange)
self.Show()
def onpaste(self, event):
if not wx.TheClipboard.IsOpened():
buf = wx.TextDataObject()
wx.TheClipboard.Open()
success = wx.TheClipboard.GetData(buf)
wx.TheClipboard.Close()
if success:
self.painted = False
self.backup = buf.GetText()
self.text.SetValue(self.backup)
self.painted = True
def ontextchange(self, event):
if self.painted:
dlg = wx.MessageDialog(self, 'Editing not allowed', '', wx.OK)
dlg.ShowModal()
dlg.Destroy()
self.painted = False
self.text.SetValue(self.backup)
self.painted = True
app = wx.App()
frame = MyWin()
app.MainLoop()
I am currently using wx.CustomTree, to use to display a series of configuration settings. I generally fill them with wx.TextCtrl / wx.Combobox, to allow the user to edit / enter stuff. Here is my code:
class ConfigTree(CT.CustomTreeCtrl):
"""
Holds all non gui drawing panel stuff
"""
def __init__(self, parent):
CT.CustomTreeCtrl.__init__(self, parent,
id = common.ID_CONTROL_SETTINGS,
style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS
| wx.TR_HAS_VARIABLE_ROW_HEIGHT | wx.TR_SINGLE)
#self.HideWindows()
#self.RefreshSubtree(self.root)
self.population_size_ctrl = None
self.SetSizeHints(350, common.FRAME_SIZE[1])
self.root = self.AddRoot("Configuration Settings")
child = self.AppendItem(self.root, "Foo", wnd=wx.TextCtrl(self, wx.ID_ANY, "Lots Of Muffins"))
The problem is, any children nodes, the data for these nodes is not filled in. When i basically expand the configuration settings tree node. I see the "Foo" node, however the textbox is empty. This is the same for both text node, Until i actually click on the child node. I've looked tried every form of update / etc. Does anyone have any ideas?
To: Anurag Uniyal
Firstly sorry for not giving the rest of the code. I've gotten around this problem by simply resizing the window everytime i demo the application.
So i tried the code on my Macbook Pro running Mac OS X, with newest wx and python 2.6. I still have the same problem, however i noticed resizing the window, or even touching the scrollbar fixes the issue.
I also noticed however, there is absolutely NO problems running on Windows Vista / Windows 7.
So trying this on another macbook running an older version of wx + python. Results in the same problem :(
Is there anyway to force the panel to redraw it self? Which i am pretty sure happens when i resize the window.
If you don't have any ideas then i'll strip it down and make a demo example, im home and won't be at work until later tommorow.
You can use RefreshItems if you are using virtual controls, or you could refresh the panel, which would update the contents of all the children windows (widgets).
I tested it on window with wx version 2.8.10.1 and it works, which OS and wx version you are using?
here is self contained code, which can be copy-pasted and run
import wx
import wx.lib.customtreectrl as CT
class ConfigTree(CT.CustomTreeCtrl):
"""
Holds all non gui drawing panel stuff
"""
def __init__(self, parent):
CT.CustomTreeCtrl.__init__(self, parent,
id = -1,
style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS
| wx.TR_HAS_VARIABLE_ROW_HEIGHT | wx.TR_SINGLE)
self.population_size_ctrl = None
self.SetSizeHints(350, 350)
self.root = self.AddRoot("Configuration Settings")
child = self.AppendItem(self.root, "Foo", wnd=wx.TextCtrl(self, wx.ID_ANY, "Lots Of Muffins"))
def main():
app = wx.App()
frame = wx.Frame(None, title="Test tree", size=(500,500))
p = wx.Panel(frame, size=(500,500))
tree = ConfigTree(p)
tree.SetSize((500,500))
frame.Show()
app.MainLoop()
if __name__ == '__main__':
main()