Can you have two instances of tkinter in Python? - python-3.x

Is it possible to have two instances of tkinter ?
import tkinter as tk
import tkinter as sk
root = tk.Tk()
root2 = sk.Tk()
....some window with tk
....some window with sk
root.mainloop()
root2.mainloop()
then have a Toplevel() in both instances.

You can, but the way it works likely won't be like what you expect. Importing it twice isn't the problem (but neither is it the solution). No matter how you import it or how often you import it, creating more than one instance of Tk is the problem. Each instance is backed by a separate internal interpreter. Images and variables and widgets created in one won't exist in the other.
If you need more than one window, it's usually best if second and subsequent windows are instances of Toplevel.

By creating 2 instances or tkinter I can close one instance and all top Levels of that instance. Leaving the second Instance open and running with it's Toplevel instances. This is useful in the sense where I use it for a User preference file. Where it checks for a userfile database for keeping track of variables. I use a csv file to save user variable using pandas. This in turn keeps all the form information in my app safe from being erased after closing the application or accidentally closing the window. Adding AtExit saves the info closing the addinfo window and continues to run the main application. That was my reasoning for having asked the question. I have since found that using multiple Toplevel(s) is a better choice as it will also produce the same result. So my menu items all have a separate instance definition and can be closed in the same manner ,making error checks with each closed window.
from tkinter import Tk,Label,Entry,Button,Toplevel
root=Tk()
def about():
ab=Toplevel()
# About stuff for this window
ab.mainloop()
def info():
inf=Toplevel()
# Information Stuff for this window.
inf.mainloop()
def getUserInfo():
# User info using pandas
getUserInfo.mainloop()
root.mainloop()

Related

Reload UI, Rather Than Recreating

import sys
import webbrowser
import hou
from PySide2 import QtCore, QtUiTools, QtWidgets, QtGui
# Calling UI File & Some Modification
class someWidget(QtWidgets.QWidget):
def __init__(self):
super(someWidget,self).__init__()
ui_file = 'C:/Users/XY_Ab/Documents/houdini18.5/Folder_CGI/someUI.ui'
self.ui = QtUiTools.QUiLoader().load(ui_file, parentWidget=self)
self.setParent(hou.qt.mainWindow(), QtCore.Qt.Window)
self.setFixedSize(437, 42)
self.setWindowTitle("Requesting For Help")
window_C = someWidget()
window_C.show()
So, I have created this small script that shows the UI, I have connected this to Houdini Menu Bar. Now The Problem is if I click the menu item multiple times it will create another instance of the same UI & the previous one stays back, What I want is something called "If Window Exist Delete It, Crate New One" sort of thing.
Can someone guide me? I am fairly new to python in Houdini and Qt so a little explanation will be hugely helpful. Also, why can't I use from PySide6 import?? Why do I have to use from PySide2?? Because otherwise Houdini is throwing errors.
For the same thing what used to do in maya is
# Check To See If Window Exists
if cmds.window(winID, exists=True):
cmds.deleteUI(winID)
Trying to do the same thing inside Houdini.
I don't have Maya or Houdini, so I can't help you too much.
According to https://www.sidefx.com/docs/houdini/hom/cb/qt.html
It looks like you can access Houdini's main window. The main reason the window is duplicated or deleted is how python retains the reference to window_C. You might be able to retain the reference to just show the same widget over and over again by accessing the main Houdini window.
In the examples below we are using references a different way. You probably do not need your code that has
self.setParent(hou.qt.mainWindow(), QtCore.Qt.Window)
Create the widget once and keep showing the same widget over and over.
import hou
# Create the widget class
class someWidget(QtWidgets.QWidget):
def __init__(self, parent=None, flags=QtCore.Qt.Window): # Note: added parent as an option
super(someWidget,self).__init__(parent, flags)
...
MAIN_WINDOW = hou.ui.mainQtWindow()
try:
MAIN_WINDOW.window_C.show()
except AttributeError:
# Widget has not been created yet!
# Save the widget reference to an object that will always exist and is accessible
# parent shouldn't really matter, because we are saving the reference to an object
# that will exist the life of the application
MAIN_WINDOW.window_C = someWidget(parent=MAIN_WINDOW)
MAIN_WINDOW.window_C.show()
To delete the previous window and create a new window.
import hou
# Create the widget class
class someWidget(QtWidgets.QWidget):
def __init__(self, parent=None, flags=QtCore.Qt.Window): # Note: added parent as an option
super(someWidget,self).__init__(parent, flags)
...
MAIN_WINDOW = hou.ui.mainQtWindow()
# Hide the previous window
try:
MAIN_WINDOW.window_C.close()
MAIN_WINDOW.window_C.deleteLater() # This is needed if you parent the widget
except AttributeError:
pass
# Create the new Widget and override the previous widget's reference
# Python's garbage collection should automatically delete the previous widget.
# You do not need to have a parent!
# If you do have a parent then deleteLater above is needed!
MAIN_WINDOW.window_C = someWidget() # Note: We do not parent this widget!
MAIN_WINDOW.window_C.show()
Another resource shows you can access the previous widget from the page level variable. https://echopraxia.co.uk/blog/pyqt-in-houdinimaya-basic This is possible, but seems odd to me. The module should only be imported once, so the page level variable "my_window" should never exist. However, it sounds like the Houdini plugin system either reloads the python script or re-runs the import. If that is the case every time you show a new window from the import of the script, you are creating a new window. If the previous window is not closed and deleted properly, Houdini could have an ever growing memory issue.
try:
my_window.close()
except (NameError, Exception):
pass # Normal python would always throw a NameError, because my_window is never defined
my_window = MyWindow()
#This is optional you can resize the window if youd like.
my_window.resize(471,577)
my_window.show()
PySide6
https://www.sidefx.com/docs/houdini/hom/cb/qt.html
The bottom of the page shows how to use PyQt5. The same would apply for PySide6. Houdini just happens to come with PySide2.

