Python tkinter сокращает путь, но открывается как полный каталог

Вот мой полный код Python:

from tkinter import *
import glob
import os
from PIL import Image, ImageTk, ImageGrab
import tkinter as tk
import pyautogui
import datetime

#date & time
now = datetime.datetime.now()

root = tk.Tk()
root.title("SIGN OFF")
root.minsize(840, 800)

# Add a grid
mainframe = tk.Frame(root)
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
mainframe.pack(pady=100, padx=100)

# Create a Tkinter variable
tkvar = tk.StringVar(root)


# Directory
directory = "C:/Users/eduards/Desktop/work/data/to-do"
choices = glob.glob(os.path.join(directory, "*.jpg"))
tkvar.set('...To Sign Off...') # set the default option

# Dropdown menu
popupMenu = tk.OptionMenu(mainframe, tkvar, *choices)
tk.Label(mainframe, text="Choose your sign off here:").grid(row=1, column=1)
popupMenu.grid(row=2, column=1)

label2 = tk.Label(mainframe, image=None)
label2.grid(row = 4, column = 1, rowspan = 10)

# On change dropdown callback.
def change_dropdown(*args):
    """ Updates label2 image. """
    imgpath = tkvar.get()
    img = Image.open(imgpath)
    img = img.resize((240,250))
    photo = ImageTk.PhotoImage(img)
    label2.image = photo
    label2.configure(image=photo)


tk.Button(mainframe, text="Open", command=change_dropdown).grid(row=3, column=1)


def var_states():
    text_file = open("logfile.txt", "a")
    text_file.write("TIME: %s, USER: %s, One %d, Two %d\n" % (now,os.getlogin(), var1.get(), var2.get()))
    text_file.close()
    print("One %d, Two %d" % (var1.get(), var2.get()))

var1 = IntVar()
Checkbutton(mainframe, text="Ingredients present in full (any allergens in bold with allergen warning if necessary)", variable=var1).grid(column = 2, row=1, sticky=W)
var2 = IntVar()
Checkbutton(mainframe, text="May Contain Statement.", variable=var2).grid(column = 2, row=2, sticky=W)
var3 = IntVar()
Checkbutton(mainframe, text="Cocoa Content (%).", variable=var3).grid(column = 2, row=3, sticky=W)
var4 = IntVar()
Checkbutton(mainframe, text="Vegetable fat in addition to Cocoa butter", variable=var4).grid(column = 2, row=4, sticky=W)
var5 = IntVar()
Checkbutton(mainframe, text="Instructions for Use.", variable=var5).grid(column = 2, row=5, sticky=W)
var6 = IntVar()
Checkbutton(mainframe, text="Additional warning statements (pitt/stone, hyperactivity etc)", variable=var6).grid(column = 2, row=6, sticky=W)
var7 = IntVar()
Checkbutton(mainframe, text="Nutritional Information Visible", variable=var7).grid(column = 2, row=7, sticky=W)
var8 = IntVar()
Checkbutton(mainframe, text="Storage Conditions", variable=var8).grid(column = 2, row=8, sticky=W)
var9 = IntVar()
Checkbutton(mainframe, text="Best Before & Batch Information", variable=var9).grid(column = 2, row=9, sticky=W)
var10 = IntVar()
Checkbutton(mainframe, text="Net Weight & Correct Font Size.", variable=var10).grid(column = 2, row=10, sticky=W)
var11 = IntVar()
Checkbutton(mainframe, text="Barcode - Inner", variable=var11).grid(column = 2, row=11, sticky=W)
var12 = IntVar()
Checkbutton(mainframe, text="Address & contact details correct", variable=var12).grid(column = 2, row=12, sticky=W)

def user():
    user_input = os.getlogin()
    tk.Label(mainframe, text = user_input, font='Helvetica 18 bold').grid(row = 0, column = 1)


user()


def save():
    # pyautogui.press('alt')
    # pyautogui.press('printscreen')
    # img = ImageGrab.grabclipboard()
    # img.save('paste.jpg', 'JPEG')

    var_states()


tk.Button(mainframe, text = "Save", command = save).grid(row = 20, column = 1)


root.mainloop()

Когда я запускаю код, будет выпадающий список файлов jpg. В настоящее время он показывает полный каталог следующим образом:

введите описание изображения здесь

Ранее я написал пост о том, как обрезать путь, и получил что-то вроде этого:

files = os.listdir("C:/Users/eduards/Desktop/work/data/to-do")
print(files)

Но если я использую этот код выше, он не откроет путь при нажатии open, потому что у него нет полного имени пути.

