Python, Tkinter - some general questions about the code - python

I have some general questions regarding working code below:
tkinter is library for graphic interface as I understand I can use it interchangeably with for example Kivy?
Would it be better to learn Kivy instead or other?
Lines import tkinter as tk and from tkinter import * do exactly the same, in the first one I have alias though?
In the code below, why do I have to use ttk in ttk.Progressbar?
I imported whole library with import tkinter as tk so why do i have to reimport ttk just for progress bar? (otherwise it is not working). I would expect to work sth. like tk.Progressbar
In the line btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress), why method "fnUpdateProgress" can't have any variables? Whenever I add any, the button stop working? -> for example btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress(24)) (ofc then some changes in def of the method itself)
I created progress bar (pb) as attribute of the class Test, but wolud it be better to define it as regular variable (without self)? To be honest, code works exactly the same.
Code:
import tkinter as tk
from tkinter import *
from tkinter import ttk
from CreateProgramMain import main
import GlobalVariables
class Test():
####################################################################################
def __init__(self):
self.Progress=0
self.root = tk.Tk()
self.root.title(GlobalVariables.strAppName)
self.root.geometry('400x200')
lbl = Label(self.root, text="Please choose environment.",font=("Arial Bold", 12))
lbl.grid(column=2, row=0,sticky='e')
def btnTestClicked():
main("TEST",self)
btnTest=tk.Button(self.root, text="Test Environment", command=btnTestClicked)
btnTest.grid(column=2, row=15)
#Place progress bar
pb = ttk.Progressbar(self.root,orient='horizontal',mode='determinate',length=200)
pb.grid(column=1, row=65, columnspan=2, padx=10, pady=20)
pb["value"]=self.Progress
pb["maximum"]=100
btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress)
btnProg.grid(column=2, row=75)
self.root.mainloop()
def fnUpdateProgress(self): #why i cant insert variable inside?
pb["value"]=self.Progress
self.Progress=self.Progress+5
pb.update()
app = Test()
Thank you

it is upto you. However, tkinter and kivy both have their own syntaxes, commands, and their own usages. It might be a little difficult to convert tkinter code to kivy.
it is upto you
Yes. In the first, you have imported tkinter as tk. In the second one. You have done a wild card import. You have imported everything
Tkinter is a folder containing various modules. It contains a file called ttk.py which you have to import to access ttk.
All other classes like Label, Entry, Tk is present in __init__.py
you have to use lambda for it. If you call the function, it will be executed wlright away and the returned value is kept as the command.
Doing command=self.fnUpdateProgress(24)) will execute the function right away. Then, the returned value is kept as a command. Here, it returns None. So the command is nothing or the button is useless.
Use a lambda expression command=lambda: self.fnUpdateProgress(24))
if you don't add self it will be local to the function only. To access ot outside, it would have to be declared global, which is the point to avoid while using classes

Related

Tkinter: ttk.Label displaying nothing when given StringVar as textvariable, inside a class

I am trying to use the textvariable attribute of ttk.Label to display & update text according to a given StringVar.
from tkinter import *
from tkinter import ttk
class RenderEvent():
def __init__(self, root):
self.root = root
self.frame = ttk.Frame(self.root, padding="20 20 20 20")
self.frame.grid(column=0, row=0, sticky=(N, W, E, S))
self.dialogue = StringVar(self.frame, value="Placeholder")
L = ttk.Label(self.frame, textvariable=self.dialogue)
L.grid(column=1, row=2, sticky=W)
self.dialogue.set("some text here")
And for reference, root is passed in from another file which looks like this, and is used to start the application:
from tkinter import *
from tkinter import ttk
from renderevent import RenderEvent
root = Tk()
RenderEvent(root)
root.mainloop()
If I use text instead of textvariable in the Label creation, it displays a static string just fine. However, once it is set to textvariable (as shown above), nothing will be displayed at all.
I have tried the same with giving the StringVar() no parameters at all in initialization, or passing in self.root.
Emulating this code outside of a class seems to work as intended (the text appears and updates along with the textvariable), but I can't think of why having a class would cause an issue like this.
The reason is that you aren't keeping a reference to the instance of RenderEvent. Since you don't save a reference, python's garbage collector will try to clean it up which causes the variable to be cleaned up as well. The ttk widgets are more sensitive to this than the normal tk widgets.
The simple and arguably best solution is to assign the result of RenderEvent(root) to a variable so that it isn't affected by python's memory management.
re = RenderEvent(root)

Is there different ways to create a menu bar?

