Accessing Temp Directory On Tkinter - python

im new in this page and i love the answers nice job, with all the help of users, im new on python and wanna make a print of dir in a entry or label doesnt matter for example:
def directory(): os.listdir('/')
files=StringVar()
files.set(directory)
entry=Entry(root, textvariable=files).grid()
obviously in tkinter, the last code make a "print" a list of directories, but make me a list horizontal with this ',' for each folder different, i want it vertical list on this "entry" or "label", suppose later need a scroll bar but, there no is a problem, and make the same for temporal folder on windows look like that...
def directory(): os.listdir('%temp%')
files=StringVar()
files.set(directory)
entry=Entry(root, textvariable=files).grid()
but this %temp% doesnt works directly on python how can i make a listdir of folder?

Since displaying the contents of a directory is going to generally require multiple lines of text, one for each item in it, you have to use atk.Labelortk.Textwidget since a tk.Entrycan only handle a single line of text.
In addition you'll need to convert thelistthat os.listdir() returns into a multi-line string before setting itstextoption. Regardless, in order to be use yourdirectory() function needs to return a value to be useful.
The following code does these basic things and shows how to expand the value of the%temp%environment variable usingos.path.expandvars(). Alternatively, you can get the same value by using thetempfile.gettempdir()function Sukrit recommended.
import os
from Tkinter import *
def directory(folder):
return '\n'.join(os.listdir(folder)) # turn list into multiline string
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
files = directory(os.path.expandvars('%temp%'))
self.label = Label(root, text=files)
self.label.pack(side=LEFT)
root = Tk()
app = App(root)
root.mainloop()

Related

Saving an instance of tkinter GUI

I am working on a GUI with an "Add entry box" button that adds an entry box when clicked. I also want to add a "Save for next session" button that, when clicked, will load the current entries when the user opens the GUI next time. The problem is that sometimes it will be 5 fields to enter, other times 305. How can I save the number of input fields and their values? I don't want to use the pickle library.
import customtkinter
import threading
import tkinter
class MyGui:
def __init__(self, app):
self.app = app
self.entry_list = []
self.entry_1 = customtkinter.CTkEntry(master=self.app, placeholder_text="entry")
self.entry_1.pack(pady=10, padx=10)
self.add_entry_button = customtkinter.CTkButton(master=self.app, text="Add entry", command=self.add_entry)
self.add_entry_button.pack(pady=10, padx=10)
self.save_button = customtkinter.CTkButton(master=self.app, text="Save for next session", command=self.save_instance)
self.save_button.pack(pady=10, padx=10)
def add_entry(self):
self.entry_list.append(self.entry_1)
self.entry_1 = customtkinter.CTkEntry(master=self.app, placeholder_text="entry")
self.entry_1.pack(pady=10, padx=10)
def save_instance(self):
pass
app = customtkinter.CTk()
running = MyGui(app)
app.mainloop()
As you can see I have this self.entry_list with all entry field objects, but I do not know how to use it to load the GUI instance later.
You will need to use some sort of storage mechanism. You don't want to use pickle, which is one mechanism. You can also use a flat file or a database. In this case, since you're using entry widgets, a flat file with the content of each entry is sufficient. A sqlite database might arguably be better, but in this specific case it might be overkill.
Whatever you choose, it's important to know that you can't save tkinter objects to disk. The implementation of tkinter makes that essentially impossible. So, you must save the data from which you can restore the tkinter object rather than saving the object itself.
In your case you're saving entries to the list self.entry_list, so writing the file could just be a matter of iterating over the entries to get the values and write them to a file (assuming you want to preserve the values)
The following example hard-codes the filename for brevity, but in production code you shouldn't hard-code it.
def save_instance(self):
data = [entry.get() for entry in self.entry_list]
with open("entries.txt", "w") as f:
text = "\n".join(data)
f.write(text)
Restoring the entries is just a matter of reversing the process. First, though, we need to modify add_entry to take the default value. Also, your implementation oddly uses self.entry_1 which isn't necessary so I've removed it.
The following example assumes the data which was saved to the file is the default value of the entry widget. If instead, it's the name of the placeholder text you can easily make that modification.
def add_entry(self, text=""):
entry = customtkinter.CTkEntry(master=self.app, placeholder_text="entry")
self.entry_list.append(entry)
entry.pack(pady=10, padx=10)
entry.insert("end", text)
Next, create a method for reading the data and creating the entries. It's important to note that readlines includes the newline on each line, which we strip out.
def restore_entries(self):
with open("entries.txt", "r") as f:
data = f.readlines()
for line in data:
self.add_entry(line.strip())
This definitely isn't the only way to solve the problem. If you don't want to save the default values (or placeholder text?) you could just store the number of entries you want to keep. Or, like I mentioned earlier, you could use a database. With a database you could store the number of rows, and then only save the text for the entries that have text. Or, instead of a flat file you could save the data in a structured format such as json.

