بعد از آشنایی با چند ویجت اساسی tkinter کم کم با سایر ویجت ها آشنا می شویم و این بار نوبت listbox است. در این ویجت می توان آیتمهایی را اضافه کرد یا حذف نمود. برای شروع ابتدا برنامه ای می نویسیم که یک لیست باکس را ایجاد کند و تعدادی آیتم را نمایش دهد.

برنامه اولیه را در زیر می بینید:

import tkinter as tk
from  tkinter import *
root=tk.Tk()
root.geometry("300x220")
root.resizable(False,False)
lst=Listbox(root)
lst.place(height=150,width=100,x=100,y=30)
lst.insert(1, "آنالوگ")
lst.insert(2, "دیجیتال")
lst.insert(3, "نرم افزار")
lst.insert(4, "برنامه نویسی")
lst.insert(5, "AVR")
lst.insert(6, "ARM")
lst.insert(7, "Rasbery Pie")
lst.insert(8, "تجهیزات پزشکی")
root.mainloop()

توضیح برنامه:

حتما می دانید پنجره اصلی را در خطوط 1 تا 5 ایجاد کردیم. در خط 1 tkinter را با نام مستعار و کوتاه و دلخواه tk فراخوانی کردیم و در ادامه برنامه هم به جای استفاده از tkinter از همان tk که به آن اختصاص داده ایم استفاده می کنیم.

در خط 6 و 7 لیست باکسی به نام lst تعریف و ابعاد و مکان آن را تعیین کردیم.

در خطوط بعدی با استفاده از دستور insert آیتمهایی را به لیست باکس اضافه می کنیم و در انتها حلقه اصلی را اجرا می کنیم.

بعد از اجرای برنامه پنجره زیر نمایش داده می شود:

همان طور که می بینید صرفا لیست باکس به همراه آیتمهایش نمایش داده می شود و برنامه کار خاصی انجام نمی دهد. برای اینکه بتوانیم کاری روی این آیتمها انجام بدهیم لازم است تا با مفهوم بسیار مهمی در tkinter آشنا بشویم به نام bind.

مدیریت رخدادها با استفاده از bind

با استفاده از bind می توانیم رخدادهی مختلف را مدیریت کنیم. مثلا اگر کاربر روی یکی از آیتمهای داخل لیست دابل کلیک کند چه اتفاقی بیفتد؟ یبایید برنامه را طوری تغییر دهیم که با دابل کلیک روی یک آیتم، شماره ایندکس آن روی یک لیبل نمایش داده شود.
برای این کار برنامه را به صورت زیر تغییر می دهیم:

import tkinter as tk
from  tkinter import *
root=tk.Tk()
root.geometry("300x220")
root.resizable(False,False)
def show(event):
    itemnumber = lst.curselection()
    lblNumber.configure(text=itemnumber)
lst=Listbox(root)
lst.place(height=150,width=100,x=100,y=30)
lst.insert(1, "آنالوگ")
lst.insert(2, "دیجیتال")
lst.insert(3, "نرم افزار")
lst.insert(4, "برنامه نویسی")
lst.insert(5, "AVR")
lst.insert(6, "ARM")
lst.insert(7, "Rasbery Pie")
lst.insert(8, "تجهیزات پزشکی")
lblNumber=Label(root, text="Number")
lblNumber.place(height=10,width=60,x=100,y=10)
lst.bind('<Double-1>', show)
root.mainloop()

توضیح برنامه:

در خط 19 یک لیبل ایجاد کردیم به نام lblNumber و در خط 20 اندازه و مکان این لیبل مشخص شده است.

در خط 6 تابعی ایجاد کردیم به نام show و در پرانتز با کلمه event مشخص کردیم که این تابع در پاسخ به یک رخداد فراخوانی خواهد شد.

در خط 21 با استفاده از دستور bind و عبارت >Double-1< مشخص کرده ایم که اگر رخداد دابل کلیک روی کلید چپ ماوس روی lst روی دهد تابع show فراخوانی خواهد شد.

خطوط 7 و 8 بدنه تابع show را شکل می دهند. عبارت curselection شماره ایندکس آیتم انتخاب شده هست. در واقع در خط 7 ما شماره آیتمی را که انتخاب شده در متغیر itemnumber  ذخیره می کنیم. سپس در خط بعد به عنوان متن لیبل نمایش می دهیم.

