0

Hi guys i'm new to Python, could you please teach me how to not allow clicks in a specific area in Tkinter? I created this window and is a calculator with buttons that i made, how to ignore the clicks only in the grey zone? I want that if the users clicks the grey area nothing happens because now if i click the grey area the strings become underlined ecc, how to ignore the clicks? The grey zone is a simple Listbox which contains the history of my calculations written in strings.

This is the code, i created Listbox in the cronologia variable in the last lines of code:

    from tkinter import *
total = ""
def button_press(num):
    global  equation_text
    equation_text = equation_text + str(num)
    equation_lable.set(equation_text)
    if equation_text.count("++") or equation_text.count("+-") or equation_text.count("+*") or equation_text.count("+/") or equation_text.count("-+") or equation_text.count("--") or equation_text.count("-*") or equation_text.count("-/") or equation_text.count("*+")  or equation_text.count("**") or equation_text.count("*/") or equation_text.count("/+") or equation_text.count("/*") or equation_text.count("//"):
        equation_lable.set("Errore")
        equation_text=""
def elimina_cronologia(*args):
   cronologia.delete(0,END)
def cancella(*args):
    global equation_text
    equation_text = equation_text[:-1]
    equation_lable.set(equation_text)
def equals(*args):
    global equation_text
    global total
    try:
        total = total + equation_text
        total = eval(total)
        total = float(total)
        total = round(total,3)
        equation_lable.set(total)
        total = str (total)
        cronologia.insert(0," "+ equation_text + " = " + total)
        equation_text = ""
    except ZeroDivisionError:
        equation_lable.set("Errore")
        equation_text = ""
    except SyntaxError:
        equation_lable.set("Errore")
        equation_text = ""
def clear(*args):
    global  equation_text
    global  total
    equation_lable.set("")
    equation_text=""
    total = ""
