2

Tkinter リストボックスの項目をエントリ ウィジェットにする方法はありますか? その結果、Listbox エントリ内のテキストを動的に変更できるようになります。リストボックスが次のようになっている場合:

 --------
| Apples  |
| Pears   |
| Oranges |
 ---------

次に、Apples をクリックして任意のテキストを書き込めるようにします。たとえば、Enter キーをバインドして、新しいテキストに基づいて関数をトリガーすることができます。

4

4 に答える 4

6

この質問からしばらく経ちましたが、「ListboxEditable」というウィジェットを作成しました。これはリストボックスとして機能し、アイテムをダブルクリックすると、ユーザーはエントリ内に何でも入力できます。次に、ユーザーが別の行をクリックすると、対応する変更されたセルに情報が保存されます。ユーザーは上下のキーを使用して、指定されたリスト全体を参照できることに注意してください (選択した行の背景色は異なります)。

このコードは、@Bryan Oakley からの回答に基づいて開発されました。

最小限の作業ケース

# Imports
from tkinter import *
from tkinter.ttk import *
# Import for the listboxEditable
from ListboxEditable import *

# Colors
colorActiveTab="#CCCCCC" # Color of the active tab
colorNoActiveTab="#EBEBEB" # Color of the no active tab
# Fonts
fontLabels='Calibri'
sizeLabels2=13

# Main window
root = Tk()

# *** Design *****
frame_name=Frame(root,bg=colorActiveTab) # Column frame
frame_name_label=Frame(frame_name,bg='blue') # Label frame
label_name=Label(frame_name_label, text="Header", bg='blue', fg='white', font=(fontLabels, sizeLabels2, 'bold'), pady=2, padx=2, width=10)
frame_name_listbox=Frame(frame_name,bg='blue') # Label frame
list_name=['test1','test2','test3']
listBox_name=ListboxEditable(frame_name_listbox,list_name)

# *** Packing ****
frame_name.pack(side=LEFT,fill=Y)
frame_name_label.pack(side=TOP, fill=X)
label_name.pack(side=LEFT,fill=X)
frame_name_listbox.pack(side=TOP, fill=X)
listBox_name.placeListBoxEditable()

# Infinite loop
root.mainloop()

ListboxEditable クラス

# Author: David Duran Perez
# Date: May 26, 2017

# Necessary imports
from tkinter import *
from tkinter import ttk

# Colors
colorActiveTab="#CCCCCC" # Color of the active tab
colorNoActiveTab="#EBEBEB" # Color of the no active tab
# Fonts
fontLabels='Calibri'
sizeLabels2=13

