Informationen zum Erstellen einer GUI mit TKinter of Python

Auslösen

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.

Excel Grepy Layoutbild

Das grobe Bild sieht folgendermaßen aus:

image.png

Nun, wie man dies in Python ausdrückt.

TKinter Layout Konfiguration bedeutet

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.

Prüfungsergebnis (Raster)

Vorerst schien Grid das einfachste zu sein, also habe ich es versucht!

image.png

Ja, rasselnd.

Prüfungsergebnis (Packung)

Dann versuchen Sie es mit Pack. image.png

Nun, es läuft nicht wie erwartet.

Also habe ich beschlossen, ein Framework zu erstellen.

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

image.png

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. image.png

Vollbild: image.png

Wie schön!

Die Quelle sieht so aus.

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()

Quellenkommentar

Was Sie tun, ist einfach:

1. Definieren Sie das Formular (root)

root = tkk.FormK(20,10,10) Dieses Argument lautet (MAX_ROW, MAX_COL, PADDING).

2. Legen Sie die Bildschirmgröße des Formulars fest

root.geometry("1000x800") Ich verwende dies so wie es ist, aber das Framework behält Breite und Höhe als Bildschirmgröße bei.

3. Erstellen Sie für jedes Objekt die Eigenschaft "layout" und legen Sie sie fest

'# 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.

4. Rufen Sie nach dem Definieren jedes Objekts die Funktion root.set_layout auf, um das Layout festzulegen

root.set_layout()

Wenn Sie dies nicht schreiben, ist der Bildschirm leer.

Inhalt von 5.4

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.

Über zukünftige Entwicklung

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

Informationen zum Erstellen einer GUI mit TKinter of Python
Erstellen Sie mit tkinter eine Python-GUI
GUI-Erstellung in Python mit tkinter 2
GUI-Erstellung in Python mit tkinter Teil 1
Grundlagen des Eingabe- / Ausgabebildschirms mit tkinter in python3
[Frage] Über die API-Konvertierung von Chat-Bot mit Python
Über verschiedene Codierungen von Python 3
Python: Grundlagen der Verwendung von Scikit-Learn ①
Über die Funktionen von Python
[Python GUI] DICOM-Kontrastanpassung und BMP-Konvertierung mit Tkinter
GUI-Programmierung in Python mit Appjar
Python Hinweis: Über den Vergleich mit is
Bilderfassung von Firefox mit Python
Trübungsentfernung mit Python detailEnhanceFilter
Implementierung von Desktop-Benachrichtigungen mit Python
Informationen zur Grundlagenliste der Python-Grundlagen
Python: Grundlagen der Bilderkennung mit CNN
Automatische Erfassung von Aktienkursen mit Python
Periodische Ausführungsverarbeitung bei Verwendung von tkinter [Python3]
Übung, dies in Python zu verwenden (schlecht)
Informationen zur virtuellen Umgebung von Python Version 3.7
Memorandum von Python-Anfängern
Python: Anwendung der Bilderkennung mit CNN
Externe Anzeige von Matplotlib-Diagrammen mit tkinter
Studie über die Miete in Tokio mit Python (3-1 von 3)
Hinweis auf Probleme hinsichtlich der Koexistenz des Python 2/3-Systems
[Python] Kapitel 02-04 Grundlagen des Python-Programms (Informationen zu Kommentaren)
Anzeigen von Zugverzögerungsinformationen in der GUI mithilfe von Python
Über Python-Slices
Versuchen Sie es mit Tkinter
Zeitvariationsanalyse von Schwarzen Löchern mit Python
Akkorderkennung mit Chromagramm der Python Library Librosa
Über Python tqdm.
Über die Python-Ausbeute
Über Python, Klasse
GUI-Bildschneidewerkzeug mit Python + Tkinter
Starten Sie Python
Einführung der Python Imaging Library (PIL) mit HomeBrew
Informationen zur Python-Vererbung
Zeichenkodierung bei Verwendung des CSV-Moduls von Python 2.7.3
Python-Grundlagen ①
Grundlagen von Python ①
Schreiben Sie eine Notiz über die Python-Version von Python Virtualenv
Über Python, range ()
Kopie von Python
Denken Sie daran, eine Python 3-Umgebung in einer Mac-Umgebung zu erstellen
Über Python Decorator
[Hinweis] Über die Rolle des Unterstrichs "_" in Python
Versuchen Sie es mit dem Sammlungsmodul (ChainMap) von python3
Anonymer Upload von Bildern mit der Imgur-API (mit Python)
Laden Sie Bilder mit tkinter mit GUI auf S3 hoch
Informationen zur Python-Referenz
Einführungsstudie zur Python-Ausgabe von Verkaufsdaten mit tapple-
Über Python-Dekorateure
[Python] Über Multi-Prozess