Is there good way to save text input from tkinter Text widget - python-3.x

I was building, a receipt using Tkinter in Text widgets, it is well-formatted in GUI
but when I save that it becomes like this
There is so much disorder in the text file
How can I get a text formatted like one in GUI, in text file ???
here is my code.
from tkinter import *
from tkinter.filedialog import asksaveasfilename
from tkinter.messagebox import askyesno
# ------------
app = Tk()
# =================== frames ========================
frame1 = Frame(app)
frame1.pack(side=TOP)
# ----
title_label = Label(frame1, text="Facture", font=("courier", 40, 'bold'))
title_label.pack()
# ----
frame2 = Frame(app, bd=5)
frame2.pack(side=TOP)
# ----
frame3 = Frame(app)
frame3.pack(side=TOP)
# ============================================
# ======--- text field -----======
text_input = Text(frame2, width=47, height=25, bg="aliceblue", fg='black', font=("arial", 14, 'bold'))
text_input.pack()
# ============ in text field ===============
text_input.insert(END, f'--------------------------------- Facture ---------------------------------\n')
text_input.insert(END, f"\nQty " + f"Product" + f" PU" + f" PV/TVAC" + f'\n')
text_input.insert(END, f"\n1 " + f"FANTA CITRON" + f" 2500" + f" 2500")
text_input.insert(END, f"\n1 " + f"BUFFET PER HEAD" + f" 10000" + f" 10000")
text_input.insert(END, f"\n1 " + f"MUKEKE GRILLE OIGNONS" + f"16000" + f" 16000" + f'\n')
text_input.insert(END, f"\nTOTAL" + f" 28500")
# --------- functions ---------
def save():
filepath = asksaveasfilename(
defaultextension = "csv",
filetypes = [("Text Files", "*.csv"), ("All Files", "*.*")])
if not filepath:
return
with open(filepath, 'w') as output_file:
text = text_input.get('1.0', END)
output_file.write(text)
def printR():
pass
def delete():
text_input.delete('1.0', END)
def exit():
iExit = askyesno("Attention", "You are on your way to quit\nAre you sure you want quit")
if iExit > 0:
app.destroy()
# ----------------------------------
# ============---------------===============
# =====--------- Buttons -----------========
save_button = Button(frame3, text="Save", height=3, width=10, command=save)
save_button.grid(row=0, column=0, padx=2)
# ----------------
print_button = Button(frame3, text="Print", height=3, width=10, command=printR)
print_button.grid(row=0, column=1, padx=2)
# ----------------
delete_button = Button(frame3, text="Delete", height=3, width=10, command=delete)
delete_button.grid(row=0, column=2, padx=2)
# ----------------
quit_button = Button(frame3, text="Exit", height=3, width=10, command=exit)
quit_button.grid(row=0, column=3, padx=2)
# ============================================
app.mainloop()
.........................
.........................
.........................
.........................

I think that the problem is that the "Text" is formatted well only using the Tkfixedfont font.
I made some changes, replaced the format type, deleted the bold and size and used the format() function to align the text.
from tkinter import *
from tkinter.filedialog import asksaveasfilename
from tkinter.messagebox import askyesno
# ------------
app = Tk()
# =================== frames ========================
frame1 = Frame(app)
frame1.pack(side=TOP)
# ----
title_label = Label(frame1, text="Facture", font=("courier", 40, 'bold'))
title_label.pack()
# ----
frame2 = Frame(app, bd=5)
frame2.pack(side=TOP)
# ----
frame3 = Frame(app)
frame3.pack(side=TOP)
# ============================================
# ======--- text field -----======
text_input = Text(frame2,bg="aliceblue", fg='black', font=('TkFixedFont'))
text_input.pack(expand = True)
# ============ in text field ===============
header = "{0} {1} {2}\n".format("-"*35,"Facture", "-"*35)
text_input.insert(END, header)
fields = "{0:10}{1:40}{2:20}{3:8}\n".format("Qty", "Product", "PU", "PV/TVAC")
text_input.insert(END, fields)
rs = (("1", "FANTA CITRON", "2500", "2500"),
("1", "BUFFET PER HEAD", "10000", "10000"),
("1", "MUKEKE GRILLE OIGNONS", "16000", "16000"),)
for i in rs:
fields = "{0:10}{1:40}{2:20}{3:10}\n".format(i[0], i[1], i[2], i[3])
text_input.insert(END, fields)
footer = "{0:70}{1}".format("TOTAL","28500")
text_input.insert(END, footer)
# --------- functions ---------
def save():
filepath = asksaveasfilename(
defaultextension = "csv",
filetypes = [("Text Files", "*.csv"), ("All Files", "*.*")])
if not filepath:
return
with open(filepath, 'w') as output_file:
text = text_input.get('1.0', END)
output_file.write(text)
def printR():
pass
def delete():
text_input.delete('1.0', END)
def exit():
iExit = askyesno("Attention", "You are on your way to quit\nAre you sure you want quit")
if iExit > 0:
app.destroy()
# ----------------------------------
# ============---------------===============
# =====--------- Buttons -----------========
save_button = Button(frame3, text="Save", height=3, width=10, command=save)
save_button.grid(row=0, column=0, padx=2)
# ----------------
print_button = Button(frame3, text="Print", height=3, width=10, command=printR)
print_button.grid(row=0, column=1, padx=2)
# ----------------
delete_button = Button(frame3, text="Delete", height=3, width=10, command=delete)
delete_button.grid(row=0, column=2, padx=2)
# ----------------
quit_button = Button(frame3, text="Exit", height=3, width=10, command=exit)
quit_button.grid(row=0, column=3, padx=2)
# ============================================
app.mainloop()

