How to click button in dialog box using PyWinAuto - python

I have an batch file that I execute that opens a program. A dialog box then appears which I type into it the username and password credentials
The I print the control identifiers and it lists;
SunAwtDialog - 'Login' (L528, T242, R853, B501)
['SunAwtDialog', 'LoginSunAwtDialog', 'Login']
child_window(title="Login", class_name="SunAwtDialog")
So after reading this post. My understanding was to use window + the button and a click method like so;
dlp.SunAwtDialog['Login'].click()
But this keeps throwing an ElementNotFoundError;
ElementNotFoundError: {'best_match': 'SunAwtDialog', 'top_level_only': False, 'parent': <win32_element_info.HwndElementInfo - 'Login', SunAwtDialog, 2164976>, 'backend': 'win32'}
Below is the full snippet of code;
from pywinauto import application
import time
app = application.Application()
app.start(r"C:\\WINDOWS\system32\cmd.exe", wait_for_idle=False)
dlg = app.top_window()
dlg.type_keys('D:{ENTER}')
dlg.type_keys('cd{SPACE}Software\\client{ENTER}')
dlg.type_keys('run_client.bat{ENTER}')
time.sleep(10)
new_app = application.Application().connect(title="iManager")
dlp = new_app.top_window()
#type username + password
dlp.type_keys('user')
dlp.type_keys('{TAB}')
dlp.type_keys('pass')
#print control identifiers
dlp.print_control_identifiers()
#click login[![enter image description here][1]][1]
dlp.SunAwtDialog['Login'].click()
You can see on the image below the "Login" button I want to be able to click. There is also another button next to the "Server" option, but it is not in my control identifiers

A solution that I use for this is using send_keys. Try this:
from pywinauto.keyboard import send_keys
send_keys("{VK_MENU down}" "l" "{VK_MENU up}")

Related

How to control desktop app windows with python

I'm trying to make a python bot for zoom.us, but to join a meeting, zoom tells us to download an application and to join the meeting from there. Is there any python module like selenium but to control desktop apps? I found PyAutoIt, but is there anything better?
Didn't understand entirely what you're planning to do, but maybe pyautogui can be helpful too
You have to download the zoom app for desktop and use the 'pyautogui' module to automate the GUI of zoom app. here is a script that I wrote to automate mine. edit the positions of the app according to your machine
import pyautogui
import time
pyautogui.FAILSAFE = False
class ZoomOpener():
def __init__(self, meeting_id, password):
self.meeting_id = meeting_id
self.password = password
def main(self):
# clicks on zoom logo in the task bar and opens it
time.sleep(1)
pyautogui.click(550, 800, duration=0.2)
# clicks on join button
time.sleep(2)
pyautogui.click(x=550, y=317, clicks=2, interval=0.2)
# types the meeting id
pyautogui.typewrite(self.meeting_id,interval=0.06)
# clicks the join button
time.sleep(2)
pyautogui.click(x=690, y=487)
# types the password
time.sleep(5)
pyautogui.click(x=550, y=317, clicks=2)
pyautogui.typewrite(self.password, interval=0.06)
# clicks the join button
time.sleep(1)
pyautogui.click(x=690, y=487, clicks=1)
# final joining
time.sleep(5)
pyautogui.click(x=900, y=590, clicks=2, interval=2)
if __name__ == '__main__':
time.sleep(10)
zoom = ZoomOpener('9656400024', '123456')
zoom.main()

PyWinAuto trouble clicking the Next Button