window = Tk()
window.resizable(width=False, height=False)
window.title("Calcolatrice")
window.geometry("643x390")
equation_text = ""
equation_lable = StringVar()
label = Label(window, textvariable=equation_lable, font=("consolas", 20), bg="#1C7B00", fg="white", width=22, height=2)
label.place(x=-45, y=0)
bottone01= Button(window, text= "7", font= ('Helvetica 20 '),width=5,height=1,bg="#008BC7", command=lambda:button_press("7"))
bottone01.configure(activebackground="#00A1E6")
bottone01.place(x=-11, y=80)
bottone02= Button(window, text= "8", font= ('Helvetica 20 '),width=4,height=1,bg="#008BC7", command=lambda:button_press("8"))
bottone02.configure(activebackground="#00A1E6")
bottone02.place(x=80, y=80)
bottone03= Button(window, text= "9", font= ('Helvetica 20 '),width=4,height=1,bg="#008BC7", command=lambda:button_press("9"))
bottone03.configure(activebackground="#00A1E6")
bottone03.place(x=165, y=80)
bottone04= Button(window, text= "-", font= ('Helvetica 20 '),width=3,height=1,bg="#FF9D12", command=lambda:button_press("-"))
bottone04.configure(activebackground="#FFB245")
bottone04.place(x=250, y=80)
bottone05= Button(window, text= "4", font= ('Helvetica 20 '),width=5,height=1,bg="#008BC7", command=lambda:button_press("4"))
bottone05.configure(activebackground="#00A1E6")
bottone05.place(x=-11, y=140)
bottone06= Button(window, text= "5", font= ('Helvetica 20 '),width=4,height=1,bg="#008BC7", command=lambda:button_press("5"))
bottone06.configure(activebackground="#00A1E6")
bottone06.place(x=80, y=140)
bottone07= Button(window, text= "6", font= ('Helvetica 20 '),width=4,height=1,bg="#008BC7", command=lambda:button_press("6"))
bottone07.configure(activebackground="#00A1E6")
bottone07.place(x=165, y=140)
bottone08= Button(window, text= "+", font= ('Helvetica 20 '),width=3,height=1,bg="#FF9D12", command=lambda:button_press("+"))
bottone08.configure(activebackground="#FFB245")
bottone08.place(x=250, y=140)
bottone09= Button(window, text= "1", font= ('Helvetica 20 '),width=5,height=1,bg="#008BC7", command=lambda:button_press("1"))
bottone09.configure(activebackground="#00A1E6")
bottone09.place(x=-11, y=200)
bottone10= Button(window, text= "2", font= ('Helvetica 20 '),width=4,height=1,bg="#008BC7", command=lambda:button_press("2"))
bottone10.configure(activebackground="#00A1E6")
bottone10.place(x=80, y=200)
bottone11= Button(window, text= "3", font= ('Helvetica 20 '),width=4,height=1,bg="#008BC7", command=lambda:button_press("3"))
bottone11.configure(activebackground="#00A1E6")
bottone11.place(x=165, y=200)
bottone12= Button(window, text= "x", font= ('Helvetica 20 '),width=3,height=1,bg="#FF9D12", command=lambda:button_press("x"))
bottone12.configure(activebackground="#FFB245")
bottone12.place(x=250, y=200)
bottone13= Button(window, text= ",", font= ('Helvetica 20 '),width=5,height=1,bg="#008BC7", command=lambda:button_press("."))
bottone13.configure(activebackground="#00A1E6")
bottone13.place(x=-11, y=260)
bottone14= Button(window, text= "0", font= ('Helvetica 20 '),width=4,height=1,bg="#008BC7", command=lambda:button_press("0"))
bottone14.configure(activebackground="#00A1E6")
bottone14.place(x=80, y=260)
bottone15= Button(window, text= "=", font= ('Helvetica 20 '),width=4,height=1,bg="#008BC7", command=equals)
bottone15.configure(activebackground="#00A1E6")
bottone15.place(x=165, y=260)
bottone16= Button(window, text= "/", font= ('Helvetica 20 '),width=3,height=1,bg="#FF9D12", command=lambda:button_press("/"))
bottone16.configure(activebackground="#FFB245")
bottone16.place(x=250, y=260)
bottone17= Button(window, text= "Cancella", font= ('Helvetica 23 '),width=10,height=1,bg="#008BC7", command=clear)
bottone17.configure(activebackground="#00A1E6")
bottone17.place(x=-20, y=320)
bottone18= Button(window,width=60,height=69, font= ('Helvetica 20 '),bg="#008BC7", command=elimina_cronologia)
bottone18.configure(activebackground="#00A1E6")
bottone18.place(x=250, y=320)
bottone19= Button(window,width=54,height=69, font= ('Helvetica 20 '),bg="#008BC7", command=cancella)
bottone19.configure(activebackground="#FFB245")
bottone19.place(x=190, y=320 )
window.bind("0", lambda _: button_press(0))
window.bind("1", lambda _: button_press(1))
window.bind("2", lambda _: button_press(2))
window.bind("3", lambda _: button_press(3))
window.bind("4", lambda _: button_press(4))
window.bind("5", lambda _: button_press(5))
window.bind("6", lambda _: button_press(6))
window.bind("7", lambda _: button_press(7))
window.bind("8", lambda _: button_press(8))
window.bind("9", lambda _: button_press(9))
window.bind("+", lambda _: button_press("+"))
window.bind("-", lambda _: button_press("-"))
window.bind("*", lambda _: button_press("*"))
window.bind("/", lambda _: button_press("/"))
window.bind(".", lambda _: button_press("."))
window.bind("<Down>", elimina_cronologia)
window.bind("<Return>", equals)
window.bind("<BackSpace>", clear)
window.bind("<Left>", cancella)
scrollbar = Scrollbar(window)
scrollbar.pack(side=RIGHT, fill=Y)
cronologia = Listbox(window)
cronologia.pack()
cronologia.place(x=315,y=0)
cronologia.configure(font=('Helvetica 20 '),width=17,height=10,bg="#4a4a4a", fg="#dedede")
cronologia.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=cronologia.yview)
window.mainloop()

Thanksenter image description here

AcK
  • 2,063
  • 2
  • 20
  • 27

1 Answers1

0

To prevent the text in a Listbox from getting underlined and highlighted, you must disable the default functionality when an item in a listbox is clicked (<Button-1>) or when the user drags (<Motion>) the mouse over an item or when the pointer is moved out of the listbox (<Leave>).

Therefore, you must bind the listbox to a function (onCronologiaSelect) which returns "break" for all the events - <Button-1>, <Motion> and <Leave>.


Why do we return "break"?

