Get position in tkinter Text widget - python

I'm trying to find a reliable way of getting the current cursor position in a tkinter text widget.
What I have so far is:
import tkinter as tk
def check_pos(event):
print(t.index(tk.INSERT))
root = tk.Tk()
t = tk.Text(root)
t.pack()
t.bind("<Key>", check_pos)
t.bind("<Button-1>", check_pos)
root.mainloop()
However, this prints the previous cursor position and not the current one. Anyone have any ideas what is going on?
Thanks in advance.

Thanks to Bryan Oakley for pointing me in the right direction with the links he posted in the comments. I chose the third choice which introduces an additional binding. The working code is below. Now the binding happens after the class is bound so that the change of position in the Text widget is visible to the function.
import tkinter as tk
def check_pos(event):
print(t.index(tk.INSERT))
root = tk.Tk()
t = tk.Text(root)
t.pack()
t.bindtags(('Text','post-class-bindings', '.', 'all'))
t.bind_class("post-class-bindings", "<KeyPress>", check_pos)
t.bind_class("post-class-bindings", "<Button-1>", check_pos)
root.mainloop()

Related

Tkinter winfo_ismapped() method not working

I have a program in python which in which I use Listboxes, buttons and labels. So today I came conflicting with a problem. I wanted to make my listbox appear when a button is clicked and disappear when the same button is clicked again. How can I achieve this? I tried using the winfo_ismapped() method but didnt seem to work. I think I might have done something crazy. If so, please point it out and give me a corrected answer. Else please tell me a better way to do it.
My Code:
import tkinter as tk
from tkinter import *
root = tk.Tk()
root.geometry('500x500')
def showMenu():
overlay = Listbox(root, bg="green", height=22, width=58)
if overlay.winfo_ismapped() == 0:
overlay.place(x=0,y=35)
else:
overlay.placeforget()
button = tk.Button(root,text="place/remove", command=showMenu)
button.place(x=0,y=0)
root.mainloop()
Actually it comes when I press the button but hide after I press it again.
In the same way I have another issue with these labels too.
CODE:
import tkinter as tk
root = tk.Tk()
def placeFun():
successtext = tk.Label(root, text="Success", anchor='nw', bg="#212121", fg="#ff3300",font=("Consolas", 15, "bold"))
if successtext.winfo_ismapped() == 0:
successtext.place(x=0,y=50)
else:
succestext.forget()
button = tk.Button(root, text='place/rem', width=25, command=placeFun)
button.place(x=0,y=0)
root.mainloop()
Please Note: I want a professional way to handle this, I said it because, I know a way in which we use variables like:
globalvartimes = 0
def somefunc():
if times % 2 == 0:
show the listbox
global times
times += 2
else:
remove the listbox
times += 1
*This shows the listbox when times is even and remove it when it's odd.
These makes the code look non-professional and long.
The problem is every time showMenu() is called another Listbox is created. To fix that, create the Listbox outside of the function (so it's a global).
(I also noticed you misspelled the name of place_forget() method.)
import tkinter as tk
from tkinter import *
root = tk.Tk()
root.geometry('500x500')
def showMenu():
if overlay.winfo_ismapped(): # Placed?
overlay.place_forget()
else:
overlay.place(x=0,y=35)
overlay = Listbox(root, bg="green", height=22, width=58)
button = tk.Button(root,text="place/remove", command=showMenu)
button.place(x=0,y=0)
root.mainloop()
This looks like it is what is wrong with your Label example, too.
Note: If you want to write "professional" code, I suggest you read (and start following) the
PEP 8 - Style Guide for Python Code.

Tkinter - can't type into entry widget after restoring the window with wm_state('normal') function

I can't find any solution, so I hope you will help me.
I'm using in my project entry widgets and wm_state('iconic') and wm_state('normal) function. Unfortunatelly after restoring tkinter main window by using wm_state('normal) function I'm unable to use entry widget. Manually minimizing and restoring the window solves the problem. Do you have any idea, how can I avoid it? Below is the testing code I prepared for better understanding. Thank you for the help. I thought root.withdraw() is the solution, but unfortunately, program disappears then from the taskbar, what is not good in my case.
import tkinter as tk
from tkinter import ttk
import time
root = tk.Tk()
root.geometry('200x200')
def test_function():
root.wm_state('iconic')
time.sleep(0.5)
root.wm_state('normal')
button = tk.Button(root, text='MINIMIZE BUTTON', command=test_function)
button.grid(row=0, column=0)
entrywidget = tk.Entry(root, width='10')
entrywidget.grid(row=1, column=0)
entrywidget.focus()
root.mainloop()
Using:
root.withdraw()
root.deiconify()
Instead of:
root.wm_state('iconic')
root.wm_state('normal')
Solves the entry widget problem, but program is no longer visible on the taskbar after root.withdraw() until root.deiconify() method call.

Tkinter OptionMenu error

I'm having some issues getting my OptionMenu to work the first issue is that it wont work on it's on i have to use some placeholder label to get it to work. so in the below example it works if i use TaxYear as the master but not if i use TaxYearLi.
The second issue is that for some reason w.set("2018/2019") is not working i get an error that I'm passing a string not a stringvar
Edit: OK I've fixed the StringVar issue and setting a default value need to deffine root as Tk.Tk() if someone also could explain why this needs to be done that would be helpful.
import Tkinter as Tk
root = Tk.Tk()
w = Tk.StringVar
w.set("2018/2019")
TaxYear = Tk.Label(text="Select tax year")
TaxYear.grid(row=1, column=0)
TaxYearLi = Tk.OptionMenu(TaxYearLi, w, "2018/2019")
TaxYearLi.grid(row=1,column=1)
Tk.mainloop()
If you need to declare a variable (root in your case) as TK() is because Tk() is a class in Tkinter code which basicly create the window by asking it to your OS.
so you need to create a variable (some call it root others master, others parents) who's gona be your root/master/parent window and evry widget need to be on this variable.
Now about your OptionMenu, as i mentioned you need to put all your widgets on the main window (root in your case)
import Tkinter as Tk
root = Tk.Tk()
w = Tk.StringVar #in Python3 i need to put StringVar() i don't know about 2.x
w.set("2018/2019")
TaxYear = Tk.Label(text="Select tax year")
TaxYear.grid(row=1, column=0)
TaxYearLi = Tk.OptionMenu(root, w, "2018/2019") #needs to be on the root window
TaxYearLi.grid(row=1,column=1)
root.mainloop()

Removing/forgetting widgets on tkinter

I'm new to the Tkinter module (and quite new to python) I can't for the life of me figure out how to use the remove or forget methods to hide widgets in a grid. I can't seem to find relevant examples online and the tutorial documents have given me everything but the syntax. Below is the code I've been using to try and figure it out. Apologies if this overly trivial...
from tkinter import *
from tkinter import ttk
def delete():
#where I would like to delete the label 'label'
window = Tk()
window.title("Window")
window.configure(background='#e4e5ff')
label = ttk.Label(window, text='text').grid(column=1, row=0)
ttk.Button(window, text='text',command = delete).grid(column=2,row=0)
window.mainloop()
To do that you will have to use 2 lines to define and layout the widget (which is good practice anyway).
from tkinter import *
from tkinter import ttk
def delete():
label.grid_forget()
window = Tk()
window.title("Window")
window.configure(background='#e4e5ff')
label = ttk.Label(window, text='text')
label.grid(column=1, row=0)
btn = ttk.Button(window, text='text',command = delete)
btn.grid(column=2,row=0)
window.mainloop()
However, I suspect this is an XY problem. Are you trying to delete it in order to replace it with another Label? If so, you need to update the current label, not delete it and replace it.
def delete():
label.config(text='new_text')

string variable not working with

I have my main window, which i refer to as mainroot, and when i press a button the secondary window root should appear
in root there is an entry and i want it to be assigned to "hohoho" whenever i press anykey, so i tied it to KeyRelease event.
All i mentioned above is working when there is no mainroot, As in this code:
import tkinter as Tk
# mainroot=Tk.Tk()
root=Tk.Tk()
root.geometry("200x200")
myvar=Tk.StringVar()
entry=Tk.Entry(root,)
entry.pack()
entry.configure(textvariable=myvar)
entry.bind('<KeyRelease>',lambda event:printing())
def printing():
myvar.set("hohohohohohoho")
print('myvar is',myvar.get())
print('value is',entry.get())
root.mainloop()
# mainroot.mainloop()
but if you commented the root.mainloop() and uncommented root.mainloop() and # mainroot.mainloop() the text shown in entrystops following myvar.
what i found is that myvar is not working properly as it should.
anyone have any idea what am doing wrong or is this bug in tkinter or what?????
I know that entry.trace() is more elegant but i didn't use it because i am not very familiar with it.
thank you
any hint will be appreciated

Categories