Related

Problem with askopenfilename() sending to converting function and saving file using asksavefile() - Python Tkinter

I wrote a CAD coordinate conversion application that reads a .txt file using filedialok.askopenfilename() using the function read_file_click().
After selecting the appropriate scale in the Combobox, the program converts the file using the convert() function, then saves it to a .txt file after calling the function save_file_click().
The problem is that when I send the returned value from the convert function to the save_file_click() function, I get two notifications about opening the file.
I don't know how to correct this error. I tried using global variables, but it doesn't help, and weak errors appears with the data_list_no_head variable. Thanks for help:)
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
import os
root = Tk()
root.title("Autocad Coordinate Converter")
root.geometry("")
root.geometry("280x320")
root.resizable(False, False)
def combo_sets():
scale_combo.set("")
def ending_message():
messagebox.showinfo("Autocad Coordinate Converter", "End")
def read_file_click():
global data_list_no_head
file_path = filedialog.askopenfilename()
return file_path
def convert():
file_path_new = read_file_click()
data_list = []
with open(file_path_new, encoding='utf-16') as file:
for line in file:
data_list.append(line.split())
data_list_no_head = data_list[4:]
return data_list_no_head
def save_file_click():
new = convert()
scale_get = scale_combo.get()
data = None
event_eng = None
cal = None
x_coordinate = None
y_coordinate = None
output_file = open(output_file_path_name, 'a')
if scale_get == "1:500" or scale_get == "1:1000":
for event in new:
for _ in event:
data = event[1]
event_eng = event[4]
x_coordinate = event[5]
y_coordinate = event[6]
cal = int(event_eng[-1])*2-2
output_file.write(f"_layer u w{data[2:4]}e{event_eng[-1]} _donut 0 {cal} {y_coordinate},"
f"{x_coordinate} \n")
output_file.close()
new_file_name = output_file_path_name[:-4] + ".scr.txt"
os.rename(output_file_path_name, new_file_name)
combo_sets()
ending_message()
elif scale_get == "1:2000":
for event in new:
for _ in event:
data = event[1]
event_eng = event[4]
x_coordinate = event[5]
y_coordinate = event[6]
cal = 2*(int(event_eng[-1])*2-2)
output_file.write(f"_layer u w{data[2:4]}e{event_eng[-1]} _donut 0 {cal} {y_coordinate},"
f"{x_coordinate} \n")
output_file.close()
new_file_name = output_file_path_name[:-4] + ".scr.txt"
os.rename(output_file_path_name, new_file_name)
combo_sets()
ending_message()
elif scale_get == "1:5000":
for event in new:
for _ in event:
data = event[1]
event_eng = event[4]
x_coordinate = event[5]
y_coordinate = event[6]
cal = 5*(int(event_eng[-1])*2-2)
output_file.write(f"_layer u w{data[2:4]}e{event_eng[-1]} _donut 0 {cal} {y_coordinate},"
f"{x_coordinate} \n")
output_file.close()
new_file_name = output_file_path_name[:-4] + ".scr.txt"
os.rename(output_file_path_name, new_file_name)
combo_sets()
ending_message()
elif scale_get == "1:10000":
for event in new:
for _ in event:
data = event[1]
event_eng = event[4]
x_coordinate = event[5]
y_coordinate = event[6]
cal = 20*(int(event_eng[-1])-2)
output_file.write(f"_layer u w{data[2:4]}e{event_eng[-1]} _donut 0 {cal} {y_coordinate},"
f"{x_coordinate} \n")
output_file.close()
new_file_name = output_file_path_name[:-4] + ".scr.txt"
os.rename(output_file_path_name, new_file_name)
combo_sets()
ending_message()
# Frame1
frame1 = LabelFrame(root, padx=15, pady=15, relief=FLAT)
frame1.grid(row=1, column=0)
button_1 = Button(frame1, text="Read .txt file", padx=15, pady=15, width=20, height=1, command=read_file_click)
button_1.grid(row=1, column=0, padx=3, pady=3)
# Frame2
frame2 = LabelFrame(root, padx=15, pady=15, relief=FLAT)
frame2.grid(row=2, column=0)
Label(frame2, text="Select scale:", width=14).grid(row=1, column=1, padx=1, pady=1)
scale_combo = ttk.Combobox(frame2, values=["1:500", "1:1000", "1:2000", "1:5000", "1:10000"], width=9, state='readonly')
scale_combo.current()
scale_combo.grid(row=2, column=1, padx=1, pady=1)
# Frame3
frame3 = LabelFrame(root, padx=50, pady=50, relief=FLAT)
frame3.grid(row=3, column=0)
button_2 = Button(frame3, text="Save file in CAD format", padx=15, pady=15, width=20, height=1,
command=save_file_click)
button_2.grid(row=0, column=0, padx=3, pady=3)
root.mainloop()

Python Serial data not displaying in Canvas on tk GUI

I am new to Python and have a problem displaying serial data on my canvas in a tk GUI. I have set up the GUI and all is working, but the data is not displaying in the canvas.
I feel that I am missing something small...
Secondly, when I click the buttons to connect, the GUI freezes up.
Her is my code.
Any help would be welcome
Here is a picture of the current GUI
import serial
import serial.tools.list_ports
import tkinter as tk
from tkinter import *
from tkinter import ttk
import time
import time as tm
from configparser import ConfigParser
import os
import logging
current_time = tm.strftime('%H:%M:%S - %D')
#Get current ports and devices connected
ports = serial.tools.list_ports.comports()
serialInst = serial.Serial()
#List available ports
portlist = []
for onePort in ports:
portlist.append(str(onePort))
#Set logfile
def logfile():
os.system("notepad.exe " + config['Logger']['logfilename'])
# Read config file settings
config = ConfigParser()
config.read('config.ini')
#global logFileName
logFileName = config['Logger']['logfilename']
## Logger Configuration
def setupLogger(filename):
logger = logging.getLogger("Log")
logger.setLevel(config['Logger']['loglevel'])
# create file handler which logs even debug messages
fh = logging.FileHandler(filename)
fh.setLevel(config['Logger']['loglevel'])
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(config['Logger']['loglevel'])
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s ~ %(name)s ~ %(levelname)s ~ %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)
# Return the Created logger
return logger
log = setupLogger(logFileName)
# Method to read config file settings
portsettings = config['serial_settings']
ser = serial.Serial(
port=config['serial_settings']['port'],
baudrate=config['serial_settings']['baudrate'],
parity=config['serial_settings']['parity'],
#stopbits=config['serial_settings']['stop bits']
)
def initPort():
while True:
if ser.in_waiting:
packet = ser.readline.decode('utf')
def connect():
ser.timeout = None
ser.writeTimeout = 0
tk.Label(dataFrame, text='Starting Up Serial Monitor').grid(row=1, column=1)
print("Starting Up Serial Monitor")
try:
ser.open()
except Exception as e:
log.info("Check if serial port is open.")
print("Check if serial port is open: " + str(e))
log.info(str(e))
if ser.isOpen():
try:
ser.flushInput()
ser.flushOutput()
ser.write((config['Commands']['maint']+'\n').encode('ascii'))
tk.Label(dataFrame, text="Serial data sent : " + config['Commands']['maint'], bg='white').grid(row=2, column=1)
ser.write((config['Commands']['inst']+'\n').encode('ascii'))
tk.Label(dataFrame, text="Serial data sent : " + config['Commands']['inst'], bg='white').grid(row=3, column=1)
ser.write((config['Commands']['dnl']+'\n').encode('ascii'))
tk.Label(dataFrame, text="Serial data sent : " + config['Commands']['dnl'], bg='white').grid(row=4, column=1)
ser.write((config['Commands']['status8']+'\n').encode('ascii'))
tk.Label(dataFrame, text="Serial data sent : " + config['Commands']['status8'], bg='white').grid(row=5, column=1)
log.info("Serial Data written to port.")
time.sleep(1)
numberOfLine = 0
while True:
response = ser.readline().decode('utf')
log.info("Reading serial data.")
log.info("Serial data read :"+response)
numberOfLine = numberOfLine + 1
Label(dataFrame, text=("Serial data read : " + response), bg='white').grid(row=7, column=1)
if numberOfLine >= 30:
break
ser.close()
except Exception as e:
print("Error communicating...: " + str(e))
else:
print("Cannot open serial port.")
log.error("Cannot open serial port.")
root = Tk()
root.resizable(True, True)
root.config(bg='light grey')
root.title(config['Info']['Application'] + config['Info']['ver'] + ' - Start Time ' + current_time)
copy_Label = Label(root, text=config['Info']['Copyright'], fg="red", font="Clibri 8 ").grid(column=1, row=50)
window_width = 600
window_height = 500
# get the screen dimension
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# find the center point
center_x = int(screen_width/2 - window_width / 2)
center_y = int(screen_height/2 - window_height / 2)
# set the position of the window to the center of the screen
root.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')
#Serial settings frame
sersetframe = Frame(root, highlightbackground="black", highlightthickness=2)
sersetframe.grid(row=1, column=1, padx=5, pady=5)
#Display serial settings from config
topLabel = Label(sersetframe, text='Serial Config Details. ', fg="black", bg='white', font="Clibri 10 bold").grid(row=2, column=1)
portLabel = Label(sersetframe, text='Port = '+config['serial_settings']['port'], fg="blue", bg='white', font="Clibri 10 bold").grid(row=3, column=1)
baudLabel = Label(sersetframe, text='Baudrate = '+config['serial_settings']['baudrate'], fg="blue", bg='white', font="Clibri 10 bold").grid(row=4, column=1)
paritytLabel = Label(sersetframe, text='Parity = '+config['serial_settings']['parity'], fg="blue", bg='white', font="Clibri 10 bold").grid(row=5, column=1)
#Button frame
buttonframe = Frame(root, highlightbackground="black", highlightthickness=2)
buttonframe.grid(row=49, column=2, padx=5, pady=5)
#Output frame
opframe = Frame(root, highlightbackground="black", highlightthickness=2)
opframelabel = Label(opframe, font='ariel 8 bold', bg='white', fg='blue', text='Serial Output')
opframelabel.grid(row=0, column=1)
opframe.grid(row=10, column=1, padx=5, pady=5)
#Output Canvas
dataCanvas = Canvas(root, width=350, height=200, bg='white')
dataCanvas.grid(row=30, column=1)
#Scrollbar
vsb = Scrollbar(root, orient='vertical', command=dataCanvas.yview)
vsb.grid(row=30, column=0, rowspan=10, sticky='ns')
dataCanvas.config(yscrollcommand=vsb.set)
dataFrame = Frame(dataCanvas, bg='white')
dataCanvas.create_window((10, 0), window=dataFrame, anchor='nw')
# Action Buttons
sendBtn = tk.Button(buttonframe, text='Send', command=connect).grid(column=1, row=7)
connectBtn = tk.Button(buttonframe, text='Connect', command=initPort).grid(column=1, row=8)
exitBtn = tk.Button(buttonframe, text='Exit', command=root.destroy).grid(column=1, row=9)
#Info frame
infoframe = Frame(root, highlightbackground="black", highlightthickness=2)
infoframelabel = Label(infoframe, font='ariel 8 bold', bg='white', fg='black', text='Info:')
infoframelabel.grid(row=0, column=1)
infoframe.grid(row=49, column=1, padx=5, pady=5)
# Check config file settings
dir_path = os.path.dirname(os.path.realpath(__file__))
config_filepath = dir_path+"\config.ini"
# check if the config file exists
exists = os.path.exists(config_filepath)
if exists:
print("**** config.ini file found at : ", config_filepath)
configfileLabel = Label(infoframe,text='Found config file at : '+config_filepath, fg="green",
bg='white', font="Clibri 10 bold").grid(row=49, column=1)
else:
print("**** config.ini file WAS NOT FOUND at : ", config_filepath)
configfileLabel = Label(root,text='DID NOT FIND config file at : ' + config_filepath, fg="red",
bg='white', font="Clibri 10 bold").grid(row=49, column=1)
comportLabel = Label(infoframe, text='Available COM ports : '+str(onePort), fg="black",
bg='white', font="Clibri 10 bold").grid(row=50, column=1)
#Run gui
root.mainloop()