Что я пытаюсь сделать, так это сократить имя пути для отображения и открыть изображение, следуя исходному полному пути.

Например:

Текущее раскрывающееся меню показывает C:/Users/eduards/Desktop/work/data/to-do/img1.jpg Мой желаемый результат - img1.jpg, но в фоновом режиме откройте весь путь, указанный выше.

Копировать комментарий: это то, что я пробовал

directory = os.path.splitdrive("C:/Users/eduards/Desktop/work/data/to-do")
choices = glob.glob(os.path.join(directory[1:], "*.jpg"))

, но говорит

expected str, bytes or os.Pathlike, not tuple. 

Добавили [1:], потому что путь разделен на 2 и возвращает вторую его часть.


person Community    schedule 17.09.2019    source источник
comment
… Добавить каталог обратно в imgpath? Вы контролируете то, что открывается.   -  person Davis Herring    schedule 18.09.2019
comment
Используйте dict для сопоставления имени файла с полным путем.   -  person Henry Yik    schedule 18.09.2019
comment
Прочтите о os.path.split   -  person stovfl    schedule 18.09.2019


Ответы (1)


Вопрос: отображать только имя файла в OptionMenu, но получить исходный полный путь из выделенного.

Создайте свой собственный OptionMenu, который содержит полный путь от всех изображений в dict и показывает только имя файла в качестве параметров.


  1. Определите свой собственный виджет FileNameOptionMenu, унаследовав от (tk.OptionMenu)
    class FileNameOptionMenu(tk.OptionMenu):
        def __init__(self, parent, directory, extension, callback):
    
  2. Получите из всех изображений полный путь и извлеките filename.
    Сохраните каждый полный путь в dict, используя filename как key и полный путь как value.
            # Save result from `glob` in a `dict`
            self.glob = {}
            for fpath in glob.glob(os.path.join(directory, "*.{}".format(extension))):
                filename, extension = os.path.splitext(os.path.split(fpath)[1])
                self.glob[filename] = fpath
    
  3. Определите переменную, которая содержит выбранный параметр для дальнейшего использования.
    Инициируйте унаследованный tk.OptionMenu с list из keys из dict.
    Передайте class method self.command как command=.
    Сохраните callback для дальнейшего использования.

            self.selected = tk.StringVar(parent, 'Select a image...')
            super().__init__(parent, self.selected, *list(self.glob),
                             command=self.command)
    
            self.callback = callback
    
    
  4. Это class method вызывается при каждом выборе варианта щелчка. По вызову он вызывает self.callback, то есть ImageLabel.configure, с полным путем к выбранной опции.
        def command(self, val):
            self.callback(image=self.glob.get(self.selected.get()))
    
  5. Определите свой собственный виджет ImageLabel, унаследовав от (tk.Label).
    Этот класс расширяет tk.Label.configure для обработки .configure(image=<full path> вместо .configure(image=<image object>.
    class ImageLabel(tk.Label):
        def __init__(self, parent):
            super().__init__(parent, image=None)
    
  6. Перегрузите унаследованный class method tk.Label.configure.
    Перехватите аргумент имени image= и замените переданный полный путь на image object.

        def configure(self, **kwargs):
            key = 'image'
            if key in kwargs:
                # Replace the filepath with the image
                fpath = kwargs[key]
    
                img = Image.open(fpath)
                img = img.resize((240, 250))
                self._image = ImageTk.PhotoImage(img)
    
                kwargs[key] = self._image
    
  7. Назовите оригинал tk.Label.configure, чтобы показать изображение
            super().configure(**kwargs)
    

Использование:

import tkinter as tk
from PIL import Image, ImageTk
import glob, os

class App(tk.Tk):
    def __init__(self):
        super().__init__()

        self.label_image = ImageLabel(parent=self)
        self.label_image.grid(row=2, column=0)

        self.option_menu = \
            FileNameOptionMenu(parent=self,
                               directory='C:/Users/eduards/Desktop/work/data/to-do',
                               extension='jpg',
                               callback=self.label_image.configure
                                               )
        self.option_menu.grid(row=0, column=0)


if __name__ == "__main__":
    App().mainloop()

Протестировано на Python: 3.5

person stovfl    schedule 18.09.2019
comment
в чем разница между class и def? - person ; 18.09.2019
comment
class - это OOP термин, прочтите руководство / классы, и используется для OOP программирование. Используя class inheritance, вы можете расширить значение по умолчанию class, например tk.Label, для ваших нужд. def - это функция для функционального программирования. - person stovfl; 19.09.2019