I have done my form in VB. I cannot access the child window controls. For instance, the alert box appears after submit button is clicked. Here is my code:
# used backend="uia"
import sys
import pyautogui
from pywinauto.application import Application
import time
print("test")
app=Application().start()
app.Form1.Edit4.type_keys("go")
app.Form1.Edit3.type_keys("12")
app.Form1.Male.click()
app.Form1.ComboBox.type_keys("in")
app.Form1.Edit2.type_keys("33")
app.Form1.Submit.click()
app.Form1.Submit.print_control_identifiers()
app.Success.print_control_identifiers()
app.Form1.Success.click()
Success is the name of child window.
you write that you've used backend="uia" but the code Application().start() uses default backend which is "win32". You have to use Application(backend="uia").start() to choose "uia".
Note: for "win32" backend the alert window is a top-level window. So you need app.Success.OK.click() to click OK button on it. For backend="uia" alert window will be child of "Form1".
EDIT: this code should work:
app.Form1.Success.OKButton.click() # alias of .invoke();
# see IsInvokePatternSupported == True in Inspect.exe
# or
app.Form1.Success.OKButton.click_input() # real click
EDIT2: It may be timing issue. pywinauto has default timeout 5 seconds waiting for dialog appearance. If dialog appears after more than 5 seconds, you need something like that: app.Form1.Success.wait('visible', timeout=20).
Another possible issue is blocking behavior of app.Form1.Submit.click() which calls InvokePattern. Sometimes this pattern implementation waits for dialog closing (this is app side issue though). You might have to change this to app.Form1.Submit.click_input().
Related
I know I can use time.sleep(), but I need something that would affect whole script.It is automatic test homework and aplication buttons are clicked almost instantly. It is a bit anoying because I cant see if everything is working as supposed(still learning).
import pyautogui
import time
from pywinauto.application import Application
app = Application(backend="uia").start(r"C:\Users\User\Desktop\WPF_RentACar_3maj\WPFRentACar\bin\Debug\WPFRentACar.exe")
pyautogui.FAILSAFE = True
#app.LoginWIndow.print_control_identifiers()
dlg =app.LoginWindow
dlg.MaximizeButton.click()
dlg.MinimizeButton.click()
dlg.MaximizeButton.click()
dlg.Restore.click()
try:
dlg.Edit1.type_keys("123")
dlg.Edit2.type_keys("123")
dlg.LoginButton.click()
dlg.Button1.click()
finally:
print("Cant login with wrong credentials!")
time.sleep(2)
dlg.Edit1.type_keys("'^a{BACKSPACE}")
dlg.Edit2.type_keys("'^a{BACKSPACE}")
dlg.LoginButton1.click()
time.sleep(5)
time.sleep() does stop the whole script. Or are you using threading or python 2? Also can you tell us what you are also trying to automate.
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.
A Python 3 and Gtk 3.22.5 application responds to a global key binding, thanks to the Keybinder library. Currently it invokes a simple callback:
def keybinder_callback(self, keystr, user_data):
print("Handling", keystr, user_data)
Elsewhere in the application is a Gtk.Window that contains a Gtk.MenuBar. The keybinder_callback needs to activate the menu bar as if the user had clicked the mouse on it.
(it's a very basic dock-type application rather than one with a typical application window)
I have tried sending a signal to a menu item:
self.menubar.get_children()[0].emit("activate-item")
without any joy. I also tried faking a button press
from Xlib.ext.xtest import fake_input
fake_input(display,X.ButtonPress,1)
which also had no effect, but feels like the wrong way to do it anyway. I thought sending a signal would be more appropriate.
Can a widget be activated programmatically as if a user mouse-clicked on it?
(it doesn't have to be a simulated mouse-click - it just needs to activate and focus the widget in the same way that a mouse-click would)
I have written an example that has a keybinder_callback like this:
def keybinder_callback(self, keystr, user_data):
print("Handling", keystr, user_data)
print("Event time:", Keybinder.get_current_event_time())
activate_the_menu()
I need to add some command to that function that will activate_the_menu.
I have tried many things, including capturing real events (by monitoring with xev) and simulating them ( ENTER_NOTIFY and FOCUS_CHANGE), by injecting them into Gdk.main_do_event.
I've tried calling menu.popup, menu.popup_at_widget, menubar.select_item and other numerous things. All to no avail.
Running out of ideas, I've even dusted off my old Xlib book...
Incidentally, whilst not a proper solution, this works from a shell:
$ xdotool mousemove 1605 10 click 1 mousemove restore
but not reliably from the keybinder_callback:
run("xdotool mousemove %d 10 click 1 mousemove restore" %
(self.get_position().root_x+5) , shell=True)
After trying many things, I found that this works.
import Xlib
from Xlib import X
from Xlib.display import Display
from Xlib.ext.xtest import fake_input
import time
def keybinder_callback(self, keystr, user_data):
time.sleep(0.2)
x = self.get_position().root_x+5
display = Display()
mpos = display.screen().root.query_pointer()._data
display.screen().root.warp_pointer(x,5)
display.sync()
fake_input(display,X.ButtonPress,1, X.CurrentTime, X.NONE, x, 5)
display.sync()
fake_input(display,X.ButtonRelease,1)
display.screen().root.warp_pointer(mpos['root_x'],
mpos['root_y'])
display.sync()
I found that the time delay was necessary to avoid this error:
Gdk-CRITICAL **: Window 0x1e7c660 has not been made visible in GdkSeatGrabPrepareFunc
I would develop some functional tests for a pyqt application that uses PyQt (or PySide) as GUI library. The tests use Unittest and Qttest library, as reported in many resources, for example this stackoverflow question: Unit and functional testing a PySide-based application?
For the main window all works fine, and the code simulate perfectly Keyboard Types and Mouse Clicks and Movements, but the "devil is in the details"... and this method does not work for a QMessageBox.
In the class of the Main Window, for manage a IOError on opening a file, I initialize a QMessageBox:
self.IOErrMsgBox = QtGui.QMessageBox()
self.IOErrMsgBox.setText("<b>Error</b>")
self.IOErrMsgBox.setInformativeText("""
<p>There was an error opening
the project file:
%s.</p>"""%(path,))
self.IOErrMsgBox.setStandardButtons(QtGui.QMessageBox.Ok)
self.IOErrMsgBox.setDefaultButton(QtGui.QMessageBox.Ok)
self.IOErrMsgBox.exec_()
To test how it works, in functional test I have:
def test__open_project(self):
self.MainWin._project_open(wrong_path, flag='c')
# the function that handles the exception
# and initializes the QMessageBox.
IOErrMsgBox = self.MainWin.IOErrMsgBox
# Reference to the initialized QMessageBox.
self.assertIsInstance(IOErrMsgBox, QMessageBox)
okWidget = self.MainWin.IOErrMsgBox.button(IOErrMsgBox.Ok)
QTest.mouseClick(okWidget, Qt.LeftButton)
or, in altenative:
def test__open_project(self):
#... some code, exactly like previous example except for last row...
QTest.keyClick(okWidget, 'o', Qt.AltModifier)
but No one works... and the Ok button is not clicked and I can do it with my mouse pointer :(
Any suggestions?
The question is in general about how to test modal dialogs.
Any modal dialog including QMessageBox will not return from exec_() until it is closed, so the test code in your second code box probably never gets executed.
You could just show() it (making it non-modal) and then follow your code but don't forget to close and delete the dialog afterwards.
Or you use a Timer and schedule a click on the OK button (similar to Test modal dialog with Qt Test). Here is an example:
from PySide import QtGui, QtCore
app = QtGui.QApplication([])
box = QtGui.QMessageBox()
box.setStandardButtons(QtGui.QMessageBox.Ok)
button = box.button(QtGui.QMessageBox.Ok)
QtCore.QTimer.singleShot(0, button.clicked)
box.exec_()
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.