Why won't Tkinter executable capture key combinations? - python

I'm building an tkinter app on Python 3.7 and creating an .exe with Pyinstaller 3.5 in Windoows 10. When running the code from the IDE, all intended keyboard commands work as expected. However, in the executable, key combinations do not work while single key presses are fine.
Here is some test code that demonstrates the problem:
import tkinter as tk
root = tk.Tk()
txt = tk.StringVar()
lbl = tk.Label(root, textvariable=txt)
def key_handle(event):
global txt
txt.set(event.keysym)
def kc_handle(event):
tk.messagebox.showinfo('Key Combo', 'Key Combo pressed')
root.bind('<Key>', key_handle)
root.bind('<Alt-b>', kc_handle)
lbl.pack()
root.mainloop()
Pyinstaller is then invoked as pyinstaller -w -F key_test.py.
One thing I do know is that the order of the binds doesn't seem to make a difference. How do I get key combinations working in the executable?

IDLE is built using tkinter and it could import all needed modules for own use and your code could work correctly but when you run it without IDLE then you have to import all modules which you use in code. In your example it will be
import tk.messagebox
BTW: Often similar problem is with mainloop(). IDLE aready runs mainloop() so code may work without own mainloop(). But normally (without IDLE) it needs to use mainloop(). It is good to check code in terminal/console/cmd.exe to see if it gives any errors.

Related

TKinter application runs perfectly fine in Visual Studio Code but crashes as an .exe

