use text from textField for naming - maya python - python

I want to use the output of a textField to serve as a name for a newly created blenshape. However when I press the button to create my shape it only consideres the text that has been defined by me as a stock text that should be replaced. It doesn't consider new letters typed in the box :
def buildUI(self, *args):
self.widgets["bs"] = cmds.textField (tx= "Replace me", editable= True, )
self.widgets["blendshape_name"] = cmds.textField(self.widgets['bs'], q=True, text=True)
cmds.button(label="Create BlendShape ", w=295, h=30, al="center", c=self.blendShape)
def blendShape (self, *args):
cmds.blendShape ( cmds.ls(sl=True)[1], cmds.ls(sl=True)[0],frontOfChain=True, n= self.widgets["blendshape_name"] )

You query the blendshape_name only when you run buildUI function. You have to read the textfield at every click. So query the blendshape_name inside the function blendShape:
def blendShape(self, *args):
blendshape_name = cmds.textField(self.widgets['bs'], q=True, text=True)
cmds.blendShape(cmds.ls(sl=True)[1], cmds.ls(sl=True)[0], frontOfChain=True, n=blendshape_name)

Related

Calling function from UI class in maya resulting in nonetype error

I'm building a toolbox UI using python in Maya, and I keep on getting a Nonetype error when I call one of the imported functions. This is the script for the toolbox:
class Toolbox():
import maya.cmds as cmds
def __init__(self):
self.window_name = "mlToolbox"
def create(self):
self.delete()
self.window_name = cmds.window(self.window_name)
self.m_column = cmds.columnLayout(p = self.window_name, adj = True)
cmds.button(p=self.m_column,label = 'MyButton', c=lambda *arg: cmds.polySphere(r = 2))
cmds.button(p=self.m_column, label = 'Make_Control', command = lambda *args: self.ControlBTN())
cmds.button(p=self.m_column, label = 'Find Center of All Selected', command = lambda *args: self.CenterBTN())
cmds.button(p=self.m_column, label = 'Find Center of Each Selected Object', command = lambda *args: self.IndiCenterBTN())
self.colorname = cmds.textField(placeholderText = 'Enter color name...')
cmds.button(p=self.m_column, label = 'ChangeColor', command = lambda *args: self.colorBtn())
self.MinAndMax = cmds.textField()
cmds.button(p=self.m_column, label = 'Random Scatter', command = lambda *args: self.ScatterBTN())
cmds.showWindow(self.window_name)
cmds.button(p=self.m_column, label = 'Select Everything', command = lambda *args: self.selectBTN())
def CenterBTN(self):
import CenterSelected
CenterSelected.Locator()
def ScatterBTN(self):
import Scatter
value = cmds.textField(self.MinAndMax, q=True)
Scatter.RandomScatter(value)
cmds.intField(self.moveMin, self.moveMax, self.rotMin, self.rotMax, self.scaleMin, self.scaleMax, e=True, text='')
def IndiCenterBTN(self):
import ManySelected
ManySelected.LocatorMany()
def colorBtn(self):
import ColorControl
value = cmds.textField(self.colorname, q=True, text = True)
ColorControl.colorControl(value)
cmds.textField(self.colorname, e=True, text='')
def selectBTN(self):
import tools
tools.selectAll()
def delete(self):
if cmds.window(self.window_name, exists=True):
cmds.deleteUI(self.window_name)
def ControlBTN(self):
import CreateControl
CreateControl.createControl()
myTool = Toolbox()
myTool.create()
And this is the function that I'm having trouble with:
def RandomScatter(MinAndMax):
import random
import maya.cmds as cmds
Stuff = cmds.ls(sl=True)
i=0
for i in range(random.randint(1,100)):
Stuff.append(cmds.duplicate(Stuff))
cmds.move( (random.randint(MinAndMax[0], MinAndMax[1])), (random.randint(MinAndMax[0], MinAndMax[1])), (random.randint(MinAndMax[0], MinAndMax[1])), Stuff[i], absolute=True )
cmds.rotate( (random.randint(MinAndMax[2], MinAndMax[3])), (random.randint(MinAndMax[2], MinAndMax[3])), (random.randint(MinAndMax[2], MinAndMax[3])), Stuff[i], absolute=True )
cmds.scale( (random.randint(MinAndMax[4], MinAndMax[5])), (random.randint(MinAndMax[4], MinAndMax[5])), (random.randint(MinAndMax[4], MinAndMax[5])), Stuff[i], absolute=True )
i = i+1
RandomScatter() works fine as long as I call it on it's own using a RandomScatter([a, b, c, d, e, f]) format, but when I try to call it Toolbox(), I get "Scatter.py line 21: 'NoneType' object has no attribute 'getitem'" as an error. It also happens when I try to use the intField() command instead of textField(). The UI window builds just fine; the error only happens after I enter input into the text field and press the button that's supposed to call RandomScatter(). It seems like the input isn't making it to the MinAndMax list, so when it reaches "cmds.move( (random.randint(MinAndMax[0]," it can't find anything to put in the MinAndMax[0] slot, or any of the slots after that, but I can't figure out why. Does anyone have any advice?
I didn't test your code and didn't read it totally, but I can already say that your strange "lambda" usage doesn't make any sens.
lambda *args: self.ControlBTN()
this lambda execute self.ControlBTN during the cmds.button definition and provide to it a function which return None.
that like doing that:
self.ControlBTN()
function = def func(): return None
cmds.button(p=self.m_column, label = 'Make_Control', command=function)
I advise you to reread the documentation about the "python lambda".
replace this by:
cmds.button(p=self.m_column, label = 'Make_Control', command=self.ControlBTN)
...
def ControlBTN(self, *args)
...
That should help
good luck
As written self.MinAndMax is a text field; even if you get the value from it it'll be a string and you won't be able to index into it to get the individual items -- and your indexing will be thrown off if any of the numbers are negative or have decimals. The lazy solution is to use a FloatFieldGrp which lets you have 2-4 numberic inputs. It's a bit annoying to get at all of the values at once (see the way it's done below) but it will avoid many issues with trying to parse the text field.
Also, this line doesn't make sense in context:
cmds.intField(self.moveMin, self.moveMax, self.rotMin, self.rotMax, self.scaleMin, self.scaleMax, e=True, text='')
You're not seeing the error because it's failing in the previous line, but the first argument ought to be the name of an existing intField.
In any case, I'd refactor this a bit to keep the argument parsing out of the scatter function, so you can separate out the working logic from the UI parsing logic. It'll make it much easier to spot where things have gone off the rails:
import random
import maya.cmds as cmds
class TestGUI(object):
def __init__(self):
self.window = cmds.window()
self.layout = cmds.rowLayout(nc=3)
self.min_xyz = cmds.floatFieldGrp( numberOfFields=3, label='min', value1=-10, value2=-10, value3=-10 )
self.max_xyz= cmds.floatFieldGrp( numberOfFields=3, label='min', value1=10, value2=10, value3=10 )
cmds.button(label='scatter', c = self.scatter)
cmds.showWindow(self.window)
def scatter(self, *_):
selected = cmds.ls(sl=True)
if not selected:
cmds.warning("select something")
return
min_xyz = (
cmds.floatFieldGrp(self.min_xyz, q=True, v1=True),
cmds.floatFieldGrp(self.min_xyz, q=True, v2=True),
cmds.floatFieldGrp(self.min_xyz, q=True, v3=True)
)
max_xyz = (
cmds.floatFieldGrp(self.max_xyz, q=True, v1=True),
cmds.floatFieldGrp(self.max_xyz, q=True, v2=True),
cmds.floatFieldGrp(self.max_xyz, q=True, v3=True)
)
print "scatter settings:", min_xyz, max_xyz
rand_scatter(selected, min_xyz, max_xyz)
def rand_scatter(selection, min_xyz, max_xyz):
dupe_count = random.randint(1, 10)
duplicates = [cmds.duplicate(selection) for n in range(dupe_count)]
for dupe in duplicates:
destination = [random.randint(min_xyz[k], max_xyz[k]) for k in range(3)]
cmds.xform(dupe, t=destination, absolute=True)
print (dupe, destination)
t = TestGUI() # shows the window; hit 'scatter' to test
My version changes your logic a bit -- you were duplicating your selection list, which would cause the number of items to grow exponentially (as each duplication would also duplicate the previous dupes). I'm not sure if that's inline with your intention or not.
You can avoid the extra lambdas by including a *_ in the actual button callback; it's a minor maya irritant that buttons always have that useless first argument.
As an aside, I'd try not to do imports inside of function bodies. If the imported module is not available, it's better to know at the time this file is imported rather than only when the user clicks a button -- it's much easier to spot a missing module if you do all your imports in a block at the top.

