How do I hook into tkinters FileDialog? - python

Using python 3 and tkinter I'm trying to create a file dialog that lets the user select existing directories (exists=True).
When they select choose I'd like to check that the directory is also readable and I can get a file lock. Since the rest of my program will rely read access to the path and it's processes will take a long time.
Whey they select cancel I'd like the dialog to close.
If the directory is not readable I'd like the file dialogue to display a askretry message. Clicking Retry will take them back to choose a file. clicking Cancel will close the dialogue.
In my first attempt, a novice to tkinter, I created this:
import os
from tkinter import filedialog
from tkinter import messagebox
class OpenDialog(object):
def __init__(self):
self.directory_path = None
self.dialog_title ="Photos Directory Selection"
def ask_for_directory(self):
while not self.directory_path:
self.directory_path = filedialog.askdirectory(mustexist=True, title=self.dialog_title)
if not os.access(os.path.dirname(self.directory_path), os.F_OK):
self.directory_path = None
if not messagebox.askretrycancel(title=self.dialog_title, message="Can't read directory."):
break
Although its not perfect. It won't let you cancel the file dialogue.
But alas, I thought I could potentially hook into the file dialogue itself...
I just can't see how I could cleanly hook into the FileDialogue class to cleanly display a askretry dialogue and repeat the process.
filedialogue.py
If there is something I'm missing please share :-)

This works, but does anyone see an issue with recursive call?
def ask_for_directory(self):
self.directory_path = filedialog.askdirectory(mustexist=True, title=self.dialog_title)
if self.directory_path:
# Check that we have access to the path
if not os.access(self.directory_path, os.R_OK):
# If we don't have access
if messagebox.askretrycancel(title=self.dialog_title, message="Can't read directory."):
self.ask_for_directory()
EDIT:
Here is my example but corrected to work...
def ask_for_directory(self):
while not self.directory_path:
self.directory_path = filedialog.askdirectory(mustexist=True, title=self.dialog_title)
if self.directory_path:
if not os.access(self.directory_path, os.R_OK):
self.directory_path = None
if not messagebox.askretrycancel(title=self.dialog_title, message="Can't read directory."):
break
else:
break

Related

Is there a way to lock and unlock an ___.exe file using python?

For example:- first the program should lock abc.exe file and the file should only be able to unlock or run when user enters the correct password for it.
This should happen using Python program, since this is just a submodule of a main program.
This program do locks the program but unlocking doesn't work.
'''
import locket
from tkinter import *
from tkinter import ttk
win = Tk()
win.title('SELECT THE PROGRAM')
path = "C:\\users\\admin\\abc\\abc.exe"
lock = locket.lock_file(path)
try:
lock.acquire()
finally:
lock.release()
#locket._unlock_file()
def close_win():
win.destroy()
def disable_event():
pass
btn = ttk.Button(win, text="Click here to Close", command=close_win)
btn.pack()
win.protocol("WM_DELETE_WINDOW", disable_event)
# Create a fullscreen window
win.attributes('-fullscreen', True)
win.mainloop()
'''
I played with your idea and "unlocking doesn't work" because the file is empty. When you try to lock the file the original file get 0 bytes and is not "unlocking" because windows can not run an empty executable file.
Try this for your self: Create an empty text file with any name and replace the extension of the file from txt to exe and try to run it. You will get same error message from windows.
In my case is look like this:
Now an work around for this is to move your original file some where in PC and rename it to something else with a different extension just to hide it from users and instead of the original file place a fake one with same name. After you get the user condition of using the file you can move it back. Roaming is most common directory for software's to save some extra files and is locket-ed under "C:\Users\USERNAME\AppData\Roaming"
I will not provide you the source code for this, instead I will let you to think on your own logic. As an hint you will need to search for os library for moving the files under a different name and file handeling.

pyside widget.show not blocking

I wrote a little application, that saves small videos it generates. The code pasted should do the following:
show dialog to the user to choose a directory
if directory is not empty show widget that has a circle running around so there's a feedback that something is going on
then generate the movies (which takes some time and most if it has handled with multiprocessing pool)
(not included in snippet, but the code would go on to do more background stuff, so the loading widget would stay on for a while
Code:
def saveMovie(self):
self.pause()
if not os.path.exists("outputs"):
os.makedirs("outputs")
dir = QtGui.QFileDialog.getExistingDirectory(self,dir="outputs",options=QtGui.QFileDialog.ShowDirsOnly)
if not dir == '':
self.loading = True
self.loadingWidget.show()
name = os.path.basename(dir) + "_"
settings = sm.fetch_settings()
swarms,l,l1,l2 = self.generate_movies()
Now instead of this, what happens is that the dialog disappears and the loading widget is shown only after the program has existed from self.generate_movies(). What am I missing?

In python is there a way to use the windows explorer to create a file path which can then be returned as a string?

I am making a program to manage a database and i need a nice way of choosing the save locations of files within the program. I was wondering if it is possible to open windows explore from my program, select a folder to save a file in, enter the file name and return the file path as a string to the main program.
Look up the Tkinter options in tkFileDialog
I don't think you necessarily need to put together a fully working GUI, you can simply call the method and select a folder location and then use that selected location in your code.
A simplistic example would be:
import Tkinter, tkFileDialog
root = Tkinter.Tk()
x = tkFileDialog.askopenfilename() # Can pass optional arguments for this...
root.destroy()

Which is the best way to interact with already open native OS dialog boxes like (Save AS) using Python?

Is there any efficient way using any Python module like PyWind32 to interact with already existing Native OS dialog boxes like 'Save As' boxes?
I tried searching on Google but no help.
EDIT:
1: The Save As dialog box is triggered when user clicks on a Save As dialog box on a web application.
2: Any suggestion are welcome to handle any native OS dialog boxes which are already triggered using Python.(Need not be specific to Selenium webdriver, I am looking for a generic suggestion.)
(When I was posting the question I thought that by 'interacting with a dialog box' will implicitly mean that it is an existing one as if I am able to create one then surely I can interact with it as it is under my programs control. After reading the first 2 answers I realized I was not explicitly clear. Thats why the EDIT )
Thanks
While looking for a possible solution for this I came across several solutions on SO and otherwise.
Some of them were using AutoIT, or editing browsers profile to make it store the file directly without a prompt.
I found all this solution too specific like you can overcome the issue for Save As dialog by editing the browser profile but if later you need to handle some other window then you are stuck.
For using AutoIT is overkill, this directly collides for the fact I choose Python to do this task. (I mean Python is itself so powerful, depending on some other tool is strict NO NO for any Pythonist)
So after a long search for a possible generic solution to this problem which not only serves any one who is looking to handle any Native OS dialog boxes like 'Save As', 'File Upload' etc in the process of automating a web application using selenium web driver but also to any one who wants to interact with a specific window using only Python APIs.
This solution makes use of Win32gui, SendKeys modules of Python.
I will explain first a generic method to get hold of any window desired then a small code addition which will also make this usable while automating a web application using Selenium Webdriver.
Generic Solution::
import win32gui
import re
import SendKeys
class WindowFinder:
"""Class to find and make focus on a particular Native OS dialog/Window """
def __init__ (self):
self._handle = None
def find_window(self, class_name, window_name = None):
"""Pass a window class name & window name directly if known to get the window """
self._handle = win32gui.FindWindow(class_name, window_name)
def _window_enum_callback(self, hwnd, wildcard):
'''Call back func which checks each open window and matches the name of window using reg ex'''
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) != None:
self._handle = hwnd
def find_window_wildcard(self, wildcard):
""" This function takes a string as input and calls EnumWindows to enumerate through all open windows """
self._handle = None
win32gui.EnumWindows(self._window_enum_callback, wildcard)
def set_foreground(self):
"""Get the focus on the desired open window"""
win32gui.SetForegroundWindow(self._handle)
win = WindowFinder()
win.find_window_wildcard(".*Save As.*")
win.set_foreground()
path = "D:\\File.txt" #Path of the file you want to Save
ent = "{ENTER}" #Enter key stroke.
SendKeys.SendKeys(path) #Use SendKeys to send path string to Save As dialog
SendKeys.SendKeys(ent) #Use SendKeys to send ENTER key stroke to Save As dialog
To use this code you need to provide a string which is the name of the window you want to get which in this case is 'Save As'. So similarly you can provide any name and get that window focused.
Once you have the focus of the desired window then you can use SendKeys module to send key strokes to the window which in this case includes sending file path where you want to save the file and ENTER.
Specific to Selenium Webdriver::
The above specified code segment can be used to handle native OS dialog boxes which are triggered through a web application during the automation using Selenium Webdriver with the addition of little bit of code.
The issue you will face which I faced while using this code is that once your automation code clicks on any Web Element which triggers a native OS dialog window, the control will stuck at that point waiting for any action on the native OS dialog window. So basically you are stuck at this point.
The work around is to generate a new thread using Python threading module and use it to click on the Web Element to trigger the native OS dialog box and your parent thread will be moving on normally to find the window using the code I showed above.
#Assume that at this point you are on the page where you need to click on a Web Element to trigger native OS window/dialog box
def _action_on_trigger_element(_element):
_element.click()
trigger_element = driver.find_element_by_id('ID of the Web Element which triggers the window')
th = threading.Thread(target = _action_on_trigger_element, args = [trigger_element]) #Thread is created here to call private func to click on Save button
th.start() #Thread starts execution here
time.sleep(1) #Simple Thread Synchronization handle this case.
#Call WindowFinder Class
win = WindowFinder()
win.find_window_wildcard(".*Save As.*")
win.set_foreground()
path = "D:\\File.txt" #Path of the file you want to Save
ent = "{ENTER}" #Enter key stroke.
SendKeys.SendKeys(path) #Use SendKeys to send path string to Save As dialog
SendKeys.SendKeys(ent) #Use SendKeys to send ENTER key stroke to Save As dialog
#At this point the native OS window is interacted with and closed after passing a key stroke ENTER.
# Go forward with what ever your Automation code is doing after this point
NOTE::
When using the above code in automating a web application, check the name of the window you want to find and pass that to find_window_wildcard(). The name of windows are browser dependent. E.g. A window which is triggered when you click on an Element to Upload a file is called 'File Upload' in Firefox and Open in Chrome.
Uses Python2.7
I hope this will help any one who is looking for a similar solution whether to use it in any generic form or in automating a web application.
EDIT:
If you are trying to run your code through command line arguments then try to use the thread to find the window using Win32gui and use the original program thread to click on the element (which is clicked here using the thread). The reason being the urllib library will throw an error while creating a new connection using the thread.)
References::
SO Question
SenKeys
Win32gui
There is a Python module called win32ui. Its found in the Python for Windows extensions package. You want the CreateFileDialog function.
Documentation
Edit:
This is a save dialog example. Check the documentation for the other settings.
import win32ui
if __name__ == "__main__":
select_dlg = win32ui.CreateFileDialog(0, ".txt", "default_name", 0, "TXT Files (*.txt)|*.txt|All Files (*.*)|*.*|")
select_dlg.DoModal()
selected_file = select_dlg.GetPathName()
print selected_file
from time import sleep
from pywinauto import Application, keyboard
app = Application(backend='uia').start('notepad.exe')
app.top_window().set_focus()
main = app.window(title='Untitled - Notepad', control_type='Window')
main.draw_outline(colour='red', thickness=2)
fileMenu = main.child_window(title='File')
fileMenu.draw_outline(colour='red', thickness=2)
fileMenu.click_input()
keyboard.send_keys("{VK_CONTROL}{VK_SHIFT}{S}")
sleep(2)
dlg = main.window(title='Save As')
dlg.draw_outline(colour='red', thickness=2)
savebtn = dlg.child_window(title='Save')
filePath = dlg.child_window(title='File name:', control_type='Edit')
savebtn.draw_outline(colour='red', thickness=2)
filePath.set_text('D:\\aa.txt')
filePath.draw_outline(colour='red', thickness=2)
savebtn.click_input()
I recommend using pywinauto lib.
If you have opened notepad and "Save as" dialog window:
from pywinauto import application
app = application.Application()
app.connect(title='test1.txt - Notepad')
app.SaveAs.Edit1.type_keys("test2.txt")
app.SaveAs.Save.click()

Python: win32gui.SetForegroundWindow

I have just written simple script to launch an applciation and I am trying to use "SendKeys" module to send keystrokes to this application. There is one "Snapshot" button, but I cant get Python to click "Snapshot" button, as the new window is not in focus. So I am planning to use Win32gui module's win32gui.FindWindow and win32gui.SetForegroundWindow functionality. But it gives me error- invalid handle. My app name is "DMCap"
Here is code snippet in Python:
handle = win32gui.FindWindow(0, "DMCap") //paassing 0 as I dont know classname
win32gui.SetForegroundWindow(handle) //put the window in foreground
Can anyone help me? Is this Python code correct? Can I send handle directly like this?
Your code should run just fine as-is, IF there is truly a window titled "DMCap." To get a list of handles and titles, run the code below:
import win32gui
def window_enum_handler(hwnd, resultList):
if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowText(hwnd) != '':
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
def get_app_list(handles=[]):
mlst=[]
win32gui.EnumWindows(window_enum_handler, handles)
for handle in handles:
mlst.append(handle)
return mlst
appwindows = get_app_list()
for i in appwindows:
print i
This will produce a list of tuples containing handle, title pairs.

Categories