Why do we store methods in a variable when using Tkinter in python?

I just started learning Tkinter and when thing that really stood out was
win=tkinter.Tk()
I mean from what it looks win is basically a reference for the main window we created but this is the first time I have seen something like this since tk() is a method and not a class . I know that everything is an object in python eh but I am kinda confused , help me senpais ....
Why do we store methods in a variable when using Tkinter in python?
This question doesn't make much sense. Most programs do not store methods.
Regardless, tkinter is no different than any other module in this regard: you save a reference to something when you need to refer to the object later or you need to prevent the garbage collector from collecting the object.
I mean from what it looks win is basically a reference for the main window we created
That is correct. In your code example win is a reference to the root window, an instance of the Tk class.
I have seen something like this since tk() is a method and not a class
That is not true. At least, not if you meant to say Tk(). Tk from the tkinter module is in fact a class. So in this case you are creating an instance of the Tk class.
tkinter.Tk() is an object of type tkinter.Tk, not a method.

Print Current Time In Tkinter

I have written some code in python for a live time in tkinter.
Whenever I run the code it comes up with some numbers on the tkinter window like 14342816time. Is there a way to fix this?
import tkinter
import datetime
window = tkinter.Tk()
def time():
datetime.datetime.now().time()
datetime.time(17, 3,)
print(datetime.datetime.now().time())
tkinter.Label(window, text = time).pack()
window.mainloop()
After some fixes to your code, I came up with the following, which should at least get you started toward what you want:
import datetime
import tkinter
def get_time():
return datetime.datetime.now().time()
root = tkinter.Tk()
tkinter.Label(root, text = get_time()).pack()
root.mainloop()
The imports are needed so that your program knows about the contents of the datetime and tkinter modules - you may be importing them already, however, I can't tell that for certain from what you posted. You need to create a window into which you put your label, which wasn't happening; following convention, I called that parent (and only) window "root". Then I put the Label into root. I changed the name of your time() function to get_time(), since it's best to avoid confusing fellow programmers (and maybe yourself) with a function that shares its name with another (the time() function in time). I removed two lines in get_time() that don't actually accomplish anything. Finally, I changed the print you had to a return, so that the value can be used by the code calling the function.
There are other improvements possible here. If you're content with the time as it is, you could eliminate the get_time function and just use datetime.datetime.now().time() instead of calling get_time(). However, I suspect you might want to do something to clean up that time before it is displayed, so I left it there. You might want to research the datetime and time modules some more, to see how to clean things up.

I want to embed python console in my tkinter window.. How can i do it?

