Python PyInstaller Tkinter Button Tied to Messagebox Does Nothing - python

I have a tiny button with a question mark in my app. When clicked, it displays the doc string from a function in my app which helps to explain what the app does.
The problem is, I build a single .exe using pyinstaller and this question mark button does nothing when clicked.
Recreation Steps
save the file below as run.py
open command-prompt
paste pyinstaller.exe --onefile --windowed run.py
go to dist folder and run single exe
click ? button and notice it does nothing
run.py below
import tkinter as tk
from tkinter import ttk
''' pyinstaller.exe --onefile --windowed run.py '''
def someotherfunction():
'''
This is some message that I
want to appear but it currently doesn\'t
seem to work
when I put try to launch a messagebox
showinfo window...
'''
pass
def showhelpwindow():
return tk.messagebox.showinfo(title='How to use this tool',
message=someotherfunction.__doc__)
root = tk.Tk()
helpbutton = ttk.Button(root, text='?', command=showhelpwindow, width=2)
helpbutton.grid(row=0, column=3, sticky='e')
root.mainloop()
My setup:
PyInstaller 3.2
Windows 7
Python 3.4.2
I tried adding --noupx option but that didn't fix it.
EDIT:
I removed --windowed option this time and the console is now showing me an error when I click this button.
Exception in Tkinter callback
Traceback (most recent call last):
File "tkinter\__init__.py", line 1533, in __call__
File "run.py", line 156, in showhelpwindow
AttributeError: 'module' object has no attribute 'messagebox'

Line 3 below is the solution. I needed to import the tkinter.messagebox module explicitly.
import tkinter as tk
from tkinter import ttk
import tkinter.messagebox
''' pyinstaller.exe --onefile --windowed run.py '''
def someotherfunction():
'''
This is some message that I
want to appear but it currently doesn\'t
seem to work
when I put try to launch a messagebox
showinfo window...
'''
pass
def showhelpwindow():
return tk.messagebox.showinfo(title='How to use this tool',
message=someotherfunction.__doc__)
root = tk.Tk()
helpbutton = ttk.Button(root, text='?', command=showhelpwindow, width=2)
helpbutton.grid(row=0, column=3, sticky='e')
root.mainloop()

Related

can't invoke “event” command: application has been destroyed

I have a simple code (test.py) to generate a popup window as shown below. It works fine when I run it directly in console.
import tkinter as tk
from tkinter.messagebox import showinfo
def popup():
print("Hello World!")
root1 = tk.Tk()
b1 = tk.Button(root1, text="Print", command=popup)
b1.pack(fill='x')
root1.mainloop()
But when I call this code (test.py) from another py script by
exec(open('test.py').read())
It gives error message "can't invoke “event” command: application has been destroyed". I have checked the prior discussion on this topic, but it doesn't seem to help my case.
can't invoke "event" command: application has been destroyed
Can anybody please help? Thanks!

how can i open multiple windows in tkinter in another file?

i have a problem in my code in python (tkinter)
I have two files (F1.py) and (F2.py), each of which is a window, and I have another file called (main.py) that opens a window with two buttons, I want to click one of the (F1) files every time Or (F2) open.
What should I do ?
this is my code:
from tkinter import *
main = Tk()
def f1():
import f1.py
# I do not know what to do to run the file f1.py here !!
def f2():
import f2.py
# I do not know what to do to run the file f2.py here !!
btn_f2 = Button(main,text="open f2",command=f2).pack()
btn_f1 = Button(main,text="open f1",command=f1).pack()
mainloop()
Here is the work around according to your need, Since you want to execute your other tkinter window from your main python script. Here is the way to do that.
in your main.py
from tkinter import *
import os
import sys
import f1,f2
main= Tk()
def open(filename):
os.chdir("D:\\PYTHON_FILES\\") #change this path to your path where your f1.py and f2.py is located
# print("current dir "+os.getcwd())
os.system('python '+filename) #runnning the python command on cmd to execute both windows
btn_f2 = Button(main,text="open f2",command=lambda: open("f1.py")).pack()
btn_f1 = Button(main,text="open f1",command=lambda: open("f2.py")).pack()
main.mainloop()
Now define f1.py for example
from tkinter import *
window= Tk()
window.title('f1 Hello Python')
window.geometry("300x200+10+10")
mainloop()
Similarly for example we have f2.py
from tkinter import *
window= Tk()
window.title('f2 Hello Python')
window.geometry("300x200+10+10")
mainloop()
Now If you want to go for the legit way using TopLevel in Tinkter as #Matiis Described then here is clean and perfect way to achieve the goal.
Simply make a main.py as below
from tkinter import *
root = Tk()
root.geometry("200x200")
#here define your f1 window
def f1():
top = Toplevel(root)
top.geometry("400x400")
top.title("I am f1 window smaller than f2 but bigger than root")
top.mainloop()
#Similarly here define your f2 window
def f2():
top = Toplevel(root)
top.geometry("500x500")
top.title("I am f2 window bigger than f1")
top.mainloop()
btn1 = Button(root, text = "open f1", command = f1)
btn2 = Button(root, text = "open f2", command = f2)
btn1.place(x=75,y=50)
btn2.place(x=75,y=20)
root.mainloop()
I might be a little late with this, but I've recently started learning python and I had the same issue with tkinter. I had a "main.py" file and I wanted it to open "f1.py" by clicking a button.
I realized that when you configure a button in tkinter you have to assign a function so I wrote "main.py" as a regular pyhon/tkinter file importing f1.py:
from tkinter import *
from tkinter import ttk
import f1
main = Tk()
main.title("Main window")
but = Button(main, text="Open f1.py", command= f1.f1_func)
but.pack()
main.mainloop()
And instead of defining the function on the main file (def but_openwindow(): etc...) I wrote that function on the "f1.py" but JUST as a function, not as a mainloop. So the f1.py would be something like this:
from tkinter import *
from tkinter import ttk
def f1_func():
other = Toplevel()
other.title("Other window")
text = Label(other, text="This is another window")
text.pack()
And you could repeat it for any number of other .py files. So far I found out 2 important things:
1- I thought it wouldn't be necessary, but apparently you have to start f1.py importing tkinter libraries, otherwise it wouldn"t work. At least for me it didn't.
2- The files that you want to import can't have a "mainloop" or it just opens the other window as soon as you execute the main file.
I have yet to try to make an .exe of the main file, but I'm hoping to get there.
Sorry again for being late, hope it helps, if not for you, at leas for anyone else that might encounter this same problem.

