Maya Python: OptionMenu Selection With Button - python

I'm new to python in Maya and I'm trying to build a UI which can generate shapes and transform them. The problem I think lies in the ObjectCreation function but I'm not to sure. So far this what I've got:
import maya.cmds as cmds
#check to see if window exists
if cmds.window("UserInterface", exists = True):
cmds.deleteUI("UserInterface")
#create actual window
UIwindow = cmds.window("UserInterface", title = "User Interface Test", w = 500, h = 700, mnb = False, mxb = False, sizeable = False)
mainLayout = cmds.columnLayout(w = 300, h =500)
def SceneClear(*args):
cmds.delete(all=True, c=True) #Deletes all objects in scene
cmds.button(label = "Reset", w = 300, command=SceneClear)
polygonSelectMenu = cmds.optionMenu(w = 250, label = "Polygon Selection:")
cmds.menuItem(label = " ")
cmds.menuItem(label = "Sphere")
cmds.menuItem(label = "Cube")
cmds.menuItem(label = "Cylinder")
cmds.menuItem(label = "Cone")
def ObjectCreation(*args):
if polygonSelectMenu.index == 2: #tried referring to index
ma.polySphere(name = "Sphere")
elif polygonSelectMenu == "Cube":
ma.polyCube(name = "Cube")
elif polygonSelectMenu == "Cylinder":
ma.polyCylinder(name = "Cylinder")
elif polygonSelectMenu == "Cone":
ma.polyCone(name = "Cone")
cmds.button(label = "Create", w = 200, command=ObjectCreation)
def DeleteButton(*args):
cmds.delete()
cmds.button(label = "Delete", w = 200, command=DeleteButton)#Deletes selected object
cmds.showWindow(UIwindow) #shows window
What I'm after is for the user to select one of the options from the option menu then to press the create button to generate that shape. I've tried to refer to it by name and index but I don't know what I'm missing. Like I said I'm new to python so when I tried searching for an answer myself I couldn't find anything and when I did find something similar I couldn't understand it. Plus for some reason the SceneClear function/Reset button doesn't seem to work so if there is answer to that please let me know.

polygonSelectMenu contains the path to your optionMenu UI element. In my case it is: UserInterface|columnLayout7|optionMenu4.
This is just a string and not a reference to a UI element.
To access it's current value you must use this:
currentValue = cmds.optionMenu(polygonSelectMenu, query=True, value=True)
All optionMenu's flags are listed here (Maya 2014 commands doc), queryable ones have a little green Q next to them.
As a result, here is your ObjectCreation(*args) function:
def ObjectCreation(*args):
currentValue = cmds.optionMenu(polygonSelectMenu, query=True, value=True)
if currentValue == "Sphere": #tried referring to index
cmds.polySphere(name = "Sphere")
elif currentValue == "Cube":
cmds.polyCube(name = "Cube")
elif currentValue == "Cylinder":
cmds.polyCylinder(name = "Cylinder")
elif currentValue == "Cone":
cmds.polyCone(name = "Cone")
Off-topic:
Avoid declaring functions between lines of code (in your case, the UI creation code), try instead putting the UI creation code inside a function and call this function at the end of your script.
It is readable as you have only few UI elements right now. But once you start having 20 or more buttons/labels/inputs it can be a mess quickly.
Also, I prefer giving an object name to the UI elements, just like you did with your window ("UserInterface").
To give you a concrete example:
cmds.optionMenu("UI_polygonOptionMenu", w = 250, label = "Polygon Selection:")
This optionMenu can be then accessed anywhere in you code using:
cmds.optionMenu("UI_polygonOptionMenu", query=True, value=True)
Here is the full modified script if you want:
import maya.cmds as cmds
def drawUI(): #Function that will draw the entire window
#check to see if window exists
if cmds.window("UI_MainWindow", exists = True):
cmds.deleteUI("UI_MainWindow")
#create actual window
cmds.window("UI_MainWindow", title = "User Interface Test", w = 500, h = 700, mnb = False, mxb = False, sizeable = False)
cmds.columnLayout("UI_MainLayout", w = 300, h =500)
cmds.button("UI_ResetButton", label = "Reset", w = 300, command=SceneClear)
cmds.optionMenu("UI_PolygonOptionMenu", w = 250, label = "Polygon Selection:")
cmds.menuItem(label = " ")
cmds.menuItem(label = "Sphere")
cmds.menuItem(label = "Cube")
cmds.menuItem(label = "Cylinder")
cmds.menuItem(label = "Cone")
cmds.button("UI_CreateButton", label = "Create", w = 200, command=ObjectCreation)
cmds.button("UI_DeleteButton", label = "Delete", w = 200, command=DeleteButton)#Deletes selected object
cmds.showWindow("UI_MainWindow") #shows window
def SceneClear(*args):
cmds.delete(all=True, c=True) #Deletes all objects in scene
def ObjectCreation(*args):
currentValue = cmds.optionMenu("UI_PolygonOptionMenu", query=True, value=True)
if currentValue == "Sphere":
cmds.polySphere(name = "Sphere")
elif currentValue == "Cube":
cmds.polyCube(name = "Cube")
elif currentValue == "Cylinder":
cmds.polyCylinder(name = "Cylinder")
elif currentValue == "Cone":
cmds.polyCone(name = "Cone")
def DeleteButton(*args):
cmds.delete()
drawUI() #Calling drawUI now at the end of the script
Hope this will help you.

as said above the maya.cmds works very much like mel and you have to use the command cmds.optionMenu() with the polygonSelectMenu as the first arg.
Alternatively if you use pymel instead, you could access the class attrs of polygonSelectMenu with the dot operator like:
import pymel.core as pm
if pm.window("UserInterface", exists = True):
pm.deleteUI("UserInterface")
UIwindow = pm.window("UserInterface", title = "User Interface Test", w = 500, h = 700, mnb = False, mxb = False, sizeable = False)
mainLayout = pm.columnLayout(w = 300, h =500)
polygonSelectMenu = pm.optionMenu(w = 250, label = "Polygon Selection:")
pm.menuItem(label = " ")
pm.menuItem(label = "Sphere")
pm.menuItem(label = "Cube")
pm.menuItem(label = "Cylinder")
pm.menuItem(label = "Cone")
pm.button(label = "Create", w = 200, command=ObjectCreation)
UIwindow.show()
def ObjectCreation(*args):
print polygonSelectMenu.getValue()
also you could make the program into a class with a drawUI method, which might make it easy to do things like store all the items you create in ObjectCreation inside of a class attr so that you can just delete them with your reset button (as i noticed you have cmds.delete(all=True) which i think is not supported anymore in maya), or store the UI elements in self.ui_element. That way they can be referenced later as the variable without the possible conflicts from having multiple windows open that all have buttons like "UI_CreateButton" or "okButton" etc...
import maya.cmds as cmds
class UI_Test_thingy():
windowName = 'UserInterface'
version = 'v1.1.1'
debug = True
createdThingys = []
def __init__(self):
self.drawUI()
def drawUI(self):
if UI_Test_thingy.debug: print 'DEBUG - drawUI called'
#check to see if window exists
try:
cmds.deleteUI(UI_Test_thingy.windowName)
except:
pass
#create actual window
UIwindow = cmds.window(UI_Test_thingy.windowName, title = "User Interface Test {}".format(UI_Test_thingy.version), w = 500, h = 700, mnb = False, mxb = False, sizeable = False)
mainLayout = cmds.columnLayout(w = 300, h =500)
cmds.button(label = "Reset", w = 300, command=self.SceneClear)
self.polygonSelectMenu = cmds.optionMenu(w = 250, label = "Polygon Selection:")
cmds.menuItem(label = " ")
cmds.menuItem(label = "Sphere")
cmds.menuItem(label = "Cube")
cmds.menuItem(label = "Cylinder")
cmds.menuItem(label = "Cone")
cmds.button(label = "Create", w = 200, command=self.ObjectCreation)
cmds.button(label = "Delete", w = 200, command=self.DeleteButton)#Deletes selected object
cmds.showWindow(UIwindow) #shows window
def DeleteButton(self, *args):
if UI_Test_thingy.debug: print 'DEBUG - DeleteButton called: args: {}'.format(args)
cmds.delete()
def SceneClear(self, *args):
if UI_Test_thingy.debug: print 'DEBUG - SceneClear called: args: {}'.format(args)
thingsToDel = UI_Test_thingy.createdThingys[:] # copy the list of things created by this script
UI_Test_thingy.createdThingys = [] # reset the list before deleteing the items
print 'deleteing: {}'.format(thingsToDel)
if thingsToDel:
cmds.delete( thingsToDel ) #Deletes all objects created by this script
def ObjectCreation(self, *args):
if UI_Test_thingy.debug: print 'DEBUG - ObjectCreation called: args: {}'.format(args)
menuVal = cmds.optionMenu(self.polygonSelectMenu, q=True, value=True)
if menuVal == "Sphere":
UI_Test_thingy.createdThingys += cmds.polySphere(name = "Sphere") # store the results to the class attr createdThingys
elif menuVal == "Cube":
UI_Test_thingy.createdThingys += cmds.polyCube(name = "Cube") # store the results to the class attr createdThingys
elif menuVal == "Cylinder":
UI_Test_thingy.createdThingys += cmds.polyCylinder(name = "Cylinder") # store the results to the class attr createdThingys
elif menuVal == "Cone":
UI_Test_thingy.createdThingys += cmds.polyCone(name = "Cone") # store the results to the class attr createdThingys
if __name__ == '__main__':
ui = UI_Test_thingy()

Related

Tkinter is opening a second windows when the first one is closing

