MessageDialog unresponsive after FileDialog ShowModal - python

Hey guys I've been trying to debug this issue for a while to no avail.
I've defined a function bound to a button that calls up a FileDialog, if the user clicks OK, the function resumes. Immediately after ID_OK I attempted to call a simple dialog prompting the user to select files from another directory. Immediately after this message dialog appears, there appears to be a delay where the user can't press OK or CANCEL on the first click. It takes repeated clicking for the buttons to respond. If anybody has any idea what's going on here or what can be done to debug this issue I will be very grateful :). I've attached the snippet of code (albeit with a SingleChoiceDialog though the behavior is the same as with MessageDialog). For the record dlg is destroyed after the conditional statement.
def openFile(self, event):
import os
import re
import csv
import sets
import datetime
dlg = wx.FileDialog(self, "Choose file(s)", os.getcwd(), "", "*.*", wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPaths()
test = wx.SingleChoiceDialog(self, 'Add more files from different directories?', 'Selected Files', path, style=wx.CHOICEDLG_STYLE)
while test.ShowModal() == wx.ID_OK:
dlgAdd = wx.FileDialog(self, "Choose file(s)", os.getcwd(), "", "*.*", wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR)
if dlgAdd.ShowModal() == wx.ID_CANCEL:
break
dlgAdd.Destroy()
path = path + dlgAdd.GetPaths()
test = wx.SingleChoiceDialog(self, 'Add more files from different directories?', 'Selected Files', path, style=wx.CHOICEDLG_STYLE)
test.Destroy()
Was digging around some more online and found reports of similar issues: http://comments.gmane.org/gmane.comp.python.wxpython/55470. It does seem to be an issue with passing focus though none of them offered fixes or workarounds however.

Try using an "if" instead of a "while" for the "test" dialog. I suspect you have an infinite or near-infinite loop thing going on whenever they press the OK button. If the user presses CANCEL on the dlgAdd dialog, your program never destroys dlgAdd since it breaks out of the loop at that point. That's also an issue and probably why the "test" dialog is hung for a while.

Ugh okay figured it out the error stems from the use of Coherence mode when using Parallels. After turning this off the dialogs worked perfectly.

Related

Python 2.7: Close a dialog without exiting the entire application

I'm running a script coded in python from a scripts menu in a desktop application. It's basically a giant macro that I wrote and added a GUI to. I'm pretty sure the GUI is a really old one that my desktop app uses called dialogKit from MIT.
GitHub still has it here.
The problem is the word "stop" at the very end of the dialog code.
I keep getting a "stop is undefined" message, which I understand, but I've tried everything to close the dialog and if I use exit(), sys.exit(), I don't get an error, but it also closes my entire desktop app.
I need to close the dialog and keep the software open.
The limited dialog documentation for what I'm using can be found here.
(you might have to click on the Dialog section. Their site uses frames.)
class MyDialog:
def __init__(self):
self.d = Dialog(self)
self.d.size = Point(300, 340)
self.d.Center()
self.d.title = "Halftone" #<----- Title of the dialogue
self.d.AddControl(STATICCONTROL, Rect(aIDENT, aIDENT, aIDENT, aIDENT), "frame", STYLE_FRAME)
# more controls and methods..
def on_ok(self, code):
return 1
def on_cancel(self, code):
print "blah"
def Run(self):
return self.d.Run()
d = MyDialog()
if d.Run()!= 1:
stop
I just need a way to change stop to something that 1) will prevent the script from running, and 2) close the dialog without quitting the entire application. This is the functionality of a typical "cancel" button, which is what I want.
Another option is the method called on_cancel(), which I also tried and could get the event itself to work, but still the entire application quits with any kind of exit().
The docs show a method called End(), which claims to terminate the dialog object, but I've tried and failed to get that to work either.
Okay, I'm posting an answer because I think I have a handle on your problem.
Try replacing stop with:
d.d.End()
If that works, you might want to try putting:
self.d.End()
inside of the on_cancel function in your class. That should close the dialogue without closing your program.

File dialog in Mac to find app