I have a TKinter application which i put together in Visual Studio Code. It runs perfectly fine in Visual Studio Code and does not freeze or anything like that. Because I want my program to run on other pcs as well, I created an .exe file using pyinstaller by running
pyinstaller --onefile -w "main.py"
This creates the desired .exe file without any problems. Sadly when put into an .exe file, my program crashes a lot, by crashing I mean that the window is not responding anymore or that the window just closes itself after some time.
I don't know if this is a commom problem but I honestly don't know what to do.
Apparently I don't have any problems in my code, because it runs perfectly fine in Visual Studio Code.
Is there anything I can do?
Edit 1:
My window freezes around these lines of my code:
I am trying to create 4 scales with a for loop:
for i in range(4):
scale = tk.Scale(self.root, state = "disabled", from_ = 100, to = 0)
scale.place(rely=0.2,relx=i*0.25,relwidth=0.25, relheight=0.8)
self.scales.append(scale)
Also I try to put my scales into the list self.scales so I can work with my scales later on. The program creates the first three scales without any problem but often fails to create the 4th.
EDIT 2:
I think I found a solution: Maybe the for loop is just too fast for Tkinter and it can't create the GUI items that fast, I added
time.sleep(0.1)
to my for loop, for now, this seems to work. But I dont really know if thats how its supposed to be.
EDIT 3:
Nevermind, this did not solve the problem. The problem has something to do with creating the scales.
I dont really know what to do.
Check out Logging, and the tutorial that comes with. After formatting to write to a file, you can put a few logging.info() here and there which can help determine the root cause of your error.
import logging
logging.basicConfig(filename='log.txt',
filemode='a',
format='%(asctime)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.INFO)
def my_func(x, y):
logging.info('Accessing Function: my_func()')
z = x + y
logging.info(f'Function myfunc() Successfully Completed, Variable Values: {x}, {y}, {z}')
my_func(2, 7)
Now you have a handy log.txt file which you can diagnose.
EDIT
Using the lines of code you provided, I tried out the following:
import tkinter as tk
class Application(tk.Frame):
def __init__(self, root=None):
super().__init__(root)
self.root = root
self.root.geometry('720x450')
self.pack()
self.scales = []
self.create_scale()
def create_scale(self):
for i in range(4):
scale = tk.Scale(self.root, state="disabled", from_=100, to=0)
scale.place(rely=0.2, relx=i*0.25, relwidth=0.25, relheight=0.8)
self.scales.append(scale)
gui = tk.Tk()
app = Application(root=gui)
app.mainloop()
I made an exe with PyInstaller 4.1, Python 3.9 and all four scales are properly produced on my screen so the problem isn't with those specific lines of code but how they interact with the rest of your code.
I can try finding out the root of your problem but I would need to see your full code or a minimal, reproducible example that successfully mimics the same problem you have.

How to open a program os.system only using python 3

I am programming a gui using tkinter. I use os.system('file extension'). when I click the button on the gui it should open the next program, but it wont because of python 2. I can use terminal and have pythem3 ./mixed_drink, and this works. Can I set up the code to make the program only run in python 3??
from tkinter import *
import os
##############
root = Tk()
root.title('GET YO DRANK MAIN ')
root.geometry("800x400")
def open_mixed_drinks():
os.system("/home/pi/mixed_drinks.py")
If I understand your question properly, try os.system("python3 /home/pi/mixed_drinks.py")
This way you are passing the .py file to the default installed python3 binary on your system, rather than the global default python which may still be 2.7 on many systems

How to cal tcl commands inside my python script using tkinter?

I am running my performance test on python and I want to call some Tcl commands using Tkinter inside my python script.
Can somebody please help me to write the code,
import Tkinter
root = Tkinter.Tk()
root.tk.eval('puts {printed by tcl}')
I tried simply above example, here when I do root=tkinter.tk() it opens up a window, I just want to execute my command and get the result
The code you have tried will not show any window until you put the root.mainloop(),but you can try something like this,
import tkinter
root = tkinter.Tk()
root.withdraw()
root.tk.eval('puts {printed by tcl}')
root.destroy()
root.mainloop()
here withdraw() will remove the window from the screen without destroying it and then you can perform your tasks and then destroy it at the end of code.

How to use idlelib.PyShell to embed an interpreter in a tkinter program?

I need to embed an interative python interpreter into my tkinter program. Could anyone help me out as to how to integrate it?
I have already looked at the main() function, but it's way to complex for my needs, but I can't seem to reduce it without breaking it.
Some details of what you must do may depend on what you want to do with IDLE's Shell once you have it running. I would like to know more about that. But let us start simple and make the minimum changes to pyshell.main needed to make it run with other code.
Note that in 3.6, which I use below, PyShell.py is renamed pyshell.py. Also note that everything here amounts to using IDLE's private internals and is 'use at your own risk'.
I presume you want to run Shell in the same process (and thread) as your tkinter code. Change the signature to
def main(tkroot=None):
Change root creation (find # setup root) to
if not tkroot:
root = Tk(className="Idle")
root.withdraw()
else:
root = tkroot
In current 3.6, there are a couple more lines to be indented under if not tkroot:
if use_subprocess and not testing:
NoDefaultRoot()
Guard mainloop and destroy (at the end) with
if not tkroot:
while flist.inversedict: # keep IDLE running while files are open.
root.mainloop()
root.destroy()
# else leave mainloop and destroy to caller of main
The above adds 'dependency injection' of a root window to the function. I might add it in 3.6 to make testing (an example of 'other code') easier.
The follow tkinter program now runs, displaying the both the root window and an IDLE shell.
from tkinter import *
from idlelib import pyshell
root = Tk()
Label(root, text='Root id is '+str(id(root))).pack()
root.update()
def later():
pyshell.main(tkroot=root)
Label(root, text='Use_subprocess = '+str(pyshell.use_subprocess)).pack()
root.after(0, later)
root.mainloop()
You should be able to call pyshell.main whenever you want.

Python Tkinter not working in a .py file

My problem is that my python code is not working when I run it as a .py file. Here is the code:
import tkinter
tk=tkinter.Tk()
canvas=tkinter.Canvas(tk, width=500, height=500)
canvas.pack()
There is more code to it than that, but that is the relevant stuff. It works fine when I use the python shell or type it directly into the python console, but when I run it as a .py file, it seems to skip this code and go on to the rest, without displaying a canvas. I am using windows, but I am not sure what version of python I'm using.
I was also using
from * import tkinter
before, with relevant changes to the code and i changed it to try and help fix it. It didn't work :(
You are missing the eventloop at the end:
import tkinter
tk=tkinter.Tk()
canvas=tkinter.Canvas(tk, width=500, height=500)
canvas.pack()
# Enter into eventloop <- this will keep
# running your application, until you exit
tk.mainloop()
Only a personal recommendation: don't use tk as a variable name, use app or root or even win/window

Categories

Resources