class ListboxEditable(object):
    """A class that emulates a listbox, but you can also edit a field"""
    # Constructor
    def __init__(self,frameMaster,list):
        # *** Assign the first variables ***
        # The frame that contains the ListboxEditable
        self.frameMaster=frameMaster
        # List of the initial items
        self.list=list
        # Number of initial rows at the moment
        self.numberRows=len(self.list)

        # *** Create the necessary labels ***
        ind=1
        for row in self.list:
            # Get the name of the label
            labelName='label'+str(ind)
            # Create the variable
            setattr(self, labelName, Label(self.frameMaster, text=self.list[ind-1], bg=colorActiveTab, fg='black', font=(fontLabels, sizeLabels2), pady=2, padx=2, width=10))

            # ** Bind actions
            # 1 left click - Change background
            getattr(self, labelName).bind('<Button-1>',lambda event, a=labelName: self.changeBackground(a))
            # Double click - Convert to entry
            getattr(self, labelName).bind('<Double-1>',lambda event, a=ind: self.changeToEntry(a))
            # Move up and down
            getattr(self, labelName).bind("<Up>",lambda event, a=ind: self.up(a))
            getattr(self, labelName).bind("<Down>",lambda event, a=ind: self.down(a))

            # Increase the iterator
            ind=ind+1

    # Place
    def placeListBoxEditable(self):
        # Go row by row placing it
        ind=1
        for row in self.list:
            # Get the name of the label
            labelName='label'+str(ind)
            # Place the variable
            getattr(self, labelName).grid(row=ind-1,column=0)

            # Increase the iterator
            ind=ind+1


    # Action to do when one click
    def changeBackground(self,labelNameSelected):
        # Ensure that all the remaining labels are deselected
        ind=1
        for row in self.list:
            # Get the name of the label
            labelName='label'+str(ind)
            # Place the variable
            getattr(self, labelName).configure(bg=colorActiveTab)

            # Increase the iterator
            ind=ind+1

        # Change the background of the corresponding label
        getattr(self, labelNameSelected).configure(bg=colorNoActiveTab)
        # Set the focus for future bindings (moves)
        getattr(self, labelNameSelected).focus_set()


    # Function to do when up button pressed
    def up(self, ind):
        if ind==1: # Go to the last
            # Get the name of the label
            labelName='label'+str(self.numberRows)
        else: # Normal
            # Get the name of the label
            labelName='label'+str(ind-1)

        # Call the select
        self.changeBackground(labelName)


    # Function to do when down button pressed
    def down(self, ind):
        if ind==self.numberRows: # Go to the last
            # Get the name of the label
            labelName='label1'
        else: # Normal
            # Get the name of the label
            labelName='label'+str(ind+1)

        # Call the select
        self.changeBackground(labelName)


    # Action to do when double-click
    def changeToEntry(self,ind):
        # Variable of the current entry
        self.entryVar=StringVar()
        # Create the entry
        #entryName='entry'+str(ind) # Name
        self.entryActive=ttk.Entry(self.frameMaster, font=(fontLabels, sizeLabels2), textvariable=self.entryVar, width=10)
        # Place it on the correct grid position
        self.entryActive.grid(row=ind-1,column=0)
        # Focus to the entry
        self.entryActive.focus_set()

        # Bind the action of focusOut
        self.entryActive.bind("<FocusOut>",lambda event, a=ind: self.saveEntryValue(a))

    
    # Action to do when focus out from the entry
    def saveEntryValue(self,ind):
        # Find the label to recover
        labelName='label'+str(ind)
        # Remove the entry from the screen
        self.entryActive.grid_forget()
        # Place it again
        getattr(self, labelName).grid(row=ind-1,column=0)
        # Change the name to the value of the entry
        getattr(self, labelName).configure(text=self.entryVar.get())

いくつかのスクリーンショット

ここに画像の説明を入力

ここに画像の説明を入力

ここに画像の説明を入力

于 2017-05-26T15:04:31.263 に答える
0
import tkinter as tk
root=tk.Tk()
# root.geometry('300x240')



sb = tk.Scrollbar(root)
sb.pack(side=tk.RIGHT,fill=tk.Y)
E1 = tk.Entry(root)
E1.pack()

mylist = [*range(15)]

v = tk.StringVar(value=mylist)
b1=tk.Listbox(root,activestyle='dotbox',yscrollcommand=sb.set,listvariable=v,selectmode='SINGLE')

sb.config(command=b1.yview)
# for i in range(1,15):
#     b1.insert(tk.END,i)
b1.pack()

def isfloat(s):
    try:
        return float(s)<float('inf')
    except:
        return False

def isInt(s):
    try:
        return int(s)<float('inf')
    except:
        return False

def set_entry_text(text):
    E1.delete(0,tk.END)
    E1.insert(0,text)


def set_item(event):
    text = E1.get()
    E1.delete(0,tk.END)
    index = b1.curselection()[0]
    b1.delete(index)
    b1.insert(index,text)
    print(v.get())

def set_item1(event):
    text = E1.get()
    E1.delete(0,tk.END)
    index = b1.curselection()[0]
    if isInt(text):
        mylist[index] = int(text)
    elif isfloat(text):
        mylist[index] = float(text)
    else:
        mylist[index] = text

    v.set(mylist)
    print(v.get())

def edit_item(event):
    text = E1.selection_get()
    # set_entry_text(text)
    E1.focus()


b1.bind('<Double-1>', edit_item)
E1.bind('<Return>',set_item1)
root.mainloop()
于 2020-10-06T00:36:32.337 に答える