Русский
Русский
English
Статистика
Реклама

Из песочницы Файловый менеджер на питоне в 430 строк для начинающих и чайников

Всем привет!

Я захотел обобщить свои знания питона и решил написать файловый менеджер для пк.



Внимание!
Это всего лишь игрушка и не более, это не реальная ОС!

Импорт библиотек:

import tkinterimport osimport subprocessfrom tkinter import messageboxfrom tkinter import simpledialog

Главное меню:

class MainContextMenu(tkinter.Menu):''' Контекстное меню для внутренней области директории'''def __init__(self, main_window, parent):super(MainContextMenu, self).__init__(parent, tearoff = 0)self.main_window = main_windowself.add_command(label="Создать директорию", command = self.create_dir)self.add_command(label="Создать файл", command = self.create_file)def popup_menu(self, event):''' функция для активации контекстного меню'''#если активны другие меню - отменяем ихif self.main_window.file_context_menu:self.main_window.file_context_menu.unpost()if self.main_window.dir_context_menu:self.main_window.dir_context_menu.unpost()self.post(event.x_root, event.y_root)def create_dir(self):''' функция для создания новой директории в текущей'''dir_name = simpledialog.askstring("Новая директория", "Введите название новой директории")if dir_name:command = "mkdir {0}".format(dir_name).split(' ')#выполняем команду отдельным процессомprocess = subprocess.Popen(command, cwd=self.main_window.path_text.get(), stdout = subprocess.PIPE, stderr = subprocess.PIPE)out, err = process.communicate()#при возникновении ошибки выводим сообщениеif err:messagebox.showwarning("Операция невозможна!","Отказано в доступе.")self.main_window.refresh_window()def create_file(self):''' функция для создания нового файла в текущей директории'''dir_name = simpledialog.askstring("Новый файл", "Введите название нового файла")if dir_name:command = "touch {0}".format(dir_name).split(' ')#выполняем команду отдельным процессомprocess = subprocess.Popen(command, cwd=self.main_window.path_text.get(), stdout = subprocess.PIPE, stderr = subprocess.PIPE)out, err = process.communicate()#при возникновении ошибки выводим сообщениеif err:messagebox.showwarning("Операция невозможна!","Отказано в доступе.")self.main_window.refresh_window()def insert_to_dir(self):''' функция для копирования файла или директории в текущую директорию'''copy_obj = self.main_window.buffto_dir = self.main_window.path_text.get()if os.path.isdir(self.main_window.buff):#выполняем команду отдельным процессомprocess = subprocess.Popen(['cp', '-r', copy_obj, to_dir], stdout = subprocess.PIPE, stderr = subprocess.PIPE)out, err = process.communicate()if err:messagebox.showwarning("Операция невозможна!", err.decode("utf-8"))else:#выполняем команду отдельным процессомprocess = subprocess.Popen(['cp', '-n', copy_obj, to_dir], stdout = subprocess.PIPE, stderr = subprocess.PIPE)out, err = process.communicate()#при возникновении ошибки выводим сообщениеif err:messagebox.showwarning("Операция невозможна!",err.decode("utf-8"))self.main_window.refresh_window()

При нажатии на файл должно выводиться контекстное меню:

image

