How to add multiline text dynamically in tkinter python? - python

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.

Related

How to align widgets in Tkinter to center

I am working on a simple counter app in tkinter. I rigged up some code looking at few tutorial on web. All the functions of a counter are set up. But when it comes to the designing of the app, I want the Count, the Count button, and the reset button to be aligned at the center.
The code is as below
from tkinter import Label, Button, Tk
from tkinter import font
window = Tk()
window.geometry('500x500')
window.title("Counter")
window.count = 0
def increment():
window.count += 1
lbl.configure(text=window.count)
def reset():
window.count = 0
lbl.configure(text=window.count)
lbl = Label(window, text="0", font=("Apple Braille", 60))
lbl.grid(column=0, row=0)
btn1 = Button(window, text="Count", command=increment)
btn1.grid(column=0, row=1)
btn2 = Button(window, text="Reset", command=reset)
btn2.grid(column=1, row=1)
btn1['font'] = btn2['font'] = font.Font(size=30)
window.mainloop()
A Screenshot of my counter app is here
Any help in this aspect will be appreciated.
Thanks,
It is easier to use pack() instead of grid() for your requirement.
lbl = Label(window, text="0", font=("Apple Braille", 60))
lbl.pack()
# frame for the two buttons
frame = Frame(window)
frame.pack()
btn1 = Button(frame, text="Count", command=increment)
btn1.grid(column=0, row=1)
btn2 = Button(frame, text="Reset", command=reset)
btn2.grid(column=1, row=1)
If you want to put at the center of the window:
# frame for the label and buttons
frame = Frame(window)
frame.place(relx=0.5, rely=0.5, anchor="c") # put at center of window
lbl = Label(frame, text="0", font=("Apple Braille", 60))
lbl.grid(row=0, column=0, columnspan=2)
btn1 = Button(frame, text="Count", command=increment)
btn1.grid(column=0, row=1)
btn2 = Button(frame, text="Reset", command=reset)
btn2.grid(column=1, row=1)

Tkinter create a hidden frame

I'm creating a GUI whose window will consists of a few frames.
I need to pack many different widgets in each frame so if all are shown it will occupy a lot of space.
The idea is that each frame will be revealed/hidden with the push of a button.
I'm able to hide and reveal each frame using buttons, however I'd like those frame to start as hidden.
Is there a way to do that?
Here's a code that hides/reveals the frames.
import tkinter as tk
from tkinter import *
from tkinter import ttk
from PIL import ImageTk, Image
import os
# Method to make Label(Widget) invisible
def hide_frame(frame):
# This will remove the widget
frame.grid_remove()
# Method to make Label(widget) visible
def show_frame(frame):
# This will recover the widget
frame.grid()
#____________________________________________________________________________________________
#This will be the main window
window = tk.Tk()
window.geometry('500x500')
window.title("daq")
#____________________________________________________________________________________________
#Upper frame
frame_logo = Frame(window)
#____________________________________________________________________________________________
#Lower frame
frame_main = Frame(window)
frame_main.place(rely=0.10, relx=0.0, relwidth=1.0)
#Create a tabcontrol
tabControl = ttk.Notebook(frame_main)
tabControl.grid(column=0, row=1)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Digitizer tab
tab_Digitizer = ttk.Frame(tabControl)
tabControl.add(tab_Digitizer, text=' Digitizer ')
digitizer_tab_dummy_label = Label(tab_Digitizer, text="")
digitizer_tab_dummy_label.grid(column=0, row=0)
#General board settings
lbl_general_board_registers = Label(tab_Digitizer,
text="General board registers",
font='bold')
lbl_general_board_registers.grid(column=0, row=1, sticky=W)
frame_general_board_registers = Frame(tab_Digitizer)
frame_general_board_registers.grid(column=0, row=2)
btn_hide_general_board_registers = Button(tab_Digitizer, text="Hide", fg="red", command=lambda: hide_frame(frame_general_board_registers) )
btn_hide_general_board_registers.grid(column=1, row=1)
btn_show_general_board_registers = Button(tab_Digitizer, text="Show", fg="green", command=lambda: show_frame(frame_general_board_registers))
btn_show_general_board_registers.grid(column=2, row=1)
lbl_threshold1 = Label(frame_general_board_registers, text="Threshold1")
lbl_threshold1.grid(column=1, row=0)
lbl_trigger1 = Label(frame_general_board_registers, text="Trigger1")
lbl_trigger1.grid(column=1, row=1)
#Channel settings
lbl_channel_registers = Label(tab_Digitizer,
text="Channel registers",
font='bold')
lbl_channel_registers.grid(column=0, row=3, sticky=W)
frame_channel_registers = Frame(tab_Digitizer)
frame_channel_registers.grid(column=0, row=4)
btn_hide_channel_registers = Button(tab_Digitizer, text="Hide", fg="red", command=lambda: hide_frame(frame_channel_registers) )
btn_hide_channel_registers.grid(column=1, row=3)
btn_show_channel_registers = Button(tab_Digitizer, text="Show", fg="green", command=lambda: show_frame(frame_channel_registers))
btn_show_channel_registers.grid(column=2, row=3)
lbl_threshold = Label(frame_channel_registers, text="Threshold")
lbl_threshold.grid(column=1, row=0)
lbl_trigger = Label(frame_channel_registers, text="Trigger")
lbl_trigger.grid(column=1, row=1)
#Misc settings
lbl_misc_registers = Label(tab_Digitizer,
text="Misc settings",
font='bold')
lbl_misc_registers.grid(column=0, row=5, sticky=W)
frame_misc_registers = Frame(tab_Digitizer)
frame_misc_registers.grid(column=0, row=6)
#_________________________________________________________________________________________________
tab_SignalViewer = ttk.Frame(tabControl)
tabControl.add(tab_SignalViewer, text=' Signal Viewer ')
#tabControl.grid(column=0, row=1)
#This keeps the window open - has to be at the end
window.mainloop()

