亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Tkinter Treeview 如何用鼠標正確選擇多個項目

Tkinter Treeview 如何用鼠標正確選擇多個項目

慕田峪9158850 2022-10-18 16:29:33
我正在嘗試使用鼠標選擇和取消選擇多個項目。我有它的工作方式,但是當用戶快速移動鼠標時會出現問題。當鼠標快速移動時,一些項目被跳過并且根本沒有被選中。我一定是走錯路了。更新 1: 我決定使用自己的選擇系統,但得到的結果與上述相同。當鼠標移動到快速時,某些項目會被跳過,因此它們沒有添加正確的顏色標簽并保持不變。如果鼠標移動緩慢,則所有項目都會被正確選擇。下面是新代碼和問題的另一個圖像。更新 2:我已經解決了這個問題并發布了工作代碼,只是為了完整性和將來幫助其他人。我最終使用了自己的選擇系統,而不是內置的系統。import tkinter as tkimport tkinter.ttk as ttkclass App(tk.Tk):    def __init__(self):        super().__init__()        self.title('Treeview Demo')        self.geometry('300x650')        self.rowconfigure(0, weight=1)        self.columnconfigure(0, weight=1)        tv = self.tv = ttk.Treeview(self)        tv.heading('#0', text='Name')        # Populate tree with test data.        for idx in range(0, 4):            tv.insert('', idx, f'!{idx}', text=f'Item {idx+1}', tags='TkTextFont', open=1)            iid = f'!{idx}_!{idx}'            tv.insert(f'!{idx}', '0', iid, text=f'Python {idx+1}', tags='TkTextFont', open=1)            for i in range(0, 5):                tv.insert(iid, f'{i}', f'{iid}_!{i}', text=f'Sub item {i+1}', tags='TkTextFont')        tv.grid(sticky='NSEW')        self.active_item = None        def motion(_):            x, y = tv.winfo_pointerxy()            item = tv.identify('item', x - tv.winfo_rootx(), y - tv.winfo_rooty())            if not item or item == self.active_item:                return            if not self.active_item:                self.active_item = item            tv.selection_toggle(item)            self.active_item = item        def escape(_):            tv.selection_remove(tv.selection())        def button_press(_):            self.bind('<Motion>', motion)        def button_release(_):            self.unbind('<Motion>')            self.active_item = None        self.bind('<Escape>', escape)        self.bind('<Button-1>', button_press)        self.bind('<ButtonRelease-1>', button_release)def main():    app = App()    app.mainloop()if __name__ == '__main__':    main()
查看完整描述

1 回答

?
HUWWW

TA貢獻1874條經驗 獲得超12個贊

工作示例:


在 Windows 和 Linux 中測試和工作


更新:我已經更新了代碼,一切都在 Windows 和 Linux 中運行,盡管在 Windows 中,藍色透明窗口在從右到左調整大小時會抖動,從左到右很好。在 Linux 中不會發生抖動,有人知道為什么嗎?如果有人可以讓我知道下面的代碼是否適用于 MacOS,那也很棒。


import tkinter as tk

import tkinter.ttk as ttk

import tkinter.font as tkfont