I am creating a budget manager and I have added a textBox in the main window.
However, there seems to be a bug: When I close the window while running the script for the first time since I started my IDE, the window opens, then restarts when I close it, but I can't figure it out.
Here are all the programs:
Main
from moneyTable import moneyTable
from textBoxManager import textBox
import tkinter as tk
import fileLoader as fl
import miscAdditions as ma
import categoryAddOrRemove as caor
filesLoaded = fl.loadFile('/home/thanatos_0173/Desktop')
isFileNotEmpty = filesLoaded[0]
moneyClass = filesLoaded[1]
moneyQuantity = filesLoaded[2]
mainWindow = tk.Tk()
mainWindow.resizable(True, True)
mainWindow.title("budgetGestionnary.th")
mainWindow.attributes('-zoomed',True)
mainWindow.config(background=(ma.rgb_to_hex(100, 100, 100)))
moneyTable(mainWindow,moneyClass,moneyQuantity,350,350,isFileNotEmpty)
textBox = tk.Text(mainWindow,height=10,width = 228)
textBox.place(x=10,y=830)
textBox.config(state = tk.DISABLED)
sb = tk.Scrollbar(tk.Frame(mainWindow))
sb.pack(side=tk.RIGHT, fill=tk.BOTH)
textBox.config(yscrollcommand=sb.set)
sb.config(command=textBox.yview)
def removeCategory():
window = tk.Toplevel()
window.minsize(200,200)
window.resizable(False,False)
clicked = tk.StringVar()
clicked.set(moneyClass[0])
dropdown = tk.OptionMenu(window, clicked, *moneyClass)
dropdown.place(x=10,y=10)
def remove():
window.destroy()
elementRemoved = caor.removeElement(moneyClass,moneyQuantity,clicked.get(),moneyQuantity[moneyClass.index(clicked.get())])
moneyTable(mainWindow,elementRemoved[0],elementRemoved[1],350,350,isFileNotEmpty)
if len(moneyClass) == 0:
remove_category_button.config(state=tk.DISABLED)
button = tk.Button(window,text = "Delete category", command = remove)
button.place(x=10,y=50)
def addCategory():
window = tk.Toplevel()
window.minsize(200,200)
window.resizable(False,False)
clicked = tk.StringVar()
clicked.set('Category Name')
nameEntry = tk.Entry(window,textvariable=clicked)
nameEntry.place(x=10,y=10)
clicked2 = tk.StringVar()
clicked2.set('Category Default Money')
moneyEntry = tk.Entry(window,textvariable=clicked2)
moneyEntry.place(x=10,y=40)
def add():
window.destroy()
elementAdded = caor.addElement(moneyClass,moneyQuantity,clicked.get(),clicked2.get())
moneyTable(mainWindow,elementAdded[0],elementAdded[1],350,350,isFileNotEmpty)
remove_category_button.config(state='normal')
button = tk.Button(window,text = "Add category", command = add)
button.place(x=10,y=150)
def addMessageMain(message):
textBox.config(state = tk.NORMAL)
textBox.insert('end',message+"\n")
textBox.config(state = tk.DISABLED)
remove_category_button = tk.Button(mainWindow,text="Remove a category",command = removeCategory)
add_category_button = tk.Button(mainWindow,text="Add a category",command = addCategory)
remove_category_button.place(x=30, y=785, height=33)
add_category_button.place(x=190, y=785, height=33)
if not isFileNotEmpty:
remove_category_button.config(state=tk.DISABLED)
mainWindow.mainloop()
moneyTable.py
import tkinter as tk
from tkinter import ttk
import miscAdditions as ma
def moneyTable(window,categoryList:list,quantityList:list,sizeX:int,sizeY:int,isEmpty:bool,*arg:str):
if len(categoryList) != len(quantityList):
raise ValueError("The list:",categoryList,"haven't the same length than the list:",quantityList)
elementList = []
total = 0
for i in range(len(categoryList)):
tempList = []
tempList.append(categoryList[i])
tempList.append(str(quantityList[i])+" €")
total += quantityList[i]
elementList.append(tempList)
elementList.append(["TOTAL", str(total) + " €"])
frame = tk.LabelFrame(window)
frame.grid(padx=30, pady=30,ipadx=sizeX, ipady=sizeY, row=0)
frame.config(background=(ma.rgb_to_hex(100, 100, 100)),bd=3)
tree = ttk.Treeview(frame)
column_list = ["Category", "Money"]
tree['columns'] = column_list
tree["show"] = "headings"
for column in column_list:
tree.heading(column, text=column)
max = 0
for i in range(len(categoryList)):
if len(categoryList[i]) > max:
max = len(categoryList[i])
if column == column_list[0]:
tree.column(column, width=max*8)
else:
tree.column(column, width=50)
tree.place(relheight=1, relwidth=1)
treescrollY = tk.Scrollbar(frame)
treescrollY.configure(command=tree.yview)
tree.configure(yscrollcommand=treescrollY.set)
treescrollY.pack(side="right", fill="y")
treescrollX = tk.Scrollbar(frame, orient=tk.HORIZONTAL)
treescrollX.configure(command=tree.xview)
tree.configure(xscrollcommand=treescrollX.set)
treescrollX.pack(side="bottom", fill="x")
def handle_click(event):
if tree.identify_region(event.x, event.y) == "separator":
return "break"
tree.bind('<Button-1>', handle_click)
if not isEmpty or arg[0] == "--devmode":
ma.reloadTreeview(tree, elementList)
return tree
textBoxManager.py
import tkinter as tk
def textBox(window,x,y,height,width):
textBox = tk.Text(
window,
height=height,
width = width,
wrap = 'word'
)
textBox.place(x=x,y=y)
textBox.config(state = tk.DISABLED)
sb = tk.Scrollbar(tk.Frame(window))
sb.pack(side=tk.RIGHT, fill=tk.BOTH)
textBox.config(yscrollcommand=sb.set)
sb.config(command=textBox.yview)
return textBox
fileLoader.py
import miscAdditions as ma
import customFileSaver as cfs
#Create the arrays outside of the function to access it from other class
__spec__ = 'test'
def loadFile(defaultPath:str):
moneyComingCategory = []
moneyAvailableComingCategory = []
cfs.loadOrCreateDirectory(defaultPath,".budgetGestionnary")
defaultPath += "/.budgetGestionnary"
cfs.loadOrCreateFile(defaultPath,".savedata.txt")
with open(".savedata.txt") as f:
lines = f.readlines()
cfs.loadOrCreateDirectory(defaultPath,".removedMoney")
defaultPath += "/.removedMoney"
cfs.loadOrCreateFile(defaultPath, ".removedMoney.txt")
with open('.removedMoney.txt') as f:
lines2 = f.readlines()
removedMoneyList = []
for i in lines2:
removedMoneyList.append(ma.str_to_list(i))
if lines != []:
moneyComingCategory = ma.str_to_list(lines[0])
moneyAvailableComingCategory = [eval(i) for i in ma.str_to_list(lines[1])]
isFileNotEmpty = True
else:
isFileNotEmpty = False
return [isFileNotEmpty,moneyComingCategory,moneyAvailableComingCategory]
miscAdditions.py
import tkinter as tk
def rgb_to_hex(r, g, b):
return("#"+"0"*(2-len(hex(r)[2:]))+hex(r)[2:]+"0"*(2-len(hex(g)[2:]))+hex(g)[2:]+"0"*(2-len(hex(b)[2:]))
+ hex(b)[2:])
def str_to_list(arg):
arg = arg.split()
return arg
def list_to_string(arg):
strl1 = ""
for ele in arg:
strl1 += str(ele) + " "
return strl1
def reloadTreeview(tree, list):
tree.delete(*tree.get_children())
for row in list:
tree.insert("", "end", values=row)
def convertActualMoneyList(list, char, list1, list2):
list.clear()
total = 0
for i in range(len(list)):
tempList = []
tempList.append(list1[i])
tempList.append(str(list2[i])+" "+char)
total += list2[i]
list.append(tempList)
list.append(["TOTAL", str(total) + " €"])
return list
def disableAndEnabledDropdownWhenListContainOneElement(list, element, dropdown):
if len(list) == 1 and list == [element]:
dropdown.config(state=tk.DISABLED)
else:
dropdown.config(state="normal")
def dropdownReloader(screen,StringVar,list,dropdown,x,y):
StringVar = tk.StringVar()
StringVar.set(list[0])
dropdown = tk.OptionMenu(screen, StringVar,*list)
dropdown.place(x=x,y=y)
def listTransformer(list:list):
for k in list:
tempList = []
for i in range(len(list)):
if i <= 2:
tempList.append(k[i])
elif i == 3:
tempList.append(str(k[i]+" €"))
else:
tempVariable = ""
for v in range(4, len(k)):
tempVariable += k[v] + " "
tempList.append(tempVariable)
list[list.index(k)] = tempList
return list
space = " "
customFileSaver.py
import os
import miscAdditions as ma
def loadOrCreateDirectory(path, dirToCheckOrCreate):
os.chdir(path)
customDir = path +"/"+ dirToCheckOrCreate
if not os.path.exists(customDir):
os.system("mkdir " + dirToCheckOrCreate)
def loadOrCreateFile(path,fileToCheckOrCreate):
os.chdir(path)
customdir = path + "/" + fileToCheckOrCreate
if not os.path.exists(customdir):
os.system("touch " + fileToCheckOrCreate)
def saveRemovedMoney(list,path,fileToOpen):
os.chdir(path)
with open(fileToOpen,"a") as file:
file.write(ma.list_to_string(list)+os.linesep)
def saveActualMoney(list1,list2,path,fileToOpen):
os.chdir(path)
file = open(fileToOpen,"a")
l1 = ma.list_to_string(list1)
l2 = ma.list_to_string(list2)
file.writelines([l1+os.linesep, l2+os.linesep])
Ok. So, the error is that I imported main (testeeeeee.py) into categoryAddOrRemove. The window initialization was not in a function, so it was initializing the window at once.

Python Tkinter: How to delete all child widgets with a single deletion of a parent widget?

I have a HangMan game created using a class. I want to delete all the child widgets with a single deletion of the parent window.
My game shows a difficulty window, which is being destroyed after the user selects a difficulty and the main game window appears; which is destroyed too after the user completes the game and then a replay window appears; which is destroyed too after the user clicks yes and a new instance of the difficulty pop-up appears again and the whole thing happens intetely until the user says no.
My code looks like this:
class HangMan:
font = ('Comic Sans MS', 20, 'bold')
theme = 'Dark'
allWords = []
stages = None
title = None
def __init__(self):
self.tries = None
self.pWord = None
self.word = None
self.used = []
self.char = None
def setup(self, path, stges, title="HangMan"):
with open(path, 'r') as file:
self.allWords = file.read().split()
del file
self.stages = stges
self.title = title
def play(self):
def setTheme(theme, place):
if theme == 'Dark':
b = 'black'
f = 'white'
else:
b = 'white'
f = 'black'
if place == 'askDiff':
self.diffWindow.config(bg = b)
self.diffFrame['bg'] = b
i = [self.diffLabel, self.db1, self.db2, self.db3]
elif place == 'Main':
self.window.config(bg = b)
inputEntry['insertbackground'] = f
for i in [frame1, frame2]:
i['bg'] = b
i = [wordLabel, themeButton, ph, inputEntry, triesLabel, usageLabel, logLabel]
elif place == 'askReplay':
self.replayWindow.config(bg = b)
self.reFrame['bg'] = b
i = [self.reLabel, self.reb1, self.reb2]
for j in i:
j['bg'] = b
j['fg'] = f
def changeTheme():
if self.theme == 'Dark':
self.theme = 'Light'
else:
self.theme = 'Dark'
themeButton['text'] = self.theme
setTheme(self.theme, 'Main')
def replay():
self.replayWindow.destroy()
self.__init__()
self.play()
def askReplay(event):
#Destroying the running game
self.window.destroy()
#Creating the replay Window
self.replayWindow = Tk()
self.replayWindow.title('Re-Experience?')
self.reLabel = Label(master = self.replayWindow, font = self.font, text = "Wanna replay?\nSwear it'll be a different word...")
self.reLabel.pack()
self.reFrame = Frame(master = self.replayWindow)
self.reFrame.pack()
self.reb1 = Button(master = self.reFrame, font = self.font, text = 'Yup', command = replay)
self.reb1.pack(side = 'left')
self.reb2 = Button(master = self.reFrame, font = self.font, text = 'Later.', command = lambda: self.replayWindow.destroy())
self.reb2.pack(side = 'left')
setTheme(self.theme, 'askReplay')
self.replayWindow.mainloop()
def askDiff():
def returnStage(num):
nonlocal x
x = num
self.diffWindow.destroy()
self.diffWindow = Tk()
self.diffWindow.title('Difficulty')
self.diffLabel = Label(master = self.diffWindow, font = self.font, text = 'Choose your level of difficulty: ')
self.diffLabel.pack()
self.diffFrame = Frame(master = self.diffWindow)
self.diffFrame.pack()
x=None
self.db1 = Button(master = self.diffFrame, font = self.font, text = self.stages[0]['stage'], command = lambda: returnStage(0))
self.db1.pack(side = 'left')
self.db2 = Button(master = self.diffFrame, font = self.font, text = self.stages[1]['stage'], command = lambda: returnStage(1))
self.db2.pack(side = 'left')
self.db3 = Button(master = self.diffFrame, font = self.font, text = self.stages[2]['stage'], command = lambda: returnStage(2))
self.db3.pack(side = 'left')
setTheme(self.theme, 'askDiff')
self.diffWindow.mainloop()
return x
def setDiff(i):
from random import choice
wordLenRange = (self.stages[i]['wordLen']['min'], self.stages[i]['wordLen']['max'])
possibleWords = []
for j in self.allWords:
if len(j) in range(wordLenRange[0], wordLenRange[1] + 1):
possibleWords.append(j)
self.word = list(choice(possibleWords).lower())
self.pWord = ''.join(self.word)
self.allWords.remove(self.pWord)
self.tries = self.stages[i]['tries']
def isValid(string):
if len(string)==1 and string.isalpha():
return True
else:
return False
def isUsed(string):
if string in self.used or string in wordLabel['text']:
return True
else:
return False
def isRight(string):
if string in self.word:
return True
else:
return False
def updateLog(x):
if x == 'invalid input':
logLabel['text'] = 'Enter a valid single alphabet'
elif x == 'in word':
logLabel['text'] = 'This letter is revealed'
elif x == 'in used':
logLabel['text'] = 'You have already used this letter'
elif x == 'right':
logLabel['text'] = 'Good Guess...'
elif x == 'wrong':
logLabel['text'] = 'You missed it.'
elif x == 'win':
logLabel['text'] += '\nYou Win...Press any key...'
else:
logLabel['text'] += '\nYou Lost...The word is revealed.\nPress any key...'
def updateWord():
txt = list(wordLabel['text'])
while self.char in self.word:
index = self.word.index(self.char)
txt[index] = self.char
self.word[index] = '*'
txt = ''.join(txt)
wordLabel['text'] = txt
def updateTries():
self.tries -= 1
triesLabel['text'] = '{} Oops left'.format(self.tries)
def updateUsage():
self.used.append(self.char)
usageLabel['text'] = 'Used Letters: {}'.format(', '.join(self.used))
def processGame(event):
self.char = inputEntry.get().strip()
if isValid(self.char):
self.char = self.char.lower()
if isUsed(self.char):
if self.char in wordLabel['text']:
updateLog('in word')
else:
updateLog('in used')
else:
if isRight(self.char):
updateWord()
updateLog('right')
else:
updateTries()
updateUsage()
updateLog('wrong')
else:
updateLog('invalid input')
inputEntry.delete(0, 'end')
if '*' not in wordLabel['text']:
updateLog('win')
inputEntry.bind('<Key>', askReplay)
if self.tries == 0:
updateLog('lost')
wordLabel['text'] = self.pWord
inputEntry.bind('<Key>', askReplay)
## GUI Design
from tkinter import Tk, Label, Entry, Button, Frame
#Diffficulty PopUp
diff = askDiff()
setDiff(diff)
# Main Window
self.window = Tk()
self.window.title(self.title)
# Frames and Buttons
frame1 = Frame(master = self.window)
frame1.pack(fill = 'x')
wordLabel = Label(master = frame1, font = self.font, text = '*'*len(self.word))
wordLabel.pack()
themeButton = Button(master = frame1, font = ("Comic Sans MS", 12), text = self.theme, command = changeTheme)
themeButton.pack(side = 'right')
frame2 = Frame(master = self.window)
frame2.pack()
ph = Label(master = frame2, font = self.font, text = 'Guess a Letter: ')
ph.pack(side = 'left')
inputEntry = Entry(master = frame2, font = self.font, width = 5)
inputEntry.focus_set()
inputEntry.pack(side = 'left')
triesLabel = Label(master = frame2, font = self.font, text = '{} Oops left'.format(self.tries))
triesLabel.pack(side = 'left')
usageLabel = Label(master = self.window, font = self.font, text = 'Used Letters: -')
usageLabel.pack()
logLabel = Label(master = self.window, font = self.font, text = "-:Log:-")
logLabel.pack()
setTheme(self.theme, 'Main')
#Event Handler and MainLoop
self.window.bind('<Return>', processGame)
self.window.mainloop()
path = "words.txt"
stages = ({'stage': 'Cool', 'tries':10, 'wordLen':{'min':3, 'max':5}}, {'stage': 'Engaging', 'tries':6, 'wordLen':{'min':6, 'max':8}}, {'stage': 'Intense', 'tries': 4, 'wordLen': {'min': 9, 'max': 15}})
game1 = HangMan()
game1.setup(path, stages)
game1.play()
At 3 places, I'm destroying the parent window - in the askReplay() fucntion of the class.play() function, in the returnStage() function of the askDiff() function in the class.play() function & in the replay() function of the class.play() function. I tried self.window.destroy(), but it is only destroying the root window and all its child widgets are still occupying the memory (I know this because I tried to print one of the child widgets after the window was destroyed). How can I do this?
This would be a problem if an obsessive player plays my game for a
thousand times, creating more than 7000 trash widgets in the memory.
One implementation would be to have the top-level object track its widgets via a list, then have a .close() method that looks something like:
def close(self):
for widget in self.widgets:
widget.destroy()
self.destroy()

