Skip to content

Commit

Permalink
Images in Widgets can be cloned, saved and generated in python
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisMcGowanAu committed Jul 19, 2024
1 parent 68648d1 commit 2d627a9
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 58 deletions.
4 changes: 2 additions & 2 deletions createWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,11 @@ def addPlace(self, placeDict):
self.widget.place(x=self.x, y=self.y, width=self.width, height=self.height)

def editPlacePopup(self):
popup = ew.widgetEditPopup(self.root, self.widget)
popup = ew.widgetEditPopup(self.root, self.widget, self.pythonName)
popup.createLayoutPopup()

def editTtkPopup(self):
popup = ew.widgetEditPopup(self.root, self.widget)
popup = ew.widgetEditPopup(self.root, self.widget, self.pythonName)
popup.createEditPopup()

def findParentObject(self,parent):
Expand Down
29 changes: 22 additions & 7 deletions editWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ class widgetEditPopup:
This class handles the popups for editing the widget
"""

def __init__(self, root, widget):
def __init__(self, root, widget, widgetName):
self.keys = None
self.specialKeys = None
self.widget = widget
self.widgetName = widgetName
self.root = root
self.stringDict = {}
# clickCanvas.bind('<B1-Motion>', leftMouseDrag) # clickCanvas2.bind('<B1-Motion>', leftMouseDragResize)
Expand Down Expand Up @@ -222,13 +223,13 @@ def leftMouseRelease(self, event):
:param event:
"""
log.debug("leftMouseRelease event %s %s", str(event), self.widget)

def selectImage(self, key):
"""
Select an image to load into the widget
:param key: Name of key or attribute
"""
# Need to convert this to skimage (or other package. PIL has issues with github pylint)
# Need to convert this file to image (or other package. PIL has issues with github pylint)
log.warning("selectImage is Expermental")
# return
f_types = [("Png Files", "*.png"), ("Jpg kFiles", "*.jpg")]
Expand All @@ -240,7 +241,21 @@ def selectImage(self, key):
self.addToStringDict(key, imageTk)
self.addToStringDict(filePath, filename)
self.widget.configure(image=imageTk)
myVars.imagesUsed.add(imageTk)
# [ 0 WIDGET 1 KEY 2 FILENAME 3 PHOTOIMAGE]
# Check to see if it is new
found = False
for f in myVars.widgetImageFilenames:
if f[myVars.WIDGET] == self.widgetName:
if [myVars.KEY] == key:
f[myVars.FILENAME] = filename
f[myVars.PHOTOIMAGE] = myVars.imageTest
found = True
if found is False:
f = [self.widgetName,key,filename,myVars.imageTest]
log.debug("Adding f %s",str(f))
myVars.widgetImageFilenames.append(f)


def applyLayoutSettings(self) -> None:
"""
Apply changed layout for the Widget
Expand Down Expand Up @@ -546,7 +561,7 @@ def createEditPopup(self) -> None:
labelCol = 0
controlCol = 3
val: str = ""
# Some widgets will need extra 'keys'
# Some widgets will need extra 'keys'
if wName == "notebook":
# self.specialKeys("Tabs")
log.warning("TBD -- Adding Tabs for notebook")
Expand Down Expand Up @@ -828,13 +843,13 @@ def createEditPopup(self) -> None:
gridRow += 1
if widgetName == "ttk::notebook":
log.info(widgetName)
# Need a Tabs button
# Need a Tabs button
keys.append(tuple(("Tabs", "Tabs")))
elif widgetName == "ttk::labelframe":
keys1 = self.widget.label.keys()
for k1 in keys1:
keys.append(tuple(("label", k1)))
keys2 = self.widget.scale.keys()
keys2 = self.widget.scale.keys()
for k2 in keys2:
keys.append(tuple(("scale", k2)))
log.debug(keys)
Expand Down
90 changes: 46 additions & 44 deletions pytkguivars.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@
projectDict: dict
childNameVars: list[tk.StringVar]
imageFileNames: list[tk.StringVar]
stringUsed: list[bool]
imageTest: any
imagesUsed: list[tk.PhotoImage]
# [ 0 WIDGET 1 KEY 2 FILENAME 3 PHOTOIMAGE]
# The PHOTOIMAGE is not saved as it is unique to an instance.
# It will get generated on load project
WIDGET: int = 0
KEY: int = 1
FILENAME: int = 2
PHOTOIMAGE: int = 3

widgetImageFilenames: []
snapTo: int
imageIndex: int
backgroundColor: str
Expand Down Expand Up @@ -59,7 +67,6 @@ def sprintf(buf: str, fmt, *args) -> str:


def initVars():
global stringUsed
global childNameVars
global imageIndex
global imagesUsed
Expand All @@ -70,18 +77,19 @@ def initVars():
global theme
global rootWidgetName
global createdWidgetOrder
global widgetImageFilenames
projectDict = {}
childNameVars = [tk.StringVar()] * 64
imageFileNames = [tk.StringVar()] * 64
imagesUsed = [tk.PhotoImage]
# stringUsed = [bool]
backgroundColor = "skyBlue3"
# snapTo = int
imageIndex = 0
snapTo = 16
theme = "default"
rootWidgetName = "rootWidget"
createdWidgetOrder = []
widgetImageFilenames = []


# Common Procs
Expand Down Expand Up @@ -166,6 +174,10 @@ def saveWidgetAsDict(widgetName) -> dict:
log.debug("Key->%s<-", key)
if key != "in":
value = w[key]
if key == "image":
if value:
# The value is w.widgetName + key
value = widgetName + key
log.debug("Value->%s<-", str(value))
attrId = "Attribute" + str(keyCount)
# Ignore empty values
Expand Down Expand Up @@ -223,7 +235,23 @@ def buildAWidget(widgetId: object, wDictOrig: dict) -> str:
key = aDict["Key"]
val = aDict["Value"]
useValQuotes = True
# Looks like a bug in tkinter scale objects ..
if key == "image":
if val:
# The problem here is the ID is for the original widget.
# Create widget keeps the count. Use the next one that will get created
# As this is a clone, find the original amd make a new entry
newWidgetName = "Widget" + str(cw.createWidget.widgetId)
for f in widgetImageFilenames:
if f[WIDGET] == widgetName:
if f[KEY] == key:
filename = f[FILENAME]
newImage = tk.PhotoImage(file=filename)
n = [newWidgetName,key,filename,newImage]
widgetImageFilenames.append(n)
log.info("New image for newWidgetName %s %s",newWidgetName,n)
break
val = "myVars.getPhotoImage('" + newWidgetName + "','" + key + "')"
# like 'to' 'from' needs to have an underscore
if key == "from":
key = "from_"
# j(' is in lists for combo boxes
Expand All @@ -233,12 +261,14 @@ def buildAWidget(widgetId: object, wDictOrig: dict) -> str:
key, val, aDict,)
# Typically, this a TK object that is in < xxx > format
continue
if val.find("(") > -1:
if key != 'image' and val.find("(") > -1:
# The 'values' key has this saved format. This might be a tk thing.
# It needs to be converted to a list
newVal = fixComboValues(key, val)
val = newVal
useValQuotes = False
if key == 'image':
useValQuotes = False
if len(val) > 0:
tmpWidgetDef: str = ""
if useValQuotes:
Expand Down Expand Up @@ -292,42 +322,14 @@ def fixWidgetTypeName(wType) -> str:
wType = t
return wType

# sigh .. chat gpt wrote this bit ... it kinda sucks
# import tkinter as tk
# from tkinter import scrolledtext
#
# class AutoResizePopup(tk.Toplevel):
# def __init__(self, master=None, text=""):
# super().__init__(master)
# self.title("Help")
#
# # Create a ScrolledText widget
# self.text_widget = scrolledtext.ScrolledText(self, wrap=tk.WORD)
# # Insert the provided text
# self.text_widget.insert(tk.END, text)
#
# # self.text_widget.pack(fill=tk.BOTH, expand=False)
# self.text_widget.pack()
#
# # Make the Text widget read-only
# self.text_widget.configure(state='disabled')
#
# # Create a close button
# self.close_button = tk.Button(self, text="Close", command=self.close)
# self.close_button.pack(pady=5)
#
# # Automatically resize the window to fit the text
# self.update_idletasks()
# # self.geometry(f"{self.text_widget.winfo_width()}x{self.text_widget.winfo_height() + 40}")
#
# def close(self):
# self.destroy()
#
# def samplePopup(rootw):
# sample_text = (
# "This is a sample text for the popup window. "
# "The window should automatically resize to fit the content. "
# "You can add more text here to see how it adjusts." )
# popup = AutoResizePopup(rootw, text=sample_text)
#
#
def getPhotoImage(widgetName,key) -> tk.PhotoImage:
# the 'image=' part of tkinter widget parameters is tricky to save and restore.
# The imageName and path to file is in myVars.widgetImageFilenames
for w in widgetImageFilenames:
if widgetName == w[WIDGET]:
if key == w[KEY]:
log.info("getPhotoImage %s",str(w))
fileName = w[FILENAME]
w[PHOTOIMAGE] = tk.PhotoImage(file=fileName)
return w[PHOTOIMAGE]

36 changes: 31 additions & 5 deletions pytkquickgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def workOutWidgetCreationOrder() -> list:
while not finished:
finished = True
sanityCheckCount += 1
if sanityCheckCount > 1000:
if sanityCheckCount > 10000:
log.critical("Loop is not exiting Ahhhhh %d", sanityCheckCount)
break
for nameEntry in cw.createWidget.widgetNameList:
Expand All @@ -100,6 +100,15 @@ def workOutWidgetCreationOrder() -> list:
finished = False
return createdWidgetOrder

def createCleanImageList() -> []:
cleanFilenames: [] = []
for f in myVars.widgetImageFilenames:
c = [f[myVars.WIDGET],f[myVars.KEY] ,f[myVars.FILENAME],None]
cleanFilenames.append(c)
log.debug("widgetImageFilenames %s",str(myVars.widgetImageFilenames))
log.debug("cleanFilenames %s",str(cleanFilenames))
return cleanFilenames


def saveProject():
widgetCount = 0
Expand All @@ -115,6 +124,7 @@ def saveProject():
"theme": myVars.theme,
"widgetNameList": cleanList,
"backgroundColor": myVars.backgroundColor,
"imageFileNames" : createCleanImageList(),
}
# Work out the order to create the Widgets so the parenting is correct
createdWidgetOrder = workOutWidgetCreationOrder()
Expand All @@ -136,14 +146,15 @@ def saveProject():
log.debug("projectData ->%s<-", str(projectData))
myVars.projectDict = projectData
fileName = myVars.projectFileName
log.info("projectFileName ->%s<-", fileName)
log.debug("projectFileName ->%s<-", fileName)
f = open(fileName, "wb")
try:
pickle.dump(projectData, f)
except TypeError as e:
log.error("Exception TypeError %s", str(e))
log.warning("Error in Project Data \n%s", str(projectData))
f.close()
log.debug("projectData %s",projectData)
myVars.lastProjectSaved = myVars.projectFileName
myVars.projectSaved = True
# Store the last project saved
Expand Down Expand Up @@ -207,6 +218,10 @@ def buildPython() -> str:
aDict = wDict.get(attribute)
key = aDict.get("Key")
val = aDict.get("Value")
if key == "image":
if val > "":
val = str(widgetName) + str(key)

if key == "command":
if val > "":
log.info("command ->%s<-",val)
Expand All @@ -220,10 +235,14 @@ def buildPython() -> str:
log.info("variable ->%s<-",val)
tkvars.append(val)

print("")
print("####### TK variables #######")
# print(tkvars)
for f in myVars.widgetImageFilenames:
name = str(f[myVars.WIDGET]) + str(f[myVars.KEY])
print(name + " = tk.PhotoImage(file='" + f[myVars.FILENAME] + "')" )
for v in tkvars:
print(v + " = tk.StringVar(rootWin,'0.0')")
print("")
print("####### Functions #######")
for f in functions:
print("")
Expand All @@ -249,7 +268,7 @@ def buildPython() -> str:
keyCount = widgetName + "-KeyCount"
widgetDef = widgetName + " = " + wType + "(" + parentName
nKeys = wDict.get(keyCount)
specialKeys = ["command","textvariable","variable"]
specialKeys = ["command","textvariable","variable","image"]
for a in range(nKeys):
useValQuotes = True
attribute = "Attribute" + str(a)
Expand Down Expand Up @@ -280,6 +299,8 @@ def buildPython() -> str:
if useValQuotes:
tmpWidgetDef = widgetDef + ", " + key + "='" + val + "'"
else:
if key == "image":
val = str(widgetName) + key
tmpWidgetDef = widgetDef + ", " + key + "=" + val
widgetDef = tmpWidgetDef
print(widgetDef + ")")
Expand Down Expand Up @@ -570,6 +591,7 @@ def loadProject(project):
myVars.backgroundColor = runDict.get("backgroundColor")
widgetNameList = runDict.get("widgetNameList")
nWidgets = runDict.get("widgetCount")
myVars.widgetImageFilenames = runDict.get("imageFileNames")
widgetsFound = 0
n = 0
while widgetsFound < nWidgets:
Expand All @@ -581,8 +603,9 @@ def loadProject(project):
widgetDef = myVars.buildAWidget(n, wDict)
try:
# widget = ast.literal_eval(widgetDef)
log.info("widgetDef ->%s<-", widgetDef)
# imageName = str(widgetId) + "image"
widget = eval(widgetDef)
log.debug("widgetDef ->%s<-", widgetDef)
except NameError as e:
log.error("%d dict %s eval() NameError %s",
n, str(wDict), str(e))
Expand Down Expand Up @@ -671,6 +694,9 @@ def widgetTree():
for nl in cw.createWidget.widgetNameList:
print("WidgetNameList", nl)

for il in myVars.widgetImageFilenames:
print("widgetImageFilename %s",il)


def chooseBackground():
# global mainCanvas
Expand Down

0 comments on commit 2d627a9

Please sign in to comment.