class Treeview(ttk.Treeview):

    def __init__(self, parent, **kwargs):

        super().__init__(parent, **kwargs)


        self.root = parent.winfo_toplevel()

        self.selected_items = []

        self.origin_x = \

            self.origin_y = \

            self.active_item = \

            self.origin_item = None


        sw = self.select_window = tk.Toplevel(self.root)

        sw.wait_visibility(self.root)

        sw.withdraw()

        sw.config(bg='#00aaff')

        sw.overrideredirect(True)

        sw.wm_attributes('-alpha', 0.3)

        sw.wm_attributes("-topmost", True)


        self.font = tkfont.nametofont('TkTextFont')

        self.style = parent.style

        self.linespace = self.font.metrics('linespace') + 5


        self.bind('<Escape>', self.tags_reset)

        self.bind('<Button-1>', self.button_press)

        self.bind('<ButtonRelease-1>', self.button_release)


    def fixed_map(self, option):

        return [elm for elm in self.style.map("Treeview", query_opt=option) if elm[:2] != ("!disabled", "!selected")]


    def tag_add(self, tags, item):

        self.tags_update('add', tags, item)


    def tag_remove(self, tags, item=None):

        self.tags_update('remove', tags, item)


    def tag_replace(self, old, new, item=None):

        for item in (item,) if item else self.tag_has(old):

            self.tags_update('add', new, item)

            self.tags_update('remove', old, item)


    def tags_reset(self, _=None):

        self.tag_remove(('selected', '_selected'))

        self.tag_replace('selected_odd', 'odd')

        self.tag_replace('selected_even', 'even')


    def tags_update(self, opt, tags, item):

        def get_items(node):

            items.append(node)

            for node in self.get_children(node):

                get_items(node)


        if not tags:

            return

        elif isinstance(tags, str):

            tags = (tags,)


        if not item:

            items = []

            for child in self.get_children():

                get_items(child)

        else:

            items = (item,)


        for item in items:

            _tags = list(self.item(item, 'tags'))

            for _tag in tags:

                if opt == 'add':

                    if _tag not in _tags:

                        _tags.append(_tag)

                elif opt == 'remove':

                    if _tag in _tags:

                        _tags.pop(_tags.index(_tag))

            self.item(item, tags=_tags)


    def button_press(self, event):

        self.origin_x, self.origin_y = event.x, event.y

        item = self.origin_item = self.active_item = self.identify('item', event.x, event.y)


        sw = self.select_window

        sw.geometry('0x0+0+0')

        sw.deiconify()


        self.bind('<Motion>', self.set_selected)


        if not item:

            if not event.state & 1 << 2:

                self.tags_reset()

            return


        if event.state & 1 << 2:

            if self.tag_has('odd', item):

                self.tag_add('selected', item)

                self.tag_replace('odd', 'selected_odd', item)

            elif self.tag_has('even', item):

                self.tag_add('selected', item)

                self.tag_replace('even', 'selected_even', item)

            elif self.tag_has('selected_odd', item):

                self.tag_replace('selected_odd', 'odd', item)

            elif self.tag_has('selected_even', item):

                self.tag_replace('selected_even', 'even', item)

        else:

            self.tags_reset()

            self.tag_add('selected', item)

            if self.tag_has('odd', item):

                self.tag_replace('odd', 'selected_odd', item)

            elif self.tag_has('even', item):

                self.tag_replace('even', 'selected_even', item)


    def button_release(self, _):

        self.select_window.withdraw()

        self.unbind('<Motion>')


        for item in self.selected_items:

            if self.tag_has('odd', item) or self.tag_has('even', item):

                self.tag_remove(('selected', '_selected'), item)

            else:

                self.tag_replace('_selected', 'selected', item)


    def get_selected(self):

        return sorted(self.tag_has('selected_odd') + self.tag_has('selected_even'))


    def set_selected(self, event):

        def selected_items():

            items = []

            window_y = int(self.root.geometry().rsplit('+', 1)[-1])

            titlebar_height = self.root.winfo_rooty() - window_y

            sw = self.select_window

            start = sw.winfo_rooty() - titlebar_height - window_y

            end = start + sw.winfo_height()


            while start < end:

                start += 1

                node = self.identify('item', event.x, start)

                if not node or node in items:

                    continue

                items.append(node)


            return sorted(items)


        def set_row_colors():

            items = self.selected_items = selected_items()


            for item in items:

                if self.tag_has('selected', item):

                    if item == self.origin_item:

                        continue


                    if self.tag_has('selected_odd', item):

                        self.tag_replace('selected_odd', 'odd', item)

                    elif self.tag_has('selected_even', item):

                        self.tag_replace('selected_even', 'even', item)


                elif self.tag_has('odd', item):

                    self.tag_replace('odd', 'selected_odd', item)

                elif self.tag_has('even', item):

                    self.tag_replace('even', 'selected_even', item)


                self.tag_add('_selected', item)


            for item in self.tag_has('_selected'):

                if item not in items:

                    self.tag_remove('_selected', item)

                    if self.tag_has('odd', item):

                        self.tag_replace('odd', 'selected_odd', item)

                    elif self.tag_has('even', item):

                        self.tag_replace('even', 'selected_even', item)

                    elif self.tag_has('selected_odd', item):

                        self.tag_replace('selected_odd', 'odd', item)

                    elif self.tag_has('selected_even', item):

                        self.tag_replace('selected_even', 'even', item)


        root_x = self.root.winfo_rootx()

        if event.x < self.origin_x:

            width = self.origin_x - event.x

            coord_x = root_x + event.x

        else:

            width = event.x - self.origin_x

            coord_x = root_x + self.origin_x


        if coord_x+width > root_x+self.winfo_width():

            width -= (coord_x+width)-(root_x+self.winfo_width())

        elif self.winfo_pointerx() < root_x:

            width -= (root_x - self.winfo_pointerx())

            coord_x = root_x


        root_y = self.winfo_rooty()

        if event.y < self.origin_y:

            height = self.origin_y - event.y

            coord_y = root_y + event.y

        else:

            height = event.y - self.origin_y

            coord_y = root_y + self.origin_y


        if coord_y+height > root_y+self.winfo_height():

            height -= (coord_y+height)-(root_y+self.winfo_height())

        elif self.winfo_pointery() < root_y + self.linespace:

            height -= (root_y - self.winfo_pointery() + self.linespace)

            coord_y = root_y + self.linespace

            if height < 0:

                height = self.winfo_rooty() + self.origin_y


        set_row_colors()

        self.select_window.geometry(f'{width}x{height}+{coord_x}+{coord_y}')



