tkinter selectmode single and multiple behavior for listbox

I have a listbox I would like to only select one item if I double-click on it, and use multiple selection mode when items are single-click. Is this possible?

The code below doesn't quite do what I would want either since it calls single click events when double-click events are called. I would ideally like to destinquish between the two.

from tkinter import *

class Message:
    def __init__(self, root):
        self.list_item = StringVar()
        self.listBoxObj = Listbox(root, listvariable=self.list_item, selectmode='multiple')
        listItems = ['Jane', 'Kate', 'Dani']
        self.listBoxObj.pack()
        self.listBoxObj.bind('<Double-Button-1>', self.on_double_click)
        self.listBoxObj.bind('<ButtonRelease-1>', self.on_single_click)
        for item in listItems:
            self.listBoxObj.insert(END, item)

    def on_double_click(self, event):
         widget = event.widget
         selection = widget.curselection()
         value = widget.get(selection[0])
         popup = Tk()
         popup.geometry('300x200')
         listBox2 = Listbox(popup)
         listBox2.insert(END, str(value))
         listBox2.pack()
         popup.mainloop()

    def on_single_click(self,event):
        print('do something different here')

if __name__ == '__main__':
    root = Tk()
    cMessageObj = Message(root)
    root.mainloop()

Upvotes: 0

Views: 4000

Answers (2)

Bruno Vermeulen
Bruno Vermeulen

Reputation: 1

In order to distinguish action between a single click and a double click, delay the call to mouse action for a brief period to allow for the double click flag to be set. See below example:

from tkinter import *

def mouse_click(event):
    '''  delay mouse action to allow for double click to occur
    '''
    aw.after(300, mouse_action, event)

def double_click(event):
    '''  set the double click status flag
    '''
    global double_click_flag
    double_click_flag = True

def mouse_action(event):
    global double_click_flag
    if double_click_flag:
        print('double mouse click event')
        double_click_flag = False
    else:
        print('single mouse click event')

root = Tk()
aw = Canvas(root, width=200, height=100, bg='grey')
aw.place(x=0, y=0)

double_click_flag = False
aw.bind('<Button-1>', mouse_click) # bind left mouse click
aw.bind('<Double-1>', double_click) # bind double left clicks
aw.mainloop()

Upvotes: 0

Bryan Oakley
Bryan Oakley

Reputation: 385880

Tkinter will always send both a single click and a double click event when the user double clicks. Think of it this way: when you click once, the computer has no idea if you are going to click a second time or not, so it sends the single click event.

If you click a second time, tkinter will compare the timestamp to the previous click event and if it's under a threshold it will register a double-click. At that point it is unable to rescind the single-click event.

If you need to distinguish between the two, you need to set it up so that any single-click action happens a short time in the future (via after). Then, if you get a double-click you can cancel the single-click action.

From a usability perspective I don't recommend doing that. Under most circumstances a single click should always do something, and a double click will do something in addition to the single click.

Upvotes: 1

Related Questions