in my code every time I press enter while typing on a entry widget the text on the entry is printed on a label below it but the text is always in the middle of the label. is there a way to make it print on the top?
from tkinter import *
root = Tk()
root.state('zoomed')
def AddList(event):
de = dataInput.get()
d = dataList['text'] + de + "\n"
dataList.config(text=d)
dataInput.delete('0', 'end')
dataLabel = Label(root, width=4, text="Dados").grid(column=0, row=0)
dataInput = Entry(root,width=4)
dataInput.bind('<Return>', AddList)
dataInput.grid(column=0, row=1)
dataList = Label(root, text="", width=4, height=43, bg='#8c8c8c')
dataList.grid(column=0, row=2, sticky=NS)
root.mainloop()
Yes there is a way:
By setting anchor='n', you force the text to be on the top.
dataList = Label(root, text="", width=4, height=43, bg='#8c8c8c',anchor='n')
Related
I have started making a tic tac toe game for Tkinter in Python. Basically in this, it's not required to win, but to just have the basic functionality. Left-click places an "X" and right-click place an "O". Pressing "C" should clear the board and it should be done using labels and bindings. I'm having trouble displaying the "X" and "O" and I do have the board drawn. I try to click on the first row and nothing happens.
It should work like this: https://youtu.be/0x6HKuyXAuU
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Tic Tac Toe")
message = StringVar()
# This is the portion that draws out the grid used in Tic Tac Toe
label1 = ttk.Label(root, text="")
label1.grid(row=1, column=0)
label2 = ttk.Label(root, text="|")
label2.grid(row=1, column=1)
label3 = ttk.Label(root, text="")
label3.grid(row=1, column=2)
label4 = ttk.Label(root, text="|")
label4.grid(row=1, column=3)
label5 = ttk.Label(root, text="-")
label5.grid(row=4, column=1)
label6 = ttk.Label(root, text="-")
label6.grid(row=4, column=2)
label7 = ttk.Label(root, text="-")
label7.grid(row=4, column=3)
label8 = ttk.Label(root, text="-")
label8.grid(row=4, column=4)
label9 = ttk.Label(root, text=" ")
label9.grid(row=5, column=0)
label10 = ttk.Label(root, text="|")
label10.grid(row=5, column=1)
label11 = ttk.Label(root, text=" ")
label11.grid(row=5, column=2)
label12 = ttk.Label(root, text="|")
label12.grid(row=5, column=3)
label13 = ttk.Label(root, text="-")
label13.grid(row=6, column=1)
label14 = ttk.Label(root, text="-")
label14.grid(row=6, column=2)
label15 = ttk.Label(root, text="-")
label15.grid(row=6, column=3)
label16 = ttk.Label(root, text="-")
label16.grid(row=6, column=4)
label17 = ttk.Label(root, text=" ")
label17.grid(row=7, column=0)
label18 = ttk.Label(root, text="|")
label18.grid(row=7, column=1)
label19 = ttk.Label(root, text=" ")
label19.grid(row=7, column=2)
label20 = ttk.Label(root, text="|")
label20.grid(row=7, column=3)
#This is the code that draws out the O and X in this the first row
label21 = ttk.Label(root, text="")
label21.grid(row=1, column=0)
label21.bind("<Button-1>", lambda e: message.set("X"))
label21.bind("<Button-3>", lambda e: message.set("O"))
label22 = ttk.Label(root, text="")
label22.grid(row=1, column=1)
label22.bind("<Button-1>", lambda e: message.set("X"))
label22.bind("<Button-3>", lambda e: message.set("O"))
label22.grid(row=1, column=3)
label22.bind("<Button-1>", lambda e: message.set("X"))
label22.bind("<Button-3>", lambda e: message.set("O"))
root.mainloop()
Use a loop instead of creating a lot of variables and labels like that:
Here is an example which you can improve:
from tkinter import *
def updateX(event):
event.widget['text'] = 'X'
def updateO(event):
event.widget['text'] = 'O'
root = Tk()
root.title("Tic Tac Toe")
for x in range(5):
for y in range(5):
label = Label(root)
if x%2==0:
if y%2!= 0:
label['text'] = '|'
else:
label.bind('<1>', updateX)
label.bind('<Button-3>', updateO)
root.grid_columnconfigure(y, weight=1)
root.grid_rowconfigure(x, weight=1)
else:
label['text']='-'
label.grid(column=y, row=x, sticky="nsew")
root.mainloop()
your clear function can be something like this:
def clear(event):
for item in root.winfo_children():
if isinstance(item, Label) and item['text'] in ['O', 'X']:
item['text'] = ''
also don't forget to bind <c> to root.
Try this:
from functools import partial
import tkinter as tk
def change_text(button, text, event=None):
# Only if the button is empty
if button.cget("text") == "":
# Change the button's text to whatever is in the variable `text`
button.config(text=text)
def clear(event=None):
for button in buttons:
button.config(text="")
# Create the tkinter window
root = tk.Tk()
# A list to store all of the buttons
buttons = []
for i in range(9):
# Create the button:
button = tk.Label(root, text="", width=3, font=("", 15), bd=3,
relief="groove")
# 1st parameter of `partial` is the function. The rest are just arguments
command = partial(change_text, button, "X")
button.bind("<Button-1>", command) # Left click
command = partial(change_text, button, "O")
button.bind("<Button-3>", command) # Right click
# Display the button:
button.grid(row=i//3, column=i%3)
# Add the button to the list of buttons:
buttons.append(button)
clear_button = tk.Label(root, text="Clear screen", width=3, font=("", 15), bd=3,
relief="groove")
clear_button.grid(row=4, column=0, columnspan=3, sticky="news")
clear_button.bind("<Button-1>", clear) # Left click
# Run tkinter's mainloop
root.mainloop()
For more info on how partial works read this.
Your binding lambda just updates the message variable which is never used by those labels.
You can use Label widgets with border to simulate the game board. Better to use list or dict to store those labels for later reference, for example to clear the game board by pressing c character.
Below is a modified example:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Tic Tac Toe")
def set_cell(lbl, mark):
if lbl["text"] == "":
lbl["text"] = mark
def clear(event):
for lbl in cells.values():
lbl["text"] = ""
cells = {} # for storing the labels
# create the 3 x 3 board using labels
for row in range(3):
for col in range(3):
lbl = ttk.Label(root, width=3, borderwidth=1, relief="solid", font="Arial 32 bold", anchor="c")
lbl.grid(row=row, column=col, sticky="nsew")
lbl.bind("<Button-1>", lambda e: set_cell(e.widget, "X"))
lbl.bind("<Button-3>", lambda e: set_cell(e.widget, "O"))
cells[row,col] = lbl # store the label
root.bind("c", clear)
root.mainloop()
The code below represents my first steps into making a calculator on python using tkinter. The idea is to put the numbers on a grid accordingly, and then make the all of the necessary adjustments. The problem here is that I get the following error:
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
I'm aware that this is because of the canvas.pack(), but isn't it necessary for the background? How can I separate them in the most efficient way possible? On that note, is there a way to put all of the buttons/grids together using fewer lines of code? Thanks in advance.
from tkinter import *
#Creating the window function (?)
window = Tk()
#Creating a frame and a background for the calculator
canvas = tk.Canvas(window, height=700, width=700, bg="#83CFF1")
canvas.pack()
frame = tk.Frame(window, bg="white")
frame.place(relwidth=0.7, relheight=0.7, relx=0.15, rely=0.15)
#Creating the buttons for the calculator
button1 = Label(window, text="1")
button2 = Label(window, text="2")
button3 = Label(window, text="3")
button4 = Label(window, text="4")
button5 = Label(window, text="5")
button6 = Label(window, text="6")
button7 = Label(window, text="7")
button8 = Label(window, text="8")
button9 = Label(window, text="9")
button0 = Label(window, text="0")
#Adding it to the screen
button1.grid(row=0, column=0)
button2.grid(row=0, column=1)
button3.grid(row=0, column=2)
button4.grid(row=1, column=0)
button5.grid(row=1, column=1)
button6.grid(row=1, column=2)
button7.grid(row=2, column=0)
button8.grid(row=2, column=1)
button9.grid(row=2, column=2)
button0.grid(row=3, column=1)
#Ending the loop (?)
window.mainloop()
Create buttons using Python list comprehension.
For the grid placment use i // 3 (floor division) and i % 3 (modulo) inside a for loop.
Then just simply add the last button manually.
This code below will do the trick:
import tkinter as tk
window = tk.Tk()
frame = tk.Frame(window, bg="white")
frame.place(relwidth=0.7, relheight=0.7, relx=0.15, rely=0.15)
#Creating the buttons for the calculator
buttons = [tk.Button(frame, text = i) for i in range(1, 10)]
for i, button in enumerate(buttons):
button.grid(row = i // 3, column = i % 3)
#Add last button 0
buttons.append(tk.Button(frame, text = 0))
buttons[-1].grid(row=3, column=1)
window.mainloop()
The point of this is to press a button and have new rows appear but currently, titles appear above each new row that is added. Instead, I would like to have one row at the top of the grid with column titles. Is there a way to modify this code I already have? Later, I will be incorporating this into a larger tkinter GUI.
from tkinter import *
#------------------------------------
def addbox():
frame =Frame(root)
frame.pack()
#Item
Label(frame, text="Item").grid(row=0, column=0)
ent1 = Entry(frame, width=10)
ent1.grid(row=2, column=0)
#Day
Label(frame, text="Day").grid(row=0, column=1)
ent2 = Entry(frame, width=10)
ent2.grid(row=2, column=1)
#Code
ent3 = Entry(frame, width=10)
ent3.grid(row=2, column=2)
#Factor
ent4 = Entry(frame, width=10)
ent4.grid(row=2, column=3)
all_entries.append( (ent1, ent2, ent3, ent4) )
#Buttons.
showButton = Button(frame, text='Print', command=refresh)
addboxButton = Button(frame, text='Add Item', fg="Red", command=addbox)
#------------------------------------
def refresh():
for number, (ent1, ent2, ent3, ent4) in enumerate(all_entries):
print (number, ent1.get(), ent2.get(), ent3.get(),ent4.get())
#------------------------------------
all_entries = []
root = Tk()
addboxButton = Button(root, text='Add Instrument', fg="Red", command=addbox)
addboxButton.pack()
root.mainloop()
You can check the row count before you add the label:
if len(all_entries) < 1:
Label(frame, text="Item").grid(row=0, column=0)
I have created a chat application, in which i use ListBox for showing the chat history. It looks good until I enter a long sting which goes beyond the screen. Is there a way to break the string and show in new line or any other way to show the complete string. I'm new to Tkinter and im not aware of many widgets available.
Here is my sample code
from tkinter import *
class Actions:
def chatUpdate(chat):
chatlist.insert(Actions.chatLast,chat)
Actions.chatLast=Actions.chatLast+1
chatlist.pack( side=LEFT, fill=BOTH)
chatBox.config(command=chatlist.yview)
def callUpdater():
txt=textBox.get()
text_text.set("")
Actions.chatUpdate(txt)
root = Tk()
root.title("Chat App")
frame1 = Frame(root, bd=4)
frame1.pack(side=TOP)
frame2 = Frame(root, bd=4)
frame2.pack(side=TOP)
frame3 = Frame(root, bd=4)
frame3.pack(side=TOP)
# chat box
chatBox = Scrollbar(frame1)
chatBox.pack(side=RIGHT, fill=Y)
chatlist = Listbox(frame1, yscrollcommand = chatBox.set, width=50)
Actions.chatLast=0
Actions.chatUpdate(" ")
# text box
textView = Label(frame2, text="Input: ")
textView.pack(side=LEFT)
text_text = StringVar()
textBox = Entry(frame2, textvariable=text_text, bd=0, width=40, bg="pink")
textBox.pack(side=RIGHT)
# send button
button = Button(frame3, text="Send", fg="black", command=callUpdater)
button.pack(side=TOP)
root.mainloop()
You can replace the Listbox by a Text widget in 'disabled' mode which automatically wraps long lines. You will just need to put the widget back in 'normal' mode each time you insert text:
from tkinter import *
def callUpdater():
text = textBox.get()
textBox.delete(0, 'end')
chat.configure(state='normal')
chat.insert('end', text + '\n')
chat.configure(state='disabled')
root = Tk()
chatBox = Scrollbar(root)
chat = Text(root, wrap='word', state='disabled', width=50,
yscrollcommand=chatBox.set)
chatBox.configure(command=chat.yview)
chat.grid(row=0, columnspan=2, sticky='ewns')
chatBox.grid(row=0, column=2, sticky='ns')
Label(root, text="Input: ").grid(row=1, column=0)
textBox = Entry(root, bd=0, width=40, bg="pink")
textBox.grid(row=1, column=1)
Button(root, text="Send", command=callUpdater).grid(row=2, columnspan=2)
root.mainloop()
By the way, both the Listbox and Text widgets support the index 'end' so you don't have to keep track of how many lines you have inserted.
I have one Input and one button. I want the value of the input (Entry) to when I press the button. When I type print(mtext) it works well, but when I put it in a Label it doesn't work.
Here is the code:
from tkinter import *
root = Tk()
root.title("Mohamed Atef")
root.geometry("900x600")
var = StringVar()
var.set("Please write something")
label = Label(root, textvariable=var, padx=10, pady=10)
#input
text = StringVar()
entry = Entry(root, textvariable=text)
def mohamed():
mtext = text.get()
mohamed = Label(root, textvariable=mtext)
mohamed.pack()
#button
buttonText = StringVar()
buttonText.set("Click me !")
button = Button(root, textvariable=buttonText, command=mohamed)
label.pack()
entry.pack()
button.pack()
root.mainloop()
Same as Flilp, your finished product would look like this
from tkinter import *
root = Tk()
root.title("Mohamed Atef")
root.geometry("900x600")
var = StringVar()
var.set("Please write something")
label = Label(root, textvariable=var, padx=10, pady=10)
#input
text = StringVar()
entry = Entry(root, textvariable=text)
def mohamed() :
mtext = text.get()
mohamed = Label(root, text=mtext)
mohamed.pack()
#button
buttonText = StringVar()
buttonText.set("Click me !")
button = Button(root, textvariable=buttonText, command=mohamed)
label.pack()
entry.pack()
button.pack()
root.mainloop()
If you just want text that's in your Entry to appear under your labels you could do:
def mohamed():
mohamed = Label(root, textvariable=text)
mohamed.pack()
Your code didn't work because value passed as textvariable should be tkinter StringVar() not string.
If you don't want the text to be constantly updated when you change your Entry you should do:
def mohamed():
mtext = text.get()
mohamed = Label(root, text=mtext)
mohamed.pack()