maya python textField + object name Assistance Please

Here is my plan. First create a joint and open your node editor. When you got your joint created, name it "A_Joint" hit "load joint" after running the script, then hit "test" upon hitting test, you should get a node created with the name "A_Joint_firstGuy"
the objective of this script is to create a node based on the name of whatever you loaded into the textField. It will take the name of the selected object and add it to the front of the name of the node
Atleast thats what should happen, but in truth I lack the knowledge to figure this out and every google search has thus far been fruitless. The script is down below for anyone willing to take a crack at it, thank you for your time and I hope to hear back from you:
https://drive.google.com/file/d/1NvL0MZCDJcKAnVu6voVNYbaW0HurZ6Rh/view?usp=sharing
Or here, in SO format:
import maya.cmds as cmds
if cmds.window(window, exists =True):
cmds.deleteUI(window)
window = cmds.window(title = "DS Selection Loader Demo", widthHeight=(300, 200) )
cmds.columnLayout(adjustableColumn=True)
def sld_loadHelperJoint():
sel = cmds.ls(selection=True)
selString = " ".join(sel)
add = cmds.textField('sld_surfaceTextHJ', edit=True, text=selString)
#def sld_loadParentJoint():
# sel = cmds.ls(selection=True)
# selString = " ".join(sel)
# add = cmds.textField('sld_surfaceTextPJ', edit=True, text=selString)
def createNode():
testNode = cmds.createNode( 'transform', selString = "sld_surfaceTextHJ", name = '_firstGuy' )
cmds.columnLayout(adjustableColumn=True)
sld_textFld = cmds.textField('sld_surfaceTextHJ', width =240)
cmds.button( label='Load Helper Joint', command = "sld_loadHelperJoint()")
cmds.setParent('..')
#cmds.columnLayout(adjustableColumn=True)
#name = cmds.textField('sld_surfaceTextPJ', width =240)
#cmds.button( label="Load Parent Joint", command = "sld_loadParentJoint()")
#cmds.setParent('..')
testNode = cmds.createNode( 'transform', name = textField +'_firstGuy' )
# you must first create "def" group for the attributes you
# want to be created via button, "testNode" is our example
# Connect the translation of two nodes together
#cmds.connectAttr( 'firstGuy.t', 'secondGuy.translate' )
# Connect the rotation of one node to the override colour
# of a second node.
#cmds.connectAttr( 'firstGuy.rotate', 'secondGuy.overrideColor' )
cmds.showWindow (window)
OK, there's a few things going on here to consider.
First, Maya gui widgets look like strings -- just like you make a polyCube and it comes back to you as the string 'pCube1', a widget will come back as a string like 'myWindow' or 'textField72'. Just like working with scene objects, you always need to capture the results of a command so you know what it's really called -- you can't guarantee you'll get the name you asked for, so always capture the results.
So you want to do something like this, just to get the graphics going:
window = cmds.window(title='selection loader demo')
column = cmds.columnLayout(adj=True)
sld_textFld = cmds.textField('sld_surfaceTextHJ', width =240)
load_button = cmds.button( label='Load Helper Joint')
cmds.show_window(window)
If you needed to ask what's in the textField, for example, you'd do:
text_contents = cmds.textField(sld_textFld, q=True, text=True)
You notice that's with the variable, not the string, so we're sure we have whatever worked.
To make the button use that information, though, the button script needs to have access to the variable. There are several ways to do this -- it's a common stack overflow question -- but the easiest one is just to define the button command where you already have that variable. So the above sample becomes:
window = cmds.window(title='selection loader demo')
column = cmds.columnLayout(adj=True)
sld_textFld = cmds.textField('sld_surfaceTextHJ', width =240)
def set_textfield(_):
sel = cmds.ls(selection=True)
add = cmds.textField(sld_textFld, edit=True, text=sel[0])
load_button = cmds.button( label='Load Helper Joint', c = set_textfield)
cmds.showWindow(window)
There are two bits here.
One is the _ in the function definition; Maya buttons always call their functions with one argument. There's nothing magical about the underscore, it's just Python slang for "ignore me" -- but if you don't have an argument in the function def, it will fail.
The more important bit is that the button is given the function definition directly, without quotes. You are saying call this function when clicked. If you use the string version -- a holdover from MEL -- you will run into problems later. The reasons are explained in detail here but the TLDR is don't use the the string form. Ever.
Now that the structural pieces are in place, you should be able to either the node creation to the function I called set_textfield() or make a second button\function combo that does the actual node creation, something like:
window = cmds.window(title='selection loader demo')
column = cmds.columnLayout(adj=True)
sld_textFld = cmds.textField('sld_surfaceTextHJ', width =240)
def set_textfield(_):
sel = cmds.ls(selection=True)
cmds.textField(sld_textFld, edit=True, text=sel[0])
load_button = cmds.button( label='Load Helper Joint', c = set_textfield)
def make_node(_):
text_value = cmds.textField(sld_textFld, q = True, text=True)
if text_value:
print "created:", cmds.createNode('transform', n=text_value +'_firstGuy')
else:
cmds.warning("select an object and add it to the window first!")
node_button = cmds.button( label='Make Node', c = make_node)
cmds.showWindow(window)

Multiple text fields refusing to load selected objects

The code I made, despite double, triple, and quadruple checking is refusing to load selected items into the text fields, that is assuming you can get maya to get over it's newfound hatred of the cmds.windows function
The errors I'm getting are threefold, if you try to load the code into a new window you will just get
Error: name 'window' is not defined" assuming you make it past that hurdle you will run into 2 problems: the first is just from pasting the code below. The menu will load just fine, but if you hit either "Load A Node" or "Load B Node" you will get the error "# Error: Object 'window1|columnLayout9|sld_surfaceTextHJ' not found.
I never put "sld_surfaceTextHJ" in the code, so I dont know why maya keeps asking for it. If you humor it however and try to change the name 'sld_surfaceTextA' or 'sld_surfaceTextB' to any other name you will get the third error: # Error: name 'window1|columnLayout9|sld_surfaceTextHJ' is not defined.
The script used to work fine loading selections, but it seems that every script I made following this format is refusing to work.
Here it is if you want to take a crack at it
import maya.cmds as cmds
if cmds.window(window, exists =True):
cmds.deleteUI(window)
window = cmds.window(title='DS selection connector demo')
column = cmds.columnLayout(adj=True)
sld_textFldA = cmds.textField('sld_surfaceText1', width =240)
load_button = cmds.button( label='Load A Node', c = set_textfield)
sld_textFldB = cmds.textField('sld_surfaceText2', width =240)
load_button = cmds.button( label='Load B Node', c = set_textfield)
node_button = cmds.button( label='Connect Node', c = make_node)
def set_textfieldA(_):
sel = cmds.ls(selection=True)
cmds.textField(sld_textFldA, edit=True, text=sel[0])
def set_textfieldB(_):
sel = cmds.ls(selection=True)
cmds.textField(sld_textFldB, edit=True, text=sel[0])
def connect_node(_):
text_value = cmds.textField(sld_textFldA, q = True, text=True)
text_value = cmds.textField(sld_textFldB, q = True, text=True)
if text_value:
print "created:", cmds.connectAttr('transform', n=text_value +'_firstGuy')
print "created:", cmds.connectAttr('transform', n=text_value +'_secondGuy')
else:
cmds.warning("select an object and add it to the window first!")
cmds.showWindow( window )
The expected results are rather simple: you hit "Load A Node" on any node you create to load the first Node, Then you hit "Load B Node" on the second node you created: then upon hitting "Connect Node" the translate attribute of your first node should be connected to your second node like the connection editor.
Never mind guys, for anyone interested: here is the fixed code, I still haven't gotten the connect attributes part figured out yet: but for anyone looking for a simple textField selection loader demo, here you go:
import maya.cmds as cmds
if cmds.window(window, exists =True):
cmds.deleteUI(window)
window = cmds.window(title='DS selection connector demo')
column = cmds.columnLayout(adj=True)
sld_textFldA = cmds.textField('sld_surfaceText1', width =240)
load_button = cmds.button( label='Load A Node', c = set_textfield1)
sld_textFldB = cmds.textField('sld_surfaceText2', width =240)
load_button = cmds.button( label='Load B Node', c = set_textfield2)
def set_textfield1(_):
sel = cmds.ls(selection=True)
cmds.textField(sld_textFldA, edit=True, text=sel[0])
def set_textfield2(_):
sel = cmds.ls(selection=True)
cmds.textField(sld_textFldB, edit=True, text=sel[0])
cmds.showWindow( window )

