How to open a Tkinter app from a PyQt GUI - python

I have built an app with PySide2 (PyQt). Now I was asked to make a QPushButton, which simply starts an independent Tkinter app which someone else has programmed.
I thought I could simply connect the method below to my QPushButton which starts the Tkinter App (Modell_final.App is the app):
def open_tkinter():
root = tkinter.Tk()
app = Modell_final.App(root)
root.mainloop()
But when I push the Button inside my GUI the first time nothing happens and the second time the Tkinter App opens and freezes immediately.
Thanks for help :)

I am not sure how independent the Tkinter app is. If it is truly just some other small window you want to run that eventually gets closed again I would opt for an own process for it.
You can try it like this. Please save it as "test_test.py"
import tkinter as tk
import subprocess
window = tk.Tk()
window.title("Window Title")
window.geometry('200x100')
lbl = tk.Label(window, text="Hello World")
lbl.pack()
def clicked(): #function before bind
subprocess.Popen(['python' , 'test_test.py'])
btn = tk.Button(window, text="Click Me", command=clicked)
btn.pack()
window.mainloop()
If it is truly completly independet this would have the benefit that you do not even need to import the Modell_final into the PyQt app. Just import subprocess and let the button call the subprocesss.popen (notsubprocesss.call, then it freezes again) python file with the tkinter app in it.
The downside is
Sharing data with the Tkinter app is difficult, but if it is independent no issue here.
If the button is pressed multiple times multiple windows of the Tkinter app open up. This might be what you want, but if not you have to take care of this.

Related

Is there a way to make a custom askopenfilenames dialog window or at least edit its title bar, close button, etc in tkinter?

I'm making an app in tkinter which uses the ttk.Scale widget to show the process of an mp3 song.
I have a function that I want to add buttons with the names of which (the buttons) should be relied on filenames. Therefore I've made this example:
from tkinter import Tk, Button
from tkinter.filedialog import askopenfilenames
from tkinter.ttk import Scale
from threading import Timer
root = Tk()
slider = Scale(root, from_=0, to=100, orient='horizontal')
slider.pack()
# slider is continuously set to a bigger number so that it keeps going
def update_slider(num):
slider.set(num)
num += 1
root.after(50, update_slider, num)
update_slider(num=0)
# this function creates buttons based on the files opened
def add_buttons():
# the 'X' button of this particular window slows down execution of update_slider function
files = askopenfilenames(title='Add Buttons')
for i in list(files):
Button(root, text=i).pack()
button = Button(root, text='Browse', command=lambda: Timer(0.1, add_buttons).start())
button.pack()
root.mainloop()
The problem I'm facing is that when I open the askopenfilenames dialog box or when I press its 'X' button, my slider which is running continuously in the background gets stuck, and as a result doesn't show the process correctly.
Here is a picture where I hold down the 'X' button and the ttk.Scale stops moving:
I've tried using threading to run the add_buttons function but the behavior of the program remains the same.
Can I edit the askopenfilenames dialog box with something similar like overrideredirect(True) so that I can make my own title bar and 'X' button and the events generated not to slow down my Scale?
Replying to:
I cannot reproduce the issue in Linux, the scale keeps moving no matter what I do with the filedialog window. So this may be an OS specific issue.
I'm aware that this problem doesn't appear on Linux. I faced the same problem with the root's close button and other Toplevels' close button, but I fixed it by replacing the title bar using overrideredirect(True).
Is there anything similar I can do with this askopenfilenames window?

new tkinter window loses focus after mainloop ends

I'm using the following code to create a window after destroying another.
from tkinter import *
tk=Tk()
def destroy():
tk.destroy()
tk.after(2000,destroy)
tk.mainloop()
tk=Tk()
tk.mainloop()
The window is created alright, but it loses focus. I tried lift() and focus() methods with no result.
You can use <tk.Tk>.focus_force() to force the window to be focused.
So your modified code will look like this:
from tkinter import *
tk = Tk()
def destroy():
tk.destroy()
tk.after(2000, destroy)
tk.mainloop()
tk = Tk()
tk.focus_force()
tk.mainloop()
Although it is much better to reuse the window. Destroy all of the widgets on the window and reuse it instead of destroying and recreating it. Creating a window takes a lot of resources.
Also something else: the variable tk is usually used for something else so please don't use it for tkinter windows. Usually people use root or window for windows.
Force the input focus to the widget using focus_force(). Just update you last part.
tk=Tk()
tk.focus_force()
tk.mainloop()
Also, You can make a Toplevel() which is basically just creating a new window over the root window.
from tkinter import *
tkk=Tk()
tkk.withdraw()
tk=Toplevel()
def destroy():
tk.destroy()
tkk.deiconify()
tk.after(2000,destroy)
tk.focus_force()
tkk.mainloop()

How to duplicate Tkinter pop-up

So the code initially begins with a pop up asking you if you are ready, then once you select yes, a pop-up appears and if you try and close it, it will duplicate itself. Right now, it cannot duplicate itself.
Sorry if code is bad and riddled with mistakes (I'm just a beginner.) Thanks for helping.
from tkinter import *
from tkinter import messagebox
def a():
window2 = Tk()
offset = 300 + 1*10
window2.geometry('250x50+'+str(offset)+'+'+str(offset))
window2.title('')
window2.resizable(False, False)
la = Label(window2,text = 'ccmeockeoowpeokv.').pack()
button = Button(window2, text = 'OK', command = a()).pack()
def begining():
window = Tk()
window.eval('tk::PlaceWindow %s center' %window.winfo_toplevel())
window.withdraw()
if messagebox.askyesno("heh", "Ready?.") == True:
a()
window.deiconify()
window.destroy()
window.quit()
begining()
Do NOT ever insert Tk() if there are the absolute root of application, because it's just gonna make a new App, and NOT a new Window
The only method is using Toplevel()
Here, i explain you a bit
What is Toplevel()?
The Toplevel() widget is used to create and display the toplevel windows which are directly managed by the window manager
What is the function of Toplevel()?
The function of Toplevel() is to create a new window, without using Tk(). The Tk() and Toplevel() is almost same, but Toplevel() is to create a new window, without even create new application, if you watch some tutorial, the Tk() function is used to be creating a new application
What is the difference between Toplevel() and Tk()?
Tk() is the absolute root of the application, it is the first widget that needs to be instantiated and the GUI will shut down when it is destroyed. Toplevel() is a window in the application, closing the window will destroy all children widgets placed on that window but will not shut down the program
I suggest you to read more of the docs, or watch some tkinter tutorials on Youtube
Happy coding!

Python 3 tkinter: focus_force on messagebox

I'm running python 3 code in background which should show a popup window in some situations. I'm using tkinter for this:
import tkinter as tk
from tkinter import messagebox
def popup(message, title=None):
root = tk.Tk()
root.withdraw()
root.wm_attributes("-topmost", 1)
messagebox.showinfo(title, message, parent=root)
root.destroy()
popup('foo')
The ok-button in this infobox should get the focus automatically when popping up. Sadly I'm not able to do this. I tried root.focus(), but it does not help. Any ideas how to solve that? TIA
BTW: The code should be platform independent (Linux and Windows).
Edit:
Maybe I missunderstood the focus keyword and I should clarify my question:
root = tk.Tk()
root.focus_force()
root.wait_window()
When calling the code above the root window is active, even if I worked in e.g. the browser before. Is this also possible for messagebox.showinfo? Adding root.focus_force() in the popup function does not help.
Is this even possible? Or is it necessary to create my own root window? I really like the appearance of the messagebox with the icon.
Edit 2:
Here is a video: https://filebin.net/no195o9rjy3qq5c4/focus.mp4
The editor is the active window, even after the popup was shown.
In Linux I it works as expected.
You can use the default argument in the messagebox function.
default constant
Which button to make default: ABORT, RETRY, IGNORE, OK, CANCEL, YES, or NO (the constants are defined in the tkMessageBox module).
So, here is an example to highlight the "ok" button.
import tkinter as tk
from tkinter import messagebox
def popup(message, title=None):
root = tk.Tk()
root.withdraw()
messagebox.showinfo(title, message, parent=root, default = "ok")
root.destroy()
popup('foo')
Hope this helps!

Restart a program in Tkinter using a button

I'm new to Python and are trying to do a small program in which the GUI-window is supposed to re-open while clicking the button.
I read online that the line of code
os.execl(sys.executable, sys.executable, *sys.argv)
is supposed to make your program restart, but all it does is exit the GUI-window and restart Shell totally clean.
from tkinter import *
import sys
import os
def restart_program():
os.execl(sys.executable, sys.executable, *sys.argv)
window = Tk()
window.title("Test")
button = Button(window, text="RESTART", width=6, command=restart_program).grid(row=5, column=0)
window.mainloop()
This is the relevant part of my code atm (I didn't include all the code - some more widgets are adding to the existing, but it's not relevant to the problem). Is there any way to re-open the window called "Test", especially without having to put it in a function? Would be very thankful for help! :)))

Categories

Resources