def WhoisWin():
win1 = Toplevel()
win1.title("Whois")
win1.config(bg="black")
win1.geometry("300x300")
win1.resizable(0,0)
text = Text()
text1 = Text()
text1.config(width=15, height=1)
text1.config(bg="black", fg="white")
text1.pack()
def button1():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("com.whois-servers.net", 43))
s.send(text1.get("1.0", END) + "\r\n")
response = ''
while True:
a = s.recv(4096)
response += a
if a == '':
break
s.close()
text.insert(END, response)
def clear():
text.delete("1.0", END)
text1.delete("1.0", END)
frame = Frame(win1)
frame.config(bg="black")
frame.pack(pady=10, padx=5)
b = Button(frame, text="Enter", width=10, height=2, command=button1)
b.config(fg="white", bg="black")
b.pack(side=LEFT, padx=5)
c = Button(frame, text="Clear", width=10, height=2, command=clear)
c.config(fg="white", bg="black")
c.pack(side=RIGHT, padx=5)
scrollbar = Scrollbar(win1)
scrollbar.pack(side=RIGHT, fill=Y)
text.config(width=35, height=15, bg="black", fg="white")
text.pack(side=LEFT, fill=Y)
scrollbar.config(command=text.yview)
text.config(yscrollcommand=scrollbar.set)
This is just a child window that will popup when you click on the menu, I don't get any errors, but Text and Tex1 is not visible on the child window, but when I run this code on its own root window it works just find, maybe the ident is messed up or something? Any help will be appreciated, Thanks.
You don't provide a parent for text or text1. When you call Text() you need to give it an argument like Text(win1) or Text(frame) so that Tkinter knows what to pack the Text widget on.
Related
from tkinter import Tk, scrolledtext, INSERT, Button, PhotoImage, Label, Text
root = Tk()
root.geometry('1000x550')
bg = PhotoImage(file='./assets/bg.png')
root.resizable(False, False)
root.title('Testing Classes')
window = Label(root, image=bg)
window.place(relheight=1, relwidth=1)
tokenBox = Text(window, bd=0, height=1, width=30)
def get_token():
token = tokenBox.get('1.0', 'end-1c')
print(token)
return token
prefixBox = Text(window, bd=0, height=1, width=20)
prefixBox.place(x=400, y=100)
tokenBox.place(x=350, y=150)
def get_prefix():
prefix = prefixBox.get('1.0', 'end-1c')
print(prefix)
return prefix
def codeInsert():
prefixBox.place(x=400, y=100)
tokenBox.place(x=350, y=150)
code = f'''
import discord
from discord.ext import commands
bot = commands.Bot(prefix={get_prefix()})
bot.run({get_token()})
'''
codeBox = scrolledtext.ScrolledText(window, width=50, height=15, bg='Black', fg='Red')
codeBox.insert(INSERT, code)
codeBox.configure(state='disabled')
codeBox.place(x=300, y=300)
submit = Button(window, command=codeInsert, text='Submit Everything', bd=0)
submit.place(x=425, y=250)
window.mainloop()
When I click on the Submit button, it hides all the textboxes. The textboxes only comes back, when I click on them. I still see the cursor change, when I hover on them, but the Labels also get hidden, and they are never shows back. It's like they become transparent, and become opaque only when I click on them.
Try this:
from tkinter import Tk, scrolledtext, INSERT, Button, PhotoImage, Label, Text
root = Tk()
root.geometry('1000x550')
bg = PhotoImage(file='./assets/bg.png')
root.resizable(False, False)
root.title('Testing Classes')
window = Label(root, image=bg)
window.place(relheight=1, relwidth=1)
tokenBox = Text(root, bd=0, height=1, width=30)
def get_token():
token = tokenBox.get('1.0', 'end-1c')
print(token)
return token
prefixBox = Text(root, bd=0, height=1, width=20)
prefixBox.place(x=400, y=100)
tokenBox.place(x=350, y=150)
def get_prefix():
prefix = prefixBox.get('1.0', 'end-1c')
print(prefix)
return prefix
def codeInsert():
# Add these lines here if you want to remove the button/entries.
#tokenBox.place_forget()
#prefixBox.place_forget()
#submit.place_forget()
code = f'''
import discord
from discord.ext import commands
bot = commands.Bot(prefix={get_prefix()})
bot.run({get_token()})
'''
codeBox = scrolledtext.ScrolledText(root, width=50, height=15, bg='Black', fg='Red')
codeBox.insert(INSERT, code)
codeBox.configure(state='disabled')
codeBox.place(x=300, y=300)
submit = Button(root, command=codeInsert, text='Submit Everything', bd=0)
submit.place(x=425, y=250)
window.mainloop()
The problem is that you had the label (named window) as the master for the other widgets. You should never have a tk.Label as a parent for anything. When I changed all their parents to root it worked.
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.
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()
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()