در تصویر زیر می بینید که چطور این برنامه اجرا شده است:

همان طور که می بینید آیتم چهارم در لیست انتخاب شده اما عدد 3 نمایش داده شده و علت این است که شماره ایندکس آیتمهای لیست باکس از صفر شروع می شود. اگر بخواهیم به جای دابل کلیک صرفا با انتخاب ساده یک آیتم شماره آن را نمایش دهیم می توانیم خط 21 از برنامه بالا را به این صورت عوض کنیم:

lst.bind(‘<<ListboxSelect>>’, show)

یک راه دیگر برای اینکه آیتمها را در لیست باکس وارد کنیم این است که به جای استفاده از insert ابتدا آیتمها را در یک لیست ذخیره کنیم، بعد یک متغیر tkinter از نوع stringVar ایجاد می کنیم و لیست را در آن ذخیره می نماییم و موقع ایجاد لیست باکس این متغیر را به عنوان لیست آیتمهای اولیه معرفی می کنیم. برنامه پایین نتیجه ای مثل برنامه قبل خواهد داشت:

import tkinter as tk
from  tkinter import *
root=tk.Tk()
root.geometry("300x220")
root.resizable(False,False)
def show(event):
    itemnumber = lst.curselection()
    lblNumber.configure(text=itemnumber)
categories=("آنالوگ","دیجیتال","نرم افزار","برنامه نویسی","AVR","ARM","Rasbery Pie","تجهیزات پزشکی")
categories_var = tk.StringVar(value=categories)
lst=Listbox(root,listvariable=categories_var)
lst.place(height=150,width=100,x=100,y=30)
lblNumber=Label(root, text="Number")
lblNumber.place(height=10,width=60,x=100,y=10)
lst.bind('<<ListboxSelect>>', show)
root.mainloop()

در خط 9 لیست مورد نظر به نام categories را ایجاد کردیم و سپس در خط 10 یک متغیر مخصوص tkinter به نام categories_var تعریف کردیم و لیست categories را در آن جاگذاری کردیم.

در خط 11 موقع تعریف لیست باکس listvariable را برابر با categories_var قرار می دهیم و به این ترتیب وقتی برنامه اجرا شود لیست مورد نظر ما در لیست باکس نمایش داده خواهد شد.

حالا می خواهیم در برنامه تغییر کوچکی بدهیم تا به جای عدد مربوط به ایندکس آیتم، خود آیتم انتخاب شده را نمایش دهد.

import tkinter as tk
from  tkinter import *
root=tk.Tk()
root.geometry("300x220")
root.resizable(False,False)
def show(event):
    itemnumber = lst.curselection()
    itemname=lst.get(itemnumber)
    lblName.configure(text=itemname)
categories=("آنالوگ","دیجیتال","نرم افزار","برنامه نویسی","AVR","ARM","Rasbery Pie","تجهیزات پزشکی")
categories_var = tk.StringVar(value=categories)
lst=Listbox(root,listvariable=categories_var)
lst.place(height=150,width=100,x=100,y=40)
lblName=Label(root, text="Item")
lblName.place(height=20,width=100,x=100,y=10)
lst.bind('<<ListboxSelect>>', show)
root.mainloop()

توضیح برنامه:

در این برنامه در خط 14 به جای lblNumber یک لیبل دیگر به نام lblName درست کردیم که کمی ابعاد بزرگتری دارد. در خط 13 هم می بینید که با تغییر پارامتر y کمی لیست باکس را پایینتر قرار داده ایم تا با لیبل هم پوشانی نداشته باشد.

مهمترین تغییر نسبت به برنامه قبل در بدنه تابع show ایجاد شده است. ابتدا مثل قبل شماره آیتم انتخاب شده را در متغیر itemnumber می ریزیم. در خط بعد با استفاده از دستور Get آیتمی را که در لیست باکس شماره itemnumber را دارد داخل متغیر itemname ذخیره می کنیم. سپس این مقدار را در لیبل lblName نمایش می دهیم.

در زیر تصویر برنامه را پس از اجرا مشاهده می کنید: