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.
Related
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()
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.
I am trying to make a popup window where someone can fill in a string in an Entry box. I have gone through many examples, but it doesn't work.
I am trying to this:
var_entry = simpledialog.askstring("Test", "Test")
I get this error message:
_tkinter.TclError: window ".!_querystring" was deleted before its visibility changed
Thanks in advance!
edit: posted wrong error message
I know this is an old thread, but I'm having the same problem and so far haven't found the root cause.
However, this workaround works for me in case anyone else needs it:
#Create a new temporary "parent"
newWin = Tk()
#But make it invisible
newWin.withdraw()
#Now this works without throwing an exception:
retVal = simpledialog.askstring("Enter Value","Please enter a value",parent=newWin)
#Destroy the temporary "parent"
newWin.destroy()
I was also able to work around the problem by using the above workaround suggested by John D.
I did some research on this, and it seems that this exception is raised when all of the following conditions are met.
The thread that called the simpledialog.askstring method is not the main thread.
The Tk window specified in the parent or the Tk window specified in the default_root variable is different from the thread that called the simpledialog.askstring method.
However, I could not come up with a process to deal with this problem. I hope this helps to solve the problem.
This issue is caused by askstring is not called in the main thread, which is the main thread.
Make sure to call this method in the main thread. For example, this code works well.
from tkinter import Tk
from tkinter.simpledialog import askstring
a = Tk()
askstring('1', '2')
a.mainloop()
And this code will throw your exception when you close the dialog window.
from tkinter import Tk
from tkinter.simpledialog import askstring
from threading import Thread
a = Tk()
Thread(target=askstring, args=('1', '2')).start()
a.mainloop()
I'm not sure without your code example but I figured that this error message means that the variable where you are putting the 'askstring' return value or initialvalue is going out of scope before the dialog window is finished.
When I had this error message I placed a declaration of the variables outside the inner scope. Forgive me if I am talking here using C concepts (which most Python users would rather ignore).
answer = "dummy"
query_str = "dummy" # without these lines query_str and answer
# can be cleaned up by Python
# before the 'askstring' is done with them
while (1):
query_str = "0"
answer = simpledialog.askstring("Get Number",
"Enter NextNumber",
initialvalue = query_str)
print(answer)
print(query_str)
time.sleep(1)
Adding the declarations outside the loop scope worked for me.
I am trying to make a basic 4 frame animation, I cannot use a tkinter canvas as I want it to use the art which I have drawn (the files). There is nothing wrong with the file type as I have tested it on its own. However the code seems to just remove the window for the 6 seconds and then show the final frame.
import time
import tkinter
window=tkinter.Tk()
frame1=tkinter.PhotoImage(file="file1.ppm")
frame2=tkinter.PhotoImage(file="file2.ppm")
frame3=tkinter.PhotoImage(file="file3.ppm")
frame4=tkinter.PhotoImage(file="file4.ppm")
image=tkinter.Label(window,image=frame1)
image.pack()
time.sleep(2)
image.configure(image=frame2)
time.sleep(2)
image.configure(image=frame3)
time.sleep(2)
image.configure(image=frame4)
I'm not sure whether it is the "time.sleep" or the "image.configure" that is the problem but I have tried to mess around with different types of timing methods which also seem to fail.
import tkinter
window=tkinter.Tk()
frame1=tkinter.PhotoImage(file="file1.ppm")
frame2=tkinter.PhotoImage(file="file2.ppm")
frame3=tkinter.PhotoImage(file="file3.ppm")
frame4=tkinter.PhotoImage(file="file4.ppm")
image=tkinter.Label(window,image=frame1)
image.pack()
def loop(n):
frame = [frame1, frame2, frame3, frame4][n]
window.after(2000, lambda : image.configure(image=frame))
window.after(2000, lambda : loop((n+1)%4))
loop(1)
I'm doing an extended project as one of my qualifications in my current College and I chose to write a python Strategy/RPG game. As a result, I ended up with the highest level of Python knowledge (Surpassing my Computing Teacher who only ever uses the basics... and used Tkinter only once a few years ago. Every one else who has decided to make a program, are either coding in Lua, Java, C++, HTML/CSS/Java-Script or, those who are coding in python, they are only using the basics learned from our teacher.)
I say "Highest level of Python knowledge" but really it isn't that high... I only know a little beyond the basics.
As a result, a forum post is the best place I can turn to for help.
So in my game I defined this function:
#"Given_String" is the question that one would want to ask. (With the answer being an integer between 1 and "Choice_Range" (inclusive)
def Value_Error(Given_String,Error_Message,Choice_Range):
while True:
try:
Temp=int(input(Given_String))
if Temp<1 or Temp>Choice_Range:
print(Error_Message)
else:
break
except ValueError:
print(Error_Message)
return Temp
I then wanted to add tkinter to my code, because the game would have to be in a separate window, and not in the console. As a result, I had to change this code so that it displays the "Given_Message" and the "Error_Message" in a tkinter window, and uses the value that has been typed into an entry box when defining "Temp".
I wrote this code to make this work: (Or at least most of it)
#This code is stored in a different file for neatness and hence I had to import "sys" to avoid circular imports.
#This code is made to be flexible so that I can later re-use it when necessary.
#This code starts with the function all the way at the bottom. The rest are made to add flexibility and to structure the algorithm.
#This code hasn't been fully run (Because of the Error crashing the Python Shell) so it can contain other Run-time Errors that I'm not aware of yet.
import sys
def Generate_Window(Window_Name,X_Parameter=5,Y_Parameter=50):
Temp=sys.modules['tkinter'].Tk()
Temp.title(Window_Name)
Temp.geometry(str(X_Parameter)+"x"+str(Y_Parameter))
return Temp
def Generate_Button(Master,Text="Submit"):
Temp=sys.modules["tkinter"].Button(Master,text=Text)
return Temp
def Generate_Entry(Master):
Temp=sys.modules["tkinter"].Entry(Master)
return Temp
def Generate_Label(Master,Given_String):
Temp=sys.modules["tkinter"].Label(Master,text=Given_String)
return Temp
def Com_Get_Entry(Given_Window,Given_Entry):
Temp=Given_Entry.get()
Given_Window.destroy()
return Temp
def Com_Confirm(Given_Window):
Given_Window.destroy()
def Generate_Entry_Box(Given_String):
Entry_Window=Generate_Window("Entry",X_Parameter=300)
Entry_Label=Generate_Label(Entry_Window,Given_String)
Entry_Entry=Generate_Entry(Entry_Window)
Entry_Button=Generate_Button(Entry_Window)
Entry_Button.configure(command=lambda:Com_Get_Entry(Entry_Window,Entry_Entry))
Entry_Label.grid(row=0,columnspan=2)
Entry_Entry.grid(row=1,column=0)
Entry_Button.grid(row=1,column=1)
def Generate_Alert_Message(Given_String):
Alert_Window=Generate_Window("Alert",X_Parameter=300)
Alert_Label=Generate_Label(Alert_Window,Given_String)
Alert_Button=Generate_Button(Alert_Window,Text="OK")
Alert_Button.configure(command=lambda:Com_Confirm(Alert_Window))
Alert_Label.grid(row=0,columnspan=2)
Alert_Button.grid(row=1,column=1)
def Get_Interger_Input_In_Range(Given_String,Error_Message,Choice_Range):
while True:
try:
Returned_Value=int(Generate_Entry_Box(Given_String))
if Returned_Value<1 or Returned_Value>Choice_Range:
Generate_Alert_Message(Error_Message)
else:
break
except ValueError:
Generate_Alert_Message(Error_Message)
return Temp
I already included in my code all that I was struggling with and that I could find an answer to.
I.E: On-click, do a certain action with given parameters.
One thing I could not find, is how to return the entered value to the original (Get_Interger_Input_In_Range()) function after the button has been clicked.
What I mean is something like this:
def Function1(GivenParameter1,GivenParameter2):
Temp=Function2(GivenParameter1)
Temp+=GiverParameter2 #random action
return Temp
def Function2(GivenParameter):
Button=Button(Master,command=Function3).grid()
Entry=Entry(Master).grid()
def Function3():
Temp=Entry.get()
return Temp
In Function1 I want Temp to equal the entered value from Function2.
Is there any way to do this without using classes? (I'm not too familiar with classes yet)
Is there any way to do this at all?
I haven't seen anyone give the answer I was looking for...
Because even if they said to use classes... I still didn't know how to return it (Explanation just below)
#The following code was written quickly for purposes of explaining what I mean. It doesn't actually work... (It seems that the button command is being called automatically...)
from tkinter import *
class Return_Value_In_Entry():
def __init__(self):
self.Master=Tk()
self.Entry=Entry(self.Master)
self.Button=Button(self.Master,text="Submit",command=self.Return())
def Return(self):
self.TempVar=self.Entry.get()
return self.TempVar
The way I see it, the Return() function would return the value to the button and not the function/assignment that called the class ... Which is the same problem I'm having with my code.
If you read this all then I really appreciate it. I hope someone can answer my question and tell me (if it's impossible otherwise) how to use classes to solve my "Little" yet large problem.
I fixed your example code (I think). The main problem is that this:
command=self.Return()
does not do what you think it does. It just assigns return value from Return() to command. This is incorrect. It should be
command=self.Return
This assigns function Return to command. Subsequently, when ever button is pressed, self.Return() is executed.
The full example is here:
from tkinter import *
class Return_Value_In_Entry():
def __init__(self):
self.Master=Tk()
self.Entry=Entry(self.Master)
self.Entry.pack()
self.Button=Button(self.Master,text="Submit",command=self.Return)
self.Button.pack()
self.Master.mainloop()
def Return(self):
self.TempVar=self.Entry.get()
print(self.TempVar)
Return_Value_In_Entry()
Now, whenever you press the Button, the value from the Entry widget is saved into self.TempVar and printed out, just to check if its working. Hope this helps.
Gif showing how the example program works: