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
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 clr
apt_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).aspx
print('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()
I have tested the code which you pasted on Pycharm 2018.1.3 with python-3.6.5 installed on win-7 64 bit machine. It works fine without any error. There are few bugs in 2017 version. Try upgrading to latest version of Pycharm
Related
I use tkinter to do GUI. When use messagebox, that can not see title and showerror icon is a file, just like that:
enter image description here
This is my env:
macOS / windows 10
python 3.8.13
tk 8.6
And this is my code
import tkinter
from tkinter import messagebox
window = tkinter.Tk()
window.withdraw()
messagebox.showerror(title="error title", message="for test message")
window.destroy()
I want to see title and error icon, just like windows system.
How can I do to fix this progrem, thanks.
If there are features that are different for different operating systems, then you can determine the operating system like this:
import sys
p = sys.platform
if p == "linux" or p == "linux2":
# linux
print('using linux')
elif p == "darwin":
# OS X
print('using mac')
elif p == "win32":
# Windows...
print('using windows')
Alternatively the mac settings (so not tkinter). How are the error messages currently displayed on the pc as one would expect tkinter to be consistent with this.
I started having some issues with miniconda and PyCharm so I had to reinstall them. However, now when I use cx_freeze to create .exe I get the error below.
Here is my code:
from tkinter import *
from tkinter import ttk
from ttkthemes import ThemedTk
from ttkthemes import themed_tk as tk
import os
from tkinter import messagebox
import getpass
import pyodbc
import test
import time
class Application(object):
def __init__(self,master):
self.master=master
self.itemIn = ttk.Button(master, text="In", width=35,
command=self.itemIn).grid(row=2, column=0, padx=10,pady=15)
self.itemOut = ttk.Button(master, text="Out", width=35,
command=self.itemOut).grid(row=3, column=0, padx=10)
def itemIn(self):
pass
def itemOut(self):
pass
def main():
global userList
strForDB = os.getcwd() + '\DBINFO.txt'
openDBFile = open(strForDB, 'r')
currentDirForDB = openDBFile.read()
openDBFile.close()
dbPath = currentDirForDB
conToSubmit = pyodbc.connect(dbPath)
curToSubmit = conToSubmit.cursor()
userName = getpass.getuser()
root = tk.ThemedTk()
root.get_themes()
root.set_theme("radiance")
app=Application(root)
root.title("Main Menu v:5.1")
root.configure(background="#F4F3F1")
root.resizable(0, 0)
# Change Application Icon with below:
root.wm_iconbitmap(os.getcwd()+'/Z Logo.ico')
### To maximize
# w, h = root.winfo_screenwidth(), root.winfo_screenheight()
# root.geometry("%dx%d+0+0" % (w, h))
root.geometry('340x510+300+80')
root.mainloop()
#else:
# messagebox.showerror("Access Denied", "You are not allowed to access this application.")
# return
if __name__=='__main__':
main()
This is cx_freeze build script, where I have imported all the relevant modules.
import cx_Freeze
import os
from cx_Freeze import *
import sys
if sys.platform == "win32":
base = "Win32GUI"
imodules=['tkinter','pyodbc','getpass','pathlib','openpyxl','datetime','os','win32print','win32ui'] #modules to include
emodules=[] ###modules to NOT include
#(useful if a module is forcefully installed
#even if you don't want that module)
build_exe_options={"packages":imodules,"excludes":emodules}
setup(
name= "WMS System",
options={"build_exe":build_exe_options},description="App to track Inventory",author="VM",
executables=[
Executable(
"WMS.py", base=base, icon="Z logo.ico"
)
]
)
I have been using cx_freeze for quite some time but I have never seen this error.
I was having identical problem as you and after a long troubleshooting session I found out that
in /lib folder of my build i had "Tkinter" folder, renaming it to "tkinter" solved the above issue
any following errors of the type module not found could be solved by either adding them to the "includes" tag of build options or finding and copying the whole module folder yourself from python installation folder
The folder name in project must be "lib/tkinter", but maybe it is "lib/Tkinter", then you must rename the folder from "Tkinter" to "tkinter".
I try to build my (fine working) python 3.6 tkinter gui app to a windows excecutable. After hours of trial an error (with some name and dll issues) I got it to run. But it seems to have varoius of bugs. Some functions seem not to work and I have no console output of the produced error... is there a way to debug the exe?
this is my setup.py
import sys
from cx_Freeze import setup, Executable
import os
os.environ['TCL_LIBRARY'] = r'C:\Users\xxx\AppData\Local\Programs\Python\Python36\tcl\tcl8.6'
os.environ['TK_LIBRARY'] = r'C:\Users\xxx\AppData\Local\Programs\Python\Python36\tcl\tk8.6'
base = None
if sys.platform == 'win32':
base = 'Win32GUI'
executables = [
Executable('myApp.py', base=base)
]
build_exe_options = {"packages": ["tkinter",
"PIL",
"savReaderWriter",
"numpy",
"scipy",
"os"],
"include_files": ["tcl86t.dll",
"tk86t.dll"]}
setup(name='myApp',
version='0.1',
description='some description',
options = {'build_exe': build_exe_options},
executables=executables
)
myApp.py
is too big to post it here. This is a snippet that only works 'unfreezed'. You need an spss.sav file like this to try this out.
from tkinter import *
from tkinter import ttk, filedialog, messagebox
from PIL import Image, ImageTk, ImageDraw
from savReaderWriter import SavReader
import numpy as np
from scipy.ndimage import gaussian_filter
import os
class MyApp:
spss_file = None
def import_spss(self, *args):
filename = filedialog.askopenfilename()
if filename:
try:
with SavReader(filename, returnHeader=True, ioUtf8=True) as reader:
spss_file = reader.all()
self.spss_file = np.array(spss_file)
except Exception as ex:
messagebox.showinfo(title="Import SPSS File",
message="Warning: wrong file format chosen! \nAccepted formats: sav")
print(ex)
return
else:
return
def main():
App = MyApp()
App.import_spss()
print("everything works fine")
main()
if you want the console window to appear, after it is frozen, just remove this code from the setup script:
if sys.platform == 'win32':
base = 'Win32GUI'
what that code does is it tells cx_Freeze to have the console window not show up, after frozen. this is only required on windows, because on other OSes,it depends on whether or not it was run from a terminal. make sure though, when you have finished debugging it, to put that code back in, or the console window will show up in your app.
by the way, one of the most annoying problems I've ever had was when making a program with tkinter and cx_Freeze. the problem was that it was starting in the wrong directory and not able to find the TK Dll. If when you run this with the console, and you see something about a file not found, chances are you are not including it or it is in the wrong directory.
have a good day!
import sys
from cx_Freeze import setup, Executable
build_exe_options = {'packages': ['os','tkinter','random',
'heapq','collections','sys','pickle']}
base = None
if sys.platform == "win32":
base = "Win32GUI"
setup( name = 'Game',
version = '0.02',
description = 'My GUI application!',
options = {'build_exe': build_exe_options},
executables = [Executable('Game.py', base=base)])
here's the code of the setup
from tkinter import *
value_a = 'hahaha'
a =messagebox.showinfo('laugh',value_a)
and the code that would executed
the erorr is Nameerorr : name "messagebox" is not defined when I typed python 123.py build or python haha.py build in cmd
I already used import *, if I run the code it shows message but neither in cmd nor .exe
Should I use import tkinter as tk? But it is difficult to read my code by adding "tk", I want to keep import * so that no "tk.xxx" is needed and it will still works on exe.
from tkinter import * does not work for messagebox, so you must import the message box individually like below
from tkinter import messagebox
I had this problem too. It worked OK in the IDE but not in direct run mode.
Adding import tkinter.messagebox as messagebox fixed the problem.
Thanks, G.
I'm trying to open a simple file dialog to ask the user to select a file. The code I have is:
from Tkinter import Tk
from tkFileDialog import askopenfilename
Tk().withdraw()
filename = askopenfilename()
print(filename)
sys.exit(0)
The program retrieves the file name successfully, however the window remains open and does not close. The only way I can exit it is through Force Quit. I am using Mac OS X 10.11 and Python 2.7.11.
Thank you
There seems to be some issues based on your development environment. See reference [2]. This worked for me:
from Tkinter import Tk
from tkFileDialog import askopenfilename
root = Tk() #To initialize Tkinter, we have to first create a Tk root widget
filename = askopenfilename() # store filename
# root.mainloop() may be necessary for your development environment (see [2])
root.destroy() #destroy the event loop - only required in some python environments (see [2])
print(filename)
[1] http://effbot.org/tkinterbook/tkinter-hello-tkinter.htm
[2] http://effbot.org/tkinterbook/tkinter-hello-again.htm