When pressing "Ping test" you get a new 'main window' with input and submit button.
when Submit is clicked, a file is created on the desktop and writes the output result of ping command.
right now, when I enter an address and click submit, I only see the menu frame and the main frame, the output frame shows up when the proccess is finished.
how can I make the output frame show "Pinging..." when I click the Submit button and update the label to "Ping Complete!" when its finished?
here's my code:
import tkinter as tk
import subprocess as sub
import easygui
import os
root = tk.Tk()
root.geometry("400x300")
# ===== Frame 1 - Left Menu =====
frame = tk.LabelFrame(root, text="Menu",height=80, width=40,
padx=5, pady=5, relief="solid")
frame.place(x=10, y=0)
# Show files button
showfilesButton = tk.Button(frame, text="Show Files", padx=5, pady=5,
command=lambda: showFiles())
showfilesButton.grid(row=1, column=0)
# ConvertURL button
convertURL = tk.Button(frame, text="Ping Test", padx=5, pady=5,
command=lambda: testPing.getURL())
convertURL.grid(row=2, column=0)
# Quit Button
endProgram = tk.Button(frame, text="Quit", padx=5, pady=5,
command=lambda: terminate())
endProgram.grid(row=3, column=0)
class testPing():
def __init__(self, host):
self.host = host
self.clearFile = clearFile
self.label = label
def getURL():
frame2 = tk.LabelFrame(root, text="Main Window", height=350, width=300, padx=30, pady=30)
frame2.pack()
urlLabel = tk.Label(frame2, text="Enter URL : ", padx=5, pady=5)
urlLabel.place(x=-30, y=-30)
urlInputBox = tk.Entry(frame2)
urlInputBox.pack()
clearLabel = tk.Label(frame2, text="Clear File?", padx=5, pady=5)
clearLabel.place(x=-30, y=20)
clearFile = tk.BooleanVar()
clearFile.set(False)
clearFileRadioYes = tk.Radiobutton(frame2, text="yes", value=True, var=clearFile,
command=lambda: testPing.callback(clearFile.get()))
clearFileRadioYes.place(x=-30, y=45)
clearFileRadioNo = tk.Radiobutton(frame2, text="no", value=False, var=clearFile,
command=lambda: testPing.callback(clearFile.get()))
clearFileRadioNo.place(x=20, y=45)
urlSubmitButton = tk.Button(frame2, text="Submit",
command=lambda: testPing.pingURL(urlInputBox.get(), clearFile.get()))
urlSubmitButton.pack(side=tk.RIGHT)
def callback(clearFile):
bul = clearFile
print(bul)
def pingURL(host, clearFile):
outputLabel = tk.LabelFrame(root, text="Output", height=35, width=150,
padx=5, pady=5, relief="solid")
outputLabel.place(x=0, y=150)
file = fr'c:/users/{os.getlogin()}/Desktop/ping.txt'
label = tk.Label(outputLabel, text=f'Pinging {host} ...')
label.grid(row=0, column=0)
clear = clearFile
if clear == True:
with open(file, 'w+') as output:
output.truncate(0)
sub.call(['ping', f'{host}'], stdout=output)
else:
with open(file, 'a') as output:
sub.call(['ping', f'{host}'], stdout=output)
output.close()
# testPing.changeLabel(host)
def changeLabel(host):
myLabel = tk.Label.config(text=f"Ping to {host} Complete!")
myLabel.pack()
def terminate():
exit()
def showFiles():
path = easygui.diropenbox() # Opens a folder dialog box.
folder = path
filelocation = f"c:\\Users\\{os.getlogin()}\\Desktop\\showFilesResult.txt"
filenames = os.listdir(folder) # Get the file names in the folder.
# Writing to file
with open(filelocation, 'a') as file:
for name in filenames:
file.write(f"Name: {name}\nFolder Path: {folder}\n!------------------------------!\n")
print("Done!")
root.mainloop()
Instead of calling changeLabel(), you can simply put:
output.close()
label.configure(text=f'Ping to {host} complete!')
# testPing.changeLabel(host)
But remember about updating your label first, if you don't at the end only complete label will be visible.
label = tk.Label(outputLabel, text=f'Pinging {host} ...')
label.grid(row=0, column=0)
label.update()
An additional tip, don't use different GUI creators in one project. If you only using easygui to get the path, check Tkinter methods -> askopenfilename and asksaveasfilename.
Related
I'm new to tkinter and i've built this so far:
import tkinter as tk
import subprocess
import os
def maingui():
window = tk.Tk()
window.title("My first GUI")
#window.state('zoomed')
window.geometry("700x205")
window.configure(bg="black")
frame1 = tk.Frame(window, width=90, bg="orange")
# frame1.pack(fill=tk.Y, side=tk.LEFT)
frame1.grid(row=0, column=0)
frame2 = tk.Frame(window, width=1890, bg="black")
# frame2.pack(fill=tk.Y, side=tk.RIGHT)
frame2.grid(row=0, column=1)
lotomat = tk.Button(frame1, text=" Start\n Lotomat", padx=10, pady=5, bg="orange", fg="black",
relief=tk.GROOVE, command=lambda : startLotomat())
# lotomat.pack()
lotomat.grid(row=1, column=0)
convert = tk.Button(frame1, text=" URL2IP \n on \n Desktop", padx=10, pady=5, bg="orange", fg="black",
relief=tk.GROOVE, command=lambda : startURL2IP())
# convert.pack()
convert.grid(row=2, column=0)
startRps = tk.Button(frame1, text=" Start \nR.P.S", padx=12, pady=5, bg="orange", fg="black",
relief=tk.GROOVE, command=lambda : startRPS())
# startRps.pack()
startRps.grid(row=3, column=0)
endRun = tk.Button(frame1, text="Quit", padx=12, pady=10, bg="orange", fg="black",
relief=tk.RIDGE, command=lambda : ending())
# endRun.pack()
endRun.grid(row=4, column=0)
def startLotomat():
os.system('python lotomat.py')
def startURL2IP():
os.system('python urltoipondesktop.py')
def startRPS():
os.system('python rockpaperscissors.py')
def ending():
exit()
window.mainloop()
maingui()
each button runs a different .py file.
how can I use frames to split the window so the program runs on the right side?
Thanks!
Edit:
I've added a pic of the GUI, the goal is to run the left menu buttons on the black frame.
Following acw1668's comment and alot of thread researching here's the thread solution. so elegant, so simple! I love python!
def thread_handler(self, host):
wt = threading.Thread(target=self.write_to_file, args=(host,))
pt = threading.Thread(target=self.print_to_box, args=(host,))
dt = threading.Thread(target=self.delete_default_lines, args=())
wt.start()
pt.start()
dt.start()
So I am working on this program that is supposed to be downloading stuff from the web using tkinter and urllib.request but it is lacking a download bar(or a progress bar if that is the true word). So I found out that you can create a progress bar using TQDM but there are two problems: first of all, I didn't seem to find a way to use it in a tkinter program. Second of all, It doesn't show the download speed, you just set a limit and it fills up until it reaches that limit. I did a bit of research again and I found out that you can create a progress bar using ttk but it still has the second problem(It does not show the user's internet(download) speed and that how much of the file has been downloaded like chrome's download bar).
Can someone help me out on this?
My code(BTW if you have any suggestions how to make my program better I would appreciate it):
from tkinter import *
from tkinter import font as tkFont
import random
import urllib.request
import requests
from tqdm import tqdm
from tqdm.auto import tqdm
def printsth():
print("Yay it works! ")
def main_menu():
root = Tk()
# the top menu
num = IntVar()
# var = IntVar()
menu = Menu(root)
root.config(menu=menu)
submenu = Menu(menu)
menu.add_cascade(label="Settings", menu=submenu)
def custom_op():
custom = Tk()
custom.mainloop()
submenu.add_command(label="Customization ", command=custom_op)
def settings_op():
set_win = Tk()
set_win.mainloop()
submenu.add_command(label="Settings ", command=settings_op)
submenu.add_separator()
submenu.add_command(label="Exit", command=root.destroy)
# the edit menu
editmenu = Menu(menu)
menu.add_cascade(label="Edit", menu=editmenu)
editmenu.add_command(label="Redo...", command=printsth)
# the tool bar
toolbar = Frame(root, bg="light gray")
insert_button = Button(toolbar, text="Insert an image", command=printsth)
insert_button.pack(side=LEFT, padx=2, pady=2)
print_button = Button(toolbar, text="Print", command=printsth)
print_button.pack(side=LEFT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
# the download function
def download_image():
global formatname
if num.get() == 1:
name = random.randrange(1, 100000)
else:
name = str(name_entry.get())
formatname = str(format_entry.get())
'''if var.get() == 1:
operator = str(url_entry.get())
formatname = '.' + operator[-3] + operator[-2] + operator[-1]
else:
pass'''
fullname = str(name) + formatname
url = str(url_entry.get())
fw = open('file-size.txt', 'w')
file_size = int(requests.head(url, headers={'accept-encoding': ''}).headers['Content-Length'])
fw.write(str(file_size))
fw.close()
path = str(output_entry.get()) + "\\"
urllib.request.urlretrieve(url, path.replace("\\", "\\\\") + fullname)
# the status bar
status_bar = Label(root, text="Downloading...", bd=1, relief=SUNKEN, anchor=W)
status_bar.pack(side=BOTTOM, fill=X)
# the download frame
body_frame = Frame(root, bg="light blue")
download_button = Button(body_frame, text="Download! ", command=download_image, border=3, width=20, height=5)
download_design = tkFont.Font(size=12, slant='italic')
download_button['font'] = download_design
download_button.pack(side=LEFT, pady=5, padx=5)
body_frame.pack(side=LEFT, fill=Y)
# the main interaction menu
inter_frame = Frame(root)
url_entry = Entry(inter_frame)
label = Label(inter_frame, text="Enter the image URL: ")
file_format = Label(inter_frame, text="Choose your file format: ")
format_entry = Entry(inter_frame)
file_name = Label(inter_frame, text="File's name: ")
name_entry = Entry(inter_frame)
check_name = Checkbutton(inter_frame, text="Give a random name", variable=num)
# check_format = Checkbutton(inter_frame, text="Download with default format", variable=var)
output_path = Label(inter_frame, text="Choose output path: ")
output_entry = Entry(inter_frame)
file_name.pack(anchor=CENTER, expand=1)
name_entry.pack(anchor=CENTER, expand=1)
check_name.pack(anchor=CENTER, expand=1)
label.pack(anchor=CENTER, expand=1)
url_entry.pack(anchor=CENTER, expand=1)
file_format.pack(anchor=CENTER, expand=1)
format_entry.pack(anchor=CENTER, expand=1)
# check_format.pack(anchor=CENTER)
output_path.pack(anchor=CENTER, expand=1)
output_entry.pack(anchor=CENTER, expand=1)
inter_frame.pack(expand=1)
root.mainloop()
# the end!
main_menu()
This is code snippet from my tool for status bar
progress = ttk.Progressbar(self, orient=HORIZONTAL, length=400, mode='determinate')
progress.grid(row=3, column=0, pady=2, padx=2, columnspan=4, sticky=SW+SE)
progress.pack(side=BOTTOM, anchor=S, expand=YES)
progress["maximum"] = 100
progerss_part = 0
you can update progress by using
progress["value"] = x
Hope this will help you.
I have a window with two parts. One part is to do some settings. I want to hide it until the user press a setting button. is it possible to hide a part of the frame that contains many widgets?
I have seen many examples to hide a widget in tkinter (eg. pack_forget and grid_forget). In my case, I am trying to hide a part of the frame through a button press (that contains more than one widgets). Any suggestions please
I can't use more than one frames because of some issues.
import tkinter as tk
def startFn():
pass
#fn body
def stopFn():
pass
#fn body
def FnToShow():
pass
#fn body ???
def FnToHide():
pass
#fn body ???
root = tk.Tk()
root.geometry('600x400')
#two containers like this.
#trying to hide container_2 untill the user press settingBtn
container_1 = tk.Frame(root, borderwidth=2, relief="solid")
container_2 = tk.Frame(root, borderwidth=2, relief="solid")
startBtn = tk.Button(container_1, text = "Start", command =startFn)
startBtn.grid(row=4, column=4)
stopBtn = tk.Button(container_1, text = "Stop", command= stopFn)
stopBtn.grid(row=5, column=4)
settingBtn = tk.Button(container_1, text = "Settings", command= FnToShow)
settingBtn.grid(row=6, column=4)
setting_1 = tk.Label(container_2, text = "Setting-1", fg='#000000')
setting_1.grid(row=3, column=10)
setting_2 = tk.Label(container_2, text = "Setting-2", fg='#000000')
setting_2.grid(row=4, column=10)
closeSettingBtn = tk.Button(container_2, text = "close Settings", command= FnToHide)
closeSettingBtn.grid(row=5, column=10)
container_1.pack(side="left", expand=True, fill="x", padx=1, pady=1)
container_2.pack(side="right",expand=True, fill="x", padx=1, pady=1)
root.mainloop()
You could show/hide the entire container_2 using the functions FnToShow and FnToHide:
something like this:
import tkinter as tk
def startFn():
pass
def stopFn():
pass
def FnToShow():
container_2.pack(side="right",expand=True, fill="x", padx=1, pady=1)
def FnToHide():
container_2.pack_forget()
root = tk.Tk()
root.geometry('600x400')
container_1 = tk.Frame(root, borderwidth=2, relief="solid")
container_2 = tk.Frame(root, borderwidth=2, relief="solid")
startBtn = tk.Button(container_1, text="Start", command =startFn)
startBtn.grid(row=4, column=4)
stopBtn = tk.Button(container_1, text="Stop", command= stopFn)
stopBtn.grid(row=5, column=4)
settingBtn = tk.Button(container_1, text="Settings", command= FnToShow)
settingBtn.grid(row=6, column=4)
setting_1 = tk.Label(container_2, text="Setting-1", fg='#000000')
setting_1.grid(row=3, column=10)
setting_2 = tk.Label(container_2, text="Setting-2", fg='#000000')
setting_2.grid(row=4, column=10)
closeSettingBtn = tk.Button(container_2, text="close Settings", command= FnToHide)
closeSettingBtn.grid(row=5, column=10)
container_1.pack(side="left", expand=True, fill="x", padx=1, pady=1)
root.mainloop()
What I want the frame to do is that when I click on the 'clear' button, the frame is cleaned but it does not and when I enter a string that is not valid and then a valid one, it shows traces of the past and past action. I already tried changing the Label.grid () by a Label.pack (), but it is worse since the 'animation' looks like a stack without removing any element when the 'clear' button is pressed
This is basically what would make it change
from tkinter import *
import tkinter.ttk as ttk
def clear():
area.delete(0,END)
frame.config(bd=1, relief=SUNKEN)
frame.update()
status = Label(frame)
status.grid(row=0, column=0, sticky=NSEW)
def statusVal(value):
if not value == 0:
status = Label(frame, background="#ff4242", fg="#262626", text="Cadena invalida", anchor="center")
status.grid(row=0, column=0)
frame.config(bd=1, relief=SUNKEN, background="#ff4242")
frame.update()
else:
status = Label(frame, background="#56ed42", fg="#262626", text="Cadena valida", anchor="center")
status.grid(row=0, column=0)
frame.config(bd=1, relief=SUNKEN, background="#56ed42")
frame.update()
#Test
def validation():
capture = area.get()
if capture == '1':
return statusVal(0)
else:
return statusVal(1)
root = Tk()
root.geometry("300x150+300+300")
area = Entry(root)
area.grid(row=1, column=0, columnspan=2, sticky=E+W+S+N, padx=5)
frame = Frame(root, bd=1, relief=SUNKEN)
frame.grid(row=2, column=0, padx=5, pady=5, columnspan=2, sticky=W+E+S+N)
frame.columnconfigure(0,weight=5)
frame.rowconfigure(0,weight=5)
abtn = Button(root, text="Validate", command=validation)
abtn.grid(row=1, column=3)
cbtn = Button(root, text="Clear", command=clear)
cbtn.grid(row=2, column=3, pady=5)
root.mainloop()
See if this works better. The main change was to have the status Label always exist and hide or unhide it as desired — instead of creating a new one every time the validation() function was called. I also removed the code that was explicitly updating the frame which isn't necessary.
from tkinter import *
import tkinter.ttk as ttk
def clear():
area.delete(0,END)
status.grid_remove() # Hide. but remember grid options.
def statusVal(value):
if not value == 0:
status.config(background="#ff4242", fg="#262626", text="Cadena invalida",
anchor="center")
status.grid() # Unhide
else:
status.config(background="#56ed42", fg="#262626", text="Cadena valida",
anchor="center")
status.grid() # Unhide
#Test
def validation():
capture = area.get()
if capture == '1':
statusVal(0)
else:
statusVal(1)
# Main
root = Tk()
root.geometry("300x150+300+300")
area = Entry(root)
area.grid(row=1, column=0, columnspan=2, sticky=E+W+S+N, padx=5)
frame = Frame(root, bd=1, relief=SUNKEN)
frame.grid(row=2, column=0, padx=5, pady=5, columnspan=2, sticky=W+E+S+N)
frame.columnconfigure(0,weight=5)
frame.rowconfigure(0,weight=5)
# Initialize status Label.
status = Label(frame, anchor="center")
status.grid(row=0, column=0)
status.grid_remove() # Hide it.
abtn = Button(root, text="Validate", command=validation)
abtn.grid(row=1, column=3)
cbtn = Button(root, text="Clear", command=clear)
cbtn.grid(row=2, column=3, pady=5)
root.mainloop()
In the code given below, I want to create a GUI in such a way that 1) In the top frame: 1st row : "x"(checkbutton), right to "x"(checkbutton) must be "Choose xFile"(button) and right to "Choose xFile"(button) must be "clear"(button) and likewise in the 2nd row : for "y". Only when the "x" checkbutton is checked, the "choose xFile" button should gets enabled. And when clicked upon "choose xFile", it has to open the file dialogbox. And the choosen file contents should get displayed using "description box" below the "Input data"(label) in the middle frame(with both horizontal and vertical scrollbar). And when "clear" button is clicked, only the selected file contents(x or y file choosen) in the "description box" must be cleared and it must enable the "Choose xFile"(button) or "Choose yFile"(button) to perform the task again(i.e to open the file dialog box). Below to the "description box" must contain "Reset" button and to the right of "Reset" button must be "Submit" button in the middle portion of the middle frame. When the "Reset" button is clicked, all the contents being displayed in the "description box" must be cleared and the all the checkboxes must be unchecked so that the user can perform the selection process again. In the bottom frame, below "Model Output"(label), a "description box" along with "horizontal" and "vertical" scrollbar must be there. Below to the "description box" must contain "Exit" button which is placed in the middle of the "bottom frame".
from tkinter import *
def forButton1():
filename1 = askopenfilename()
with open(filename1) as f:
for i in f:
myList.insert(END, i)
print(filename1)
def forButton2():
filename1 = askopenfilename()
with open(filename1) as f:
for i in f:
myList.insert(END, i)
print(filename1)
def forButton7():
root.destroy()
root = Tk()
root.title("Spatialization of DSSAT")
topFrame = LabelFrame(root, text = "Select input file")
MyVar1 = IntVar()
MyVar2 = IntVar()
MyCheckbutton1 = Checkbutton(topFrame, text="x", variable=MyVar1)
#MyCheckbutton1.grid(row=0, column=0)
MyCheckbutton1.pack()
MyCheckbutton2 = Checkbutton(topFrame, text="y", variable=MyVar2)
#MyCheckbutton2.grid(row=1, column=0)
MyCheckbutton2.pack()
Button1 = Button(topFrame, text = "Choose xFile", command = forButton1)
#button1.grid(row=0, column=1)
Button1.pack()
Button2 = Button(topFrame, text = "Choose yFile", command = forButton2)
#button2.grid(row=0, column=1)
Button2.pack()
Button3 = Button(topFrame, text = "Clear")
Button3.pack()
Button4 = Button(topFrame, text = "Clear")
Button4.pack()
topFrame.pack(side=TOP)
middleFrame = Frame(root)
label1 = Label(middleFrame, text = "Input data:")
label1.grid(row = 4)
scrollbar = Scrollbar(middleFrame)
myList = Listbox(middleFrame, yscrollcommand = scrollbar.set)
myList.pack()
scrollbar.config( command = myList.yview )
scrollbar.pack()
Button5 = Button(middleFrame, text = "Reset")
#button1.grid(row=0, column=1)
Button5.pack()
Button6 = Button(middleFrame, text = "Submit")
#button1.grid(row=0, column=1)
Button6.pack()
middleFrame.pack()
bottomFrame = Frame(root)
label2 = Label(bottomFrame, text = "Model Output:")
label2.grid(row = 10)
Button7 = Button(bottomFrame, text = "Exit", command = forButton7)
#button1.grid(row=0, column=1)
Button7.pack()
bottomFrame.pack()
root.geometry("500x500")
root.mainloop()
Here I have fixed the placement of the given widgets (not their functionalities) as asked in question. You can follow this way to get your desired format:
from tkinter import *
from tkinter import filedialog
def forButton1():
filename1 = filedialog.askopenfilename()
with open(filename1) as f:
for i in f:
myList.insert(END, i)
print(filename1)
def forButton2():
filename1 = filedialog.askopenfilename()
with open(filename1) as f:
for i in f:
myList.insert(END, i)
print(filename1)
def forButton7():
root.destroy()
root = Tk()
root.title("Spatialization of DSSAT")
root.grid_columnconfigure(0, weight=1)
topFrame = LabelFrame(root, text="Select input file")
topFrame.grid(row=0, column=0, padx=8, pady=8, sticky=N+E+S+W)
topFrame.grid_rowconfigure(0, weight=1)
topFrame.grid_rowconfigure(1, weight=1)
topFrame.grid_columnconfigure(0, weight=1)
topFrame.grid_columnconfigure(1, weight=1)
topFrame.grid_columnconfigure(2, weight=1)
middleFrame = LabelFrame(root, text="Input data")
middleFrame.grid(row=1, column=0, padx=8, pady=8, sticky=N+E+S+W)
middleFrame.grid_rowconfigure(0, weight=1)
middleFrame.grid_rowconfigure(1, weight=0)
middleFrame.grid_columnconfigure(0, weight=1)
middleFrame.grid_columnconfigure(1, weight=1)
bottomFrame = LabelFrame(root, text="Model Output")
bottomFrame.grid(row=2, column=0, padx=8, pady=8, sticky=N+E+S+W)
bottomFrame.grid_rowconfigure(0, weight=1)
bottomFrame.grid_columnconfigure(0, weight=1)
MyVar1 = IntVar()
MyVar2 = IntVar()
MyCheckbutton1 = Checkbutton(topFrame, text="x", variable=MyVar1)
MyCheckbutton1.grid(row=0, column=0, padx=4, pady=4)
Button1 = Button(topFrame, text="Choose xFile", command=forButton1)
Button1.grid(row=0, column=1, padx=4, pady=4)
Button3 = Button(topFrame, text="Clear")
Button3.grid(row=0, column=2, padx=4, pady=4)
MyCheckbutton2 = Checkbutton(topFrame, text="y", variable=MyVar2)
MyCheckbutton2.grid(row=1, column=0, padx=4, pady=4)
Button2 = Button(topFrame, text="Choose yFile", command=forButton2)
Button2.grid(row=1, column=1, padx=4, pady=4)
Button4 = Button(topFrame, text="Clear")
Button4.grid(row=1, column=2, padx=4, pady=4)
innerMiddleFrame = Frame(middleFrame)
innerMiddleFrame.grid(row=0, column=0, columnspan=2, padx=4, pady=4)
innerMiddleFrame.grid_columnconfigure(0, weight=1)
innerMiddleFrame.grid_columnconfigure(1, weight=0)
scrollbar = Scrollbar(innerMiddleFrame)
myList = Listbox(innerMiddleFrame, yscrollcommand=scrollbar.set)
myList.grid(row=0, column=0, sticky=N+E+S+W)
scrollbar.config(command=myList.yview)
scrollbar.grid(row=0, column=1, sticky=N+E+S+W)
Button5 = Button(middleFrame, text="Reset")
Button5.grid(row=1, column=0, padx=4, pady=4)
Button6 = Button(middleFrame, text="Submit")
Button6.grid(row=1, column=1, padx=4, pady=4)
Button7 = Button(bottomFrame, text="Exit", command=forButton7)
Button7.grid(row=0, column=0, padx=4, pady=4)
root.geometry("250x425")
root.mainloop()