Possible to create varying number of frame/tab objects and bind each to a name?

I am reading a folder structure for a game where each account has subfolders for servers and then subfolders for characters and in the character folders there is a text file.
What i am trying to create with tkinter and ttk in my root window is 1tab / frame for each account and under each account 1 tab for each server and then 1 tab for each character where i will finaly put text from each characters file.
Since i read this from the file system the amount of accounts, servers and characters can vary so i am looping through these to make the tkinter widget objects.
Problem is i can't figure out how to bind each object to a name so i can make comparisons / modify values of the objects after they are created, in order to just have 1 tab per server for example where all characters are put.
I have tried googling but can't seem to find what i am looking for. So far i have tried creating a class for each file i will read and the class contains all necessary info. But i get stuck when creating the tkinter objects and trying to figure out how to go about it.
This is my class from which i am successfully creating an instance with all info populated for each file, although they are in a list of objects with no bound name/variable:
class MacroObject(object):
def __init__(self, name, realm, account, path):
self.account = account
self.realm = realm
self.name = name
self.path = path
self.macroName = ''
self.macroText = []
And this is my current approach to create the gui:
root = tk.Tk()
tabControl = ttk.Notebook(root)
tabControl.pack()
account_tabs = []
realm_tabs = []
character_tabs = []
accounts = []
realms = []
for objects in macro_objects:
if objects.account not in accounts:
tabControl.add(ttk.Frame(tabControl), text=objects.account)
accounts.append(objects.account)
for objects in macro_objects:
if objects.account == ttk.Frame.text and objects.realm not
This is where i get stuck and the last line obviously wouldn't work, the ttk.Frame is instantiated with seemingly no way for me to refer to it and i can't seem to figure out how to solve it.
I am still very much a beginner so I'm guessing this might be a stupid question and there is probably a much simpler approach for this?
My problem was solved thanks to Martineau reminding/making me realize i could store the widgets in a dictionary.
I used values from my MacroObject class instances as keys and after a while i got the result i wanted with a ttk notebook tab hierarchy:
https://i.imgur.com/IsNmXiO.png

Trying to populate a window dynamically in Maya using separate py files to essentially build modules

So I'm trying build a window in Maya, that will have contents that will be populated dynamically. My folder structure is this:
/scripts/modularMenu/ <-- which contains:
init.py
modMenu.py
and a /modules/ folder
in the modules folder I have:
modList.py
mod1.py
mod2.py
mod3.py etc. etc.
In modMenu.py I tell Maya to draw the window, but also run the function that populates it based on the contents of the modules folder, with the goal being to create new modules that are, if tagged correctly, populated in the window.
import maya.cmds as cmds
import sys, os.path
from functools import partial
import modules.modList as mList
def modMenu():
if (cmds.window('modMenu', exists=True)):
cmds.deleteUI('modMenu')
else:
window = cmds.window( 'modMenu', title="Mod Menu v1.1", iconName='mRig', widthHeight=(400, 800))
cmds.scrollLayout(width=400, cr=True)
cmds.columnLayout(adj=True )
#This all needs to be generated Dynamically.
mList.populateWindow()
cmds.showWindow( window )
In modList.py I have a list of categories and a function to populate the window.
typeList = ['Type One', 'Type Two', Type Three']
def populateWindow():
for type in typeList:
cmds.frameLayout(label = type, collapsable = True, borderStyle = 'etchedIn')
cmds.text(label = type, al = 'center', height = 15)
#Need to then go through each module and import the rest of the form here, each form will have to have a tag to determine if it
#needs to go in this Category or not. Perhaps the equivalent of...
#for each mod.py in /modules folder if their tag == type then add
cmds.setParent( '..' )
What I'm trying to figure out next is one, how to safely import the contents of each separate mod1.py, mod2.py, etc etc into this modList.py file and two how to tag each separate mod.py file so its placed within the menu system correctly. Ideally I'd like to include one identical function in each mod.py file and a string that correct tags it, that I could call in the modList.py file, but I'm not sure how to correctly import from those mod files en masse to successfully call that function. Any help would be welcome.
On one level, this is pretty simple. You can always add gui elements to a Maya layout if you have a string reference to it, using the setParent() command to tell Maya where the new stuff goes.
In a case like this you just need to pass the shared layout to a bunch of functions --- it doesn't matter where they come froms -- and have each of them call 'setParent` to make the layout active and add to it. Here's an example of how it would go, using separate functions instead of separate modules -- it would not make a difference if these different functions had different module origins.
def button_section(parent):
cmds.columnLayout(adj=True)
cmds.frameLayout(label='buttons')
cmds.columnLayout(adj=True)
cmds.rowLayout(nc=2, cw = (200,200))
cmds.button(label = 'red', backgroundColor=(1,0.5,0.5), width=100)
cmds.button(label = 'blue', backgroundColor =(0.5, 0.5, 1), width=100)
def text_section(parent):
cmds.separator()
cmds.text(label = 'time:')
cmds.text(label = 'It is currently ' + str(datetime.datetime.now()))
cmds.text(label = 'main layout is ' + parent)
cmds.separator()
def object_section(parent):
cmds.columnLayout(adj=True)
cmds.frameLayout(label = 'scene')
cmds.columnLayout(adj=True, rs = 12, columnAttach = ('both', 8) )
for object in cmds.ls(type='transform'):
select_the_thing = lambda b: cmds.select(object)
cmds.button(label = object, c = select_the_thing)
def create_window(*sections):
window = cmds.window(title = 'example')
main_layout = cmds.columnLayout(adj=True)
for each_section in sections:
cmds.setParent(main_layout)
each_section(main_layout)
cmds.setParent(main_layout)
cmds.columnLayout(adj=1, columnAttach = ('both', 8))
cmds.separator()
cmds.text(label = 'here is a footer')
cmds.showWindow(window)
create_window(button_section, text_section, object_section)
If you're not familiar with the syntax the create_window function with a * takes any number of arguments. In this case it's just taking the three individual section functions. You could, however write it to just take a list of functions. In any case the logic is the same -- just setParent back to the main layout and you'll be able to add new stuff to the layout.
In this example I passed the name of the main layout into each of the different layout functions. This is useful so you can do things like get the width of a layout element that owns you, or work your way up to a higher level recursively.
In general the thing you'll have to watch out for here is designing this so that the different sections really are independent of each other. Things will get complicated fast if a button in section A needs to know the state of a checkbox in section B. However this shows you the basics of how to compose layouts in Maya.
I'd be very careful about trying to populate the menu based on the contents of your module folder -- if you delete a module but don't remember to delete the pyc file that is produced by it, you can end up with a phantom section of UI that you don't expect. It would be better to just organize the code as conventional modules and then have a simple script that asked for the modules explicitly. Then you can know exactly what to expect on a local install.
1 - you will have to use exec() or "import mod, mod.doIt()", but what is "safely" will rely on your checks
2 - Im not sure to understand. Do you want to reorder mod by number ?
if not, I supposed you can do a json to store the order or maybe store some metadata

Python variable equal to class method? Syntax

so I'm starting to learn python and I need to write a script that edits a CSV file. I found this online and had a few questions about what it's exactly doing since the original programmer didn't explain. My question right now though is about syntax. I'm a little confused about some of these lines:
import Tkinter,tkFileDialog
root = Tkinter.Tk()
root.filename = tkFileDialog.askopenfilename(initialdir = "/", title =
"Select a file", filetypes = (("csv files", "*.csv"),))
So my first question is what root equals. I understand I imported two modules called Tkinter and tkFileDialog(Correct me if I'm wrong) into my file. I then created a variable called root and set it equal to a method call?
root = Tkinter.tk()
Next, what does this line do? Is filename a method in one of those modules? I read something about widgets...are widgets methods? As in the word is used interchangeably?
root.filename
Thank you in advance!
You may benefit more form some youtube tutorials on python methods/functions and classes but I can answer your questions in general terms.
So my first question is what root equals.
root is the variable name assigned to the instance that is being created with tkinter.Tk()
This allows you to interact with that instance of tkinter and you can use root to place widgets on the main window of the GUI.
Next, what does this line do? root.filename
root.filename is only a variable name. tkFileDialog.askopenfilename is the class method being used to get the file and assign the file information to the variable name root.filename
So what you are doing here is importing the library tkinter that contains many class methods that can be used to build and manipulate a GUI interface.
note that for an instance of tkinter you will need a mainloop() at the end of your code to make it work. So at the end of your code you will need to have something like root.mainloop() to make sure the program will work as long as everything else is done correctly.

How to loop through subfolders showing jpg in Tkinter?

It's a Python beginner question.
I want to loop through several subfolders of parent folder (subfolders contain jpg and txt files). I want to show images using Tkinter. There should be an image and Next button beside - when button is clicked the next image from the list should be loaded.
How to force an application to stop on each image and wait for user reaction?
In the test code below the image loaded is from the last directory in the loop (images from other directories are not displayed although I can print their names during the loop run).
import Tkinter, os, glob
from PIL import Image, ImageTk
class simpleapp_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
self.grid
parentSrcFolder = r"D:\2012\RCIN\test"
srcFoldersLst = os.listdir(parentSrcFolder)
for srcFolder in srcFoldersLst:
jpgFilesPathLst = glob.glob(os.path.join(parentSrcFolder, srcFolder, "*.jpg"))
self.labelVariable = Tkinter.StringVar()
label = Tkinter.Label(self,textvariable=self.labelVariable,anchor="w")
label.grid(column=0,row=0,columnspan=2,sticky='EW')
self.labelVariable.set(jpgFilesPathLst[0])
cardImage = Image.open(jpgFilesPathLst[0])
indexCard = ImageTk.PhotoImage(cardImage)
labelImage = Tkinter.Label(self,image=indexCard)
labelImage.image = indexCard
labelImage.grid(column=0,row=3)
def main():
app = simpleapp_tk(None)
app.title('my application')
app.mainloop()
if __name__ == '__main__':
main()
The easiest way that I can think of doing this :
first, create a method display_next which will increment an index and display the image associated with that index in a list (assume the list is a list of filenames). Enclosing the list inquiry in a try/except clause will let you catch the IndexError that happens when you run out of images to display -- At this point you can reset your index to -1 or whatever you want to happen at that point.
get the list of filenames in __init__ and initialize some index to -1 (e.g. self.index=-1).
create a tk.Button in __init__ like this:
self.Button = Tkinter.Button(self,text="Next",command=self.display_next)
Another side note, you can use a widget's config method to update a widget on the fly (instead of recreating it all the time). In other words, move all the widget creation into __init__ and then in display_next just update the widget using config. Also, it's probably better to inherit from Tkinter.Frame...
class SimpleAppTk(Tkinter.Frame):
def __init__(self,*args,**kwargs):
Tkinter.Frame.__init__(self,*args,**kwargs)
self.filelist=[] #get your files here
#it probably would look like:
#for d in os.listdir(parentDir):
# self.filelist.extend(glob.glob(os.path.join(parentDir,d,'*.jpg'))
self.index=-1
self.setup()
self.display_next()
def setup(self):
self.Label=Tkinter.Label(self)
self.Label.grid(row=0,column=0)
self.Button=Tkinter.Button(self,text="Next",command=self.display_next)
self.Button.grid(row=0,column=1)
def display_next(self):
self.index+=1
try:
f=self.filelist[self.index]
except IndexError:
self.index=-1 #go back to the beginning of the list.
self.display_next()
return
#create PhotoImage here
photoimage=...
self.Label.config(image=photoimage)
self.Label.image=photoimage
if __name__ == "__main__":
root=Tkinter.Tk()
my_app=SimpleAppTk(root)
my_app.grid(row=0,column=0)
root.mainloop()
EDIT
I've given an example of how to actually grid the Frame. In your previous example, you had self.grid in your initialization code. This really did nothing. The only reason you had results was because you were inheriting from Tkinter.Tk which gets gridded automatically. Typically it's best practice to grid after you create the object because if you come back later and decide you want to put that widget someplace else in a different gui, it's trivial to do so. I've also changed the name of the class to use CamelCase in agreement with PEP 8 ... But you can change it back if you want.

Categories

Resources