Je voulais faire une recherche Grep pour Excel en utilisant Python, et je faisais beaucoup d'essais et d'erreurs. C'est bien d'avoir créé une application Windows appelée "Excel Grepy" techniquement, mais je ne peux pas bien créer une interface utilisateur. .. .. ..
D'une certaine manière, la conception de la mise en page est gênante.
Il y avait plusieurs options pour configurer l'interface utilisateur.
Hormis TKinter adopté cette fois, Kivy, wxPython, PySimpleGUI, etc.
Il existe de nombreux sites qui comparent chacun, alors jetez un œil.
L'image approximative ressemble à ceci:
Maintenant, comment exprimer cela en Python.
Eh bien, il existe différents moyens, mais reportez-vous au site suivant ... https://www.delftstack.com/ja/tutorial/tkinter-tutorial/tkinter-geometry-managers/
1.pack() On a l'impression que le formulaire est considéré comme un écran unique et organisé dans quatre directions. Je ne comprends pas vraiment.
2.grid() C'est comme diviser le formulaire verticalement et horizontalement et définir la grille, qui est similaire à la structure de mise en page du HTML? Non, c'est difficile pour les personnes atteintes de VB. Et c'est plus original que HTML. Je ne comprends pas vraiment.
3.place() C'était le plus simple à comprendre. Mais c'est ennuyeux. Pourquoi en 2020, je dois spécifier toute la hauteur de largeur X Y.
Pour le moment, Grid semblait être le plus simple, alors je l'ai essayé!
Oui, cliquetis.
Alors essayez avec Pack.
Eh bien, ça ne se passe pas comme prévu.
Si vous les essayez et les combinez de manière agréable, la composition de l'écran en Python aura fière allure, non? Le concept est comme ça.
・ Un écran est divisé à l'avance et la mise en page est composée d'images de lignes et de colonnes. ・ Divisez la mise en page en 10x10 afin que la mise en page puisse être placée de manière intuitive. -La mise en page peut être spécifiée comme X, Y, Col_SPAN, ROW_SPAN. ・ Pour prendre en charge la mise à l'échelle de l'écran
J'ai utilisé "3.place ()" pour implémenter cela. Après de nombreuses recherches, j'ai trouvé une propriété qui peut être réglée proportionnellement à la largeur de l'écran et au ressenti.
・ Relex: rapport de largeur d'écran en coordonnées X ・ Rely: rapport de la hauteur de l'écran des coordonnées Y -Relwidth: rapport de la largeur de l'objet à la largeur de l'écran ・ Relheight: rapport entre la hauteur de l'objet et la hauteur de l'écran
Chacun a un maximum de 1,0, et s'il est de 0,1, sa taille est de 1/10. -Taille de l'écran: largeur = 1000px hauteur = 600px Dans ce cas, 0,1 correspond à 100 pixels, 0,05 correspond à 50 pixels.
L'avantage de cette propriété est qu'elle prend en charge la mise à l'échelle. Si vous modifiez la largeur de l'écran, chaque objet changera également.
Résultat: cela ressemble à ceci.
Plein écran:
Comme c'est gentil!
Je me demande s'il peut être commercialisé s'il est un peu amélioré.
Tout d'abord, le côté FrameWork:
TKinterK.py
# -*- coding: utf-8 -*-
####importer
import tkinter as tk
import tkinter.ttk as ttk
class FormK(tk.Tk):
pass
def __init__(self, p_max_row, p_max_col, p_padding):
super(FormK, self).__init__()
##Propriétés de mise en page
self.MAX_ROW = p_max_row
self.MAX_COL = p_max_col
self.PAD_OUT = p_padding
self.PAD_IN = p_padding
#Réglage constant
self.CONST_MSG_ICON_INFO = 1
self.CONST_MSG_ICON_ALERT = 2
self.CONST_MSG_ICON_ERROR = 3
self.CONST_MSG_QUES_YES_NO = 1
self.CONST_MSG_QUES_OK_CANCEL = 2
self.CONST_MSG_QUES_RETRY_CANCEL = 4
##Réglage de la taille de l'écran à la définition
def geometry(self,newGeometry=None):
super(FormK, self).geometry(newGeometry)
sp = newGeometry.split("x")
self.WIDTH = int(sp[0])
self.HEIGHT = int(sp[1])
##messagerie
def MsgBox(self,p_msg,p_title,p_icon,p_ques):
#Valeur de retour valeur initiale
o_res = None
if (p_ques == None):
if (p_icon == self.CONST_MSG_ICON_INFO):
messagebox.showinfo(p_title,p_msg)
if (p_icon == self.CONST_MSG_ICON_ALERT):
messagebox.showwarning(p_title,p_msg)
if (p_icon == self.CONST_MSG_ICON_ERROR):
messagebox.showerror(p_title,p_msg)
if (p_ques == self.CONST_MSG_QUES_YES_NO):
if (p_icon == self.CONST_MSG_ICON_INFO):
o_res = messagebox.askyesno(p_title,p_msg)
if (p_icon == self.CONST_MSG_ICON_ALERT):
o_res = messagebox.askyesno(p_title,p_msg)
if (p_icon == self.CONST_MSG_ICON_ERROR):
o_res = messagebox.askyesno(p_title,p_msg)
if (p_ques == self.CONST_MSG_QUES_OK_CANCEL):
if (p_icon == self.CONST_MSG_ICON_INFO):
o_res = messagebox.askokcancel(p_title,p_msg)
if (p_icon == self.CONST_MSG_ICON_ALERT):
o_res = messagebox.askokcancel(p_title,p_msg)
if (p_icon == self.CONST_MSG_ICON_ERROR):
o_res = messagebox.askokcancel(p_title,p_msg)
if (p_ques == self.CONST_MSG_QUES_RETRY_CANCEL):
if (p_icon == self.CONST_MSG_ICON_INFO):
o_res = messagebox.askretrycancel(p_title,p_msg)
if (p_icon == self.CONST_MSG_ICON_ALERT):
o_res = messagebox.askretrycancel(p_title,p_msg)
if (p_icon == self.CONST_MSG_ICON_ERROR):
o_res = messagebox.askretrycancel(p_title,p_msg)
return o_res
##Placer un objet
def set_layout(self):
n_height_in = self.HEIGHT - (self.PAD_OUT * 2)
n_height_one = (n_height_in - ((self.MAX_ROW - 1) * self.PAD_IN)) / self.MAX_ROW
n_width_in = self.WIDTH - (self.PAD_OUT * 2)
n_width_one = (n_width_in - ((self.MAX_COL - 1) * self.PAD_IN)) / self.MAX_COL
for v in self.children:
try:
if self.children[v].layout != None:
sp = self.children[v].layout.split(",")
self.children[v].place_configure(
relx =round((float(self.PAD_OUT) + ((int(sp[0])-1) * n_width_one) + ((int(sp[0]) - 1) * self.PAD_IN)) / self.WIDTH ,4)
,rely =round((float(self.PAD_OUT) + ((int(sp[1])-1) * n_height_one) + ((int(sp[1]) - 1) * self.PAD_IN)) / self.HEIGHT ,4)
,relwidth =round(((int(sp[2]) * n_width_one) + ((int(sp[2]) - 1) * self.PAD_IN)) / self.WIDTH ,4)
,relheight=round(((int(sp[3]) * n_height_one) + ((int(sp[3]) - 1) * self.PAD_IN)) / self.HEIGHT ,4)
)
except:
print("No TkinterK Object(" + v +").")
pass
pass
class ButtonK(tk.Button):
pass
def __init__(self):
super(ButtonK, self).__init__()
self.layout = None
class EntryK(tk.Entry):
pass
def __init__(self):
super(EntryK, self).__init__()
self.layout = None
self["highlightthickness"] = 1
self.config(highlightcolor= "red")
class ProgressbarK(ttk.Progressbar):
pass
def __init__(self):
super(ProgressbarK, self).__init__()
self.layout = None
class LabelK(tk.Label):
pass
def __init__(self):
super(LabelK, self).__init__()
self.layout = None
class TreeviewK(ttk.Treeview):
pass
def __init__(self):
super(TreeviewK, self).__init__()
self.layout = None
Puis Excel Grepy:
ExcelGrepy.py
# -*- coding: utf-8 -*-
####importer
import os
import tkinter as tk
import tkinter.ttk as ttk
import openpyxl as px
import subprocess
import TKinterK as tkk
from tkinter import messagebox
from tkinter import filedialog
from pathlib import Path
####paramètres du cadre racine
root = tkk.FormK(20,10,10)
root.title("Excel Grepy")
root.geometry("1000x800")
#Couleur de l'arrière plan
root.bg = '#B7E899'
root.configure(background=root.bg)
root.result = tk.StringVar()
#Paramètres de style
style = ttk.Style()
style.configure('TButton', font =
('calibri', 20, 'bold'),
borderwidth = '4')
# Changes will be reflected
# by the movement of mouse.
style.map('Button'
, foreground = [('active', '!disabled', 'green')]
, background = [('active', 'black')]
)
####Fonction d'événement d'écran
#Boîte de dialogue de sélection de dossier
def btnFolderDir_click():
root = tk.Tk()
root.withdraw()
iDir = ""
file = filedialog.askdirectory(initialdir = iDir)
#Sortie du nom du fichier de traitement
if file != "":
txtPath.delete(0, tk.END)
txtPath.insert(0, file)
#Bouton Effacer
def btnClear_click():
#Initialisation du message
root.result.set("")
#Initialisation de divers chemins
txtPath.delete(0, tk.END)
txtStr.delete(0, tk.END)
#initialisation de la grille
x = tree.get_children()
for item in x:
tree.delete(item)
#Mise à jour de la barre de progression (initialisation)
progress.configure(value=0, maximum=100)
progress.update()
#Bouton d'examen
def btnCheck_click():
#Initialisation du message
root.result.set("")
#initialisation de la grille
x = tree.get_children()
for item in x:
tree.delete(item)
#Acquisition de paramètres
p_temp = Path(txtPath.get())
#Vérification des erreurs
if txtPath.get() == "":
messagebox.showerror("Erreur", "Sélectionnez le dossier que vous souhaitez rechercher.")
return
cnt = 0
for i in p_temp.glob('**/*.xlsx'):
row_data =[i.name, '-', i]
tree.insert("","end",tags=cnt,values=row_data)
cnt += 1
if cnt == 0:
root.result.set(str(cnt) + "Le fichier xlsx n'existait pas dans ce dossier.")
else:
root.result.set(str(cnt) + "Trouvé 1 fichiers!")
#Bouton Grep
def btnGrep_click():
#Initialisation du message
root.result.set("")
#initialisation de la grille
x = tree.get_children()
for item in x:
tree.delete(item)
#Acquisition de paramètres
p_temp = Path(txtPath.get())
s_str = txtStr.get()
#Vérification des erreurs
if txtPath.get() == "":
messagebox.showerror("Erreur", "Sélectionnez le dossier que vous souhaitez rechercher.")
return
if s_str == "":
messagebox.showerror("Erreur", "Veuillez saisir la chaîne de caractères à rechercher.")
return
cnt = 0
prg_cnt = 0
max_cnt = 0
#Comptez le nombre de résultats de recherche
for i in p_temp.glob('**/*.xlsx'):
max_cnt += 1
#Définir la barre de progression
progress.configure(value=prg_cnt, maximum=max_cnt)
for i in p_temp.glob('**/*.xlsx'):
#Ouvrez le fichier Excel d'argument
wb = px.load_workbook(i, data_only=True)
for nm in wb.get_sheet_names():
ws = wb[nm]
value_matrix = str(list(ws.values))
value_matrix = value_matrix.replace('(None','')
value_matrix = value_matrix.replace('None), ','')
value_matrix = value_matrix.replace(', None','')
if (s_str in str(value_matrix)):
row_data =[i.name, nm, i]
tree.insert("","end",tags=cnt,values=row_data)
cnt += 1
#Mise à jour de la barre de progression
prg_cnt += 1
progress.configure(value=prg_cnt)
progress.update()
#Mise à jour de la barre de progression (FIN)
progress.configure(value=max_cnt, maximum=max_cnt)
progress.update()
if cnt == 0:
root.result.set("La chaîne de recherche n’existait pas dans le dossier.")
else:
root.result.set(str(cnt) + "Trouvé 1 fichiers!")
#arborescence double-cliquez
def tree_row_dclick(self):
#Obtenir des données de ligne
selected_items = tree.selection()
row_data = tree.item(selected_items[0])
#Obtenez le chemin
row_value = row_data['values']
file_path = row_value[2]
#Fichier ouvert
#print (file_path)
subprocess.Popen(['start', file_path], shell=True)
####Création d'objets d'écran
# 1.Paramètres du menu
btnQuit = tkk.ButtonK()
btnQuit["text"] = "Fin"
btnQuit["command"] = root.destroy
btnQuit.layout = "10,1,1,1"
#Génération d'étiquettes
lblProg = tkk.LabelK()
lblProg["text"] = "le progrès"
lblProg["bg"] = root.bg
lblProg["anchor"] = "e"
lblProg.layout = "1,1,1,1"
progress = tkk.ProgressbarK()
progress.configure( value=0
, mode='determinate'
, maximum=1000
, length=600)
progress.layout = "2,1,8,1"
## 2 row ################################################
#Génération d'étiquettes
lblFilePath = tkk.LabelK()
lblFilePath["text"] = "Chemin du dossier"
lblFilePath["bg"] = root.bg
lblFilePath["anchor"] = "e"
lblFilePath.layout = "1,2,1,1"
#Zone de saisie(FilePath)
txtPath = tkk.EntryK()
txtPath.layout = "2,2,8,1"
#Bouton Parcourir
btnFolderDir = tkk.ButtonK()
btnFolderDir["text"] = "référence"
btnFolderDir["command"] = btnFolderDir_click
btnFolderDir.layout = "10,2,1,1"
## 3 row ################################################
#Génération d'étiquettes
lblFilePath = tkk.LabelK()
lblFilePath["text"] = "Chaîne de recherche"
lblFilePath["bg"] = root.bg
lblFilePath["anchor"] = "e"
lblFilePath.layout = "1,3,1,1"
#Caractère de recherche
txtStr = tkk.EntryK()
txtStr.layout = "2,3,8,1"
## 4 row ################################################
#Génération d'étiquettes
lblCond = tkk.LabelK()
lblCond["text"] = "Résultats de recherche"
lblCond["bg"] = root.bg
lblCond["anchor"] = "e"
lblCond.layout = "1,4,1,1"
lblCondResult = tkk.LabelK()
lblCondResult["textvariable"] = root.result
lblCondResult["anchor"] = "w"
lblCondResult.layout = "2,4,8,1"
## 5 row ################################################
#Processus de recherche
btnGrep = tkk.ButtonK()
btnGrep["text"] = "Grep"
btnGrep["command"] = btnGrep_click
btnGrep.layout = "10,5,1,1"
btnCheck = tkk.ButtonK()
btnCheck["text"] = "Examen minutieux"
btnCheck["command"] = btnCheck_click
btnCheck.layout = "9,5,1,1"
btnCheck = tkk.ButtonK()
btnCheck["text"] = "clair"
btnCheck["command"] = btnClear_click
btnCheck.layout = "1,5,1,1"
## 6-20 row ################################################
#Créer une arborescence
tree = tkk.TreeviewK()
tree["columns"] = (1,2,3)
tree["show"] = "headings"
tree.column(1,width=100)
tree.column(2,width=75)
tree.column(3,width=100)
tree.heading(1,text="nom de fichier")
tree.heading(2,text="Nom de la feuille")
tree.heading(3,text="Chemin du fichier")
tree.bind('<Double-1>', tree_row_dclick)
tree.layout = "1,6,10,15"
#Organiser les objets selon la disposition
root.set_layout()
#Boucle principale
root.mainloop()
Ce que vous faites est simple:
root = tkk.FormK(20,10,10) Cet argument est (MAX_ROW, MAX_COL, PADDING).
root.geometry("1000x800") Je l'utilise tel quel, mais le Framework conserve la largeur et la hauteur comme tailles d'écran.
'# 1. Paramètres du menu btnQuit = tkk.ButtonK() btnQuit ["text"] = "fin" btnQuit["command"] = root.destroy
Le bouton de fin est organisé. Lors de la définition originale du Button, il est possible de définir des propriétés dans l'argument au moment de la définition, Je ne peux pas bien le faire avec ce cadre. Veuillez définir chacun après avoir créé l'objet.
btnQuit.layout = "10,1,1,1"
Cela crée des boutons pour la 10e colonne, la 1ère ligne, 1/10 de largeur et 1/10 de hauteur.
root.set_layout()
Si vous n'écrivez pas ceci, l'écran sera vide.
Eh bien, il est plus rapide de regarder le code, donc je ne vais pas l'expliquer en détail. -Calculer la taille d'une colonne et la taille d'une ligne à partir de la taille de l'écran et du nombre de divisions lorsque FormK est défini. -Split la propriété layout de chaque objet par ',' et calculez la largeur que vous souhaitez afficher -En fonction du résultat du calcul, redéfinissez OK avec Object.place_configure (...)
Seulement ça. J'ai lutté avec la formule pendant un moment, mais c'est tout.
Je pense développer un framework pour ceux qui créent actuellement des applications Windows et ceux qui créent des applications Python avec diverses fonctions.
Je pense qu'il existe un moyen de l'élever vers Git et de le développer, mais combien de personnes ont la même opinion?
Il n'y a aucune motivation pour créer quelque chose qui n'a pas de besoins w Il y a des choses qui n'ont pas encore atteint le plein potentiel de Python ... Eh bien, la mise en page est intuitivement facile à comprendre, donc si elle devient un jour courante, j'aurai une plus large gamme de technologies. .. .. En premier lieu, est-il acceptable de transformer l'outil GUI en un framework et de le licencier? ?? w
Eh bien, restez à l'écoute w
Recommended Posts