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

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.

Related

Python, Tkinter - some general questions about the code

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

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.

Removing Base Window When Using Tkinter Python 3 (Askopenfiledialogue)

This is my first post on here, so bear with me as far as post etiquette goes. I've been struggling to get rid of the base Tkinter window that appears when I'm using the askopenfilename function of Tkinter. I've tried using Withdraw and destroy (in combination and alone) to fix this issue, but it seems to leave my code stuck in a loop and unable to continue to the next sections.
I have seen several solutions to this in Python 2, but I have no idea how they translate to python 3. Tkinter isn't a module I have a lot of experience with, so it is likely a simple oversight I am making.
Any suggestions or comments are much appreciated
Here is a sample of my code I am using (CSV module is for another section of my code)
import csv
from tkinter import filedialog
from tkinter import *
root= Tk()
root.filename= filedialog.askopenfilename(initialdir = r"\Users",title="Select A File", filetypes= [("Csv Files","*.csv")])
root.mainloop()
Use withdraw to hide root window, deiconify to show root window
import csv
from tkinter import filedialog
from tkinter import *
root=Tk()
# Hide Window
root.withdraw()
filename= filedialog.askopenfilename(initialdir = r"\Users",title="Select A File", filetypes= [("Csv Files","*.csv")])
# Show Window
root.deiconify()
root.mainloop()

Call same function using different buttons

How can i call the same function using different buttons? Currently i am creating different functions for different buttons.
from tkinter import *
from tkinter import filedialog
window=Tk()
window.title("CNO")
def browsefunc():
filename=filedialog.askopenfilename(parent=window,initialdir="C:\\Users\\jyoti\\Documents\\Python")
pathlabel_lbl1.config(text=filename)
def browsefunc1():
filename=filedialog.askopenfilename(parent=window,initialdir="C:\\Users\\jyoti\\Documents\\Python")
pathlabel_lbl2.config(text=filename)
Browse_btn=Button(window,text="Browse",command=browsefunc)
Browse_btn.grid(row=1,column=2,sticky=W+E)
pathlabel_lbl1=Label(window)
pathlabel_lbl1.grid(row=1,column=0,columnspan=2,sticky=W+E)
Browse_btn=Button(window,text="Browse",command=browsefunc1)
Browse_btn.grid(row=2,column=2,sticky=W+E)
pathlabel_lbl2=Label(window)
pathlabel_lbl2.grid(row=2,column=0,columnspan=2,sticky=W+E)
Tkinter does not limit the number of times that a function can be called through different widgets. So, you can simply put the browsefunc() as the command attribute of any number of buttons. Use the following:
from tkinter import *
from tkinter import filedialog
window=Tk()
window.title("CNO")
def browsefunc():
filename=filedialog.askopenfilename(parent=window,initialdir="C:\\Users\\jyoti\\Documents\\Python")
pathlabel_lbl1.config(text=filename)
def browsefunc1():
filename=filedialog.askopenfilename(parent=window,initialdir="C:\\Users\\jyoti\\Documents\\Python")
pathlabel_lbl2.config(text=filename)
Browse_btn=Button(window,text="Browse",command=browsefunc)
Browse_btn.grid(row=1,column=2,sticky=W+E)
pathlabel_lbl1=Label(window)
pathlabel_lbl1.grid(row=1,column=0,columnspan=2,sticky=W+E)
Browse_btn=Button(window,text="Browse",command=browsefunc)
Browse_btn.grid(row=2,column=2,sticky=W+E)
pathlabel_lbl2=Label(window)
pathlabel_lbl2.grid(row=2,column=0,columnspan=2,sticky=W+E)
window.mainloop()
You might sometimes wanna use lambda also. Although in your case it isn't required at all.
Hope this helps.
Simply edit the command=browsefunc to match your function name in both of your buttons.
Currently you have Browse_btn=Button(window,text="Browse",command=browsefunc) and Browse_btn=Button(window,text="Browse",command=browsefunc1), so just edit the last one to have the same function name to call.

How to clear Tkinter ListBox Python

How to clear a listbox when a button is clicked to re-populate it? The code below is giving me an error.
code:
self.listNodes.delete(0,END)
error:
NameError: name 'END' is not defined
Depending on how you imported tkinter you may have to put end in quotations
Try:
self.listNodes.delete(0,'end')
you can also use:
self.listNodes.delete(0,tk.END)
Replace:
self.listNodes.delete(0,END)
with:
self.listNodes.delete('0','end')
END is a variable of tkinter module, which suggests either a wildcard(from tkinter import *) import or from tkinter import END was supposed to be used.
You can use this is you imported tkinter as:
import tkinter as tk
self.listnodes.delete(0, tk.END)
Or you can do:
from tkinter import *
self.listnodes.delete(0, END)
Destruction is the best way to delete something.
self.listNode.destroy()
and then add Your data again to your ListBox.
You can Distroy list node like this
from tkinter import *
self.listnodes.delete(0, END) *

Categories

Resources