I have some Python code which works well in Windows and Ubuntu Linux, but has a problem on Mac.
What I am doing is presenting a user (within my app) the ability to choose an application he wants opened whenever he presses a button on my app (so that he can invoke without having to search for it every time)
The setup code goes like this (simplified):
self.app_opt = options = {}
options['title'] = 'Please choose an app from your computer'
options['initialdir'] = '~/'
chosen_app = "~/"
chosen_app = askopenfilename(parent = self.parent, **self.app_opt)
self.chosen_app = chosen_app
Later on, the button is pressed and the code in the button looks like this:
subprocess.Popen(self.chosen_app)
As I said, it works fine in Windows (I go over to "Program Files", select an executable and all is fine), it runs when I push the button. Also in Ubuntu - (I select from say /usr/bin) and app runs fine when I push the button.
Tried to do this in Mac - just as an example we would like to open iTunes when pressing the button - Now the real app to run iTunes is found at e.g.
/Applications/iTunes.app/Contents/MacOS/iTunes
But I can't select deeper than
/Applications/iTunes.app
Is there some option/setting I need to put in the file dialog to make this work?
After asking a friend (thanks DJ!) It seems I was going about this the wrong way
In Mac I should not be calling
subprocess.Popen(self.chosen_app)
but something more like
subprocess.Popen('open -a \"' + self.chosen_app + '\"')
as explained here
Will report back on how this works

Trouble Adding The Save Menu Item To My GUI

I used PythonCard to make my GUI and the only menu items I have currently are Save and Exit. Exit is fully functional and closes the program; but when I click on Save nothing happens. I can only assume the command is wrong. I have done some thorough searching and have found nothing. The command I used was "save". Obviously this is not correct. Can anyone tell me what command I need to use?
Resource File
There's really not enough information here. You need to bind EVT_MENU to an event handler for the save menu item. Then in the event handler, you'll have to define what the "Save" behavior is. For example, does it save to a database, a file, or what? Once you have that figured out, you put it in your handler and do it or have the handler spin up a thread.
EDIT: If you want to save a file, see the wx.FileDialog and set the style flag to wx.SAVE. Something like this should work:
def onSaveFile(self, event):
"""
Create and show the Save FileDialog
"""
wildcard = "Text (*.txt)|*.txt|" \
"All files (*.*)|*.*"
dlg = wx.FileDialog(
self, message="Save file as ...",
defaultDir=self.currentDirectory,
defaultFile="", wildcard=wildcard, style=wx.SAVE
)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
print "You chose the following filename: %s" % path
dlg.Destroy()
See also the wxPython demo, or this or the docs

Return multiple file paths to use in another function using wxPython

