My code is pretty straight forward, but I keep getting the error below. I researched the error and it pretty much says IDLE and my own GUI are screwing each other up, but I don't really know how to avoid it. I mean, if I just click on the .py file for my GUI without having IDLE open, I get the same error.
Any ideas?
Python 2.7
Windows XP
import wx
class applicationName(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, 'Title', size=(300,200))
panel = wx.Panel(self)
box = wx.TextEntryDialog(None, "How old are you?", "Title", "default text")
if box.ShowModal() == wx.ID_OK:
answer = box.GetValue()
if __name__ =='__main__':
app = wx.PySimpleApp()
frame = applicationName(parent=None, id=-1)
frame.Show()
app.MainLoop()
Error:
PyNoAppError: The wx.App object must be created first!
I guess you encountered this problem when you were debugging your program second time.
You can add the line at the end of the code.
del app
I hope it can help you.
Your __init__ function is not indented properly. It should be
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, 'Title', size=(300,200))
panel = wx.Panel(self)
box = wx.TextEntryDialog(None, "How old are you?", "Title", "default text")
if box.ShowModal() == wx.ID_OK:
answer = box.GetValue()
Quoted from: http://wxpython-users.1045709.n5.nabble.com/PyNoAppError-The-wx-App-object-must-be-created-first-td2362821.html
The key is to use an editor/IDE that runs the Python code you are
editing in an external process, rather than running it in the same
process as the editor itself.
Try closing the terminal/console and re-running it (if the option is available).
worked for me when i got this massage in Spyder (3.3.2) when ran similar code to the above.
Running this inside Psychopy builder, adding the following to the beginning of the experiment helped:
import wx
tmpApp = wx.PySimpleApp()
I had the same problem, but the:
del app
close the window and stop the kernel, so it was not of great help
I found that this worked for me:
app=[]; app = wx.App(None)
whitout the app=[]-part, the program run once, but not the second time when it stops and gives the "wx.app object must be created first"-error
Hope this can be of use for others.
Per
Related
I am new to Python and so i am new to wxPython as well. I was just wondering if there is any difference between these wx.TextCtrl functions. This mini code shows three times the same output. If there is no difference, is there a historic reason for these functions?
import wx
class testUI(wx.Panel):
textCtrl = ''
def __init__(self, parent, name):
super(testUI, self).__init__(parent, name=name)
self.buildUI()
self.Show(True)
self.textCtrl.write('bli\n')
self.textCtrl.WriteText('bla\n')
self.textCtrl.AppendText('blub\n')
def buildUI(self):
self.textCtrl = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_READONLY)
box = wx.BoxSizer(wx.VERTICAL)
box.Add(self.textCtrl, proportion=1, flag=wx.EXPAND)
def main():
app = wx.App(False)
root = wx.Frame(parent=None, title='testUI')
testUI(parent=root, name='testUI')
root.Show(True)
app.MainLoop()
# Standard boilerplate to call the main() function.
if __name__ == '__main__':
main()
thanks :)
Guessing people may hit this thread for the same reason I did, which is that the "new" version of wxPython (4.0.1) lists write() as a method on the wx.TextCtrl class - but it's not defined. I needed a write function to be able to use the logging.StreamHandler class; because these methods should all do the same thing, I recreated the missing write method with an assignment - this works:
import wx
import logging
lgr = logging.getLogger(__name__)
lgr.setLevel(logging.DEBUG)
fmt = logging.Formatter('%(asctime)s: %(name)s [%(levelname)s] %(message)s')
debug = lgr.debug
class LogTab(wx.Panel):
def __init__(self, *args, **kwds):
kwds["style"] = wx.TAB_TRAVERSAL
wx.Panel.__init__(self, *args, **kwds)
self.text_log = wx.TextCtrl(self, wx.ID_ANY, "",
style=wx.TE_MULTILINE | wx.TE_READONLY)
self.text_log.write = self.text_log.WriteText
self.__set_properties()
self.__do_layout()
self.log_handler = logging.StreamHandler(self.text_log)
self.log_handler.setFormatter(fmt)
lgr.addHandler(self.log_handler)
The 3 methods appear to be functionally the same. However, I would argue that you would use AppendText for adding additional text to a text control to make what you're doing very clear in the code itself. Most of the time, you will normally use SetValue. I have used WriteText when redirecting stdout, but that's it. You can read about that use case here:
http://www.blog.pythonlibrary.org/2009/01/01/wxpython-redirecting-stdout-stderr/
EDIT:
Ok, instead of reading my entire answer the difference between .AppendText() and .WriteText() appears to be that the first one adds text to the end of the textcontrol and the second one adds it at the current insertion point as explained here.
Old answer (may still be usefull as an example):
Hmm.. strange. I ended up here because using .WriteText() on my wx.stc.StyledTextCtrl() was giving strange results. I now changed it to .write() and it works.
I am using my wx.stc.StyledTextCtrl() as a drag and drop window that lists the dropped filepaths. However, since the window is also editable (I need it to be) the InsertionPoint can be located anywhere.
So, whenever someone drops a new filepath (or multiple filepaths) onto my wx.stc.StyledTextCtrl() I need it to check where the current InsertionPoint is located. If the InsertionPoint is located in a line that already holds text, it needs to be moved to the end of that specific line. From there it needs to print a newline and the received filepath(s).
My code looks like this:
def write_interactive(self, text):
curPos = self.interactivewindow.GetInsertionPoint()
lineVal,curCol,curRow = self.interactivewindow.PositionToXY(curPos)
lineNum = curRow
lineText = self.interactivewindow.GetLineText(lineNum)
if len(lineText) > 0:
endOfLine = self.interactivewindow.XYToPosition(len(lineText), curRow)
self.interactivewindow.SetInsertionPoint(endOfLine)
self.interactivewindow.write('\n' + text)
else:
self.interactivewindow.write(text)
Now, as to your question, I have noticed that when using self.interactivewindow.WriteText(text) the text that is located between the initial InsertionPoint and the end of that specific line vanishes. And the new text is written over it. However, when using self.interactivewindow.write(text), everything works fine.
Is it possible to create a message box (with wx.MessageDialog or anything else) without parent window ?
For example, I sometimes may want to display an error message before the GUI has really started. Then I would need to be able to display a message box before having a parent window :
With parent = None, this doesn't work :
wx.MessageDialog(parent, 'This is a message box.', 'Test', wx.OK | wx.ICON_INFORMATION).ShowModal()
How to display a message box without a parent window ?
Just saw this old question and wanted to answer it, better late than never:
By default, the main application window is used as the dialog parent even if no parent is specified explicitly, because this is what you want in 99% of cases -- modal dialogs without parent/owner window are quite unusual. If you really, really need to prevent the dialog from having a parent, you must use wx.DIALOG_NO_PARENT style explicitly.
It should work, try this:
import wx
app = wx.App()
wx.MessageDialog(None, 'This is a message box.', 'Test', wx.OK | wx.ICON_INFORMATION).ShowModal()
frame = wx.Frame(None)
frame.Center()
frame.Show()
app.MainLoop()
I know this is an old question, but I believe that parent=None does not work as one might expect. Consider the example above, but with the wx.Frame shown first, and the wx.MessageDialog after, like so:
import wx
app = wx.App()
frame = wx.Frame(None)
frame.Center()
frame.Show()
wx.MessageDialog(None, 'This is a message box.', 'Test', wx.OK | wx.ICON_INFORMATION).ShowModal()
app.MainLoop()
The result is a wx.Frame with the wx.MessageDialog shown on top of it (as expected), but the wx.Frame cannot be resized or draged around the screen (not expected). The wx.MessageDialog can be draged around the screen, but the wx.MessageDialog moves with it (not expected). The two frames clearly do not work independent of each other, and it seems the wx.MessageDialog is owned by the wx.Frame. I therefore think that wxPython applies some magic that is not obvious; at least I couldn't see anything in the docs.
Without parent frame.
There seems no need to use a frame for showing a 'stand alone' dialog. This works fine. (Tested only on Win10.)
Apparently wxpython takes the dialog, which is of course also just a window, as the 'frame' to display.
import wx
# -------------------------------------------------------
def wx_ask_question_windowed(question, caption):
app = wx.App()
dlg = wx.MessageDialog(None, question, caption, wx.YES_NO | wx.ICON_INFORMATION)
dlg.Center()
dlg_result = dlg.ShowModal()
result = dlg_result == wx.ID_YES
dlg.Destroy()
app.MainLoop()
app.Destroy()
return result
# ==============================================================
def main():
if wx_ask_question_windowed('Do you like this?', 'A windowed question'):
print('You like it')
else:
print("You don't like it")
# ==============================================================
if __name__ == '__main__':
main()
Let's say I have a frame
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
self.InitUI()
self.SetSize((380,340))
self.Show()
self.something = 0
Which I start like so:
if __name__ == '__main__':
app = wx.App()
frame = Frame(None)
app.MainLoop()
And during debugging I find a bug I think is related to self.something. Can I view the contents self.something through IDLE's Console?
For you would find it worth looking for an IDE with built in debugger, there are several good free ones.
Alternatively you could use winpdb this would give you a full debugger as a standalone and it works fine with wxPython.
It is also worth looking at the python documents on debugging as you can open a debug console from within your code.
There is also the wx inspection tool, in your code try:
import wx.lib.inspection
wx.lib.inspection.InspectionTool().Show()
I doubt it. You need some kind of debugger that can pause the main process so you can take a look under the hood. I've heard that PyDev/Eclipse works and I know WingWare's IDE has a debugger that works with wx as I use it all the time. I haven't found any hard data about whether or not Python debugger (pdb) can attach itself to wx or not.
You might find the following threads useful though:
http://wxpython-users.1045709.n5.nabble.com/Simple-pdb-debugging-from-shell-td2305039.html
https://groups.google.com/forum/#!topic/wxpython-users/jO7YzV-wVkI
https://groups.google.com/forum/#!msg/wxpython-users/0T6hmqSkfW0/WIPqD3PkcdcJ
Solved:
Thanks to Aya's answer below I now know that the issue was caused by self.panel = wx.Panel(self, -1) on line 18. I created a panel and didn't attach anything to it. The original issue description is still below for reference.
My Google-fu has failed me. I'm building the text editor that you can find here, written in Python with wxPython:
https://github.com/joshsaintjacque/py-ed/blob/master/pyed.py
The issue that I'm running into is this: when I open a text file (the only functionality built in at this point) that's larger than the viewable area in the TextCtrl the scroll bar remains disabled until the window is re-sized, then it works fine.
I know that the act of re-sizing the window is running some command that I'm neglecting to include in my OpenFile function (or perhaps in init), but I can't figure out what.
Any thoughts anyone has that could lead me in the right direction would be greatly appreciated.
Thanks!
+1 for including a link to the full source code - makes it so much easier to test.
I couldn't reproduce the fault you describe on wxPython 2.8.12 on Win32, but upon running your code, I found a seemingly extraneous wx.Panel object being created on pyed.py line 18...
self.panel = wx.Panel(self, -1)
...which seems to be interfering with the correct operation of the program. After commenting out that line, it seems to work fine.
A couple of other things I noticed: line 56...
self.SetTitle("PyEd - Editing ... " + filename)
...should probably be put in the preceding if-block, otherwise you'll get an error if the user clicks "Cancel" on the wx.FileDialog, and on line 16...
wx.Frame.__init__(self, parent, id, 'PyEd', (-1, -1), wx.Size(640, 480))
...if you use keyword args rather than positional args...
wx.Frame.__init__(self, parent=parent, id=id, title='PyEd', size=wx.Size(640, 480))
...you needn't bother re-specifying the default value for the window position, which is also slightly safer, in case the wxPython developers decide to change the defaults in a future version.
You can also factor out constant values, and the optional creation of the wx.Size object to reduce that line to...
wx.Frame.__init__(self, parent=None, title='PyEd', size=(640, 480))
Finally, with regards to IDs: in most cases you'll probably find they're of little use. Where they come in handy is where you want many similar controls, and it makes more sense to have them handled by a single event handler function.
Consider this example...
def create_buttons(parent):
parent.button1 = wx.Button(label='Button 1')
parent.button2 = wx.Button(label='Button 2')
parent.button3 = wx.Button(label='Button 3')
parent.button1.Bind(wx.EVT_BUTTON, on_button_1)
parent.button2.Bind(wx.EVT_BUTTON, on_button_2)
parent.button3.Bind(wx.EVT_BUTTON, on_button_3)
def on_button_1(event):
print 'You clicked button 1'
def on_button_2(event):
print 'You clicked button 2'
def on_button_3(event):
print 'You clicked button 3'
...which is fine, but if you need, say, 100 buttons, you may prefer to implement it like this...
def create_buttons(parent):
parent.buttons = [wx.Button(id=i, label='Button %d' % i) for i in range(100)]
parent.Bind(wx.EVT_BUTTON, on_button)
def on_button(event):
button_id = event.GetId()
print 'You clicked button %d' % button_id
Oh, and be careful using id as a variable name, because it's also a Python built-in function name.
It looks as if you're not setting the min or max size hints for the window, nor are you calling Self.Fit() to fit the box sizer to the window size (or is it the other way round? I'm rusty on my wxPython...)
Right where you call self.SetSizer(sizer), you should be able to fix this by adding:
self.Fit()
self.SetSizeHintSz(minSize=wx.Size(640, 480))
You may be able to get around the separate call to self.Fit() by using self.SetSizerAndFit()
(edited for spelling.)
Can anybody help me figure out what I'm doing wrong I've very little experience with GUIs.
code:
import wx
class bucky(wx.Frame):
#constructor
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Frame aka window',size=(300,200))
panel=wx.Panel(self)
button=wx.Button(panel,label="exit",pos=(130,10),size=(60,60))
self.Bind(wx.EVT_BUTTON, self.closebutton,button)
self.Bind(wx.EVT_CLOSE, self.closewindow)
def closebutton(self,event):
self.close(True)
def closewindow(self,event):
self.Destroy()
if __name__=='__main__':
app=wx.PySimpleApp()
frame=bucky(parent=None,id=-1)
frame.Show()
app.MainLoop()
Error:
PyNoAppError: The wx.App object must be created first!
win32ui.error: Error in Command Message handler for command ID 36864, Code 0
This code runs for me on Windows 7 with wxPython 2.8.12.1 and Python 2.6.6. What OS and Python versions are you using? I've seen this error message from time to time when I've run my code in IDLE. If you're doing that, then don't. Tkinter's mainloop (which is what IDLE is made with) will interfere with other GUI toolkit's main loops.
There is an issue in the closebutton method in that it call a "close" method which does not exist.