insert() method seems to fail in a subframe

I am writing a 'change' dialog for records in a database.
The 'enter data' dialog (terminErfassen) for the same data records works fine.
In order to reuse as much of the existing code I have made a class for Labels and the values.
The Entry and Text Widgets are repeated in each of the programs.
The dialog 'terminAendern' (change due date) starts with a small window asking for the record number. Pressing the 'lookup' (Daten einlesen) button opens the second window which has the same look as the 'enter data' dialog.
Problem: Although the code is identically written, it works for the Entry-Fields in the main frame, and it fails for the Entry fields in the subframes.
However I am not sure the Frames are the culprits - it seems just the single item which is not identical in the structure.
Here is the code. Rows 0 to 5 get filled with data from the database, the Radiobuttons also work, just the Entries in the subframe have this problem. Find below also an image of the screen.
class TerminAendern(te2.DatenFenster):
"Termine können geändert werden. Erweiterung von terminErfassen"
def __init__(self, el):
"Übernimmt das Fenster aus dem Erfassungsdialog"
super().__init__()
self.ROOT.title("Termin ändern")
# Datensatz-Nummer
self.num_wrt = el["nummer"]
# die Werte aus der Datenbank in das Fenster setzen
#--------- row 0 -----------
#self.art_wrt = tk.StringVar() # Operation zB backup, apt-update, extrahieren
self.art_wrt.set(el["art"])
self.ART_EING = tk.Entry(self.FRMEINGAB, textvariable=self.art_wrt, bg='white')
self.ART_EING.grid(column=1, row=0)
self.ART_EING.insert(0, el["art"])
#--------- row 1 -----------
#self.gertwrt = tk.StringVar() # Rechnername oder Gerät (BoschNyon)
self.gertwrt.set(el["geraet"])
self.GERTEING = tk.Entry(self.FRMEINGAB, textvariable=self.gertwrt, bg='white')
self.GERTEING.insert(90, el["geraet"])
self.GERTEING.grid(column=1, row=1)
#--------- row 2 -----------
#self.brchwrt = tk.StringVar() # Partition/Gegenstand/Aktion/'': TB2, Karten, apt-update
self.brchwrt.set(el["bereich"])
self.BRCHEING = tk.Entry(self.FRMEINGAB, textvariable=self.brchwrt, bg='white')
self.BRCHEING.insert(0, el["bereich"])
self.BRCHEING.grid(column=1, row=2)
#--------- row 3 -----------
#self.bescwrt = tk.StringVar() # Kurztext
self.bescwrt.set(el["kurztext"])
self.BESCEING = tk.Label(self.FRMEINGAB, textvariable=self.bescwrt, bg='lightblue',
text=el["kurztext"],anchor=tk.W, relief=tk.RAISED)
self.BESCEING.grid(column=1, row=3)
#--------- row 4 -----------
#self.haufwrt = tk.IntVar() # Häufigkeit
self.haufwrt.set(el["haeufigkeit"])
self.HAUFEING = tk.Entry(self.FRMEINGAB, textvariable=self.haufwrt, bg='white')
self.HAUFEING.insert(0, el["haeufigkeit"])
self.HAUFEING.grid(column=1, row=4)
#--------- row 5 -----------
#self.ist_wrt = tk.StringVar() # Datum: Letzte Durchführung
dbdatum = el["wann"]
dbm = dbdatum.find("-", 6)
dbd = dbdatum[dbm+1:] + "." + str(dbdatum[5:dbm]) + "." + str(dbdatum[:4])
self.IST_EING = tk.Entry(self.FRMEINGAB, textvariable=self.ist_wrt, bg='white')
self.IST_EING.insert(0, dbd)
self.IST_EING.grid(column=1, row=5)
#--------- row 6 Frame 'Prüfung' -----------
for val, txt in self.pruefwerte: # (int,str)
if el["pruefen"] == txt:
self.prufwrt.set(val)
break
self.PRUFEING = {} # leeres Dict
for val, txt in self.pruefwerte: # (int,str)
self.PRUFEING[val] = tk.Radiobutton(self.FRMPRUEFG, text=txt, padx=5, pady=2,
variable=self.prufwrt, value=val)
self.PRUFEING[val].grid(column=0, row=val+1, sticky=tk.W)
if val == self.prufwrt.get():
self.PRUFEING[val].select()
#---- Prüfdatei ----
if "testen" in el:
self.testwrt.set(el["testen"])
else:
self.testwrt.set("")
print("testwrt = " + self.testwrt.get())
self.TESTEING = tk.Entry(self.FRMPRUEFG, textvariable=self.testwrt, bg='white')
#self.TESTEING.delete(0, tk.END)
self.TESTEING.insert(0, self.testwrt)
self.TESTEING.grid(column=4, row=2)
#--------- row 7 Frame 'Machen' -----------
if el["machen"] == "manuell":
self.machwrt.set(0)
self.skrpwrt.set("")
else:
self.machwrt.set(1)
self.skrpwrt.set(el["machen"])
self.MACHEING = {} # leeres Dict
for val, txt in self.machwerte:
self.MACHEING[val] = tk.Radiobutton(self.FRMMACHEN, text=txt, padx=5, pady=3,
variable=self.machwrt, value=val)
self.MACHEING[val].grid(column=1, row=val+1, sticky=tk.W)
if val == self.machwrt.get():
self.MACHEING[val].select()
#---- Arbeitsskript ----
self.SKRPEING = tk.Entry(self.FRMMACHEN, textvariable=self.skrpwrt, bg='white')
self.SKRPEING.insert(0, self.skrpwrt)
self.SKRPEING.grid(column=4, row=2)
#--------- row 8 -----------
self.ANLTeing = tk.Text(self.FRMEINGAB, height=3, width=80, bg='white')
self.ANLTeing.insert('1.0', el["anleitung"])
self.ANLTeing.grid(column=1, row=8, columnspan=3)
#------------ GRID = Alle aktivieren -----------
self.FRMPRUEFG.grid(column=0, row=6, columnspan=5, sticky=tk.W)
self.FRMMACHEN.grid(column=0, row=7, columnspan=5, sticky=tk.W)
self.FRMEINGAB.grid(row=0)
#------------
self.PROGENDEBUTTON = tk.Button(self.FRMSCHALT, text='Quit', bg="red",
command=self.ROOT.quit)\
.grid(row=0, column=4, sticky=tk.E, padx=20, pady=4)
self.FRMSCHALT.grid(row=1)
class DatenAuswahl:
"Fenster zur Auswahl des Datensatzes"
def __init__(self):
self.fenster = tk.Tk()
self.fenster.title('Datensatz auswählen')
self.MYFRAME = tk.Frame(self.fenster, borderwidth=5, relief=tk.RIDGE, pady=4)
self.satznr = tk.IntVar()
self.SATZNR_TXT = tk.Label(self.MYFRAME, text="Nummer des Termins ", padx=5, pady=9)\
.grid(column=0, row=1, sticky=tk.W)
self.SATZEIN = tk.Entry(self.MYFRAME, textvariable=self.satznr, bg='white')\
.grid(column=1,row=1)
self.DATENBUTTON = tk.Button(self.MYFRAME, text="Daten einlesen", bg="lightblue",
command=self.DatenLesen) #self.satznr ??
self.DATENBUTTON.grid(column=0, row=3, padx=20, pady=20)
self.MYFRAME.grid(row=0)
def DatenLesen(self):
"""Versucht, den Termin-Satz mit Nummer 'satznr' aus der Datenbank zu lesen,
danach wird das Fenster zur Datenkorrektur geöffnet."""
el = createTerminListe.terminAuslesen(int(self.satznr.get()))
# Ausgabe der Werte auf demn Bildschirm
for k in el.keys():
print(k + " = " + str(el[k]))
ausgabe = TerminAendern(el)
myprog = DatenAuswahl()
tk.mainloop()
The definition of the frames in the base class is simple:
class DatenFenster:
'Klasse zur Bearbeitung von Terminen'
def __init__ (self):
locale.setlocale(locale.LC_ALL, 'de_DE.utf8')
self.ROOT = tk.Tk()
self.ROOT.title("Termin erfassen")
self.FRMEINGAB = tk.Frame(self.ROOT, borderwidth=5, relief=tk.RIDGE, pady=4)
self.FRMPRUEFG = tk.Frame(self.FRMEINGAB, borderwidth=2, relief=tk.RIDGE)
self.FRMMACHEN = tk.Frame(self.FRMEINGAB, borderwidth=2, relief=tk.RIDGE)
self.FRMSCHALT = tk.Frame(self.ROOT, borderwidth=4, relief=tk.RAISED, pady=4, padx=6,
bg="orange")
--etc.---
'terminAendern' window
The Entry at 'Prüfdatei (Pfad)' is filled with a default instead of the supplied value from the database.
I have no idea where to look further (apart from the tk source, which I am not sure I can master).
I'd be happy if someone could tell me what I am missing.
I found the source of my problem myself.
First, a StringVar() created in one Tk() is not visible in another Tk():
see here.
Of course, I detected this problem in my code.
I have now 2 ways of resolution:
(1) to make my 'change'-dialog and my 'enter' dialog two separate programs, i.e. not reusing code. I did not intend this, but it may lead me to a running solution quicker.
(2) to use Toplevel(). This would allow me to keep the original program dependencies and to avoid duplicating code, but I did not find a lot of explanations on multi-window programming so far. Anyway, my problem is explained even if not solved.

How do i change the font in my text editor from the font menu

from tkinter import *
import tkinter.filedialog
from tkinter import ttk
class TextEditor:
#staticmethod
def quit_app(event=None):
root.quit()
def change_font(self, event=None):
print(text_font.get())
def open_file(self, event=None):
txt_file = tkinter.filedialog.askopenfilename(parent=root, initialdir="C:/Users/Cesar/PycharmProjects")
if txt_file:
self.text_area.delete(1.0, END)
with open(txt_file) as _file:
self.text_area.insert(1.0, _file.read())
root.updata_idletasks()
def save_file(self, event=None):
file = tkinter.filedialog.asksaveasfile(mode='w')
if file != None:
data = self.text_area.get(1.0, END + '-1c')
file.write(data)
file.close()
def __init__(self, root):
self.text_to_write = ""
root.title("Text Editor")
root.geometry("600x500")
frame = Frame(root, width=600, height=500)
scrollbar = Scrollbar(frame)
self.text_area = Text(frame, width=600, height=500, yscrollcommand=scrollbar.set, padx=10, pady=10)
scrollbar.config(command=self.text_area.yview)
scrollbar.pack(side=RIGHT, fill="y")
self.text_area.pack(side="left", fill="both", expand=True)
frame.pack()
the_menu = Menu(root)
# ---------- file menu -------------
file_menu = Menu(the_menu, tearoff=0)
file_menu.add_command(label="Open",command=self.open_file)
file_menu.add_command(label="Save", command=self.save_file)
file_menu.add_separator()
file_menu.add_command(label="Quit", command=self.quit_app())
the_menu.add_cascade(label="File", menu=file_menu)
# ---------- format menu and font menu--------
"""
font_menu = Menu(the_menu, tearoff=0)
text_font = StringVar()
text_font.set("Times")
def change_font():
style = ttk.Style()
style.configure(self.text_area, font = text_font)
print("Font picked: ", text_font.get())
font_menu = Menu(the_menu, tearoff=0)
font_menu.add_radiobutton(label="Times", variable=text_font, command=change_font)
font_menu.add_radiobutton(label="Arial", variable=text_font, command=change_font)
font_menu.add_radiobutton(label="Consoles", variable=text_font, command=change_font)
font_menu.add_radiobutton(label="Courier", variable=text_font, command=change_font)
font_menu.add_radiobutton(label="Tahoma", variable=text_font, command=change_font)
the_menu.add_cascade(label="Fonts", menu=font_menu)
"""
root.config(menu=the_menu)
root = Tk()
text_edit = TextEditor(root)
root.mainloop()
i put the code for the font menu in a comment to make sure the program is working
ttk.Style is used to style objects from ttk, which Text is not. To set the font on a tkinter.Text widget you need to use tkinter.font.Font.
import tkinter.font
#...
def __init__(self):
# ...
# ---------- format menu and font menu--------
self.text_font = StringVar()
self.text_font.set("Times")
font_menu = Menu(the_menu, tearoff=0)
self.fonts = {}
for font in ("Times","Arial", "Consoles", "Courier", "Tahoma"):
self.fonts[font] = tkinter.font.Font(font=font)
font_menu.add_radiobutton(label=font, variable=self.text_font, command=self.change_font)
the_menu.add_cascade(label="Fonts", menu=font_menu)
root.config(menu=the_menu)
def change_font(self):
self.text_area.config(font = self.fonts[self.text_font.get()])
BTW a scrolled Text widget is built into tkinter in the ScrolledText widget.

