Habe mir mit tkinter eine GUI für meine Firmware erstellt.
Das Display meines PC ist 1680 x 1050 und meine tkinter-GUI habe ich darauf angepasst.
Leider habe ich versäumt, daß meine tkinter-GUI auch auf anderen Displaygrößen, die z.B. auch kleiner sind, verwenden zu können.
Nun habe ich das selbst gemachte Problem, daß auf meinem 15 Zoll Notebook, ein Teil meiner tkinter-GUI einfach abgechnitten ist.
Gibt es da eine Möglichkeit, die komplette GUI zu Zoomen, so daß alle sich darin befindlichen grafischen Elemente, der aktuellen Displaygröße anpassen?
Ich poste hier mal meine tkinter GUI (Grundgerüst), sollte bei Euch auch lauffähig sein.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x
"""Python Module"""
import os
import time
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import font
import tkinter.messagebox
import datetime
from datetime import date
now = date.today()
heute = now.strftime('%Y.%m.%d')
########################################################################
"""Programmname"""
PROGRAMMNAME = 'gui_work.py'
########################################################################
"""Hauptkonfiguration für die GUI Tkinter."""
CONFIG = {
'width' : 0,
'button_width' : 12,
'title' : "EDV-Work",
'start_font': ('NimbusSansL', 80), # Startfenster
'info_font': ('NimbusSansL', 40), # Infofenster
'bbig_font': ('NimbusSansL', 14, 'bold'), # Buttons
'btxt_bground': 'darkgrey', # Buttons
'bfont_white': 'white',
'bfont_color': 'darkred',
'big_font': ('NimbusSansL', 14), # Buttons, Texteingabe
'sub_font': ('NimbusSansL', 12), # Buttons, Texteingabe
'txt_font': ('NimbusSansL', 12), # Textausgabe
'txt_bground': 'grey', # Texteingabe, Textfenster, Buttons
'font_color': 'black',
'back_ground' : 'darkgrey'
}
########################################################################
def myinfo(text):
"""Aufruf Messagebox.
Bei leerem Text myinfo(''), wird Text 'Bitte warten ...' ausgegeben.
Bei Text z.B. myinfo('Möchten Sie da machen?'), wird mit Ja (True)
der Ablauf fortgesetzt und mit 'Nein' (False) abgebrochen."""
if text == '':
text = 'Bitte warten .....................'
return tkinter.messagebox.askokcancel('Info', text)
def yesno(frage):
"""Aufruf Messagebox.
Bei Frage z.B. yesno('Möchten Sie da machen?'), wird mit Ja (True)
der Ablauf fortgesetzt und mit 'Nein' (False) abgebrochen."""
if frage != '':
return tkinter.messagebox.askyesno('Frage', frage)
class MyButton(tk.Button):
"""Steuerung der Hauptbuttons"""
selected_button_obj = None
HIGHLIGHT_COLOR = 'green'
HIGHLIGHT_CONF = dict(bg=HIGHLIGHT_COLOR,
activebackground=HIGHLIGHT_COLOR)
def __init__(self, parent, **options):
try:
self.command_call = options['command']
del options['command']
except KeyError:
self.command_call = None
tk.Button.__init__(self, parent, **options)
self.bind('<Button-1>', self.callback)
self.std_conf = dict(bg=self['bg'],
activebackground=self['activebackground'])
def callback(self, event=None):
button_obj = MyButton.selected_button_obj
if button_obj is not None:
button_obj.config(self.std_conf)
if self.command_call:
self.config(MyButton.HIGHLIGHT_CONF)
MyButton.selected_button_obj = self
self.command_call(event.widget['text'])
class MySubButton(tk.Button):
"""Steuerung der Subbuttons"""
selected_sub_button_obj = None
HIGHLIGHT_COLOR = 'green'
HIGHLIGHT_CONF = dict(bg=HIGHLIGHT_COLOR,
activebackground=HIGHLIGHT_COLOR)
def __init__(self, parent, **options):
try:
self.command_call = options['command']
del options['command']
except KeyError:
self.command_call = None
tk.Button.__init__(self, parent, **options)
self.bind('<Button-1>', self.callback)
self.std_conf = dict(bg=self['bg'],
activebackground=self['activebackground'])
def callback(self, event=None):
sub_button_obj = MySubButton.selected_sub_button_obj
if sub_button_obj is not None:
sub_button_obj.config(self.std_conf)
if self.command_call:
self.config(MySubButton.HIGHLIGHT_CONF)
MySubButton.selected_sub_button_obj = self
self.command_call(event.widget['text'])
########################################################################
class View(object):
def __init__(self, controller):
self.root = tk.Tk()
self.conf = CONFIG
self.root.title(self.conf['title'])
self.controller = controller
xpos = 0
ypos = 0
self.screenx = self.root.winfo_screenwidth()
self.screeny = self.root.winfo_screenheight()
self.root.geometry("%dx%d+%d+%d" % (self.screenx, self.screeny,
xpos, ypos))
self.frame = tk.Frame(self.root)
self.frame.pack(side='top', fill='both', expand=True)
# Frame links
self.button_frame_left = tk.Label(self.frame, width=16,
bg=self.conf['back_ground'])
self.button_frame_left.pack(side='left', fill='both')
# Frame rechts
button_frame_right = tk.Label(self.frame,
bg=self.conf['back_ground'])
button_frame_right.pack(side='right', fill='both')
# Frame für Textfenster
self.winLabel = tk.Label(self.frame, bg=self.conf['back_ground'],
fg='brown', text=self.conf['title'],
font=(self.conf['start_font']))
self.winLabel.pack(anchor='n', expand='YES', fill='both')
# Frame unten
self.label_down = tk.Label(self.frame, heigh=8,
bg=self.conf['back_ground'])
self.label_down.pack(anchor='s', fill='x')
# Frame unten, für Beschriftung,Eingabefeld und Buttons
self.label_down1 = tk.Label(self.label_down, heigh=2,
bg=self.conf['back_ground'])
self.label_down1.pack(anchor='e')
self.label_down2 = tk.Label(self.label_down, heigh=3,
bg=self.conf['back_ground'])
self.label_down2.pack(anchor='e', pady=10)
self.label_down4 = tk.Label(self.label_down, heigh=3,
bg=self.conf['back_ground'])
self.label_down4.pack(anchor='w', side='left')
self.label_down5 = tk.Label(self.label_down, heigh=3,
bg=self.conf['back_ground'])
self.label_down5.pack(anchor='e', side='right')
self.listboxWindow = tk.Listbox(self.winLabel,
bg=self.conf['txt_bground'], fg=self.conf['font_color'],
font=self.conf['big_font'], selectmode=tk.SINGLE,
bd=0, highlightthickness=0)
self.listboxWindow.pack(anchor='n', expand=True, fill='both')
"""Konfiguration Text-Eingabefelder unten"""
# Text-Beschriftung
self.blank = tk.Label(self.label_down1, text='', width=34,
bg=self.conf['back_ground'])
self.blank.pack(anchor='e', side='left', padx=34, pady=10)
self.txt = tk.Label(self.label_down1, text='', width=17,
bg=self.conf['back_ground'], fg=self.conf['font_color'],
font=(self.conf['big_font']))
self.txt.pack(anchor='e', side='left', padx=30)
self.txt2 = tk.Label(self.label_down1, text='Textfeld', width=60,
bg=self.conf['back_ground'], fg=self.conf['font_color'],
font=(self.conf['big_font']))
self.txt2.pack(anchor='e', side='right', padx=20)
# Text-Eingabe Suchfelder
self.article = tk.Entry(self.label_down2, width=17,
bg=self.conf['txt_bground'], fg=self.conf['font_color'],
font=(self.conf['big_font']))
self.article.pack(anchor='e', side='left', ipady=3, padx=30)
self.txt_line = tk.Entry(self.label_down2, width=60,
bg=self.conf['txt_bground'], fg=self.conf['font_color'],
font=(self.conf['big_font']))
self.txt_line.pack(anchor='e', side='right', ipady=3, padx=20)
########################################################################
## Button-Definition
## Hauptmenü
## Hauptbuttons (Masterbutton) rechte Seite
## Unterbuttons zu Hauptbuttons (Subbutton) linke Seite
## Buttons, Fensterleiste unten
########################################################################
"""Konfiguration Hauptmenü Kopfleiste"""
# Hauptmenü
self.mainMenu = tk.Menu(self.frame, bg=self.conf['back_ground'])
self.root.config(menu=self.mainMenu)
mainmenu = {
'01_Datei' : 'Datei',
'02_EDV' : 'EDV',
'03_Sicherheit' : 'Sicherheit',
}
submenu = {
'011_Öffnen' : ['Öffnen', ''],
'012_Speichern' : ['Speichern', ''],
'013_Einstellungen' : ['Einstellungen', ''],
'014_Beenden' : ['Beenden', self.close_Window_Work],
'021_Daten_Update' : ['Daten-Update', ''],
'031_Backup' : ['Backup', ''],
'032_Restore' : ['Restore', ''],
}
for m in sorted(mainmenu):
name = ''.join(m[:2])
name = tk.Menu(self.mainMenu)
self.mainMenu.add_cascade(label=m[3:], menu=name)
for s in sorted(submenu):
if m[:2] == s[:2]:
name.add_command(label=submenu[s][0],
command=submenu[s][1])
"""Hauptbuttons rechts mit Bezug auf Unterbuttons links"""
# Namen der Sub-Buttons für Kunden (linke Seite)
sub_buttons_kunden = ['Neuanlage', 'Filialeanlage',
'Statusänderung', 'LieferNorm', 'RechnungNorm', 'Kunden-ALT',
'Formulare', 'Kunden', 'Bestellung', 'Auftrag', 'Angebot']
# Namen der Sub-Buttons für Lieferanten (linke Seite)
sub_buttons_lieferanten = ['Neuanlage', 'Filialeanlage',
'Lieferanten-ALT', 'Formulare', 'Lieferanten', 'Bestellung',
'Auftrag']
# Namen der Sub-Buttons für Hersteller (linke Seite)
sub_buttons_hersteller = ['Neuanlage', 'Hersteller',
'Kurz-EAN', 'Produkt-EAN', 'Check-EAN', 'Datenupdate']
# Produktgruppen
sub_buttons_gruppen = ['Basisgruppen', 'Hauptgruppen', 'Gruppen']
# Namen der Sub-Buttons für Verwaltung (linke Seite)
sub_buttons_verwaltung = ['Raumkosten', 'Kommunikation',
'Versandkosten', 'Beiträge', 'Beratung', 'Büroverbrauch']
# Namen der Sub-Buttons für Aufträge (linke Seite)
sub_buttons_verwaltung2 = ['Lagerbestand', 'Leergut']
# Namen der Sub-Buttons für Buchhaltung (linke Seite)
sub_buttons_buchhaltung = ['Kunden', 'Lieferanten', 'Änderung']
# Daten-Update
sub_buttons_update = ['Backup', 'Restore', 'FullUpdate',
'Lieferantendaten', 'Update-EAN', 'Update-VE',
'Update-Gruppen', 'Update-Base', 'Update-List', 'Bericht']
# Namen der Sub-Buttons für Kalkulation (linke Seite)
sub_buttons_kalkulation = ['Hauptgruppen', 'Untergruppen',
'Sonderpreise', 'Sonderprodukt', 'Update-Preise',
'MSAccess-Datei']
# Produkte
sub_buttons_produkte = ['Neuanlage', 'Basisdaten',
'Produktdaten', 'Produktliste', 'Produkte']
# Zusammenfassung aller Sub-Buttons
self.my_sub_buttons = {
'Kunden': sub_buttons_kunden,
'Lieferanten': sub_buttons_lieferanten,
'Hersteller': sub_buttons_hersteller,
'Produktgruppen': sub_buttons_gruppen,
'Verwaltung': sub_buttons_verwaltung,
'Verwaltung2': sub_buttons_verwaltung2,
'Buchhaltung': sub_buttons_buchhaltung,
'Daten-Update': sub_buttons_update,
'Kalkulation': sub_buttons_kalkulation,
'Produkte': sub_buttons_produkte,
}
# Namen der Haupt-Buttons (rechte Seite)
my_buttons = ['Kunden', 'Lieferanten', 'Hersteller',
'Produktgruppen', 'Verwaltung', 'Verwaltung2', 'Buchhaltung',
'Daten-Update', 'Kalkulation', 'Produkte']
# Erzeuge Haupt-Buttons (rechte Seite)
for button_name in my_buttons:
MyButton(button_frame_right, width=self.conf['button_width'],
font=(self.conf['big_font']), text=button_name,
command=self.button_callback).pack(padx=8, ipady=2, pady=19,
fill='x')
"""Konfiguration der Buttons unten (Arbeitsbuttons)"""
# Buttons unten
button = {
'01-Löschen' : lambda: self.check_base_button('Löschen'),
'02-Erstellen' : lambda: self.check_base_button('Erstellen'),
'03-Ändern' : lambda: self.check_base_button('Ändern'),
'04-Suchen' : lambda: self.check_base_button('Suchen'),
'05-Übernehmen' : lambda: self.check_base_button('Übernehmen'),
'06-Zurück' : lambda: self.check_base_button('Zurück'),
'07-Clean' : lambda: self.check_base_button('Clean'),
}
for index, b in enumerate(sorted(button)):
if index < 3:
self.workButtonLeft = tk.Button(self.label_down4, width=10,
text=b.split('-')[1], bg=self.conf['btxt_bground'],
font=(self.conf['bbig_font']), state='disabled',
fg=self.conf['bfont_color'], command=button[b])
self.workButtonLeft.pack(side='left', padx=15, pady=10)
if index > 2:
self.workButtonRight = tk.Button(self.label_down5, width=11,
text=b.split('-')[1], bg=self.conf['txt_bground'],
font=(self.conf['big_font']), state='disabled',
fg=self.conf['font_color'], command=button[b])
self.workButtonRight.pack(side='left', padx=34, pady=10)
if index == 0:
self.workButton_del = self.workButtonLeft # Löschen
if index == 1:
self.workButton_new = self.workButtonLeft # Erstellen
if index == 2:
self.workButton_chance = self.workButtonLeft # Ändern
if index == 3:
self.workButton_search = self.workButtonRight # Suchen
if index == 4:
self.workButton_take = self.workButtonRight # Übernehmen
if index == 5:
self.workButton_back = self.workButtonRight # Zurück
if index == 6:
self.workButton_clean = self.workButtonRight # Clean
# Abfangen von X-Button des Hauptfensters,
# sowie über das Auswahlmenü 'Schließen' über die Fensterleiste.
self.root.protocol("WM_DELETE_WINDOW", self.close_Window_Work)
########################################################################
## PROGRAMMENDE
## Überprüfung auf Datenänderung
## Manuelle Abfrage bei Datensicherung für geänderte Daten
########################################################################
## Programmende abfangen, zur Datensicherung
def close_Window_Work(self):
"""Auswertung und Ablauf für Programmende"""
text = 'Möchten Sie das Programm beenden?'
if myinfo(text) == True:
return self.root.quit(), self.root.destroy(), exit()
########################################################################
## StringVar()
## Übergebe die Daten aus Var an self.new_data
## Für Auswertung und Weierverarbeitung
########################################################################
def my_new_data(self):
"""Hole die Daten von StringVar() aus:
self.set_scrolled_entries(label_names, result)
TWork.Controller(listresult, name, max_width, AB_SPALTENNUMMER)
und übergebe diese zur Weiterverarbeitung."""
self.new_data = dict()
try:
for index, entry_var in enumerate(self.entry_vars):
self.new_data[index] = entry_var.get()
except AttributeError:
pass
return self.new_data
########################################################################
## Button-Komunikations
## Hauptbuttons (Masterbutton) rechte Seite
## Unterbuttons zu Hauptbuttons (Subrbutton) linke Seite
## Funktionen: button_callback
## sub_button_callback
########################################################################
def button_callback(self, button_name):
"""Rückruf der Haupt-Buttons"""
print("Button (rechts): {0}".format(button_name))
self.master_check = button_name
self.sub_check = ''
# Entferne alle bestehende Sub-Buttons aus dem linken Frame
for button in self.button_frame_left.winfo_children():
button.destroy()
# Kontrolle: Hat der aktivierte rechte Button zugehörige Sub-Buttons?
try:
MySubButton.selected_sub_button_obj = None
for button_name in self.my_sub_buttons[button_name]:
MySubButton(self.button_frame_left,
width=self.conf['button_width'],
font=(self.conf['sub_font']), text=button_name,
command=self.sub_button_callback).pack(padx=8, ipady=2,
pady=19, fill='x')
# Ja es gibt Sub-Buttons!
except KeyError:
print("Für {} gibt es keine Liste mit Sub-Buttons!".format(
button_name))
def sub_button_callback(self, sub_button_name):
"""Rückruf der Sub-Buttons"""
print("Sub-Button (links): {0}".format(sub_button_name))
def run(self):
self.frame.mainloop()
class Controller(object):
def __init__(self):
self.view = View(self)
def run(self):
self.view.run()
def main():
Controller().run()
if __name__ == '__main__':
main()