Python self.after() changes running order

I am (still!) writing a Noughts and Crosses program using Tkinter in Python 3.
I wanted to implement a short pause between the player's move and the computer's move, so in the add_move_comp() method implemented self.after() function.
I expected this to pause the program for 1000ms then continue by 'drawing' on the computer's move.
However when I run my code, the program only recognises the computer's move the next move after, causing problems with identifying a 3-in-a-row.
I think this is due to line 62 running after 1000ms while the rest of the program continues running, but I don't know how to stop the whole program and continue running with line 62 after the pause.
from tkinter import *
from functools import partial
from itertools import *
import random
class Window(Frame):
def __init__(self, master = None): # init Window class
Frame.__init__(self, master) # init Frame class
self.master = master # allows us to refer to root as master
self.rows = 3
self.columns = 3
self.guiGrid = [[None for x in range(self.rows)] for y in range(self.columns)] # use this for the computer's moves
self.noText = StringVar(value = '')
self.cross = StringVar(value = 'X')
self.nought = StringVar(value = 'O')
self.button_ij = None
self.myMove = True
self.create_window()
self.add_buttons()
def create_window(self):
self.master.title('Tic Tac Toe')
self.pack(fill = BOTH, expand = 1)
for i in range(0,3): # allows buttons to expand to frame size
self.grid_columnconfigure(i, weight = 1)
self.grid_rowconfigure(i, weight = 1)
def add_buttons(self):
rows = 3
columns = 3
for i in range (rows):
for j in range(columns):
self.button_ij = Button(self, textvariable = self.noText, command = lambda i=i, j=j: self.add_move(i,j))
self.guiGrid[i][j] = self.button_ij
self.button_ij.grid(row = i,column = j, sticky =E+W+S+N)
def add_move(self, i,j):
# player's move
while self.myMove:
pressedButton = self.guiGrid[i][j]
self.guiGrid[i][j].config(textvariable = self.cross)
# computer's turn
self.myMove = False
while (self.myMove == False):
self.add_move_comp()
def add_move_comp(self):
repeat = True
while repeat:
i = random.randint(0,0) # row - only allow O to be drawn on 1st row for testing purposes
j = random.randint(0,2) # column
testText = self.guiGrid[i][j].cget('text')
if testText == '':
self.after(1000,lambda i = i, j = j :self.guiGrid[i][j].config(textvariable = self.nought)) # search up rules with returning values using lambda
print('Should plot O at row: ',i,' column: ',j)
print('TEXT ACTUALLY PLOTTED IS: ',self.guiGrid[i][j].cget('text'))
self.myMove = True
repeat = False
print(self.guiGrid[0][0].cget('text'), self.guiGrid[0][1].cget('text'), self.guiGrid[0][2].cget('text')+'THIS IS PRINTING')
root = Tk() # creating Tk instance
rootWidth = '500'
rootHeight = '500'
root.geometry(rootWidth+'x'+rootHeight)
ticTacToe = Window(root) # creating Window object with root as master
root.mainloop() # keeps program running
This is due to the fact that self.after imeadiately returns and starts the given function after passing trough a queque to prevent the actual Window from beeing unable to responde because there is some code running. A way to work around this is to create a BooleanVariable for validation and using self.wait_variable as follows:
from tkinter import *
from functools import partial
from itertools import *
import random
class Window(Frame):
def __init__(self, master = None): # init Window class
Frame.__init__(self, master) # init Frame class
self.master = master # allows us to refer to root as master
self.rows = 3
self.columns = 3
self.guiGrid = [[None for x in range(self.rows)] for y in range(self.columns)] # use this for the computer's moves
self.noText = StringVar(value = '')
self.cross = StringVar(value = 'X')
self.nought = StringVar(value = 'O')
self.button_ij = None
self.myMove = True
self.validationVar = BooleanVar(self)
self.create_window()
self.add_buttons()
def create_window(self):
self.master.title('Tic Tac Toe')
self.pack(fill = BOTH, expand = 1)
for i in range(0,3): # allows buttons to expand to frame size
self.grid_columnconfigure(i, weight = 1)
self.grid_rowconfigure(i, weight = 1)
def add_buttons(self):
rows = 3
columns = 3
for i in range (rows):
for j in range(columns):
self.button_ij = Button(self, textvariable = self.noText, command = lambda i=i, j=j: self.add_move(i,j))
self.guiGrid[i][j] = self.button_ij
self.button_ij.grid(row = i,column = j, sticky =E+W+S+N)
def add_move(self, i,j):
# player's move
while self.myMove:
pressedButton = self.guiGrid[i][j]
self.guiGrid[i][j].config(textvariable = self.cross)
# computer's turn
self.myMove = False
while (self.myMove == False):
self.add_move_comp()
def add_move_comp(self):
repeat = True
while repeat:
i = random.randint(0,0) # row - only allow O to be drawn on 1st row for testing purposes
j = random.randint(0,2) # column
testText = self.guiGrid[i][j].cget('text')
if testText == '':
self.after(1000, self.validationVar.set, True)
self.wait_variable(self.validationVar)
self.guiGrid[i][j].config(textvariable = self.nought) # search up rules with returning values using lambda
print('Should plot O at row: ',i,' column: ',j)
print('TEXT ACTUALLY PLOTTED IS: ',self.guiGrid[i][j].cget('text'))
self.myMove = True
repeat = False
print(self.guiGrid[0][0].cget('text'), self.guiGrid[0][1].cget('text'), self.guiGrid[0][2].cget('text')+'THIS IS PRINTING')
root = Tk() # creating Tk instance
rootWidth = '500'
rootHeight = '500'
root.geometry(rootWidth+'x'+rootHeight)
ticTacToe = Window(root) # creating Window object with root as master
root.mainloop() # keeps program running

maya python print state of checkbox?

I'm trying to get the state of a checkbox in a maya UI using python. I was wondering if someone would help me. currently when the user hits the Distribute button, it calls a function which should print the true/false state of the 'x' checkbox.
import maya.cmds as cmds
class createMyLayoutCls(object):
def __init__(self, *args):
pass
def show(self):
self.createMyLayout()
def createMyLayout(self):
#check to see if our window exists
if cmds.window('utility', exists = True):
cmds.deleteUI('utility')
# create our window
self.window = cmds.window('utility', widthHeight = (200, 200), title = 'Distribute', resizeToFitChildren=1, sizeable = False)
cmds.setParent(menu=True)
# create a main layout
mainLayout = cmds.columnLayout(w = 200, h = 200, cw = 10, rs = 8, co = ['both',2])
# X Control
self.xAxis = cmds.checkBox('X')
# Distribute Button
btnDistribute = cmds.button(label = 'Distribute', width = 200, height = 40, c = self.GetSelectedNodes)
# show window
cmds.showWindow(self.window)
def GetSelectedNodes(self,*args):
cal = cmds.checkBox(self['X'],q = True, v = True)
print cal
b_cls = createMyLayoutCls()
b_cls.show()
you need to pass the checkbox's name into the call to checkBox in GetSelectedNodes:
def GetSelectedNodes(self,*args):
cal = cmds.checkBox(self.xAxis,q = True, v = True)
print cal

tkinter GUI errors with class declaration and global name "parent" not defined?

this is the current code i have that i edited and tried to get working, but still doesnt work :/ debugging help would be awesome :) it gives errors with the variables "self" and "parent" not being defined in the mainWindow class, as well as an error with the line "class mainWindow". not entirely sure what they both mean or how to fix
import sys, Tkinter
sys.modules['tkinter'] = Tkinter
import Pmw
class Print:
def __init__(self, text):
self.text = text
def __call__(self):
print self.text
class mainWindow:
def __init__(self,parent,balloon):
self.balloon = Pmw.Balloon(parent)
self.parent = parent
self.menuBar = menuBar
self.mainPart = mainPart
self.buttonBox = buttonBox
def Quit():
root.destroy()
menuBar = Pmw.MenuBar(parent,hull_relief = 'raised',hull_borderwidth = 1,balloon = self.balloon)
menuBar.pack(fill = 'x')
menuBar.addmenu('Run Control','Calibration,Download Configuration,Number of Triggers,Data Output File,Upload Configuration,Start DAQ,Quit')
menuBar.addcascademenu('Run Control','Calibration','View and/or change the calibration',traverseSpec = 'z',tearoff = 1)
menuBar.addmenuitem('Calibration','command','Display the DAC calibration',command = Print('display the DAC calibration'),label = 'Display DAC Calibration')
menuBar.addmenuitem('Calibration','command','Display the calibration mask',command = Print('display the calibration mask'),label = 'Display Calibration Mask')
menuBar.addmenuitem('Calibration','command','Change the DAC calibration',command = Print('change the DAC calibration'),label = 'Change DAC Calibration')
menuBar.addmenuitem('Calibration','command','Change the calibration mask',command = Print('change the calibration mask'),label = 'Change Calibration Mask')
menuBar.addmenuitem('Run Control','command','Download a configuration',command = Print('download configuration'),label = 'Download Configuration')
menuBar.addmenuitem('Run Control','command','Set the number of triggers',command = Print('set number of triggers'),label = 'Number of Triggers')
menuBar.addmenuitem('Run Control','command','Change the file where the data will be sent to',command = Print('set data output file'),label = 'Data Output File')
menuBar.addmenuitem('Run Control','command','Upload a configuration',command = Print('upload a configuration'),label = 'Upload Configuration')
menuBar.addmenuitem('Run Control','command','Start the data aquisition',command = Print('start data aquisition'),label = 'Start DAQ')
menuBar.addmenuitem('Run Control','separator')
menuBar.addmenuitem('Run Control','command','Close the GUI',command = Quit,label = 'Quit')
menuBar.addmenu('Slow Control','Voltage, Current,Temperature,DAC Settings')
menuBar.addmenuitem('Slow Control','command','Display the voltage',command = Print('display voltage'),label = 'Voltage')
menuBar.addmenuitem('Slow Control','command','Display the current',command = Print('display current'),label = 'Current')
menuBar.addmenuitem('Slow Control','command','Display the temperature',command = Print('display temperature'),label = 'Temperature')
menuBar.addmenuitem('Slow Control','command','Display the DAC settings',command = Print('display DAC settings'),label = 'DAC Settings')
menuBar.addmenu('Graphics','Channel Map,Energy Detector,Root Output,Slow Control Time,Histograms,One Event Display')
menuBar.addmenuitem('Graphics','command','Display the channel map',command = Print('display channel map'),label = 'Channel Map')
menuBar.addmenuitem('Graphics','command','Display the energy detector',command = Print('display energy detector'),label = 'Energy Detector')
menuBar.addmenuitem('Graphics','command','Display the root output',command = Print('display root output'),label = 'Root Output')
menuBar.addmenuitem('Graphics','command','Display the slow control time',command = Print('display slow control time'),label = 'Slow Control Time')
menuBar.addmenuitem('Graphics','command','Display various histograms',command = Print('display histograms'),label = 'Histograms')
menuBar.addmenuitem('Graphics','command','Display the one event display',command = Print('display one event display'),label = 'One Event Display')
menuBar.addmenu('Edit Data Base','Make Configuration Files')
menuBar.addmenuitem('Edit Data Base','command','Make the Configuration Files',command = Print('create configuration files'),label = 'Create Configuration Files')
mainPart = Tkinter.Label(parent,text = 'GUI',background = 'white',foreground = 'white',padx = 100,pady = 100)
mainPart.pack(fill = 'both', expand = 1)
buttonBox = Pmw.ButtonBox(parent)
buttonBox.pack(fill = 'x')
buttonBox.add('Start\nRoot', command = Print('start root'))
if __name__ == '__main__':
root = Tkinter.Tk()
Pmw.initialise(root)
root.title('pCT GUI')
root.mainloop()
You should post all of your code and the exact error message so I can better help but from what you posted it seems that your problems are:
class foo:
is empty. So you need it to look like
class foo:
pass
in order to not get an error.
Parent not being defined is probably due to that fact that you never defined the variable parent so you probably want something along the lines of:
parent = Tkinter.Tk()
The first argument for MenuBar is to specify the parent window whose MenuBar belongs to. You get an error since you didn't define it. If MenuBar is a top-level widget, just link it the root :
root = Tk()
menuBar = Pmw.MenuBar(root,
hull_relief = 'raised',
hull_borderwidth = 1,
balloon = self.balloon)
menuBar.pack(fill = 'x')
root.mainloop()

Categories