This code gets the first window from InstallShield.
from pywinauto import application
from pywinauto import findwindows
app = application.Application()
app.start("MyInstallShieldApp.exe")
time.sleep(15)
hwnd = findwindows.find_windows(title=u"InstallShield Wizard", class_name="MsiDialogCloseClass")
print ("|", str(hwnd), "|")
dlg = app.Window_(handle=hwnd).Wait("enabled", timeout=25, retry_interval=0.5)
Now I want to click the Next button. Swapy says that the Next button has the text '&Next >' and the Button number is 1. But none of these click statements have any effect.
dlg.Click("Next")
dlg.Click(coords=(977, 711))
dlg.Click(button="left")
You misapply Click method. It has the next signatire - Click(button=u'left', pressed=u'', coords=(0, 0), double=False, absolute=False)
To click a button, click should be performed on the button object. So you shoud navigate to the button at first.
In your case the code may look something like:
dlg['&Next >'].Click()
Again, please do not guess, read the docs and see the examples

(no longer seeking answers) Python input box inside a message box

is there any way to have an input box inside of an message box opened with the ctypes library? so far I have:
import ctypes
messageBox = ctypes.windll.user32.MessageBoxA
title = 'Title'
text = 'Message box!'
returnValue = messageBox(None, text, title, 0x40 | 0x1)
print returnValue
and this gives a message box with an image icon and two buttons, both of which I know how to change, and it sets a variable "returnValue" to a number representing the button clicked. However, I also need a variable that will set to a string input in the message box. The reason I need this and I can't just do simple a = raw_input('prompt') is that I want the program itself to run in the background (it would launch itself on logon).
If you want a simple solution, use the PyMsgBox module. It uses Python's built-in tkinter library to create message boxes, including ones that let the user type a response. Install it with pip install pymsgbox.
The documentation is here: https://pymsgbox.readthedocs.org/
The code you want is:
>>> import pymsgbox
>>> returnValue = pymsgbox.prompt('Message box!', 'Title')
Message box is for messages only. What you need is QDialog. You can create it in QtDesigner(I have login dialog created this way, with 2 QLineEdit for username and pass, 2 buttons in QDialogButtonBox and QCombobox for language choose). You'll get .ui file, which you'll need to convert into .py this way in cmd:
pyuic4 -x YourLoginDialogWindow.ui -o YourLoginDialogWindow.py
import created YourLoginDialogWindow.py and you can use it and implement any method you need:
import YourLoginDialogWindow
class YourLoginDialog(QtGui.QDialog):
def __init__(self, parent = None):
super(YourLoginDialog, self).__init__(parent)
self.__ui = YourLoginDialogWindow.Ui_Dialog()
self.__ui.setupUi(self)
...
self.__ui.buttonBox.accepted.connect(self.CheckUserCredentials)
self.__ui.buttonBox.rejected.connect(self.reject)
def GetUsername(self):
return self.__ui.usernameLineEdit.text()
def GetUserPass(self):
return self.__ui.passwordLineEdit.text()
def CheckUserCredentials(self):
#check if user and pass are ok here
#you can use self.GetUsername() and self.GetUserPass() to get them
if THEY_ARE_OK :
self.accept()# this will close dialog and open YourMainProgram in main
else:# message box to inform user that username or password are incorect
QtGui.QMessageBox.about(self,'MESSAGE_APPLICATION_TITLE_STR', 'MESSAGE_WRONG_USERNAM_OR_PASSWORD_STR')
in your __main__ first create login dialog and then your main window...
if __name__ == "__main__":
qtApp = QtGui.QApplication(sys.argv)
loginDlg = YourLoginDialog.YourLoginDialog()
if (not loginDlg.exec_()):
sys.exit(-1)
theApp = YourMainProgram.YourMainProgram( loginDlg.GetUsername(), loginDlg.GetPassword())
qtApp.setActiveWindow(theApp)
theApp.show()
sys.exit(qtApp.exec_())

Clicking a link inside a frame works in debug mode but not otherwise

