I'm new to programming and I'm trying to run a program that asks a user for a directory which which they will move their files to.
import tkinter as tk
from tkinter import filedialog, ttk
class Unzip():
def __init__(self):
# initialising the screen name, size title
root = tk.Tk()
root.geometry('650x550')
root.title("Move Files")
root.resizable(0, 0)
root.configure(bg='#002060')
# Initialising the frame to insert our widget
top_frame = tk.Frame(root, bg='#002060')
button_top = tk.Frame(root, bg='#002060')
button_bottom = tk.Frame(root, bg='#002060')
footer_frame = tk.Frame(root, bg='#002060')
top_frame.pack(side='top', fill='both')
button_top.pack(side='top', fill='both')
button_bottom.pack(side='top', fill='both')
footer_frame.pack(side='bottom', fill='both')
# Setting the title name
label_title = tk.Label(top_frame, text='Move Files', font='Arial 36 bold', fg='#948a54',
bg='#002060', pady=60)
label_title.pack(side='top')
# call button to get output file
output_file = ttk.Button(button_bottom, text='Choose location to save files', width=25, command=self.output_path)
output_file.pack(side='left', padx=(120, 10), pady=10)
root.mainloop()
# Get output directory
def output_path(self):
self.output_file_dir = filedialog.askdirectory()
if __name__ == '__main__':
Unzip()
The problem is that when you run the program and try to run the output_file button, the program will not be responding. I decided to use the self because I wanted it to be accessible to other instance methods that I want to create that will use the directory output_path.
So what exactly are you expecting? Your program does respond, but it is not supposed to do anything with the information.
Try
def output_path(self):
self.output_file_dir = filedialog.askdirectory()
print(self.output_file_dir)
Do you see what happens?
Maybe example 2 from this link can help you: https://www.programcreek.com/python/example/95888/tkinter.filedialog.askdirectory
Related
Hi I am pretty new to tkinter and have being trying to create a button that opens a window then a have a button in the new window the gives a message when pressed. I ran into the problem that the only whay I could get it to recognise the function I wrote was to write it inside the function that opens the second window. I don't know if I have being searching for the wrong things but I can't find how to do this properly. Can someone help me out Here is my code
from tkinter import *
master = Tk()
master.title("frame control")
def win():
window2 = Toplevel()
def open():
stamp = Label(window2, text="Staped").pack()
lab2 = Button(window2,text = "yo ",command = open).pack()
lab1 = Button(master,text = " open a new window" , command = win).pack()
mainloop()
This is your code but with best practises:
import tkinter as tk
def create_stamp():
stamp = tk.Label(window2, text="Stamp")
stamp.pack()
def create_second_win():
global window2
window2 = tk.Toplevel(root)
lab2 = tk.Button(window2, text="Click me", command=create_stamp)
lab2.pack()
root = tk.Tk()
root.title("Frame control")
button = tk.Button(root, text="Open a new window", command=create_second_win)
button.pack()
root.mainloop()
I made window2 a global variable so that I can access it from create_stamp. Generally it is discouraged to use from ... import *. As #Matiiss said, sometimes you can have problems with global variables if you don't keep track of the variable names that you used.
If you want to avoid using global variables and want to use classes, look at this:
import tkinter as tk
class App:
def __init__(self):
self.stamps = []
self.root = tk.Tk()
self.root.title("Frame control")
self.button = tk.Button(self.root, text="Open a new window", command=self.create_second_win)
self.button.pack()
def create_stamp(self):
stamp = tk.Label(self.window2, text="Stamp")
stamp.pack()
self.stamps.append(stamp)
def create_second_win(self):
self.window2 = tk.Toplevel(self.root)
self.lab2 = tk.Button(self.window2, text="Click me", command=self.create_stamp)
self.lab2.pack()
def mainloop(self):
self.root.mainloop()
if __name__ == "__main__":
app = App()
app.mainloop()
As #Matiiss mentioned it would be more organised if you move the second window to its own class. For bigger projects it is a must but in this case you don't have to.
I have a readymade game(2048), where the game starts without a welcome window, so, I have just made a welcome window with a bunch of buttons like New Game and AI mode, now when I click the New Game button, I expect to get a new window where the game can be played. However, the game displays at the bottom of the main window, and another window that is supposed to display the actual game displays nothing.
# mainwindow.py file:
from tkinter import *
from PIL import ImageTk, Image
import game_2048
root = Tk()
root.iconbitmap('unnamed.ico')
root.title('2048')
bg = ImageTk.PhotoImage(Image.open("welcome.png"))
my_canvas = Canvas(root, width=780, height=550)
my_canvas.grid()
my_canvas.create_image(0, 0, image=bg, anchor=NW)
button1 = Button(root, text="New Game", fg="black", bg="#ddf0d0", padx=3,
pady=3, font=('Helvetica', '12', 'bold'), activebackground="#94d3c3", command=lambda: game_2048.mains(root)
)
button2 = Button(root, text="AI Mode", fg="black", bg="#ddf0d0",
padx=3, pady=3, font=('Helveica', '12', 'bold'), activebackground="#94d3c3")
button1_window = my_canvas.create_window(10, 10, anchor=NW, window=button1)
button2_window = my_canvas.create_window(120, 10, anchor=NW, window=button2)
root.mainloop()
And I have tried to modify the game_2048 file i.e. 2048 game like this:
def mains(root):
Top = Toplevel(root)
l1 = Button(Top, command=lambda:Game())
l1.pack()
class Game(tkinter.Frame):
def __init__(self):
tkinter.Frame.__init__(self)
self.grid()
self.master.title('2048')
self.main_grid = tkinter.Frame(
self, bg=c.GRID_COLOR, bd=3, width=400, height=400)
self.main_grid.grid(pady=(80, 0))
self.make_GUI()
self.start_game()
self.master.bind("<Left>", self.left)
self.master.bind("<Right>", self.right)
self.master.bind("<Up>", self.up)
self.master.bind("<Down>", self.down)
self.mainloop()
if __name__ == "__main__":
mains()
I am pretty sure that I have made some mistakes in the mains() function as a result of which I am not getting the desired output. So my question is what should I do to rectify these mistakes?
Here are the changes I made to your code:
Removed import mainwindow from game_2048.py, as it will lead to circular import calling the functions twice.
You created a class inheriting from a Frame, this frame is just like any other tkinter widget, requires to be placed in the window using geometric manager, like pack()/grid()/place(), you did not do that
I also destroyed the root window before creating another new root window. Also note that instead of using Toplevel, I used Tk. This is done, so that closing the game window will close the app. But if using Toplevel, you will have to close the menu window too.
from tkinter import *
import tkinter
import random
import colors as c
def mains(root):
root.destroy()
root = Tk()
def init(root):
l1.destroy()
game = Game(root)
game.pack()
l1 = Button(root, text='Start Game',command=lambda: init(root))
l1.pack()
class Game(tkinter.Frame):
def __init__(self, parent):
tkinter.Frame.__init__(self, parent)
.......
But if you were to ask me, I would not go for such structure, but this will work here too. Understand this, work on it, implement your own structure that does not call more than one Tk().
Here is my code. It works how I want it to but I have always been told it is poor coding practice to use global variables and that they can cause problems, although I cannot figure out how to get the labels to change without using them. Any help is appreciated.
import tkinter as tk
from tkinter import filedialog, Text
import os
status = 'Start'
startStopBG = 'light green'
def main():
root = configure_screen()
root.mainloop()
def configure_screen():
root = tk.Tk()
root.title('APP')
root.config(bg='snow3')
root.minsize(700, 700)
browse_button = tk.Button(root, text='Browse', width='10', command=browse)
browse_button.place(x=605, y=10)
global text
text = tk.Text(root, height=1.3, width=73)
text.insert(tk.END, 'Enter Path to Storage HERE')
text.place(x=10, y=13)
global start_stop
start_stop = tk.Button(root, height=1, width=12, text=status, bg=startStopBG,
font=('Helvetica', '40'), command=start_scanning)
start_stop.pack(pady=50)
return root
def browse():
path = filedialog.askdirectory(initialdir='/', title='Select where you want to save your file')
text.delete('1.0', tk.END)
text.insert(tk.END, path)
def start_scanning():
global status
global startStopBG
global start_stop
if status == 'Start':
status = 'Stop'
startStopBG = 'red'
else:
status = 'Start'
startStopBG = 'light green'
start_stop.config(text=status, bg=startStopBG)
if __name__ == '__main__':
main()
First of all you can use a class to your main window and instead of global variables you use class variables. Second I would recommend you to use tkinter variables to store important data from widget since the path and the status. For example, if you use text=tk.StringVar() you can set or get the value from text with text.set('value') or text.get(). Tkinter variables are object and if you define an object in your main you can access it as a global variable inside functions without the need of using global. However, in your code, to use text as a StringVar you should change the Text widget for an Entry widget, which is more appropriated since path is a single entry value and not a text. The same way you can change your start_stop button to a Checkutton and it will make the color change unnecessary since you can define colors for background and selectcolor.
The code bellow includes all changes I suggest here:
import tkinter as tk
from tkinter import filedialog, Text
import os
class Main(tk.Tk):
def __init__(self):
super(Main, self).__init__()
self.title('APP')
self.config(bg='snow3')
self.minsize(700, 700)
self.status = tk.IntVar()
self.text = tk.StringVar(self, value='Enter Path to Storage HERE')
browse_button = tk.Button(self, text='Browse', width='10',
command=self.browse)
browse_button.place(x=605, y=10)
tk.Entry(self, width=73, textvariable=self.text).place(x=10, y=13)
self.start_stop = tk.Checkbutton(self, height=1, width=12, text="start",
font=('Helvetica', '40'), indicator=False,
bg='light green', selectcolor='red',
variable=self.status, command=self.start_scanning)
self.start_stop.pack(pady=50)
def browse(self):
path = filedialog.askdirectory(initialdir='/', title='Select where you want to save your file')
self.text.set(path)
def start_scanning(self):
if self.status.get():
self.start_stop.config(text='stop')
else:
self.start_stop.config(text='start')
if __name__ == '__main__':
Main().mainloop()
As I understood you want to change label
Try This:
import tkinter as tk
def main():
def change_label_text():
mylabel.config(text="yeee My Text has Been changed")
def change_button_text():
mybutton.config(text="yee Button text has been changed")
root = tk.Tk()
root.title('Change Label')
root.config(bg='snow3')
root.geometry('400x300')
mybutton = tk.Button(root, text='Press Me To Change Button Text', command=change_button_text)
mybutton.pack(side='top')
mylabel = tk.Label(root, text='Press The Button Above To Change My text')
mylabel.pack(side='bottom')
mybutton2 = tk.Button(root, text="Press me", command=change_label_text)
mybutton2.pack(side='bottom')
root.mainloop()
main()
By making functions inside the mainloop you dont need to do global stuff and all
I'd like to know how I can add or delete widgets from within an imported module. I fail to access them correctly. I know, using OOP would make it easier, but I tried to grasp OOP and while the principles are easy I can't get my head around the details, so since I lack a proper teacher, I need a procedural solution.
This is the main script:
#!/usr/bin/python
try:
# Python2
import Tkinter as tk
except ImportError:
# Python3
import tkinter as tk
import os
import sys
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
import target
def myfunction(event):
canvas.configure(scrollregion=canvas.bbox("all"),width=300,height=200)
def test():
target.secondWindow()
root = tk.Tk()
root.geometry("600x350+30+50")
myframe = tk.Frame(root,relief="groove",bd=1)
myframe.place(x=20, y=30, width=560, height=200 )
canvas = tk.Canvas(myframe)
frame = tk.Frame(canvas)
myscrollbar=tk.Scrollbar(myframe, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=myscrollbar.set)
myscrollbar.pack(side="right", fill="y")
canvas.pack(side="left")
canvas.create_window((0,0), window=frame, anchor='nw')
allMissions = {
"1":{"name":"go"},
"2":{"name":"see"},
"3":{"name":"win"},
"4":{"name":"party"}} # this would be a text file
for a in allMissions.keys():
mn = allMissions[a]["name"]
tk.Label(frame, text=mn, justify="left").grid(row=int(a), column=0)
# what's bind really doing?
frame.bind("<Configure>", myfunction)
test = tk.Button(root, command=test, text="TEST")
test.place(x = 20, y = 250, width=580, height=40)
tk.mainloop()
and this is the imported module: target.py
try:
# Python2
import Tkinter as tk
except ImportError:
# Python3
import tkinter as tk
def changeMainWindow():
# here's where I'm stuck
print("What do I have to do to add a new")
print("label in the main window from here?")
print("Or to delete it?")
def secondWindow():
amWin = tk.Toplevel()
amWin.geometry("300x200+720+50")
button = tk.Button(amWin, text="OK", command=changeMainWindow)
button.place(x = 20, y = 80, width=260, height=30)
#amWin.mainloop() comment noticed (:
You do it by passing the memory address of whatever widget to the second program. There is no reason to import Tkinter again as you can just pass a pointer to the existing instance. If you are going to be doing anything more than simple experimenting with Tkinter, then it is well worth the time to learn classes first at one of the online sites like this one http://www.greenteapress.com/thinkpython/html/thinkpython016.html More here https://wiki.python.org/moin/BeginnersGuide/NonProgrammers
You aren't going to get many answers with the way the program is structured because most programmers use the class structure AFAIK, so do not know how to pound the code into a non-class environment, so will not have any answers. If the first program below used classes then the second program's class could be inherited, and the functions would become part of the first program's class and could be accessed in the same way as the existing classes, so no passing of pointers, or any other hack, would be necessary.
## I deleted some code for simplicity
def myfunction(event):
canvas.configure(scrollregion=canvas.bbox("all"),width=300,height=200)
def test():
TG.secondWindow()
root = tk.Tk()
root.geometry("600x350+30+50")
myframe = tk.Frame(root,relief="groove",bd=1)
myframe.place(x=20, y=30, width=560, height=200 )
canvas = tk.Canvas(myframe)
frame = tk.Frame(canvas)
myscrollbar=tk.Scrollbar(myframe, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=myscrollbar.set)
myscrollbar.pack(side="right", fill="y")
canvas.pack(side="left")
canvas.create_window((0,0), window=frame, anchor='nw')
# what's bind really doing?
frame.bind("<Configure>", myfunction)
test = tk.Button(root, command=test, text="TEST", bg="lightblue")
test.place(x = 20, y = 250, width=580, height=40)
tk.Button(root, text="Quit All", command=root.quit,
bg="orange").place(x=20, y=300)
""" instance of the class in the imported program
a pointer to the root window and the Tk instance are passed
"""
TG=target.Target(tk, root)
tk.mainloop()
And target.py. Notice there are no imports.
class Target():
def __init__(self, tk, root):
self.tk=tk
self.root=root
def changeMainWindow(self):
# here's where I'm stuck
self.tk.Label(self.amWin, bg="yellow", text =""""What do I have to do to add a new
label in the main window from here?
Or to delete it?""").place(x=50,y=20)
def secondWindow(self):
self.amWin = self.tk.Toplevel(self.root)
self.amWin.geometry("300x200+720+50")
button = self.tk.Button(self.amWin, text="Add Label",
command=self.changeMainWindow)
button.place(x = 20, y = 90, width=260, height=30).
I have a bit of difficulty with the code below. Basically, I want the code to, when I press the Enter button, to open the window2 but also close window1 simultaneously so that there is only one window and not two of them.
The code is...
from tkinter import *
def window1():
window = Tk()
window.title("Welcome")
f = Frame()
f.pack()
label1 = Label(window, text = "Welcome to the random window")
label1.pack()
button1 = Button(window, text = "Enter...", command = window2)
button1.pack()
def window2():
screen = Tk()
screen.title("Pop-Up!")
fr = Frame()
fr.pack()
label2 = Label(screen, text = "This is a pop-up screen!")
label2.pack()
button2 = Button(screen, text = "Return", command = window1)
button2.pack()
window1()
This is "Bad" because you're using two instances of Tk. Try instead using TopLevels.
import tkinter as tk
def window1():
window = tk.Toplevel(root)
window.title("Welcome")
# etc etc ...
tk.Button(window,text="Enter...",command=lambda: window2(window)).pack()
def window2(old_window):
old_window.destroy()
# window2 stuff
root = tk.Tk()
root.iconify() # to minimize it, since we're just using Toplevels on top of it
window1()
root.mainloop()
When you are using the Tk() function, you are creating a new instance of the Tcl/tkinter interpreter. Instead use Toplevel() which will make a new window in the current interpreter.