Ich wollte mit Python eine Grep-Suche nach Excel durchführen und habe viel versucht. Es ist schön, eine Windows-Anwendung namens "Excel Grepy" technisch erstellt zu haben, aber ich kann eine Benutzeroberfläche nicht gut machen. .. .. ..
Irgendwie ist das Layoutdesign problematisch.
Es gab verschiedene Möglichkeiten, die Benutzeroberfläche zu konfigurieren.
Abgesehen von TKinter, der diesmal adoptiert wurde, haben Kivy, wxPython, PySimpleGUI usw.
Es gibt viele Websites, die sich vergleichen. Schauen Sie also bitte mal rein.
Das grobe Bild sieht folgendermaßen aus:
Nun, wie man dies in Python ausdrückt.
Nun, es gibt verschiedene Möglichkeiten, aber beziehen Sie sich auf die folgende Seite ... https://www.delftstack.com/ja/tutorial/tkinter-tutorial/tkinter-geometry-managers/
1.pack() Es fühlt sich an, als würde das Formular als ein Bildschirm betrachtet und in vier Richtungen angeordnet. Ich verstehe nicht wirklich.
2.grid() Es ist, als würde man das Formular vertikal und horizontal teilen und das Raster einstellen, was der Layoutstruktur von HTML ähnelt. Nein, es ist schwer für Menschen mit VB-Aufstieg. Und es ist skurriler als HTML. Ich verstehe nicht wirklich.
3.place() Dies war am einfachsten zu verstehen. Aber es ist nervig. Warum im Jahr 2020 muss ich alle X Y Breite Höhe angeben.
Vorerst schien Grid das einfachste zu sein, also habe ich es versucht!
Ja, rasselnd.
Dann versuchen Sie es mit Pack.
Nun, es läuft nicht wie erwartet.
Wenn Sie diese ausprobieren und auf schöne Weise kombinieren, sieht die Bildschirmkomposition in Python gut aus, oder? Das Konzept ist so.
・ Ein Bildschirm ist im Voraus unterteilt, und das Layout besteht aus Zeilen- und Spaltenbildern. ・ Teilen Sie das Layout in 10x10, damit das Layout intuitiv platziert werden kann. -Das Layout kann als X, Y, Col_SPAN, ROW_SPAN angegeben werden. ・ Zur Unterstützung der Bildschirmskalierung
Ich habe "3.place ()" verwendet, um dies zu implementieren. Nach vielen Recherchen habe ich eine Eigenschaft gefunden, die proportional zur Bildschirmbreite und zum Gefühl eingestellt werden kann.
・ Relex: X-Koordinaten-Bildschirmbreitenverhältnis ・ Rely: Verhältnis der Bildschirmhöhe der Y-Koordinaten -Relwidth: Verhältnis von Objektbreite zu Bildschirmbreite ・ Relheight: Verhältnis von Objekthöhe zu Bildschirmhöhe
Jedes hat ein Maximum von 1,0 und wenn es 0,1 ist, ist es 1/10 Größe.
Das Schöne an dieser Eigenschaft ist, dass sie die Skalierung unterstützt. Wenn Sie die Breite des Bildschirms ändern, ändert sich auch jedes Objekt.
Ergebnis: Es sieht so aus.
Vollbild:
Wie schön!
Ich frage mich, ob es kommerzialisiert werden kann, wenn es ein wenig mehr aktualisiert wird.
Zunächst die FrameWork-Seite:
TKinterK.py
# -*- coding: utf-8 -*-
####importieren
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__()
##Layout-Eigenschaften
self.MAX_ROW = p_max_row
self.MAX_COL = p_max_col
self.PAD_OUT = p_padding
self.PAD_IN = p_padding
#Konstante Einstellung
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
##Einstellung der Bildschirmgröße bei der Definition
def geometry(self,newGeometry=None):
super(FormK, self).geometry(newGeometry)
sp = newGeometry.split("x")
self.WIDTH = int(sp[0])
self.HEIGHT = int(sp[1])
##Nachrichtenbox
def MsgBox(self,p_msg,p_title,p_icon,p_ques):
#Rückgabewert Anfangswert
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
##Platziere ein Objekt
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
Dann Excel Grepy:
ExcelGrepy.py
# -*- coding: utf-8 -*-
####importieren
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
####Root-Frame-Einstellungen
root = tkk.FormK(20,10,10)
root.title("Excel Grepy")
root.geometry("1000x800")
#Hintergrundfarbe
root.bg = '#B7E899'
root.configure(background=root.bg)
root.result = tk.StringVar()
#Stileinstellungen
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')]
)
####Bildschirmereignisfunktion
#Ordnerauswahldialog
def btnFolderDir_click():
root = tk.Tk()
root.withdraw()
iDir = ""
file = filedialog.askdirectory(initialdir = iDir)
#Ausgabe des Verarbeitungsdateinamens
if file != "":
txtPath.delete(0, tk.END)
txtPath.insert(0, file)
#Schaltfläche Löschen
def btnClear_click():
#Nachrichteninitialisierung
root.result.set("")
#Initialisierung verschiedener Pfade
txtPath.delete(0, tk.END)
txtStr.delete(0, tk.END)
#Gitterinitialisierung
x = tree.get_children()
for item in x:
tree.delete(item)
#Aktualisierung des Fortschrittsbalkens (Initialisierung)
progress.configure(value=0, maximum=100)
progress.update()
#Schaltfläche "Überprüfung"
def btnCheck_click():
#Nachrichteninitialisierung
root.result.set("")
#Gitterinitialisierung
x = tree.get_children()
for item in x:
tree.delete(item)
#Parametererfassung
p_temp = Path(txtPath.get())
#Fehlerüberprüfung
if txtPath.get() == "":
messagebox.showerror("Error", "Wählen Sie den Ordner aus, den Sie durchsuchen möchten.")
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) + "Die xlsx-Datei war in diesem Ordner nicht vorhanden.")
else:
root.result.set(str(cnt) + "1 Dateien gefunden!")
#Grep-Taste
def btnGrep_click():
#Nachrichteninitialisierung
root.result.set("")
#Gitterinitialisierung
x = tree.get_children()
for item in x:
tree.delete(item)
#Parametererfassung
p_temp = Path(txtPath.get())
s_str = txtStr.get()
#Fehlerüberprüfung
if txtPath.get() == "":
messagebox.showerror("Error", "Wählen Sie den Ordner aus, den Sie durchsuchen möchten.")
return
if s_str == "":
messagebox.showerror("Error", "Bitte geben Sie die zu suchende Zeichenkette ein.")
return
cnt = 0
prg_cnt = 0
max_cnt = 0
#Zählen Sie die Anzahl der Suchergebnisse
for i in p_temp.glob('**/*.xlsx'):
max_cnt += 1
#Fortschrittsbalken einstellen
progress.configure(value=prg_cnt, maximum=max_cnt)
for i in p_temp.glob('**/*.xlsx'):
#Öffnen Sie das Argument Excel-Datei
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
#Aktualisierung des Fortschrittsbalkens
prg_cnt += 1
progress.configure(value=prg_cnt)
progress.update()
#Fortschrittsbalken-Update (ENDE)
progress.configure(value=max_cnt, maximum=max_cnt)
progress.update()
if cnt == 0:
root.result.set("Die Suchzeichenfolge war im entsprechenden Ordner nicht vorhanden.")
else:
root.result.set(str(cnt) + "1 Dateien gefunden!")
#Doppelansicht der Baumansicht
def tree_row_dclick(self):
#Zeilendaten abrufen
selected_items = tree.selection()
row_data = tree.item(selected_items[0])
#Holen Sie sich den Weg
row_value = row_data['values']
file_path = row_value[2]
#Datei öffnen
#print (file_path)
subprocess.Popen(['start', file_path], shell=True)
####Bildschirmobjekterstellung
# 1.Menüeinstellungen
btnQuit = tkk.ButtonK()
btnQuit["text"] = "Ende"
btnQuit["command"] = root.destroy
btnQuit.layout = "10,1,1,1"
#Etikettenerstellung
lblProg = tkk.LabelK()
lblProg["text"] = "Fortschritt"
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 ################################################
#Etikettenerstellung
lblFilePath = tkk.LabelK()
lblFilePath["text"] = "Ordnerpfad"
lblFilePath["bg"] = root.bg
lblFilePath["anchor"] = "e"
lblFilePath.layout = "1,2,1,1"
#Eingabefeld(FilePath)
txtPath = tkk.EntryK()
txtPath.layout = "2,2,8,1"
#Schaltfläche Durchsuchen
btnFolderDir = tkk.ButtonK()
btnFolderDir["text"] = "Referenz"
btnFolderDir["command"] = btnFolderDir_click
btnFolderDir.layout = "10,2,1,1"
## 3 row ################################################
#Etikettenerstellung
lblFilePath = tkk.LabelK()
lblFilePath["text"] = "Suchbegriff"
lblFilePath["bg"] = root.bg
lblFilePath["anchor"] = "e"
lblFilePath.layout = "1,3,1,1"
#Zeichen suchen
txtStr = tkk.EntryK()
txtStr.layout = "2,3,8,1"
## 4 row ################################################
#Etikettenerstellung
lblCond = tkk.LabelK()
lblCond["text"] = "Suchergebnisse"
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 ################################################
#Suchvorgang
btnGrep = tkk.ButtonK()
btnGrep["text"] = "Grep"
btnGrep["command"] = btnGrep_click
btnGrep.layout = "10,5,1,1"
btnCheck = tkk.ButtonK()
btnCheck["text"] = "Überprüfung"
btnCheck["command"] = btnCheck_click
btnCheck.layout = "9,5,1,1"
btnCheck = tkk.ButtonK()
btnCheck["text"] = "klar"
btnCheck["command"] = btnClear_click
btnCheck.layout = "1,5,1,1"
## 6-20 row ################################################
#Erstellen einer Baumansicht
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="Dateiname")
tree.heading(2,text="Blattname")
tree.heading(3,text="Dateipfad")
tree.bind('<Double-1>', tree_row_dclick)
tree.layout = "1,6,10,15"
#Ordnen Sie Objekte nach Layout an
root.set_layout()
#Hauptschleife
root.mainloop()
Was Sie tun, ist einfach:
root = tkk.FormK(20,10,10) Dieses Argument lautet (MAX_ROW, MAX_COL, PADDING).
root.geometry("1000x800") Ich verwende dies so wie es ist, aber das Framework behält Breite und Höhe als Bildschirmgröße bei.
'# 1. Menüeinstellungen btnQuit = tkk.ButtonK() btnQuit ["text"] = "end" btnQuit["command"] = root.destroy
Der Endknopf ist angeordnet. Zum Zeitpunkt der ursprünglichen Button-Definition ist es möglich, Eigenschaften im Argument zum Zeitpunkt der Definition festzulegen. Ich kann es mit diesem Framework nicht gut machen. Bitte setzen Sie jede nach dem Erstellen des Objekts.
btnQuit.layout = "10,1,1,1"
Dadurch werden Schaltflächen für die 10. Spalte, 1. Zeile, 1/10 Breite und 1/10 Höhe erstellt.
root.set_layout()
Wenn Sie dies nicht schreiben, ist der Bildschirm leer.
Nun, es ist schneller, sich den Code anzusehen, deshalb werde ich ihn nicht im Detail erklären.
Nur das. Ich hatte eine Weile mit der Formel zu kämpfen, aber das war's.
Ich denke darüber nach, ein Framework für diejenigen zu entwickeln, die derzeit Windows-Anwendungen erstellen, und für diejenigen, die Python-Anwendungen mit verschiedenen Funktionen erstellen.
Ich denke, es gibt eine Möglichkeit, es auf Git zu bringen und zu entwickeln, aber wie viele Leute haben die gleiche Meinung?
Es gibt keine Motivation, etwas zu schaffen, das keine Bedürfnisse hat w Es gibt Dinge, die das volle Potenzial von Python noch nicht erreicht haben ... Nun, das Layout ist intuitiv leicht zu verstehen. Wenn es eines Tages zum Mainstream wird, werde ich ein breiteres Spektrum an Technologien haben. .. .. Ist es überhaupt in Ordnung, das GUI-Tool in ein Framework zu verwandeln und es zu lizenzieren? ?? w
Nun, bleiben Sie dran w
Recommended Posts