print current selected file name - python-3.x

I am using the following function to set the text of a Label to be the file name
i just picked , but i want to get the name of the file i'm currently selecting before canceling or opening the file from the dialog
is there any way to do so by using tkinter or any other framework/lib
here's the code
def pick_csv(self):
filename = filedialog.askopenfilename()
filelabel.config(text=filename)
#filelabel should get the name of the selected file
#before closing the dialog

I don't think you can use the native askopenfilename to achieve this. But you can write your own class that inherit from FileDialog. It will look ugly and needs some work on the layout.
from tkinter import *
from tkinter import filedialog
import os
root = Tk()
a = Label(root,text="Waiting for selection")
a.pack()
class CustomDialog(filedialog.FileDialog):
def __init__(self,master,path=""):
filedialog.FileDialog.__init__(self,master)
self.files.bind("<Button-1>",self.set_label)
self.selected = None
self.go(path)
def set_label(self,*args):
a.config(text=self.files.get(self.files.curselection()))
self.selected = os.path.join(self.directory, self.files.get(self.files.curselection()))
def cancel_command(self, event=None):
self.selected = None
self.quit()
def click():
f = CustomDialog(root)
if f.selected:
print (f.selected)
b = Button(root,text="Browse",command=click)
b.pack()
root.mainloop()

Related

Tkinter Label class not appearing when used within a class

I am creating a basic GUI with multiple, but similar, label structures. However, when I created a class to help minimize the text, and placed it within a label frame, the label frame does not appear. This only happens when I use the class within a class, and if I use the regular label and label frame classes everything works out well. I'm trying to figure out as to why this is the case.
My code:
main.py
from tkinter import *
def main():
main_window = Tk()
app = First(main_window)
main_window.mainloop()
class GPULabel(Label):
def __init__(self, master, varText):
varText = varText
super().__init__()
self["text"] = varText
self["anchor"] = "w"
self["width"] = 25
class First:
def __init__(self, root):
self.root = root
self.root.title('First Window')
self.myFrame = LabelFrame(self.root, text="frame")
self.myFrame.pack()
label1 = GPULabel(self.myFrame, "label")
lable1.pack()
if __name__ == '__main__'
main()
This opens a window but it is completely empty. However, if I swap to a regular Label(self.myFrame...) then the window pops up correctly. Why is that? And is there a way to make my original method work?

Sending a signal from a button to a parent window

I'm making an app with PyQt5 that uses a FileDialog to get files from the user and saves the file names in a list. However I also want to be able to remove those entries after they are added, so I created a class that has a name(the file name) and a button. The idea is that when this button is clicked the widget disappears and the file entry is removed from the list. The disappearing part works fine but how to I get the widget to remove the entry form the list? How can i send a signal from one widget inside the window to the main app and tell it to remove the entry from the list?
I know the code is very bad, I'm still very new to PyQt and Python in general so any advice would be greatly appreciated.
from PyQt5 import QtWidgets as qw
import sys
class MainWindow(qw.QMainWindow):
def __init__(self):
super().__init__()
# List of opened files
self.files = []
# Main Window layout
self.layout = qw.QVBoxLayout()
self.file_display = qw.QStackedWidget()
self.file_button = qw.QPushButton('Add File')
self.file_button.clicked.connect(self.add_file)
self.layout.addWidget(self.file_display)
self.layout.addWidget(self.file_button)
self.setCentralWidget(qw.QWidget())
self.centralWidget().setLayout(self.layout)
# Open File Dialog and append file name to list
def add_file(self):
file_dialog = qw.QFileDialog()
self.files.append(file_dialog.getOpenFileName())
self.update_stack()
# Create new widget for StackedWidget remove the old one and display the new
def update_stack(self):
new_stack_item = qw.QWidget()
layout = qw.QVBoxLayout()
for file in self.files:
layout.addWidget(FileWidget(file[0]))
new_stack_item.setLayout(layout)
if len(self.file_display) > 0:
temp_widget = self.file_display.currentWidget()
self.file_display.removeWidget(temp_widget)
self.file_display.addWidget(new_stack_item)
class FileWidget(qw.QWidget):
def __init__(self, name):
# This widget is what is added when a new file is opened
# it has a file name and a close button
# my idea is that when the close button is pressed the widget is removed
# from the window and from the files[] list in the main class
super().__init__()
self.layout = qw.QHBoxLayout()
self.file_name = qw.QLabel(name)
self.close_button = qw.QPushButton()
self.close_button.clicked.connect(self.remove)
self.layout.addWidget(self.file_name)
self.layout.addWidget(self.close_button)
self.setLayout(self.layout)
def remove(self):
self.close()
if __name__ == '__main__':
app = qw.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
You need to remove from the list in the remove method of theFileWidget class.
import sys
from PyQt5 import QtWidgets as qw
class FileWidget(qw.QWidget):
def __init__(self, name, files): # + files
super().__init__()
self.files = files # +
self.name = name # +
self.layout = qw.QHBoxLayout()
self.file_name = qw.QLabel(name)
self.close_button = qw.QPushButton("close {}".format(name))
self.close_button.clicked.connect(self.remove)
self.layout.addWidget(self.file_name)
self.layout.addWidget(self.close_button)
self.setLayout(self.layout)
def remove(self):
self.files.pop(self.files.index(self.name)) # <<<-----<
self.close()
class MainWindow(qw.QMainWindow):
def __init__(self):
super().__init__()
# List of opened files
self.files = []
# Main Window layout
self.layout = qw.QVBoxLayout()
self.file_display = qw.QStackedWidget()
self.file_button = qw.QPushButton('Add File')
self.file_button.clicked.connect(self.add_file)
self.layout.addWidget(self.file_display)
self.layout.addWidget(self.file_button)
self.setCentralWidget(qw.QWidget())
self.centralWidget().setLayout(self.layout)
# Open File Dialog and append file name to list
def add_file(self):
file_name, _ = qw.QFileDialog().getOpenFileName(self, 'Open File') # +
if file_name: # +
self.files.append(file_name) # +
self.update_stack()
# Create new widget for StackedWidget remove the old one and display the new
def update_stack(self):
new_stack_item = qw.QWidget()
layout = qw.QVBoxLayout()
for file in self.files:
layout.addWidget(FileWidget(file, self.files)) # + self.files
new_stack_item.setLayout(layout)
if len(self.file_display) > 0:
temp_widget = self.file_display.currentWidget()
self.file_display.removeWidget(temp_widget)
self.file_display.addWidget(new_stack_item)
if __name__ == '__main__':
app = qw.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

