Python tkinter.filedialog askfolder interfering with clr

2024/9/24 9:38:26

I'm mainly working in Spyder, building scripts that required a pop-up folder or file Browse window.

The code below works perfect in spyder. In Pycharm, the askopenfilename working well, while askdirectory do nothing (stuck). But, if running in debug mode - the script works well. I tried to run the script from SAS jsl - same issue.

Any Idea what should I do? Python 3.6 Pycharm 2017.2

Thanks.

The Code I'm using includes:

import clr #pythonnet 2.3.0
import os
import tkinter as tk
from tkinter.filedialog import (askdirectory,askopenfilename)root = tk.Tk()
root.withdraw()
PPath=askdirectory(title="Please select your installation folder location", initialdir=r"C:\Program Files\\")t="Please select jdk file"
if os.path.exists(os.path.expanduser('~\Documents')):FFile = askopenfilename(filetypes=(("jdk file", "*.jdk"),("All Files", "*.*")),title=t, initialdir=os.path.expanduser('~\Documents'))
else:FFile= askopenfilename(filetypes=(("jdk file", "*.jdk"),("All Files", "*.*")),title=t)sys.path.append(marsDllPath)
a = clr.AddReference('MatlabFunctions')
aObj = a.CreateInstance('Example.MatlabFunctions.MatLabFunctions')

edit: seems like issue related to the pythonnet "imoprt clr", but I do need it in the code.

Similar question asked here: https://github.com/pythonnet/pythonnet/issues/648

Answer

Your problem is rather mediocre, although not so obvious. The problem is not in tinker or pythonnet, it stems from the COM threading model.

To begin with, since you're using the clr, let's try to use dialogs directly with it (it's not absolutely necessary to import the tinker module):

#   importing pythonnet
import clr#   adding reference (if necessary) to WinForms and importing dialogs
#   clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import OpenFileDialog, FolderBrowserDialog#   creating instances of dialogs
folder_dialog = FolderBrowserDialog()
file_dialog = OpenFileDialog()#   try to show any of them
folder_dialog.ShowDialog()
file_dialog.ShowDialog()

As you can see, it hangs just like in your case. The reason, as was mentioned above, stems from the threading's apartment state([1], [2]).

Therefore the clr implicilty sets this state to MTA (Multi-threaded apartment), which can be tested via CoGetApartmentType function:

#   importing ctypes stuff
import ctypes
get_apartment = ctypes.windll.ole32.CoGetApartmentType#   comment/uncomment this import to see the difference
#   import clrapt_type = ctypes.c_uint(0)
apt_qualifier = ctypes.c_uint(0)if get_apartment(ctypes.byref(apt_type), ctypes.byref(apt_qualifier)) == 0:#   APPTYPE enum: https://msdn.microsoft.com/en-us/library/windows/desktop/ms693793(v=vs.85).aspx#   APTTYPEQUALIFIER enum: https://msdn.microsoft.com/en-us/library/windows/desktop/dd542638(v=vs.85).aspxprint('APTTYPE = %d\tAPTTYPEQUALIFIER = %d' % (apt_type.value, apt_qualifier.value))
else:print('COM model not initialized!')

However, many older COM objects, such as shell dialogs, require STA mode. Good explanation about the difference between those two states can be found here or there.

Finally, the solutions:

1) Use STA thread for dialogs:

#   importing tkinter stuff
import tkinter as tk
from tkinter.filedialog import askdirectory, askopenfilename#   importing pythonnet
import clr#   adding reference (if necessary) to WinForms and importing dialogs
#clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import OpenFileDialog, FolderBrowserDialog#   adding reference (if necessary) to Threading and importing Thread functionality
#clr.AddReference('System.Threading')
from System.Threading import Thread, ThreadStart, ApartmentState#   WinForms thread function example
def dialog_thread():folder_dialog = FolderBrowserDialog()file_dialog = OpenFileDialog()folder_dialog.ShowDialog()file_dialog.ShowDialog()#   Tk thread function example
def tk_dialog_thread():root = tk.Tk()root.withdraw()askdirectory()askopenfilename()#   check again apartment state at start
current_state = Thread.CurrentThread.GetApartmentState()
if current_state == ApartmentState.STA:print('Current state: STA')
elif current_state == ApartmentState.MTA:print('Current state: MTA')#   start dialogs via CLR
thread = Thread(ThreadStart(dialog_thread))
thread.SetApartmentState(ApartmentState.STA)
thread.Start()
thread.Join()#   start dialogs via Tkinter
thread = Thread(ThreadStart(tk_dialog_thread))
thread.SetApartmentState(ApartmentState.STA)
thread.Start()
thread.Join()

2) Force STA mode via CoInitialize/CoInitializeEx before CLR does so for MTA:

#   importing ctypes stuff
import ctypes
co_initialize = ctypes.windll.ole32.CoInitialize#   importing tkinter stuff
import tkinter as tk
from tkinter.filedialog import askdirectory, askopenfilename#   Force STA mode
co_initialize(None)# importing pythonnet
import clr #   dialogs test
root = tk.Tk()
root.withdraw()askdirectory()
askopenfilename()
https://en.xdnf.cn/q/71684.html

Related Q&A

Run a function for each element in two lists in Pandas Dataframe Columns

df: col1 [aa, bb, cc, dd] [this, is, a, list, 2] [this, list, 3]col2 [[ee, ff, gg, hh], [qq, ww, ee, rr]] [[list, a, not, 1], [not, is, this, 2]] [[this, is, list, not], [a, not, list, 2]]What Im tryin…

cannot filter palette images error when doing a ImageEnhance.Sharpness()

I have a GIF image file. I opened it using PIL.Image and did a couple of size transforms on it. Then I tried to use ImageSharpness.Enhance() on it...sharpener = PIL.ImageEnhance.Sharpness(img) sharpene…

Is there a PyPi source download link that always points to the lastest version?

Say my latest version of a package is on PyPi and the source can be downloaded with this url:https://pypi.python.org/packages/source/p/pydy/pydy-0.3.1.tar.gzId really like to have a url that looks like…

Can this breadth-first search be made faster?

I have a data set which is a large unweighted cyclic graph The cycles occur in loops of about 5-6 paths. It consists of about 8000 nodes and each node has from 1-6 (usually about 4-5) connections. Im d…

How to remove rows of a DataFrame based off of data from another DataFrame?

Im new to pandas and Im trying to figure this scenario out: I have a sample DataFrame with two products. df = Product_Num Date Description Price 10 1-1-18 Fruit Snacks 2.9910 1-2-18 …

Amazon S3 Python S3Boto 403 Forbidden When Signature Has + sign

I am using Django and S3Boto and whenever a signature has a + sign in it, I get a 403 Forbidden. If there is no + sign in the signature, I get the resource just fine. What could be wrong here?UPDATE: …

List comparison of element

I have a question and it is a bit hard for me to explain so I will be using lots of examples to help you all understand and see if you could help me.Say I have two lists containing book names from best…

Partition pyspark dataframe based on the change in column value

I have a dataframe in pyspark. Say the has some columns a,b,c... I want to group the data into groups as the value of column changes. SayA B 1 x 1 y 0 x 0 y 0 x 1 y 1 x 1 yThere will be 3 grou…

Error group argument must be None for now in multiprocessing.pool

Below is my python script.import multiprocessing # We must import this explicitly, it is not imported by the top-level # multiprocessing module. import multiprocessing.pool import timefrom random impor…

Making the diamond square fractal algorithm infinite

Im trying to generate an infinite map, as such. Im doing this in Python, and I cant get the noise libraries to correctly work (they dont seem to ever find my VS2010, and doing it in raw Python would be…