I am using the following: Selenium 2.33.0, Python 2.7.3, Firefox 21.0, Debian Wheezy:
Using selenium, I have to click on a logout button which is inside a frame to logout of the site. The below code works in debug mode. In normal mode, the script executes the below logout method without raising any exceptions but the Logout() JavaScript method isn't being executed.
Can any one either point out what I am doing wrong, or suggest a better or alternative way to accomplish the logout functionality using selenium.
The following code works only in debug mode:
class BankInfo:
...
logout_btn_selector='//a/img[#src="preferred/gif/logoutbtn.gif"]/..'
...
class Automaton():
self.browser = webdriver.Firefox(firefox_profile=self.get_browser_preferences())
self.bank_info = BankInfo
def click_button_by_xpath(self, btn_xpath):
btn = self.browser.find_element_by_xpath(btn_xpath)
btn.click()
def logout(self, logout_btn_selector):
self.browser.switch_to_default_content()
self.browser.switch_to_frame('common_menu1')
self.click_button_by_xpath(logout_btn_selector)
def execute(self):
...
self.logout(self.bank_info.logout_btn_selector)
...
if __name__ == '__main__':
Automaton.execute()
The markup for the page in which the button resides:
I added a the following line in get_browser_preferences() method:
firefox_profile.set_preference("browser.download.useToolkitUI", True)
I suspect that the download window which has the link "Show all downloads" was preventing the selenium webdriver to click on the logout button which was underneath the download window. The above setting prevented the download window from showing up.

A problem with downloading a file with Python

I try to automatically download a file by clicking on a link on the webpage.
After clicking on the link, I get the 'File Download' Window dialog with 'Open', 'Save' and 'Cancel' buttons. I would like to click the Save button.
I use watsup library in the following way:
from watsup.winGuiAuto import *
optDialog = findTopWindow(wantedText="File Download")
SaveButton = findControl(optDialog,wantedClass="Button", wantedText="Save")
clickButton(SaveButton)
For some reason it does not work. The interesting thing is that exactly the same
code works perfectly to click on 'Cancel' button, however it refuses to work with
'Save' or 'Open'.
Anybody knows what I should do?
Thank you very much,
Sasha
Sasha,
It is highly likely that the file dialog you refer to (the Security Warning file download dialog) will NOT respond to windows messages in this manner, for security reasons. The dialog is specifically designed to respond only to a user physically clicking on the OK button with his mouse. I think you will find that the Run button will not work this way either.
Try this:
from watsup.winGuiAuto import *
optDialog = findTopWindow(wantedText="File Download")
SaveButton = findControl(optDialog, wantedClass="Button", wantedText="Submit")
clickButton(SaveButton)
Sasha,
The code at this link is supposed to work. It uses ctypes instead of watsup.winGuiAuto, and relies on win32 calls. Here is the code:
from ctypes import *
user32 = windll.user32
EnumWindowsProc = WINFUNCTYPE(c_int, c_int, c_int)
def GetHandles(title, parent=None):
'Returns handles to windows with matching titles'
hwnds = []
def EnumCB(hwnd, lparam, match=title.lower(), hwnds=hwnds):
title = c_buffer(' ' * 256)
user32.GetWindowTextA(hwnd, title, 255)
if title.value.lower() == match:
hwnds.append(hwnd)
if parent is not None:
user32.EnumChildWindows(parent, EnumWindowsProc(EnumCB), 0)
else:
user32.EnumWindows(EnumWindowsProc(EnumCB), 0)
return hwnds
Here's an example of calling it to click the Ok button on any window that has
the title "Downloads properties" (most likely there are 0 or 1 such windows):
for handle in GetHandles('Downloads properties'):
for childHandle in GetHandles('ok', handle):
user32.SendMessageA(childHandle, 0x00F5, 0, 0) # 0x00F5 = BM_CLICK
It's possible that the save button is not always enabled. While it may look to your eye that it is, a program might see an initial state that you're missing. Check it's state and wait until it's enabled.
[EDIT] But it's possible that Robert is right and the dialog will just ignore you for security reasons. In this case, I suggest to use BeautifulSoup to parse the HTML, extract the URL and download the file in Python using the urllib2 module.

Categories