class FileContextMenu(tkinter.Menu):def __init__(self, main_window, parent):super(FileContextMenu, self).__init__(parent, tearoff = 0)self.main_window = main_windowself.add_command(label="Открыть файл", command = self.open_file)self.add_separator()self.add_command(label="Копировать", command = self.copy_file)self.add_command(label="Переименовать", command = self.rename_file)self.add_separator()self.add_command(label="Удалить", command = self.delete_file)def open_file(self):''' функция для открытия файла сторонними программами'''ext = self.main_window.take_extention_file(self.main_window.selected_file)full_path = self.main_window.path_text.get() + self.main_window.selected_fileif ext in ['txt', 'py', 'html', 'css', 'js']:if 'mousepad' in self.main_window.all_program:subprocess.Popen(["mousepad", full_path], start_new_session = True)else:self.problem_message()elif ext == 'pdf':if 'evince' in self.main_window.all_program:subprocess.run(["evince", full_path], start_new_session = True)else:self.problem_message()elif ext in ['png', 'jpeg', 'jpg', 'gif']:if 'ristretto' in self.main_window.all_program:subprocess.run(["ristretto", full_path], start_new_session = True)else:self.problem_message()else:self.problem_message()def problem_message(self):messagebox.showwarning("Проблема при открытии файла", 'Прости, но я не могу открыть этот файл')def copy_file(self):''' функция для копирования файла'''#заносим полный путь к файлу в буфферself.main_window.buff = self.main_window.path_text.get() + self.main_window.selected_fileself.main_window.refresh_window()def delete_file(self):''' функция для удаления выбранного файла'''full_path = self.main_window.path_text.get() + self.main_window.selected_file#выполняем команду отдельным процессомprocess = subprocess.Popen(['rm', full_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)output, err = process.communicate()#при возникновении ошибки выводим сообщениеif err:messagebox.showwarning("Проблема при удалении файла", 'У Вас нет прав для удаления данного файла')self.main_window.refresh_window()def rename_file(self):''' функция для переименования выбранного файла'''new_name = simpledialog.askstring("Переименование файла", "Введите новое название файла")if new_name:old_file = self.main_window.path_text.get() + self.main_window.selected_filenew_file = self.main_window.path_text.get() + new_name#выполняем команду отдельным процессомprocess = subprocess.Popen(['mv', old_file, new_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)output, err = process.communicate()#при возникновении ошибки выводим сообщениеif err:messagebox.showwarning("Проблема при переименовании файла", 'У Вас нет прав для переименования данного файла')self.main_window.refresh_window()def popup_menu(self, event):''' функция для активации контекстного меню'''self.post(event.x_root, event.y_root)#если активны другие меню - отменяем ихif self.main_window.main_context_menu:self.main_window.main_context_menu.unpost()if self.main_window.dir_context_menu:self.main_window.dir_context_menu.unpost()self.main_window.selected_file = event.widget["text"]

То же самое для директории:

class DirContextMenu(tkinter.Menu):def __init__(self, main_window, parent):super(DirContextMenu, self).__init__(parent, tearoff = 0)self.main_window = main_windowself.add_command(label="Переименовать", command = self.rename_dir)self.add_command(label="Копировать", command = self.copy_dir)self.add_separator()self.add_command(label="Удалить", command = self.delete_dir)def copy_dir(self):''' функция для копирования директории'''self.main_window.buff = self.main_window.path_text.get() + self.main_window.selected_fileself.main_window.refresh_window()def delete_dir(self):''' функция для удаления выбранной директории'''full_path = self.main_window.path_text.get() + self.main_window.selected_fileif os.path.isdir(full_path):#выполняем команду отдельным процессомprocess = subprocess.Popen(['rm', '-rf', full_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)output, err = process.communicate()#при возникновении ошибки выводим сообщениеif err:messagebox.showwarning("Проблема при удалении директории", 'У Вас нет прав для удаления данной директории')self.main_window.refresh_window()def rename_dir(self):''' функция для переименования выбранной директории'''new_name = simpledialog.askstring("Переименование директории", "Введите новое название директории")if new_name:old_dir = self.main_window.path_text.get() + self.main_window.selected_filenew_dir = self.main_window.path_text.get() + new_name#выполняем команду отдельным процессомprocess = subprocess.Popen(['mv', old_dir, new_dir], stdout=subprocess.PIPE, stderr=subprocess.PIPE)output, err = process.communicate()#при возникновении ошибки выводим сообщениеif err:messagebox.showwarning("Проблема при переименовании директории", 'У Вас нет прав для переименования данной директории')self.main_window.refresh_window()def popup_menu(self, event):''' функция для активации контекстного меню'''self.post(event.x_root, event.y_root)#если активны другие меню - отменяем ихif self.main_window.main_context_menu:self.main_window.main_context_menu.unpost()if self.main_window.file_context_menu:self.main_window.file_context_menu.unpost()self.main_window.selected_file = event.widget["text"]