I've come across two different ways to create a menu bar:
import tkinter as tk
window = tk.Tk()
menu_bar = tk.Menu() ■
window.config(menu = menu_bar) #2
window.mainloop()
import tkinter as tk
from tkinter import Menu
window = tk.Tk()
menu_bar = Menu(window) ■
window.configure(menu = menu_bar)
window.mainloop()
Question: what's the difference between these lines of code? By this I mean, why is the syntax different If they do the same? (I've marked the referred lines of code as ■). How importing Menu from tkinter affect the lines of code?
What's the difference between these lines of code?
It does the same thing(except the imports. With from tkinter import Menu, you are specifically just importing Menu and nothing else from tkinter. But in the first example, you are importing whole tkinter and you can refer to tkinter.Menu as tk.Menu. But in the second example, you just have to say Menu.
Note that in the second example you can still use tk.Menu as well as Menu. So the second import is rendered useless, and can be removed. It is better to follow the first example.
As mentioned by AST, if you say Menu(), an existing instance of Tk() will be passed as the master argument implicitly. But if you say Menu(win), you are passing win explicitly. It is always recommended to pass the parent argument explicitly while you work with multiple windows so as to not cause confusions.

Tkinter text widget - Why does INSERT not work as text index?

I have a problem that annoys me. I am currently building a small app with a Tkinter GUI.
On the front page, I want some introductory text in either a text or a scrolledtext widget. The code examples I've come across uses keywords such as INSERT, CURRENT and END for indexation inside the widget.
I have literally copy pasted the below code into my editor, but it doesn't recognise INSERT (throws error: "NameError: name 'INSERT' is not defined"):
import tkinter as tk
from tkinter import scrolledtext
window = tk.Tk()
window.title("test of scrolledtext and INSERT method")
window.geometry('350x200')
txt = scrolledtext.ScrolledText(window,width=40,height=10)
txt.insert(INSERT,'You text goes here')
txt.grid(column=0,row=0)
window.mainloop()
I can get the code to work if I change [INSERT] with [1.0], but it is very frustrating that I cannot get INSERT to work, as I've seen it in every example code I've come across
Use tk.INSERT instead of only INSERT. Full code is shown.
import tkinter as tk
from tkinter import scrolledtext
window = tk.Tk()
window.title("test of scrolledtext and INSERT method")
window.geometry('350x200')
txt = scrolledtext.ScrolledText(window,width=40,height=10)
txt.insert(tk.INSERT,'You text goes here')
txt.grid(column=0,row=0)
window.mainloop()
You don't need to use the tkinter constants. I personally think it's better to use the raw strings "insert", "end", etc. They are more flexible.
However, the reason the constants don't work for you is that you're not directly importing them. The way you're importing tkinter, you need to use tk.INSERT, etc.
INSERT could not be used directly.
You can use it in the past just because you used this in the past:
from tkinter import * # this is not a good practice
INSERT,CURRENT and END are in tkinter.constants.Now in your code,you even didn't import them.
If you want to use them,you can use
from tkinter.constants import * # not recommended
...
txt.insert(INSERT,'You text goes here')
Or
from tkinter import constants
...
txt.insert(constants.INSERT,'You text goes here') # recommend
If didn't want to import them,you can also use:
txt.insert("insert",'You text goes here')
Edit:I found in the source code of tkinter,it had import them,reboot's answer is also OK.

How to set focus in tkinter entry box

have spent a while looking for an answer. I'm new to Python but not to coding in general. Finding the various versions quite challenging!
Anyway I'm very Gui orientated and have managed to get tkinter working with Python 3.5.1
Just playing with basics and have the following code but cannot set focus to the first entry box. Have tried mEntry1.focus() and mEntry1.focus_set() but always get object has no attribute error. Any help?
from tkinter import *
def calc(*args):
try:
value1 = float(V1.get())
value2 = float(V2.get())
result.set(value1 * value2)
except ValueError:
pass
mGui = Tk()
mGui.geometry('450x450+200+200')
mGui.title('Test Gui')
V1 = StringVar()
V2 = StringVar()
result = StringVar()
mEntry1 = Entry(textvariable=V1,width=10).grid(row=0,column=0,sticky=W)
mEntry2 = Entry(textvariable=V2).grid(row=1,column=0)
mButton = Button(text='Calculate',command=calc).grid(row=3,column=0)
mlabel = Label(textvariable=result).grid(row=4,column=2)
Every Tkinter widget has the focus_set method.
The problem with your code is that the .grid method returns None. Thus
mEntry1 = Entry(textvariable=V1,width=10).grid(row=0,column=0,sticky=W)
sets mEntry1 to None, not the widget. So you need to create the widget and put it in the grid in two steps:
mEntry1 = Entry(textvariable=V1,width=10)
mEntry1.grid(row=0,column=0,sticky=W)
Of course, if you don't actually need a reference to the widget object then it's ok to do it in one step. So something like
Entry(textvariable=V1,width=10).grid(row=0,column=0,sticky=W)
would be fine.
BTW, it's not a good idea to use from tkinter import *. It imports over 130 names into your namespace, which can lead to name collisions with your own names, or with those of other modules if you also import them with a "star" import statement. It also makes the code harder to read. Instead, you can do
import tkinter as tk
and then refer to Tkinter names using the tk. prefix, eg tk.Entry instead of Entry.

Python Tkinter module not showing output

I am trying to learn Python and trying something GUI in Python and came across this Tkinter module. My code runs but the window does not appear when I run. My code is as follows:
from Tkinter import *
#to create a root window
root = Tk()
The program runs, gives no errors but the window does not show up.
Add this to your code root.mainloop(), Here's a tutorial.
In response to your comment
#Also note that `from <module> import *` is generally frowned upon
#since it can lead to namespace collisions. It's much better to only
#explicitly import the things you need.
from Tkinter import Tk, Label
root = Tk()
w = Label(root, text="Hello, world!")
w.pack()
root.mainloop()
As other answers have pointed out, you need to call mainloop on the root object.
I recommend an OO-style of programming, and I also recommend not doing a global import (ie: not 'from Tkinter import *').
Here's a template I usually start out with:
import Tkinter as tk
class ExampleView(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
l = tk.Label(self, text="your widgets go here...", anchor="c")
l.pack(side="top", fill="both", expand=True)
if __name__=='__main__':
root = tk.Tk()
view = ExampleView(root)
view.pack(side="top", fill="both", expand=True)
root.mainloop()
This makes it easy to keep your main logic at the start of the file, and keep the creation of the root and the calling of mainloop together, which I think makes the code a little bit easier to understand. It also makes reusing this code a little easier (ie: you could create a larger program where this is one of several windows that can be created)
Add root.mainloop() at the end.

Categories

Resources