Why aren't my buttons properly aligned with python TKinter

I am creating a password manager which includes some buttons, but for some reason these buttons aren't aligning properly, could someone help out?
Here is the code i've done usint Tkinter for these buttons:
btn = Button(window, text="Exit Securely", command=exit)
btn.grid(column=2)
btn = Button(window, text="Add Entry", command=addEntry)
btn.grid(column=1)
btn = Button(window, text="Generate", command=run)
btn.grid(column=0)
lbl = Label(window, text="Website")
lbl.grid(row=3, column=0, padx=80)
lbl = Label(window, text="Username")
lbl.grid(row=3, column=1, padx=80)
lbl = Label(window, text="password")
lbl.grid(row=3, column=2, padx=80)
which makes my program look like this:
Any general tips or helpful links for how to make a nicer GUI would be appreciated as well, as I have been struggling with that.
As #acw1668 said if you don't specify row in grid(), it will take the next available row.
# Code to make this example work:
from tkinter import *
def addEntry():pass
def run():pass
window = Tk()
# Added `row=0` for each one of them
btn = Button(window, text="Exit Securely", command=exit)
btn.grid(row=0, column=2)
btn = Button(window, text="Add Entry", command=addEntry)
btn.grid(row=0, column=1)
btn = Button(window, text="Generate", command=run)
btn.grid(row=0, column=0)
# Changed the row to 1 for all of them
lbl = Label(window, text="Website")
lbl.grid(row=1, column=0, padx=80)
lbl = Label(window, text="Username")
lbl.grid(row=1, column=1, padx=80)
lbl = Label(window, text="password")
lbl.grid(row=1, column=2, padx=80)
By the way it is a good idea to use different names for the different buttons/labels.
I have been trying various method of aligning the widgets of tkinter in the program window lately and well I have found a better working solution to this.
In you program you have been using grid for aligning. I would say that you replace with place instead.
place will allow you to set a definite x and y coordinate for the widget and it would be easy to use.
If I alter your code accordingly, I can show you the code (after alteration) and the image of the output.
Code (After Alteration)
# Code to make this example work:
from tkinter import *
def addEntry():pass
def run():pass
window = Tk()
# Adding geometry ettig.
window.geometry('500x500')
btn = Button(window, text="Exit Securely", command=exit)
btn.place(x=410, y=20)
btn = Button(window, text="Add Entry", command=addEntry)
btn.place(x=210, y=20)
btn = Button(window, text="Generate", command=run)
btn.place(x=10, y=20)
lbl = Label(window, text="Website")
lbl.place(x=10, y=50)
lbl = Label(window, text="Username")
lbl.place(x=210, y=50)
lbl = Label(window, text="password")
lbl.place(x=410, y=50)
The Output Screen

Looking for a solution to a tkinter error and efficiency/design problems

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()

New window label

how do I position my label which says "Question One" in my def new_window() function. As you run it the label is being positioned at the bottom, And i want it to be applied on the top.
from tkinter import *
from tkinter import ttk
#User Interface Code
root = Tk() # Creates the window
root.title("Quiz Game")
def new_window():
newWindow = Toplevel(root)
display = Label(newWindow, width=150, height=40)
message = Label(newWindow, text="Question One", font = ("Arial", "24"))
display.pack()
message.pack()
display2 = Label(root, width=100, height=30, bg='green')
button1 = Button(root, text ="Continue", command=new_window, width=16,
bg="red")
message_label1 = Label(text="A Quiz Game", font = ("Arial", "24"), padx=40,
pady=20)
message_label2 = Label(root, text="Click 'Continue' to begin.",
wraplength=250)
display2.pack()
button1.pack()
message_label1.pack()
message_label2.pack()
root.mainloop() # Runs the main window loop
You are packing in the wrong order. Do not pack display before your message. So just swapping the order will fix the issue.
Here is the code. Replace your def new_window(): with this
def new_window():
newWindow = Toplevel()
message = Label(newWindow, text="Question One", font = ("Arial", "24"))
display = Label(newWindow, width=150, height=40)
message.pack()
display.pack()
pack method just blindly packs the widget into the window. And the next pack will be done below it if there is space. So take care of the order while packing widgets :)

Categories