What I'm trying to do here is select multiple files from within a wxPython frame app and then utilize those file paths within another function within the same wxPython app. I realize I can use the following code to select multiple files:
def OnOpen(self,e)
dialog = wx.FileDialog(self, "Choose a file", "", "", "*.", wx.MULTIPLE)
if dialog.ShowModal() == wx.ID_OK:
filelist = dialog.GetPaths()
So the 'filelist' variable is now a list of the files the user selects. However, I can't seem to find a way to utilize this list in another function. I was hoping I could just use a return statement within this function in another function and assign it to a variable, but it doesn't seem to allow me to do this. I guess this is because I have a button event already using this function. Any help on this would be greatly appreciated.
I don't think I fully understand the issue here. The OnOpen function is an event handler for a button click? So it is executed when button is clicked. A windowed application (like yours using wxPython) is usually event driven, it responds to events like a button click. The main GUI thread loops and analyses events which can be handled by you application. So when you write an application these event handlers are entry points for actions you would like to perform.
I think the best way to do is simply the other function and pass filelist in parameter e.g:
def OnOpen(self,e)
dialog = wx.FileDialog(self, "Choose a file", "", "", "*.", wx.MULTIPLE)
if dialog.ShowModal() == wx.ID_OK:
filelist = dialog.GetPaths()
self.otherFunc(filelist)
def otherFunc(self, filelist):
"do something here"
saving filelist to an attribute may be problematic sometimes. As I said you may have multiple entry points which would like to use filelist attribute, you have to predict possible problems. But as I said at the beginning - I might have not fully understood your problem.
Another possiblity: maybe your problem is that you would like to actually reuse OnOpen? First possibility is to pass None as an argument because e is not used. Another, better possibility is to define OnOpen without e argument and change the event binding to self.Bind(wx.EVT_BUTTON, self.OnButtonwx.EVT_BUTTON(<some object>, lambda evt: self.OnOpen()). You explicitly say here that you don't need the evt argument.
Put the list as an attribute in self, or have self contain as an attribute a listener that gets the paths, or call the other function giving it the paths as an argument?

How to stop a warning dialog from halting execution of a Python program that's controlling it?

Using Win32GUI and Watsup, I'm writing a bit of Python code to automate a search across a database that is accessed through a program that doesn't come with an interface for it. As such, I can take a string from a list and then input it into the search box and press 'lookup'.
However, when the search returns more than 1000 results, the program throws a warning dialog --which is simply a notification of the number of results--which halts the execution of the Python code. I can't get the code to progress past the line where it presses lookup.
At a guess, this would be because it doesn't expect a window or know how to handle a warning--but I don't either, other than manually accepting it. Below is the relevent sample of code, though it's probably not very enlightening. After "clickButton(LookupButton)", the execution halts.
LookupButtonlocation = elemstring.find("Lookup", AuthNameFieldlocation) - 15
#Use Regex search to find handles
number_regex = re.compile(';(\d+);')
AuthNameEdit = int(number_regex.search(elemstring[AuthNameFieldlocation:]).group(1))
LookupButton = int(number_regex.search(elemstring[LookupButtonlocation:]).group(1))
#Input new Author into Edit Field
setEditText(AuthNameEdit, "John Campbell")
#Click lookup button
clickButton(LookupButton)
I'm not a WATSUP user, but I do something very similar using pywinauto - in my case I'm running a number of automated tests that open various 3rd party programs that, in a similar way, throw up inconvenient warning dialogs. It's a bit difficult to deal with dialogs that you don't know about, however if you do know which dialogs appear, but not when they appear, you can start a thread to just deal with those pop-ups. The following is a simple example from what I'm doing, and uses pywinauto but you could adapt the approach for WATSUP:
import time
import threading
class ClearPopupThread(threading.Thread):
def __init__(self, window_name, button_name, quit_event):
threading.Thread.__init__(self)
self.quit_event = quit_event
self.window_name = window_name
self.button_name = button_name
def run(self):
from pywinauto import application, findwindows
while True:
try:
handles = findwindows.find_windows(title=self.window_name)
except findwindows.WindowNotFoundError:
pass #Just do nothing if the pop-up dialog was not found
else: #The window was found, so click the button
for hwnd in handles:
app = application.Application()
app.Connect(handle=hwnd)
popup = app[self.window_name]
button = getattr(popup, self.button_name)
button.Click()
if self.quit_event.is_set():
break
time.sleep(1) #should help reduce cpu load a little for this thread
Essentially this thread is just an infinite loop that looks for a pop-up window by name, and if it finds it, it clicks on a button to close the window. If you have many pop-up windows you can open one thread per popup (bug that's not overly efficient, though). Because it's an infinite loop, I have the thread looking to see if an event is set, to allow me to stop the thread from my main program. So, in the main program I do something like this:
#Start the thread
quit_event = threading.Event()
mythread = ClearPopupThread('Window Popup Title', 'Yes button', quit_event)
# ...
# My program does it's thing here
# ...
# When my program is done I need to end the thread
quit_event.set()
This is not necessarily the only way to deal with your issue, but is a way that's worked for me. Sorry I can't really help you much with dealing with WATSUP (I always found pywinauto a bit easier to use), but I noticed on the WATSUP homepage (http://www.tizmoi.net/watsup/intro.html), Example 2 does something similar without using threads, i.e., looks for a named window and clicks a specific button on that window.

Categories

Resources