How do you execute another file when a button is pressed(tkinter) in Python?

I'm trying to make a launcher for another program but I just started with Python so I made a button, but I struggle to figure out how to execute another .py file. Any help?
When the button is pressed it activates the open_file() function and os opens the .py script.
from tkinter import *
import os
def open_file():
os.system('python file path here')
root=Tk()
btn = Button(root, text='Open .PY File', command=open_file)
btn.pack()
root.mainloop()
Here is a solution using from subprocess import call. All you have to do is replace 'YOUR_FILE_NAME' with... your file name :D
from tkinter import *
from subprocess import call
root=Tk()
root.geometry('200x100')
frame = Frame(root)
frame.pack(pady=20,padx=20)
def Open():
call(["python", "YOUR-FILE-NAME.py"])
btn=Button(frame,text='Open File',command=Open)
btn.pack()
root.mainloop()
What it will look like:
I hope this works for you :D

Python: Tkinter iconbitmap assignment only works at module level

I'm using a tkinter.ttk window and I'm using an icon to set the iconbitmap of my window. However root.iconbitmap() is ignored on Windows 10. But There is an easy way to avoid an error: root.tkinter.call('wm', 'iconphoto', root._w, icon)
So:
from tkinter import *
from tkinter.ttk import *
root=Tk()
root.call('wm', 'iconphoto', root._w, icon)
works.
BUT:
def func():
root=Tk()
root.call('wm', 'iconphoto', root._w, icon)
does NOT work. An error occurs. It's interesting that that error is exactly the same one that occurs when you use root.iconbitmap():
Traceback (most recent call last):
File "E:\test.py", line 95, in <module>
func()
File "E:\test.py", line 36, in func
t.call('wm', 'iconphoto', t._w, icon)
_tkinter.TclError: can't use "pyimagex" as iconphoto: not a photo Image
And there is one interesting fact left: In another file I tried to use it as a function too, it worked. In the new file (test.py) it didn't work (and it was the same function).
Does anybody know why it doesn't work and what I can do to avoid an error? Thanks in advance...
If you've a window opened already and wants to open another one with it's own icon then you should use Toplevel() instead of Tk() and to change the icon use
W2 = Toplevel()
icon = PhotoImage(file='icon.png')
W2.tk.call('wm', 'iconphoto', root._w, icon)
Example:
from tkinter import *
from tkinter.ttk import *
def test():
root = Toplevel()
icon = PhotoImage( file='icon.png' ) # path to the icon
root.tk.call('wm', 'iconphoto', root._w, icon)
r = Tk()
b = Button(r, text='press', command=test)
b.pack()
mainloop()

Python 3.6 tk ScrolledText on TopLevel won't insert

I am having issues with the code below when I use Pyinstaller to compile an executable.
I am attempting to open a second GUI window using TopLevel, adding a ScrolledText widget to it, then take the output of ipconfig /all and put it in the ScrolledText.
I stripped the code down to just the code relevant to this issue. If I run the python file directly, or compile with Pyinstaller without the --windowed command pyinstaller --onefile toolbox.py, then everything appears to work.
When I compile with --windowed pyinstaller --onefile --windowed toolbox.py, then the TopLevel window opens and I get the error message listed in the code and the ScrolledText widget is blank.
I have confirmed that using a normal string on the txt.insert command does work, so the issues appear to be with the os.popen command. I did attempt to use subprocess.check_output in place of os.popen but I get the same error message. Also, assigning the os.popen command to a variable then inserting the variable in txt.insert has the same result.
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from tkinter import scrolledtext
import os
import sys
def netIPInfo():
"""Open a second window, displays output of ipconfig /all."""
window2 = Toplevel()
window2.title("NIC IP Info")
window2.geometry("663x650")
txt = scrolledtext.ScrolledText(window2, width=80, height=40)
txt.pack(expand=1, fill="both")
try:
txt.insert(INSERT, os.popen("ipconfig /all").read()) # ISSUE!!
except:
e = sys.exc_info()
messagebox.showinfo("Error", e) # Error message below
# {<class 'OSError'}
# {[WinError 6] The handle is invalid}
# {<traceback object at 0x02EEB260>}
txt.configure(state="disabled")
window2.mainloop()
# Primary GUI Window
window = Tk()
window.title("ProTech QST")
tab_control = ttk.Notebook(window)
tab1 = ttk.Frame(tab_control)
tab_control.add(tab1, text='Network')
lfr5 = ttk.LabelFrame(tab1, text="Information")
lfr5.pack(fill=X)
btn30 = Button(lfr5, text="NIC IP Info")
btn30.config(width=18, command=netIPInfo)
btn30.grid(column=0, row=1, sticky=W)
tab_control.pack(expand=1, fill="both")
if __name__ == "__main__":
window.mainloop()
EDIT
I was playing with the code some more and found that if I run pyinstaller with --windowed but without --onefile it works. Same for running pyinstaller with --onefile but without --windowed. So is this an issue not with the code, but with pyinstaller?

Categories