Change the color of a single word in a tk option menu?

So I'm grabbing links of events off a website and putting them into a drop down menu to be selected. My code for the menu:
import Tkinter as tk
from Tkinter import StringVar
selectMenu = tk.Tk()
# #-> this is what I have
# Followed by what you can use
#var = Vars()
#events = var.GetVars('Event')
events = " "
options = []
links = []
#forms = (driver.find_elements_by_class_name("with-cats")) #This is what I have
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
for x in forms:
#info = x.text
info = x #Again, this is so you can try it for yourself
if events in info.lower():
links.append(x)
for link in range(0,len(links)):
#options.append(links[link].text)
options.append(links[link])
list(set(options))
selection = []
for link in range(0,len(options)):
selection.append(options[link])
select = StringVar(selectMenu)
select.set("--None Selected--")
menu = tk.OptionMenu(selectMenu, select, *(selection))
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menu.pack(side="top", pady=10)
selectMenu.attributes('-topmost', True)
selectMenu.mainloop()
So this works fine and dandy, but I would like to improve the look to make it more obvious which events are open. To clarify, an event found that is open and put into the menu may look like "This is a cool event", but one that is closed would be read as "This is a cool event Closed". My aim is to be able to make the foreground red of either just the word Closed or the string containing Closed, whichever is possible if any (And I'm not sure if it's possible because menus and buttons on osx are usually defaulted to system settings, maybe there is a way around this?).
Current: Desired:
According to the documentation for OptionMenu here and here I don't think there is a way to set the color of text.
You might be able to get something close to what you want by using a listBox instead. See post here for the listBox example.
Found a solution! Using a Menu inside of a MenuButton the same way Tkinter creates MenuOptions, I was able to create a custom MenuOption. If you want to add more options, you can use the menbutton.configure() option to edit the button, and menbutton.menu to edit the menu items.
import Tkinter as tk
from Tkinter import Menu, Menubutton
class Vars():
global vari
vari = {}
def GetVars(self, var):
return vari.get(str(var))
def SendVars(self, var, val):
vari[str(var)] = val
class App():
def buttselect(self, link, menbutton, selectMenu):
var = Vars()
var.SendVars("Selection", link) # Store selected event
menbutton.configure(text=link) # Set menu text to the selected event
def prnt(self, link):
var = Vars()
print var.GetVars("Selection") # Print event
def __init__(self, selectMenu):
events = " "
options = []
links = []
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
menbutton = Menubutton (selectMenu, text="--None Selected--", relief="raised")
menbutton.grid()
menbutton.menu = Menu (menbutton, tearoff=0)
menbutton["menu"] = menbutton.menu
#Get a list of event names
for x in forms:
info = x #Again, this is so you can try it for yourself
#If desired event keyword is in an event name, add it to the correct links
if events in info.lower():
links.append(x)
#Remove duplicates
for link in range(0,len(links)):
options.append(links[link])
list(set(options))
#Final list of event names turned into menu commands
for link in options:
if "Closed" in link:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu), foreground='red')
else:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu))
b = tk.Button(selectMenu, text="Selection", command= lambda link=link: self.prnt(link)) #Print selected event
b.pack()
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menbutton.pack(side="top", pady=10)
selectMenu = tk.Tk()
selectMenu.attributes('-topmost', True)
app = App(selectMenu)
selectMenu.mainloop()
This results in exactly the result desired:
I found a way!
Let's say x is an optionmenu with options:
options=['Red','Blue','Green']
defopt=tk.StringVar(options[0]) #StringVariable to hold the selected option.
x=tk.OptionMenu(self.optmenuframe,defopt,*options)
Now, get the menu object from the optionmenu and use entryconfig method. That's it!
x.children['menu'].entryconfig(0,foreground='red')
x.children['menu'].entryconfig(1,foreground='blue')
x.children['menu'].entryconfig(2,foreground='green')
#0 is the index of the option you want to apply the configurations to.

How can i make the browsed file the target for process, instead of it being hard coded in?

Instead of "mbox = ?????????" in the def start_processing(self) section, how do i make it the file that has been uploaded. This was originaly hard coded however have changed it to a file upload? Thanks
class App:
def __init__(self, master):
self.master = master
# call start to initialize to create the UI elemets
self.start()
def start(self):
self.master.title("Extract Email Headers")
self.now = datetime.datetime.now()
# CREATE A TEXT/LABEL
# create a variable with text
label01 = "Please select the .mbox file you would like to analyse"
# put "label01" in "self.master" which is the window/frame
# then, put in the first row (row=0) and in the 2nd column (column=1),
# align it to "West"/"W"
tkinter.Label(
self.master, text=label01).grid(row=0, column=0, sticky=tkinter.W)
# CREATE A TEXTBOX
self.filelocation = tkinter.Entry(self.master)
self.filelocation["width"] = 60
self.filelocation.focus_set()
self.filelocation.grid(row=1, column=0)
# CREATE A BUTTON WITH "ASK TO OPEN A FILE"
# see: def browse_file(self)
self.open_file = tkinter.Button(
self.master, text="Browse...", command=self.browse_file)
# put it beside the filelocation textbox
self.open_file.grid(row=1, column=1)
# now for a button
self.submit = tkinter.Button(
self.master, text="Execute!", command=self.start_processing,
fg="red")
self.submit.grid(row=3, column=0)
def start_processing(self):
date1= "Tue, 18 Jan 2015 15:00:37"
date2="Wed, 23 Jan 2015 15:00:37"
date1 = parser.parse(date1)
date2 = parser.parse(date2)
f = open("results.txt","w")
mbox = ????????????????????
count = 0
for msg in mbox:
pprint.pprint(msg._headers, stream = f)
tempdate = parser.parse(msg['Date'])
print(tempdate)
f.close()
print(count)
pass
def browse_file(self):
# put the result in self.filename
self.filename = filedialog.askopenfilename(title="Open a file...")
# this will set the text of the self.filelocation
self.filelocation.insert(0, self.filename)
I'm assuming you want to store the file path in a StringVar. TK uses special control variables to provide functionality for Entry objects. You can create a string control variable by calling the function tk.StringVar().
You want to create the variable when you initialize your UI, so in your start() method:
# CREATE A TEXTBOX
self.filepath = tkinter.StringVar() # This will hold the value of self.filelocation
# We set it to the "textvariable" option of the new entry
self.filelocation = tkinter.Entry(self.master, textvariable=self.filepath)
self.filelocation["width"] = 60
self.filelocation.focus_set()
self.filelocation.grid(row=1, column=0)
Now when we want to retrieve the value of it we use the get() method. In your start_processing() method:
# Here it opens the file, but you may want to do something else
mbox = open(self.filepath.get(),'r')
The way you set the value in your browse_file() method can be updated to use the control variable quite easily. Instead of inserting into the entry box directly, we'll set the value of our control variable and it will automatically update in the text entry field. In browse_file():
# this will set the text of the self.filelocation
self.filepath.set( self.filename )
Now you can properly set and retrieve the value of self.filelocation the intended way. You can change the name of self.filepath to whatever you want, of course.
For more information:
Tkinter 8.5 Reference - Control Variables
TkDocs - Tk Tutorial - Basic Widgets - Entry
I don't know for certain if mbox is supposed to be an open file, a list, a tuple, or some custom object. I'm going to assume it's an open file, since you have a function to pick a filename.
If that's the case, all you need to do is call the get method of the entry widget to get whatever the user typed:
mbox_name = self.filelocation.get()
mbox = open(mbox_name, "r")
for msg in mbox:
...

Categories