I am making a text editor and want to add a feature of IDLE in my app. So i want an frame with python IDLE embedded in it with all menus and features which original python IDLE gives.
I looked in source of idle lib but cannot find a solution.
try:
import idlelib.pyshell
except ImportError:
# IDLE is not installed, but maybe pyshell is on sys.path:
from . import pyshell
import os
idledir = os.path.dirname(os.path.abspath(pyshell.__file__))
if idledir != os.getcwd():
# We're not in the IDLE directory, help the subprocess find run.py
pypath = os.environ.get('PYTHONPATH', '')
if pypath:
os.environ['PYTHONPATH'] = pypath + ':' + idledir
else:
os.environ['PYTHONPATH'] = idledir
pyshell.main()
else:
idlelib.pyshell.main()
This code is of pyshell.pyw found under idlelib folder in all python install
I searched the idle.pyw and found that it uses a program pyshell which is real shell. So how can i embed it.
I want a Tkinter frame with python IDLE shell embedded in it.Please give the code. Thanks in advance.
idlelib implements IDLE. While you are free to use it otherwise, it is private in the sense that code and interfaces can change in any release without the usual back-compatibility constraints. Import and use idlelib modules at your own rish.
Currently, a Shell window is a Toplevel with a Menu and a Frame. The latter has a Text and vertical Scrollbar. It is not possible to visually embed a Toplevel within a frame (or within another Toplevel or root = Tk()). top = Toplevel(myframe) works, but top cannot be placed, packed, or gridded within myframe.
I hope in the future to refactor editor.py and pyshell.py so as to separate the window with menu from the frame with scrollable text. The result should include embeddable EditorFrame and ShellFrame classes that have parent as an arguments. But that is in the future.
Currently, one can run IDLE from within python with import idlelib.idle. However, because this runs mainloop() (on its own root), it blocks and does not finish until all IDLE windows are closed. This may not be what one wants.
If having Shell run in a separate window is acceptable, one could extract from python.main the 10-20 lines needed to just run Shell. Some experimentation would be needed. If the main app uses tkinter, this function should take the app's root as an argument and not call mainloop().
Tcl having Tkcon.tcl . when each thread source (means run/exec) the Tkcon.tcl
each thread will pop up a Tk shell/Tk console/tkcon.tcl very good idea for debug. and print message individually by thread.
Python having idle.py ... and how to use it ? still finding out the example .
The are same Tk base . why can't find an suitable example? so far ... keep finding...

Adding items to a Listbox using Entries from another class

I have created two classes, one is in People.py (which will be the parent class) which contains a list box that can be populated by just opening a file and adding content to the list box line by line.
Another class is in Names.py (which I want it to be child class), which contains entries of first name, last name, and a combo box for titles that should (will implement once question/problem is answered) go into the list in the main window where the class is People. I am trying to use an OOP model. Right now, it's not fully OOP, but I will refactor the code later.
I have tried posting this code before but people are having trouble running it due to indentation problems, so I'm providing the links to the classes. In Dropbox Name Class and People Class:
Note: I'm running this in a Linux environment, so you may have to modify the file choosing line in the People class if using Windows (or another OS).
f = os.path.expanduser('~/Desktop')
Actually, you still have a problem of inconsistent use of tabs and spaces, which I solved, but maybe other people cannot solve it.
First of all, you should name your files/modules with lower cases (by convention, and you should follow it!). Then, in Names.py you are doing from Tkinter import * and then from Tkinter import Tk, which does not make any sense: with the first you are already importing Tk.
Your problem is the following:
People.people_list.insert(Tk.END, FirstName.get()) AttributeError:
'module' object has no attribute 'people_list'
In fact, you are trying to access an inexistent attribute of the module People called people_list, which is a local variable to some functions, from what I have been seeing.
If you want to fill a Listbox which is a property of some Toplevel A, with the input from another Toplevel B, you should pass a reference of the Toplevel A to B, maybe during its construction.
Here you have an example:
from tkinter import * # python 3
class Other(Toplevel):
"""Note that the constructor of this class
receives a parent called 'master' and a reference to another Toplevel
called 'other'"""
def __init__(self, master, other):
Toplevel.__init__(self, master)
self.other = other # other Toplevel
self.lab = Label(self, text="Insert your name: ")
self.lab.grid(row=0, column=0)
self.entry = Entry(self)
self.entry.grid(row=0, column=1)
# When you click the button you call 'self.add'
self.adder = Button(self, text='Add to Listbox', command=self.add)
self.adder.grid(row=1, column=1)
def add(self):
"""Using a reference to the other window 'other',
I can access its attribute 'listbox' and insert a new item!"""
self.other.listbox.insert("end", self.entry.get())
class Main(Toplevel):
"""Window with a Listbox"""
def __init__(self, master):
Toplevel.__init__(self, master)
self.people = Label(self, text='People')
self.people.grid(row=0)
self.listbox = Listbox(self)
self.listbox.grid(row=1)
if __name__ == "__main__":
root = Tk()
root.withdraw() # hides Tk window
main = Main(root)
Other(root, main) # passing a reference of 'main'
root.mainloop()
I noticed also that you are using 2 instance of Tk for each of your windows, which is bad. You should use just one instance of Tk for every application. If you want to use multiple windows, just use Toplevels, as I mentioned.
In general, your structure is not so good. You should start by creating simple good applications, and then pass to big ones once you grasp the basic concepts.

Resources