class App(tk.Tk):

    def __init__(self):

        super().__init__()


        def print_selected_items(_):

            print(tv.get_selected())

            return 'break'


        style = self.style = ttk.Style()


        tv = Treeview(self)

        style.map("Treeview", foreground=tv.fixed_map("foreground"), background=tv.fixed_map("background"))


        tv.heading('#0', text='Name')

        tv.tag_configure('odd', background='#ffffff')

        tv.tag_configure('even', background='#aaaaaa')

        tv.tag_configure('selected_odd', background='#b0eab2')

        tv.tag_configure('selected_even', background='#25a625')


        color_tag = 'odd'

        for idx in range(0, 4):

            # Populating the tree with test data.

            color_tag = 'even' if color_tag == 'odd' else 'odd'

            tv.insert('', idx, f'{idx}', text=f'Item {idx+1}', open=1, tags=(color_tag,))

            color_tag = 'even' if color_tag == 'odd' else 'odd'

            iid = f'{idx}_{0}'

            tv.insert(f'{idx}', '0', iid, text=f'Menu {idx+1}', open=1, tags=(color_tag,))

            for i in range(0, 5):

                color_tag = 'even' if color_tag == 'odd' else 'odd'

                tv.insert(iid, i, f'{iid}_{i}', text=f'Sub item {i+1}', tags=(color_tag,))


            color_tag = 'even' if color_tag == 'odd' else 'odd'

            tv.insert(iid, 5, f'{iid}_{5}', text=f'Another Menu {idx+1}', open=1, tags=(color_tag,))

            iid = f'{iid}_{5}'

            for i in range(0, 3):

                color_tag = 'even' if color_tag == 'odd' else 'odd'

                tv.insert(iid, i, f'{iid}_{i}', text=f'Sub item {i+1}', tags=(color_tag,))


        self.title('Treeview Demo')

        self.geometry('275x650+3000+250')

        self.rowconfigure(0, weight=1)

        self.columnconfigure(0, weight=1)


        tv.config(selectmode="none")

        tv.grid(sticky='NSEW')


        button = ttk.Button(self, text='Get Selected Items')

        button.grid()

        button.bind('<Button-1>', print_selected_items)



def main():

    app = App()

    app.mainloop()



if __name__ == '__main__':

    main()


查看完整回答
反對 回復 2022-10-18
  • 1 回答
  • 0 關注
  • 250 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號