Класс основного окна:

class MainWindow():''' Класс основного окна'''def __init__(self):self.root = tkinter.Tk()self.root.title("FileManager")self.root.resizable(width = False, height = False)self.root.geometry('450x300')self.hidden_dir = tkinter.IntVar()self.buff = Noneself.all_program = os.listdir('C:/')self.root.bind('<Button-1>', self.root_click)self.root.bind('<FocusOut>', self.root_click)#top frameself.title_frame = tkinter.Frame(self.root)self.title_frame.pack(fill = 'both', expand = True)#back buttonself.back_button = tkinter.Button(self.title_frame, text = "..", command = self.parent_dir, width = 1, height = 1)self.back_button.pack(side = 'left')#path entryself.path_text = tkinter.StringVar()self.path_text.set('/')self.current_path = tkinter.Entry(self.title_frame, textvariable = self.path_text, width = 40, state='readonly')self.current_path.pack(side = 'left')#button show/hidde hidden dir/fileself.check_button = tkinter.Checkbutton(self.title_frame, text = "Hidden", font = ("Helvetica", 10), padx = 1, pady = 1, variable = self.hidden_dir, command = self.refresh_window)self.check_button.pack(side = 'left')#main frameself.main_frame = tkinter.Frame(self.root)self.main_frame.pack()# scroll barself.scrollbar_vert = tkinter.Scrollbar(self.main_frame, orient="vertical")self.scrollbar_vert.pack(side = 'right', fill = 'y')self.scrollbar_hor = tkinter.Scrollbar(self.main_frame, orient="horizontal")self.scrollbar_hor.pack(side = 'bottom', fill = 'x')#canvasself.canvas = tkinter.Canvas(self.main_frame, borderwidth=0,  bg = 'white')self.inner_frame = tkinter.Frame(self.canvas,  bg = 'white')#команды для прокруткиself.scrollbar_vert["command"] = self.canvas.yviewself.scrollbar_hor["command"] = self.canvas.xview#настройки для canvasself.canvas.configure(yscrollcommand=self.scrollbar_vert.set, xscrollcommand = self.scrollbar_hor.set, width=400, heigh=250)self.canvas.pack(side='left', fill='both', expand=True)self.canvas.create_window((0,0), window=self.inner_frame, anchor="nw")#отрисовываем содержимое лиректорииself.dir_content()def root_click(self, event):''' функция для обработки события клика в root'''#если есть контекстные меню - отменяемif self.file_context_menu:self.file_context_menu.unpost()if self.main_context_menu:self.main_context_menu.unpost()if self.dir_context_menu:self.dir_context_menu.unpost()def dir_content(self):''' функция для определения содержимого текущей директории'''#содержимое в текущей директорииdir_list = os.listdir(self.path_text.get())path = self.path_text.get()if not dir_list:#общее контекстное менюself.main_context_menu = MainContextMenu(self, self.canvas)self.canvas.bind('<Button-3>', self.main_context_menu.popup_menu)if self.buff:self.main_context_menu.add_command(label="Вставить", command = self.main_context_menu.insert_to_dir)self.inner_frame.bind('<Button-3>', self.main_context_menu.popup_menu)#контекстное меню для файловself.file_context_menu = None#контекстное меню для директорииself.dir_context_menu = Nonereturn None#общее контекстное менюself.main_context_menu = MainContextMenu(self, self.canvas)self.canvas.bind('<Button-3>', self.main_context_menu.popup_menu)if self.buff:self.main_context_menu.add_command(label="Вставить", command = self.main_context_menu.insert_to_dir)#контекстное меню для файловself.file_context_menu = FileContextMenu(self, self.inner_frame)#контекстное меню для директорииself.dir_context_menu = DirContextMenu(self, self.inner_frame)i = 0for item in dir_list:if os.path.isdir(str(path) + item):#обрабатываем директорииif os.access(str(path) + item, os.R_OK):if (not self.hidden_dir.get() and  not item.startswith('.')) or self.hidden_dir.get():photo = tkinter.PhotoImage(file ="img/folder.png")icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')icon.image = photoicon.grid(row=i+1, column=0)folder_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white', cursor = 'hand1')folder_name.bind("<Button-1>", self.move_to_dir)folder_name.bind("<Button-3>", self.dir_context_menu.popup_menu)folder_name.grid(row=i+1, column=1, sticky='w')else:if (not self.hidden_dir.get() and not item.startswith('.')) or self.hidden_dir.get():photo = tkinter.PhotoImage(file ="img/folder_access.png")icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')icon.image = photoicon.grid(row=i+1, column=0)folder_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white')folder_name.bind("<Button-1>", self.move_to_dir)folder_name.grid(row=i+1, column=1, sticky='w')else:#обрабатываем файлыif (not self.hidden_dir.get() and not item.startswith('.')) or self.hidden_dir.get():ext = self.take_extention_file(item)#фото, картинкиif ext in ['jpeg', 'jpg', 'png', 'gif']:photo = tkinter.PhotoImage(file ="img/photo.png")icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')icon.image = photoicon.grid(row=i+1, column=0)file_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white')file_name.grid(row=i+1, column=1, sticky='w')file_name.bind("<Button-3>", self.file_context_menu.popup_menu)else:#другие файлыif os.access(str(path) + item, os.R_OK):photo = tkinter.PhotoImage(file ="img/file.png")icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')icon.image = photoicon.grid(row=i+1, column=0)folder_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white')folder_name.grid(row=i+1, column=1, sticky='w')folder_name.bind("<Button-3>", self.file_context_menu.popup_menu)else:photo = tkinter.PhotoImage(file ="img/file_access.png")icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')icon.image = photoicon.grid(row=i+1, column=0)folder_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white')folder_name.grid(row=i+1, column=1, sticky='w')i += 1#обновляем inner_frame и устанавливаем прокрутку для нового содержимогоself.inner_frame.update()self.canvas.configure(scrollregion=self.canvas.bbox("all"))def move_to_dir(self, event):''' функция для перехода в выбранную директорию'''elem = event.widgetdir_name = elem["text"]fool_path = self.path_text.get() + dir_nameif os.path.isdir(fool_path) and os.access(fool_path, os.R_OK):old_path = self.path_text.get()self.path_text.set(old_path + dir_name + '/')self.root_click('<Button-1>')self.refresh_window()def parent_dir(self):''' функция для перемещения в родительскую директорию'''old_path = [i for i in self.path_text.get().split('/') if i]new_path = '/'+'/'.join(old_path[:-1])if not new_path:new_path = '/'if os.path.isdir(new_path):if new_path == '/':self.path_text.set(new_path)else:self.path_text.set(new_path + '/')self.refresh_window()def take_extention_file(self, file_name):''' функция для получения расширения файла'''ls = file_name.split('.')if len(ls)>1:return ls[-1]else:return Nonedef refresh_window(self):''' функция для обновления текущего отображения директорий/файлов'''for widget in self.inner_frame.winfo_children():widget.destroy()self.dir_content()self.canvas.yview_moveto(0)

И наконец, создание окна и запаковка виджетов:

win = MainWindow()win.root.mainloop()

Файлы, ассеты, бинарники здесь

Буду рад, если вы поделитесь со мной улучшенной версией этой программы!
Пишите: ki1killer@yandex.ru
Источник: habr.com
К списку статей
Опубликовано: 01.11.2020 04:06:50
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Python

Программирование

Питон

Программирование для начинающих

Утилиты для пк своими руками

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru