Tkinter image_create производительность при вставке изображения в текстовое поле - PullRequest
1 голос
/ 22 марта 2020

Я создаю приложение Python (3.7.4) для отображения элементов из текстовой базы данных руководств поставщиков. Одной из функций является отображение списка «наименований предметов» из базы данных для каждого руководства (он же «продукт»). Для этой функции я использую прокручиваемый виджет текстового поля Tkinter и просто строю строки с именами элементов с помощью вкладок для их разделения. Я хотел бы вставить маленький значок (16x20 пикселей) перед каждым именем элемента, и успешно сделал это, используя код ниже. Проблема, с которой я сталкиваюсь, заключается в том, что для больших руководств в базе данных (например, 10K + имен элементов) я получаю значительное снижение производительности из функции image_create. Без вставки изображений отображение списка имен элементов происходит почти мгновенно для имен элементов размером 10К. При вставке изображений это может занять до 10-12 секунд.

Есть предложения по улучшению производительности? Я даже пытался создать шрифт «изображения» с помощью FontForge, но предпочел бы не go этот маршрут, если это возможно.

Заранее благодарен за вашу помощь.

По Брайану Оукли запрос, я прикрепил исполняемый код здесь. Если вы откомментируете следующие строки:

tabContents_text.image_create("current", image=open_book_image)

, вы увидите разницу в производительности.

Ссылка на файл png ЗДЕСЬ


import tkinter as tk
import tkinter.scrolledtext as tkst

win = tk.Tk()
frame1 = tk.Frame(master = win)
frame1.pack(fill='both', expand='yes')
win.state('zoomed')
tabContents_text = tkst.ScrolledText(frame1, cursor="arrow", wrap="none", tabs=150, font=('helvetica', 10, 'normal'))
tabContents_text.pack(side='top')
open_book_image = tk.PhotoImage(file="C:\\Users\\rhkea\\Downloads\\document_icon.png")
product_item_list=[]
for i in range(10000):
    product_item_list.append("Item" + str(i).zfill(5))
col_count=4
row_count=2500
row_remain=0
tabContents_text.delete("1.0", "end")
row = 0
item = 0

while row < row_count:
    col = 0
    while col < col_count:
#        tabContents_text.image_create("current", image=open_book_image)
        tabContents_text.insert("end", product_item_list[item] + '\t')
        col += 1
        item += 1
    tabContents_text.insert("end", "\n")
    row += 1

col = 0
while col < row_remain:
#    tabContents_text.image_create("current", image=open_book_image)
    tabContents_text.insert("end", product_item_list[item] + '\t')
    col += 1
    item += 1
tabContents_text.insert("end", "\n")

win.mainloop()

Ответы [ 2 ]

0 голосов
/ 23 марта 2020

Вы можете объединить изображение и текст в один Label, а затем использовать .window_create(...) для вставки в поле Text:

font = tabContents_text.cget('font') # get the Text font
for i in range(len(product_item_list)):
    # create label with both image and text
    lbl = tk.Label(tabContents_text, text=product_item_list[i]+'\t',
                   image=open_book_image, compound='left',
                   bg='white', font=font)
    # insert the label into text box
    tabContents_text.window_create('end', window=lbl)
    # insert line break after showing 'col_count' items
    if i%col_count == col_count-1:
        tabContents_text.insert('end', '\n')

Это может уменьшить общее количество элементов, вставленных в текст коробка наполовину.

0 голосов
/ 22 марта 2020

К сожалению, я думаю, что нельзя добиться лучшей производительности. Но вы можете использовать .update(), чтобы сразу показать изображение, а не блокировать его в своем коде.

Я не Не знаю, какова цель второго while l oop

Вы можете попробовать этот код, он продолжит загружать образ после его запуска:

import tkinter as tk
import tkinter.scrolledtext as tkst

win = tk.Tk()
frame1 = tk.Frame(master = win)
frame1.pack(fill='both', expand='yes')
win.state('zoomed')
tabContents_text = tkst.ScrolledText(frame1, cursor="arrow", wrap="none", tabs=150, font=('helvetica', 10, 'normal'))
tabContents_text.pack(side='top')
open_book_image = tk.PhotoImage(file="document_icon.png")
product_item_list=[]
for i in range(10000):
    product_item_list.append("Item" + str(i).zfill(5))
col_count=4
row_count=2500
row_remain=0
tabContents_text.delete("1.0", "end")
row = 0
item = 0

try:
    while row < row_count:
        col = 0
        while col < col_count:
            tabContents_text.image_create("end", image=open_book_image) # It's "end" instead of current.
            tabContents_text.insert("end", product_item_list[item] + '\t')
            win.update() # update right away.
            col += 1
            item += 1
        tabContents_text.insert("end", "\n")
        win.update()
        row += 1

    col = 0
    # This while loop seems that it will create two empty lines
    while col < row_remain:
        tabContents_text.image_create("current", image=open_book_image)
        tabContents_text.insert("end", product_item_list[item] + '\t')
        win.update()
        col += 1
        item += 1
    tabContents_text.insert("end", "\n")

except BaseException: # Catch the raised exception when you close the window if it doesn't load image completely.
    pass

except Exception as e:
    print(e.args)


win.mainloop()

Может быть, использовать .after() тоже нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...