python tkinter update content of a label when a file is opened

I'm currently programming a GUI using tkinter and Python 3.
My problem here is i made a Label with which i want to display the path of a file i opened via the askopenfilename() method and this path is not "generated" when i start the program, obviously, so the Label is empty which makes sense but i don't know how to fix it.
I'm gonna put the needed code below (I'm going to cut unnecessary code for this question):
import tkinter as tk
class Graphicaluserinterface(tk.Frame):
def __init__(self,master=None):
super().__init__(master)
self.grid()
self.fileopenname=tk.StringVar()
self.menubar = tk.Menu(self)
self.create_widgets()
def create_widgets(self):
self.inputpathdisplay = tk.Label(self,textvariable=self.fileopenname,bg="white",width=30)
self.inputpathdisplay.grid(row=1,column=8,columnspan=3,sticky = "W")
def fileopening(self):
from tkinter.filedialog import askopenfilename
self.fileopenname = askopenfilename(filetypes = [("binary files","*.bin*"),("all files","*.*")])
root = tk.Tk()
app = Graphicaluserinterface(master=root)
root.config(menu=app.menubar)
app.mainloop()
I read about using update_idletasks(). If this is correct in my case how would i go about implementing it here?
Right now you are doing self.fileopenname = askopenfilename() and this will redefine self.fileopenname as a string instead of a StringVar(). To correct this you need to set the value of StringVar with set().
That said you should also define all your imports at the top of your code instead of in your function.
import tkinter as tk
from tkinter.filedialog import askopenfilename
class Graphicaluserinterface(tk.Frame):
def __init__(self,master=None):
super().__init__(master)
self.grid()
self.fileopenname=tk.StringVar()
self.menubar = tk.Menu(self)
self.inputpathdisplay = tk.Label(self, textvariable=self.fileopenname, bg="white")
self.inputpathdisplay.grid(row=1,column=8,columnspan=3,sticky = "W")
self.fileopening()
def fileopening(self):
self.fileopenname.set(askopenfilename(filetypes = [("binary files","*.bin*"),("all files","*.*")]))
root = tk.Tk()
app = Graphicaluserinterface(master=root)
root.config(menu=app.menubar)
app.mainloop()

Open a file with a button then storing the path in Python3

As the title states, I want to open a file with a browse button then store the file path for later use. I have no issue browsing the file, I just can't get the path to store into a variable. Many thanks.
from tkinter import *
from tkinter import filedialog
import openpyxl
from termcolor import cprint
# initializing tk
root = Tk()
root.title("Tools")
root.geometry("600x300")
frame = Frame(root)
frame.pack()
bottomframe = Frame(root)
bottomframe.pack(side = BOTTOM )
def getFile():
# open dialog box to select file
root.filename = filedialog.askopenfilename(initialdir="/", title="Select file")
#create button
browsebutton = Button(frame, text="Browse", command=getFile)
browsebutton.pack(side = BOTTOM)
#store the open file path into a variable
path = root.filename
You can use global(you should avoid global if possible) or use a class
def getfile():
path.set(filedialog.askopenfilename(initialdir="/", title="Select file")
def do_other_work_with_path():
#your Code here
print(path.get())
path = StringVar()
#using global
def getfile():
global path
path = filedialog.askopenfilename(initialdir="/", title="Select file")
# or using a class for your whole gui
from tkinter import *
from tkinter import filedialog
root = Tk()
class GUI:
def __init__(self, parent):
self.parent=parent
self.button=Button(self.parent, text='Browse', command=self.getfile)
self.button.pack()
def getfile(self):
self.path=filedialog.askopenfilename(initialdir="/", title="Select file")
gui=GUI(root)
#you can also call gui.path with a class
root.mainloop()

Tkinter - Changing label text via another function

I know that it's often best practice to write Tkinter GUI code using object-oriented programming (OOP), but I'm trying to keep things simple because I'm new to Python.
I have written the following code to create a simple GUI:
#!/usr/bin/python3
from tkinter import *
from tkinter import ttk
def ChangeLabelText():
MyLabel.config(text = 'You pressed the button!')
def main():
Root = Tk()
MyLabel = ttk.Label(Root, text = 'The button has not been pressed.')
MyLabel.pack()
MyButton = ttk.Button(Root, text = 'Press Me', command = ChangeLabelText)
MyButton.pack()
Root.mainloop()
if __name__ == "__main__": main()
The GUI looks like this.
I thought the text in the GUI (MyLabel) would change to "You pressed the button!" when the button is clicked, but I get the following error when I click the button:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\elsey\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
File "C:/Users/elsey/Documents/question code.py", line 6, in ChangeLabelText
MyLabel.config(text = 'You pressed the button!')
NameError: name 'MyLabel' is not defined
What am I doing wrong? Any guidance would be appreciated.
MyLabel is local to main() so the way you can not access it that way from ChangeLabelText().
If you do not want to change the design of your program, then you will need to change the definition of ChangeLabelText() like what follows:
def ChangeLabelText(m):
m.config(text = 'You pressed the button!')
And withing main() you will need to pass MyLabel as an argument to ChangeLabelText().
But again, you will have a problem if you code this command = ChangeLabelText(MyLabel) when you declare and define MyButton because the program will execute directly the body of ChangeLabelText() at the start and you will not have the desired result.
To resolve this later problem, you will have to use (and may be read about) lambda
Full program
So your program becomes:
#!/usr/bin/python3
from tkinter import *
from tkinter import ttk
def ChangeLabelText(m):
m.config(text = 'You pressed the button!')
def main():
Root = Tk()
MyLabel = ttk.Label(Root, text = 'The button has not been pressed.')
MyLabel.pack()
MyButton = ttk.Button(Root, text = 'Press Me', command = lambda: ChangeLabelText(MyLabel))
MyButton.pack()
Root.mainloop()
if __name__ == "__main__":
main()
Demo
Before clicking:
After clicking:
Are your sure you don't want to do it as a class (i think it makes the code a bit more clean as your project grows)? Here is a way to accomplish what you'e looking for:
#!/usr/bin/python3
from tkinter import *
from tkinter import ttk
class myWindow:
def __init__(self, master):
self.MyLabel = ttk.Label(root, text = 'The button has not been pressed.')
self.MyLabel.pack()
self.MyButton = ttk.Button(root, text = 'Press Me', command = self.ChangeLabelText)
self.MyButton.pack()
def ChangeLabelText(self, event=None):
self.MyLabel.config(text = 'You pressed the button!')
if __name__ == "__main__":
root = Tk()
mainWindow = myWindow(root)
root.mainloop()
In a Mac, is looks like this before pressing the button:
And when you press it:
But basically, in order to be able to change the text in a Label or a button, you need to ensure it has an active reference. In this case, we are doing it by creating the window as a class and referencing the widgets in the form self. widget_name = widget().
but I'm trying to keep things simple because I'm new to Python Hopefully this helps in understanding that classes are the simple way, otherwise you have to jump through hoops and manually keep track of many variables. Also, the Python Style Guide suggests that CamelCase is used for class names and lower_case_with_underlines for variables and functions. https://www.python.org/dev/peps/pep-0008/
from tkinter import *
from tkinter import ttk
class ChangeLabel():
def __init__(self):
root = Tk()
self.my_label = ttk.Label(root, text = 'The button has not been pressed.')
self.my_label.pack()
## not necessary to keep a reference to this button
## because it is not referenced anywhere else
ttk.Button(root, text = 'Press Me',
command = self.change_label_text).pack()
root.mainloop()
def change_label_text(self):
self.my_label.config(text = 'You pressed the button!')
if __name__ == "__main__":
CL=ChangeLabel()

Resources