Tkinter background color issue at scrollbar

I am working on a tkinter script which has a vertical and horizontal scrollbar.
A portion of the window below the vertical scrollbar is not picking up the background color I'm applying.
I have tried the following color options still the small portion is not picking up.
Image:
Sample window snapshot
Full Code:
from tkinter.tix import *
from tkinter import *
import collections
root = Tk()
root.configure(background='steel blue')
# Global variables
fname = ''
# Variables for setting the height and width of widget
# Variables to set Height
actualRootHeight = 300
rootHScale = 25
rootHOffset = 100
canvasHeight = 300
root2CanvasHMargin =65
# Variables to set Width
rootWScale = 10
rootWOffset = 200
canvasWidth = 300
root2CanvasWMargin = 20
inpWidth = 0
# Lists to save configs
inpParamList = collections.OrderedDict()
paramListRef = collections.OrderedDict()
updatedParamList = collections.OrderedDict()
entryList = []
labels = []
# All widget coding is done here
class guiList(Frame):
global root
# Constructor - Use as a control structure
def __init__(self,parent):
Frame.__init__(self,parent)
self.parent = parent
self.readParams()
self.setGeometry()
self.initUI()
self.controlUI()
def onFrameConfigure(self, event, Canvas1):
# Reset the scroll region to encompass the inner frame
Canvas1.configure(scrollregion=Canvas1.bbox("all"), background='steel blue')
# All widget edition is done here
def initUI(self):
global paramListRef
titleStr = sys.argv[1]
self.parent.title(titleStr)
self.grid(row=0, column=0)
inpConfigs = inpParamList.items()
# Add a canvas and call Frame as it's child widget
# Scrollbar can be added to Canvas
Canvas1 = Canvas(self, width=canvasWidth, height=canvasHeight, borderwidth=0, bg="light steel blue")
vsb = Scrollbar(self, orient="vertical", command=Canvas1.yview, bg="light steel blue", troughcolor="steel blue", highlightcolor="light steel blue", activebackground="light steel blue", highlightbackground="light steel blue")
Canvas1.configure(yscrollcommand=vsb.set)
vsb.grid(column=2, sticky='NS')
hsb = Scrollbar(self, orient="horizontal", command=Canvas1.xview, bg="light steel blue", troughcolor="steel blue")
Canvas1.configure(xscrollcommand=hsb.set)
hsb.grid(column=0, sticky='EW')
Canvas1.grid(row=0, column=0, sticky='NWES')
# Create new Frame for input configs
Frame1 = Frame(Canvas1, width=canvasWidth, height=canvasHeight, bg="light steel blue")
Canvas1.create_window((1,1),window=Frame1, anchor="nw", tags="Frame1")
Frame1.bind("<Configure>", lambda event, arg=Canvas1: self.onFrameConfigure(event, arg))
# Loop through the input configs
i = 0
# Add label and combobox in loop
for k,v in inpConfigs:
# Label widgets
lbl1 = Label(Frame1, text=k, bg="light steel blue", font=("Helvetica", 12, "bold"), fg="steel blue")
lbl1.grid(row = i, column = 0, padx=10, pady=5, sticky='W')
labels.append(lbl1)
# Combo-box widget for configurations
tkvar = StringVar(Frame1)
tkvar.set(v[0])
entry1 = OptionMenu(Frame1, tkvar, *v)
entry1.configure(width=20, anchor=W, bg="steel blue", fg="white", font=("Helvetica", 11, "bold"))
entry1.grid(row = i, column=1, padx=10, pady=5, sticky='E')
#entry1.grid_columnconfigure(2, weight=2)
paramListRef[k] = tkvar
i += 1
# Read the updated configs after the button click
def readUpdatedParams(self):
global updatedParamList
for k,v in paramListRef.items():
updatedParamList[k] = v.get()
root.destroy()
self.writeBack()
# Seperate Frame for buttons
# Upon clicking read updted params
def controlUI(self):
Frame2 = Frame(self, bg="steel blue")
Frame2.grid(row=2, column = 0, sticky="EW")
b = Button(Frame2, text="OK", command=self.readUpdatedParams, bg="light steel blue", fg="steel blue", font=("Helvetica", 11, "bold"))
#b.grid(row=1, column=1, pady=10)
b.pack(fill="none", expand=True, pady = 10)
# Read the file and create a key, value pair for configs
# Lines in file is split with space as delimiter
# First column is the config name and rest are all possible value
def readParams(self):
global inpParamList
global inpWidth
f = open(fname)
for line in f:
val = {}
val = line.split()
key = val.pop(0)
# Get the max width of key to adjust widget width
inpWidth = len(key) if (len(key) > inpWidth) else inpWidth
inpParamList[key] = val
# Geometry ( X-width x Y-width + X-position + Y-position)
# Based on the number of elements in the config list
# the height of the widget is set (Max is 75% of screen size)
def setGeometry(self):
global actualRootHeight
global canvasWidth
global canvasHeight
listLen = len(inpParamList)
rootWinwidth = int(inpWidth *rootWScale) + rootWOffset
rootWinheight = (listLen * rootHScale ) + rootHOffset
screenWidth = self.winfo_screenwidth()
screenHeight = int(self.winfo_screenheight() * 0.75)
if rootWinheight < screenHeight :
actualRootHeight = rootWinheight
else :
actualRootHeight = screenHeight
canvasWidth = rootWinwidth - root2CanvasWMargin
canvasHeight = actualRootHeight - root2CanvasHMargin
rootWinresolution = str(rootWinwidth)+'x'+str(actualRootHeight)+'+'+'0'+'+'+'0'
root.geometry(rootWinresolution)
# Sub routine to write back the config file.
def writeBack(self):
fr = open("bt_top.param.config",'w')
for k,v in updatedParamList.items():
print(k,v)
fr.write(k)
fr.write(" ")
fr.write(v)
fr.write("\n")
fr.close()
# Main Function
# Define Window geometry and other top level stuff here
# Do not go into widget coding here
def main():
global fname
# Get File name from command line argument
fname = sys.argv[2]
app = guiList(root)
root.mainloop()
# The __name__ variable decides what to run
# Below lines make this file run stand-alone
if __name__ == '__main__':
Any suggestions are welcome. Thanks
-Vinay
The piece of black is the background of self, your guiList class. Add a line self.config(bg="steel blue") to its __init__() function (or to initUI() I suppose) to fix it.

Resources