In tkinter, an event can be bound to multiple event handlers (functions). These event handlers have an order of execution. To stop tkinter from executing the next handler in the queue, the current handler must return "break". Note that this is not equivalent to break which is used to exit a loop.

As onCronologiaSelect returns "break", the default handler which underlines/highlightes an item is not executed.


Solution:

def onCronologiaSelect(event):
    return "break"

cronologia = Listbox(window)
cronologia.place(x=315,y=0)
cronologia.configure(font=('Helvetica 20 '),width=17,height=10,bg="#4a4a4a", fg="#dedede",yscrollcommand=scrollbar.set)
cronologia.bind('<Button-1>', onCronologiaSelect)
cronologia.bind('<Motion>', onCronologiaSelect)
cronologia.bind('<Leave>', onCronologiaSelect)

Alternatively, lambda can be used as follows:

cronologia.bind('<Button-1>', lambda e: "break")
cronologia.bind('<Motion>', lambda e: "break")
cronologia.bind('<Leave>', lambda e: "break")


Alternative Approach:

Instead of individually disabling the default class bindings, you can directly remove the class tag ('Listbox') from the binding tags as shown below:

bind_tags = list(cronologia.bindtags())
bind_tags.remove('Listbox')
cronologia.bindtags(bind_tags)

From https://tkdocs.com/shipman/universal.html :

w.bindtags(tagList=None)

If you call this method, it will return the “binding tags” for the widget as a sequence of strings. A binding tag is the name of a window (starting with '.') or the name of a class (e.g., 'Listbox').

You can change the order in which binding levels are called by passing as an argument the sequence of binding tags you want the widget to use.

Sriram Srinivasan
  • 650
  • 2
  • 4
  • 14
  • Ok thanks i tried to implement it but sometimes the clicks are ignored sometimes don't, there is simply a way to ignor at all the clicks in a delimited zone of the windows?? – Stefano9669 Apr 15 '22 at 11:06
  • @Stefano9669 I have updated my answer now to resolve the issue you faced. You would have faced the issue when you dragged your mouse over an item in the listbox. If that event (``) is also disabled, you will get the desired output, as explained in the answer. – Sriram Srinivasan Apr 15 '22 at 11:17
  • @Stefano9669 Do let me know if it works properly now. Also, if you have doubts, please feel free to ask. – Sriram Srinivasan Apr 15 '22 at 11:37
  • OK thanks a lot now works and all the random clicks are ignored thanks again, could you please explain me more how your solutions works in order to understand better what i'm doing, for example "Button 1" is referred to what? To the left click of the mouse? – Stefano9669 Apr 15 '22 at 11:55
  • You can refer to [this](https://stackoverflow.com/questions/32289175/list-of-all-tkinter-events) answer to understand events in tkinter. – Sriram Srinivasan Apr 15 '22 at 11:57
  • Sorry Sriram i have one last question, what means the "return" in the function? def onCronologiaSelect(event): return "break" What's his purpose i mean? Why i can't just write the "break" function? thanks – Stefano9669 Apr 15 '22 at 12:52
  • @Stefano9669 An event can be bound to multiple event handlers (functions). These event handlers have an order of execution. If you want to stop tkinter from continuing with the next handler in queue, the current handler must return `"break"`. Note that this is not the same as the `break` which is used to exit a loop. In your code, as the function returns `"break"`, the default function which underlines/highlightes an item is not executed. – Sriram Srinivasan Apr 15 '22 at 13:10
  • Hi Sriram sorry but there is still one "bug", if you copy and try my code even with the function Motion and Button-1 that are connected to the onCronologiaSelect function, if i make only one operation for example 3+5 and press equal, if you drag and drop the left botton of the mouse starting in the middle of the grey are until you cover the text, the text is still selected, could you try and eventually give me a solution? I can't resolve this :( – Stefano9669 Apr 16 '22 at 09:46
  • @Stefano9669 It turns out that if you also bind `` to `onCronologiaSelect`, your problem gets solved. I will update my answer with the same. – Sriram Srinivasan Apr 16 '22 at 10:46
  • 1
    Hey it worked, thanks again you really helped me :D – Stefano9669 Apr 16 '22 at 10:48
  • @Stefano9669 If you are interested, do check out the alternative approach I have added to the answer. It is probably shorter/simpler than the earlier approach. – Sriram Srinivasan Apr 16 '22 at 16:50