Changed the structure of the JSON output, added timestamp recording, exif reading and did some UI changes
This commit is contained in:
parent
2cadd3f8f8
commit
5afa52b1d9
@ -17,6 +17,10 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#TODO:
|
||||||
|
#Weather image is cropped
|
||||||
|
#Make save button red if any data is inparsable
|
||||||
|
|
||||||
#import stuff that's needed for both gui and check mode plus tkinter to make inheritance easier (for now)
|
#import stuff that's needed for both gui and check mode plus tkinter to make inheritance easier (for now)
|
||||||
import sys
|
import sys
|
||||||
import hashlib
|
import hashlib
|
||||||
@ -24,6 +28,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
from tkinter import ttk
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
@ -32,18 +37,21 @@ def main():
|
|||||||
|
|
||||||
image_path = sys.argv[1]
|
image_path = sys.argv[1]
|
||||||
|
|
||||||
#import matplotlib.pyplot
|
import matplotlib.pyplot
|
||||||
import numpy
|
import numpy
|
||||||
import time
|
import time
|
||||||
from tkinter import messagebox
|
from tkinter import messagebox
|
||||||
from tkinter import Frame
|
from tkinter import Frame
|
||||||
from tkinter import ttk
|
from tkcalendar import Calendar
|
||||||
#from tkcalendar import Calendar
|
|
||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
#from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
from PIL.ExifTags import TAGS
|
||||||
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||||
from time import strftime, localtime
|
from time import strftime, localtime
|
||||||
|
from datetime import datetime
|
||||||
#import tkintermapview
|
#import tkintermapview
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from exif import Image as exifImage
|
||||||
|
from fractions import Fraction
|
||||||
|
|
||||||
device_data = {
|
device_data = {
|
||||||
"lights": [ { "id": 0, "brand":"", "name": "other" },
|
"lights": [ { "id": 0, "brand":"", "name": "other" },
|
||||||
@ -71,29 +79,56 @@ def main():
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#Get current timestamp
|
||||||
|
current_event_timestamp=int(time.time())
|
||||||
|
|
||||||
|
#Get exif from image file
|
||||||
|
image = Image.open(image_path)
|
||||||
|
exif_data = image._getexif()
|
||||||
|
|
||||||
|
shutter_speed_apex = None
|
||||||
|
exposure_time = None
|
||||||
|
create_datetime= None
|
||||||
|
|
||||||
|
for tag_id, value in exif_data.items():
|
||||||
|
tag = TAGS.get(tag_id, tag_id)
|
||||||
|
if tag == 'ExposureTime':
|
||||||
|
exposure_time = float(Fraction(value))
|
||||||
|
elif tag == 'DateTimeOriginal':
|
||||||
|
dt_str = value
|
||||||
|
dt = datetime.strptime(dt_str, '%Y:%m:%d %H:%M:%S')
|
||||||
|
create_datetime=int(dt.timestamp()) # Unix epoch time
|
||||||
|
|
||||||
|
#JSON output template
|
||||||
data = {
|
data = {
|
||||||
"program_version": "v0.0",
|
"program_version": "v1.0-dev",
|
||||||
"data_spec_version": "v0.0",
|
"data_spec_version": "v1.0-dev",
|
||||||
"title": { "text" : "",
|
|
||||||
"timestamp": 0
|
"title": {
|
||||||
},
|
"text" : "",
|
||||||
#"capture_time_start": 0,
|
"event_id" : -1
|
||||||
#"capture_time_end": 0,
|
},
|
||||||
"image_sha512": sha512Checksum(image_path),
|
|
||||||
"image_filename": os.path.realpath(sys.argv[1]),
|
|
||||||
"description": {
|
"description": {
|
||||||
"text" : "",
|
"text" : "",
|
||||||
"timestamp" : 0
|
"event_id" : -1
|
||||||
},
|
},
|
||||||
# "events" : [{ "time": 1733055790, "text": "Data captured" },
|
"capture_duration_seconds": exposure_time,
|
||||||
# { "time": 1741745288, "text": "Raw file developed"},
|
"single_capture_picture": True,
|
||||||
# { "time": 1747012088, "text": "Metadata written" },
|
|
||||||
# { "time": 1747876088, "text": "Metadata modified" },
|
"image_sha512": sha512Checksum(image_path),
|
||||||
# { "time": 1759876088, "text": "Metadata version updated" }
|
"image_filename": os.path.realpath(sys.argv[1]),
|
||||||
# ],
|
"capture_start_on_original_metadata_ts": create_datetime,
|
||||||
|
"capture_start_time_offset": 0,
|
||||||
|
|
||||||
|
"events" : [{ "event_id":0, "event_type": "capture_start", "time": 0, "text": "" },
|
||||||
|
#{ "event_id":2, "event_type": "data_modification", "time": 1741745288, "text": "Raw file developed"},
|
||||||
|
{ "event_id":1, "event_type": "metadata_modification", "time": current_event_timestamp, "text": "Initial metadata written" },
|
||||||
|
#{ "event_id":5, "event_type": "version_upgrade", "time": 1759876088, "text": "Metadata version updated" }
|
||||||
|
],
|
||||||
|
|
||||||
#"GPS_lat_dec_N": 51.500789280409016,
|
#"GPS_lat_dec_N": 51.500789280409016,
|
||||||
#"GPS_long_dec_W": -0.12472196184719725,
|
#"GPS_long_dec_W": -0.12472196184719725,
|
||||||
|
|
||||||
#"lights": [{ "source":2, "type":"Flash", "Usage":"pointing to his face" },
|
#"lights": [{ "source":2, "type":"Flash", "Usage":"pointing to his face" },
|
||||||
# { "source":3, "type":"continious", "Usage":"hair light" },
|
# { "source":3, "type":"continious", "Usage":"hair light" },
|
||||||
# { "source":1, "type":"continious", "Usage":"doing its thing" },
|
# { "source":1, "type":"continious", "Usage":"doing its thing" },
|
||||||
@ -101,15 +136,22 @@ def main():
|
|||||||
# ]
|
# ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def save_and_exit():
|
def save_and_exit():
|
||||||
update_timestamp=int(time.time())
|
try:
|
||||||
description_value = description_entry.get("1.0",'end-1c')
|
attribution_event=int(event_attribution.get().split()[2])
|
||||||
|
except ValueError as e:
|
||||||
|
print("Error: internal error getting event id for save")
|
||||||
|
return -1
|
||||||
|
|
||||||
data["title"]["text"] = title.get()
|
data["title"]["text"] = title.get()
|
||||||
data["title"]["timestamp"] = update_timestamp
|
data["title"]["event_id"] = attribution_event
|
||||||
#data["capture_time_start"] = int(time.mktime(time.strptime(timestamp_start.get(), '%Y-%m-%d %H:%M:%S')))
|
data["description"]["text"] = description.get("1.0",'end-1c')
|
||||||
#data["capture_time_end"] = int(time.mktime(time.strptime(timestamp_end.get(), '%Y-%m-%d %H:%M:%S')))
|
data["description"]["event_id"] = attribution_event
|
||||||
data["description"]["text"] = description_value
|
data["single_capture_picture"] = one_capture_var.get()
|
||||||
data["description"]["timestamp"] = update_timestamp
|
data["capture_start_time_offset"] = float(cap_offset_var.get())
|
||||||
|
data["capture_duration_seconds"] = float(cap_duration_var.get())
|
||||||
|
data["events"][0]["time"] = int(data["capture_start_time_offset"])+int(data["capture_start_on_original_metadata_ts"])
|
||||||
|
|
||||||
output_path = Path(data["image_filename"]).with_suffix(".json")
|
output_path = Path(data["image_filename"]).with_suffix(".json")
|
||||||
|
|
||||||
@ -123,51 +165,134 @@ def main():
|
|||||||
root.title("Metadata Writer")
|
root.title("Metadata Writer")
|
||||||
background_color=root.cget('bg')
|
background_color=root.cget('bg')
|
||||||
|
|
||||||
# Load and display image
|
|
||||||
img = Image.open(image_path)
|
|
||||||
img.thumbnail((400, 400)) # Resize for display
|
|
||||||
photo = ImageTk.PhotoImage(img)
|
|
||||||
img_label = tk.Label(root, image=photo, borderwidth=15)
|
|
||||||
|
|
||||||
editables=Frame()
|
editables=Frame()
|
||||||
|
|
||||||
#title field
|
#################
|
||||||
title=TitledEntry(editables,"Ttile","",input_state=tk.NORMAL)
|
# display image #
|
||||||
|
#################
|
||||||
|
display_image_frame=TitledFrame(root, "Image" )
|
||||||
|
img = Image.open(image_path)
|
||||||
|
img.thumbnail((400, 400)) # Resize for display
|
||||||
|
photo = ImageTk.PhotoImage(img)
|
||||||
|
img_label = tk.Label(display_image_frame, image=photo, borderwidth=4)
|
||||||
|
|
||||||
#Description field
|
img_label.grid(row=0,column=0)
|
||||||
description=Frame(editables)
|
|
||||||
tk.Label(description, text="Description:").pack(side=tk.LEFT)
|
|
||||||
description_entry = TextScrollCombo(description)
|
|
||||||
description_entry.pack()
|
|
||||||
description_entry.config(width=600, height=100)
|
|
||||||
|
|
||||||
# #Start/end timestamp fields
|
#########
|
||||||
# timestamp=Frame(editables)
|
# Texts #
|
||||||
# start_var = tk.StringVar(value=strftime('%Y-%m-%d %H:%M:%S', localtime(data["capture_time_start"])))
|
#########
|
||||||
# end_var = tk.StringVar(value=strftime('%Y-%m-%d %H:%M:%S', localtime(data["capture_time_end"])))
|
texts_frame=TitledFrame(editables,"[1] Texts")
|
||||||
# timestamp_start = tk.Entry(timestamp,textvariable=start_var)
|
|
||||||
# timestamp_end = tk.Entry(timestamp,textvariable=end_var)
|
title = TitledEntry(texts_frame,"Ttile","",input_state=tk.NORMAL)
|
||||||
# tk.Label(timestamp, text="Shot time/date start:").grid(row=0,column=0,padx=(0,5))
|
description = TextScrollCombo(texts_frame,"Description:")
|
||||||
# tk.Label(timestamp, text="Shot time/date end:").grid(row=0,column=2,padx=5)
|
|
||||||
# timestamp_start.grid(row=0,column=1)
|
title.grid (row=0,column=0,sticky='we',padx=3,pady=3)
|
||||||
# timestamp_end.grid(row=0,column=3)
|
description.grid (row=1,column=0,sticky='we',padx=3,pady=3)
|
||||||
|
texts_frame.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Timestamp #
|
||||||
|
#############
|
||||||
|
timestamp=TitledFrame(editables,"[2] Timestamp")
|
||||||
|
|
||||||
|
#Callback for updating the explanation
|
||||||
|
def update_timestamp_description(*args):
|
||||||
|
date_value = cap_start_var.get()
|
||||||
|
duration_value = cap_duration.get()
|
||||||
|
check_value = one_capture_var.get()
|
||||||
|
|
||||||
|
try:
|
||||||
|
duration_value=str(float(duration_value))
|
||||||
|
date=time.strftime('%A %-d of %B %Y %H:%M:%S',time.gmtime(data["capture_start_on_original_metadata_ts"]+int(cap_offset_var.get())))
|
||||||
|
if check_value == False:
|
||||||
|
explanation_var.set("A multi-picture image (focus stack/exposure stack/etc) that started being taken at " + date + " and took " + str(duration_value) + " seconds to capture" )
|
||||||
|
else:
|
||||||
|
explanation_var.set("An image taken at " + date + " with a "+str(duration_value)+" second shutter speed")
|
||||||
|
explanation.config(bg="grey64")
|
||||||
|
except ValueError as e:
|
||||||
|
explanation_var.set("Invalid vlaues!")
|
||||||
|
explanation.config(bg="red")
|
||||||
|
|
||||||
|
# explanation text
|
||||||
|
explanation_var = tk.StringVar()
|
||||||
|
explanation = tk.Label(timestamp, textvariable=explanation_var, wraplength=450)
|
||||||
|
explanation.config(width=70)
|
||||||
|
|
||||||
|
# Original capture date
|
||||||
|
cap_start_var = tk.StringVar(value=strftime('%Y-%m-%d %H:%M:%S', time.gmtime(data["capture_start_on_original_metadata_ts"]) )) #TODO: don't hardcode these values
|
||||||
|
#cap_start_var.trace_add("write", update_timestamp_description)
|
||||||
|
cap_start_label=tk.Label(timestamp, text="Original capture start date:")
|
||||||
|
cap_start = tk.Entry(timestamp,textvariable=cap_start_var,state=tk.DISABLED)#,state=tk.DISABLED)
|
||||||
|
|
||||||
|
# Capture date offset
|
||||||
|
cap_offset_var = tk.StringVar(value=data["capture_start_time_offset"]) #TODO: don't hardcode these values
|
||||||
|
cap_offset_var.trace_add("write", update_timestamp_description)
|
||||||
|
cap_offset_label=tk.Label(timestamp, text="Capture start date offset seconds:")
|
||||||
|
cap_offset = tk.Entry(timestamp,textvariable=cap_offset_var)#,state=tk.DISABLED)
|
||||||
|
|
||||||
|
# Capture duration
|
||||||
|
cap_duration_var = tk.StringVar(value=str(data["capture_duration_seconds"]))
|
||||||
|
cap_duration_var.trace_add("write", update_timestamp_description)
|
||||||
|
cap_duration_label=tk.Label(timestamp, text="Capture duration (seconds):")
|
||||||
|
cap_duration = tk.Entry(timestamp,textvariable=cap_duration_var)#,state=tk.DISABLED)
|
||||||
|
|
||||||
|
# One shot checkbox
|
||||||
|
one_capture_var = tk.BooleanVar()
|
||||||
|
one_capture_var.trace_add( "write", update_timestamp_description)
|
||||||
|
one_capture = tk.Checkbutton(timestamp, text="Final picture is comprised of one capture",variable=one_capture_var )
|
||||||
|
one_capture.select() #this also calles update_timestamp_description. If removed place a call to it to write the inital value on the text box
|
||||||
|
|
||||||
|
|
||||||
#sha512 field
|
cap_start_label.grid (row=0,column=0,padx=3,pady=3)
|
||||||
sha512sum=TitledEntry(editables,"Image SHA512",data["image_sha512"],input_state=tk.DISABLED)
|
cap_start.grid (row=0,column=1,padx=3,pady=3)
|
||||||
filename=TitledEntry(editables,"Image Filename",data["image_filename"],input_state=tk.DISABLED)
|
cap_duration_label.grid (row=0,column=2,padx=3,pady=3)
|
||||||
|
cap_duration.grid (row=0,column=3,padx=3,pady=3)
|
||||||
|
cap_offset_label.grid (row=1,column=0,padx=3,pady=3)
|
||||||
|
cap_offset.grid (row=1,column=1,padx=3,pady=3)
|
||||||
|
one_capture.grid (row=1,column=2,padx=3,pady=3,columnspan=2)
|
||||||
|
explanation.grid (row=2,column=0,padx=3,pady=3,columnspan=4)
|
||||||
|
|
||||||
#version field
|
#############
|
||||||
versions=Frame(editables)
|
# Constants #
|
||||||
program_version=TitledEntry(versions,"Program version",data["program_version"],width=8,input_state=tk.DISABLED)
|
#############
|
||||||
data_spec_version=TitledEntry(versions,"Data specification version",data["data_spec_version"],width=8,input_state=tk.DISABLED)
|
constants_frame=TitledFrame(editables,"Constants")
|
||||||
program_version.grid(row=0,column=0,padx=(0,5))
|
|
||||||
data_spec_version.grid(row=0,column=1,padx=5)
|
|
||||||
|
|
||||||
# Save button
|
sha512sum=TitledEntry(constants_frame,"Image SHA512",data["image_sha512"],input_state=tk.DISABLED)
|
||||||
save_button = tk.Button(editables, text="Save and Exit", command=save_and_exit)
|
sha512sum=TitledEntry(constants_frame,"Image SHA512",data["image_sha512"],input_state=tk.DISABLED)
|
||||||
|
filename=TitledEntry(constants_frame,"Image Filename",data["image_filename"],input_state=tk.DISABLED)
|
||||||
|
program_version=TitledEntry(constants_frame,"Program version",data["program_version"],width=8,input_state=tk.DISABLED)
|
||||||
|
data_spec_version=TitledEntry(constants_frame,"Data specification version",data["data_spec_version"],width=8,input_state=tk.DISABLED)
|
||||||
|
|
||||||
# # Map widget
|
filename.grid (row=0,column=0,padx=3,pady=3,columnspan=2,sticky='we')
|
||||||
|
sha512sum.grid (row=1,column=0,padx=3,pady=3,columnspan=2,sticky='we')
|
||||||
|
program_version.grid (row=2,column=0,padx=3,pady=3,sticky='we')
|
||||||
|
data_spec_version.grid (row=2,column=1,padx=3,pady=3,sticky='we')
|
||||||
|
constants_frame.grid_columnconfigure(0, weight=1)
|
||||||
|
constants_frame.grid_columnconfigure(1, weight=1)
|
||||||
|
|
||||||
|
########
|
||||||
|
# Save #
|
||||||
|
########
|
||||||
|
save_frame=TitledFrame(editables,"[3] Save")
|
||||||
|
save_button = tk.Button(save_frame, text="Save and Exit", command=save_and_exit)
|
||||||
|
save_button.config(bg='green')
|
||||||
|
|
||||||
|
event_list=[]
|
||||||
|
for item in data["events"]:
|
||||||
|
if item["event_type"] == "metadata_modification":
|
||||||
|
event_list.append("event id "+str(item["event_id"])+" : "+item["text"])
|
||||||
|
|
||||||
|
event_attribution=TitledDropdown(save_frame,"Metadata change event attribution:",event_list,0)
|
||||||
|
|
||||||
|
event_attribution.grid (row=0,column=0,padx=3,pady=3,sticky='we')
|
||||||
|
save_button.grid (row=0,column=1,padx=3,pady=3)
|
||||||
|
#save_button.grid (row=0,column=1,padx=3,pady=3,sticky='e')
|
||||||
|
save_frame.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
# ##############
|
||||||
|
# # Map widget #
|
||||||
|
# ##############
|
||||||
# map_frame=Frame(root)
|
# map_frame=Frame(root)
|
||||||
# map_widget = tkintermapview.TkinterMapView(map_frame, width=400, height=400, corner_radius=10)
|
# map_widget = tkintermapview.TkinterMapView(map_frame, width=400, height=400, corner_radius=10)
|
||||||
# map_widget.set_position(data["GPS_lat_dec_N"], data["GPS_long_dec_W"])
|
# map_widget.set_position(data["GPS_lat_dec_N"], data["GPS_long_dec_W"])
|
||||||
@ -175,12 +300,34 @@ def main():
|
|||||||
# map_widget.set_zoom(15)
|
# map_widget.set_zoom(15)
|
||||||
# map_widget.pack(pady=15)
|
# map_widget.pack(pady=15)
|
||||||
|
|
||||||
# #timeline field
|
##################
|
||||||
# timeline = event_timeline(root,data["events"],matplotlib.pyplot,numpy,FigureCanvasTkAgg,background_color)
|
# timeline field #
|
||||||
# timeline.configure(bg=background_color)
|
##################
|
||||||
|
def events_to_tags(json_events):
|
||||||
|
capture_start=-1
|
||||||
|
return_data=[]
|
||||||
|
for item in json_events:
|
||||||
|
if item["event_type"] == "capture_start":
|
||||||
|
capture_start=item["time"]
|
||||||
|
else:
|
||||||
|
return_data.append({"time":item["time"],"text":item["text"]})
|
||||||
|
return_data.append({"time":capture_start,"text":"Captured data"})
|
||||||
|
return return_data
|
||||||
|
|
||||||
|
timeline_frame=TitledFrame(root,"Timeline")
|
||||||
|
timeline = event_timeline(timeline_frame,events_to_tags(data["events"]),matplotlib.pyplot,numpy,FigureCanvasTkAgg,background_color)
|
||||||
|
timeline.configure(bg=background_color)
|
||||||
|
timeline.grid(row=0,column=0)
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Media aqusition #
|
||||||
|
###################
|
||||||
#media_aqusition=TitledDropdown(root,"Media Aquisition",["unkown","Direct digital off of taking device","Received digitial unmodified from taking device","Received digital re-encoded and or metadata stripped","Received digital editied"],0)
|
#media_aqusition=TitledDropdown(root,"Media Aquisition",["unkown","Direct digital off of taking device","Received digitial unmodified from taking device","Received digital re-encoded and or metadata stripped","Received digital editied"],0)
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Lights #
|
||||||
|
##########
|
||||||
|
|
||||||
# #light table
|
# #light table
|
||||||
# table=[]
|
# table=[]
|
||||||
@ -189,23 +336,21 @@ def main():
|
|||||||
# if device["id"] == item["source"]:
|
# if device["id"] == item["source"]:
|
||||||
# table.append([device["brand"]+device["name"],item["type"],item["Usage"]])
|
# table.append([device["brand"]+device["name"],item["type"],item["Usage"]])
|
||||||
|
|
||||||
# light_table=TitledTable(editables,"List of lights / flashes used:",ttk,table,["Device","Type","Usage"],[140,100,450],['w','w','w'])
|
# light_table=TitledTable(editables,"List of lights / flashes used:",table,["Device","Type","Usage"],[140,100,450],['w','w','w'])
|
||||||
|
|
||||||
|
|
||||||
#Window layout
|
#Root frame layout
|
||||||
img_label .grid(row=0,column=0,sticky='n')
|
display_image_frame .grid(row=0,column=0,sticky='n')
|
||||||
editables .grid(row=0,column=1,rowspan=2,sticky='ns')
|
editables .grid(row=0,column=1,rowspan=2,sticky='ns')
|
||||||
# map_frame .grid(row=1,column=0)
|
# map_frame .grid(row=1,column=0)
|
||||||
# timeline .grid(row=2,column=0,columnspan=2)
|
timeline_frame .grid(row=2,column=0,columnspan=2)
|
||||||
|
|
||||||
title .grid(row=0,column=0,sticky="we",pady=(10,5))
|
#editables frame layout
|
||||||
description .grid(row=1,column=0,sticky="we",pady=5)
|
texts_frame .grid(row=0,column=0,sticky="we",pady=5)
|
||||||
# timestamp .grid(row=2,column=0,sticky="we",pady=5)
|
timestamp .grid(row=1,column=0,sticky="we",pady=5)
|
||||||
sha512sum .grid(row=3,column=0,sticky="we",pady=5)
|
constants_frame .grid(row=2,column=0,sticky="we",pady=5)
|
||||||
filename .grid(row=4,column=0,sticky="we",pady=5)
|
# light_table .grid(row=6,column=0,sticky="we",pady=5)
|
||||||
versions .grid(row=5,column=0,sticky="we",pady=5)
|
save_frame .grid(row=3,column=0,sticky="we",pady=5)
|
||||||
# light_table .grid(row=6,column=0,sticky="we",pady=5)
|
|
||||||
save_button .grid(row=7,column=0,pady=(20,5))
|
|
||||||
|
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
|
|
||||||
@ -224,41 +369,43 @@ def sha512Checksum(filePath):
|
|||||||
#Got TextScrollCombo from stack overflow https://stackoverflow.com/questions/13832720/how-to-attach-a-scrollbar-to-a-text-widget
|
#Got TextScrollCombo from stack overflow https://stackoverflow.com/questions/13832720/how-to-attach-a-scrollbar-to-a-text-widget
|
||||||
class TextScrollCombo(tk.Frame):
|
class TextScrollCombo(tk.Frame):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, root_window, title):
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(root_window)
|
||||||
|
|
||||||
# ensure a consistent GUI size
|
|
||||||
self.grid_propagate(False)
|
|
||||||
# implement stretchability
|
# implement stretchability
|
||||||
self.grid_rowconfigure(0, weight=1)
|
self.grid_rowconfigure(0, weight=1)
|
||||||
self.grid_columnconfigure(0, weight=1)
|
self.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
# create a Text widget
|
# create a Text widget
|
||||||
self.txt = tk.Text(self,height=10)
|
self.txt = tk.Text(self,height=10)
|
||||||
self.txt.grid(row=0, column=0, sticky="nsew")
|
self.txt.config(height=5)
|
||||||
|
|
||||||
|
tk.Label(self, text=title).grid(row=0, column=0, sticky="w")
|
||||||
|
self.txt.grid(row=1, column=0, sticky="we")
|
||||||
|
|
||||||
# create a Scrollbar and associate it with txt
|
# create a Scrollbar and associate it with txt
|
||||||
scrollb = tk.Scrollbar(self, command=self.txt.yview)
|
scrollb = tk.Scrollbar(self, command=self.txt.yview)
|
||||||
scrollb.grid(row=0, column=1, sticky='nsew')
|
scrollb.grid(row=1, column=1, sticky='nsew')
|
||||||
self.txt['yscrollcommand'] = scrollb.set
|
self.txt['yscrollcommand'] = scrollb.set
|
||||||
|
|
||||||
def get(c,a,b):
|
def get(c,a,b):
|
||||||
return c.txt.get(a,b)
|
return c.txt.get(a,b)
|
||||||
|
|
||||||
#TODO: delete if unused before release
|
class TitledDropdown(tk.Frame):
|
||||||
#class TitledDropdown(tk.Frame):
|
|
||||||
#
|
def __init__(self, root_window, text, options, default_opt):
|
||||||
# def __init__(self, root_window, text, options, default_opt):
|
|
||||||
#
|
super().__init__(root_window)
|
||||||
# super().__init__(root_window)
|
|
||||||
#
|
self.titled_dropdown = ttk.Combobox(self,value=options)
|
||||||
# self.titled_dropdown = tk.OptionMenu(self,tk.StringVar(value=options[default_opt]),*options)
|
self.titled_dropdown.set(options[default_opt])
|
||||||
# self.titled_dropdown.config(width=8)
|
self.titled_dropdown.config(width=8)
|
||||||
# tk.Label(self, text=text).pack(side=tk.LEFT)
|
tk.Label(self, text=text).grid (row=0,column=0,sticky='w')
|
||||||
# self.titled_dropdown.pack(fill=tk.X)
|
self.titled_dropdown.grid (row=0,column=1,sticky='we')
|
||||||
# def get(c):
|
self.grid_columnconfigure(1, weight=1)
|
||||||
# return c.titled_dropdown.get()
|
def get(c):
|
||||||
|
return c.titled_dropdown.get()
|
||||||
|
|
||||||
class TitledEntry(tk.Frame):
|
class TitledEntry(tk.Frame):
|
||||||
|
|
||||||
@ -268,14 +415,16 @@ class TitledEntry(tk.Frame):
|
|||||||
|
|
||||||
self.title_entry = tk.Entry(self,state=input_state,textvariable=tk.StringVar(value=init_text),width=width)
|
self.title_entry = tk.Entry(self,state=input_state,textvariable=tk.StringVar(value=init_text),width=width)
|
||||||
|
|
||||||
tk.Label(self, text=text).pack(side=tk.LEFT)
|
self.label=tk.Label(self, text=text)
|
||||||
self.title_entry.pack(fill=tk.X)
|
self.label.grid(row=0,column=0,sticky='w')
|
||||||
|
self.title_entry.grid(row=0,column=1,sticky='we')
|
||||||
|
self.grid_columnconfigure(1, weight=1)
|
||||||
def get(c):
|
def get(c):
|
||||||
return c.title_entry.get()
|
return c.title_entry.get()
|
||||||
|
|
||||||
class TitledTable(tk.Frame):
|
class TitledTable(tk.Frame):
|
||||||
|
|
||||||
def __init__(self, root_window, text, ttk, table, header, widths, anchors):
|
def __init__(self, root_window, text, table, header, widths, anchors):
|
||||||
|
|
||||||
super().__init__(root_window)
|
super().__init__(root_window)
|
||||||
|
|
||||||
@ -355,5 +504,10 @@ def event_timeline(window,events,plt,np,FigureCanvasTkAgg,background_color):
|
|||||||
|
|
||||||
return canvas.get_tk_widget()
|
return canvas.get_tk_widget()
|
||||||
|
|
||||||
|
def TitledFrame(root,title):
|
||||||
|
frame=ttk.LabelFrame(root,text=title,padding=2,borderwidth=4,relief="ridge")
|
||||||
|
return frame
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
Loading…
Reference in New Issue
Block a user