Making a rectangle border around text in Textbox python tkinter - python

I want to have a rectangle border around certain text that is added to the text box from the end and will be placed at the center.
For example:
Unfortunately, I can't find a way to do that, because I
don't know how to place texts at the center of the line in the text box, and don't know how to surround a text with a rectangle.

You can wrap a Label with border between a space and newline with justify='center' in a Text widget.
Below is an example:
import tkinter as tk
root = tk.Tk()
textbox = tk.Text(root, width=30, height=10)
textbox.pack()
textbox.tag_config('center', justify='center')
def center_label(textbox, **kwargs):
textbox.insert('end', ' ', 'center')
lbl = tk.Label(textbox, bd=3, relief='solid', **kwargs)
textbox.window_create('end', window=lbl)
textbox.insert('end', '\n\n')
center_label(textbox, text='hello', width=10, font='Arial 12 bold')
center_label(textbox, text='............', width=20)
textbox.insert('end', '\nhello\n')
root.mainloop()
Result:

Try putting the text box into it's own frame.
Some thing like this:
from Tkinter import *
root = Tk()
labelframe = LabelFrame(root, text="LabelFrame")
labelframe.pack()
text = Label(labelframe, text="Text inside labelframe")
text.pack()
root.mainloop()

You can add the border to the Entry using relief = "solid", centre the text with outline and you can use grid to align the widgets the way you want.
import tkinter as tk
root = tk.Tk()
root.geometry("400x200")
root.grid_columnconfigure(0, weight = 1)
ent1 = tk.Entry(root, relief = "solid", justify = "center")
ent1.insert(0, "hello")
ent1.grid(row = 0, column = 0, pady = 10)
ent2 = tk.Entry(root, relief = "solid", justify = "center")
ent2.insert(0, ".......")
ent2.grid(row = 1, column = 0, pady = 10)
lab1 = tk.Label(root, text = "hello")
lab1.grid(row = 2, column = 0, sticky = "w")
lab2 = tk.Label(root, text = "hello")
lab2.grid(row = 3, column = 0, sticky = "w")
root.mainloop()
Most of this is straightforward, the root.grid_columnconfigure line makes the grid take up the full width of the root window by giving the first column a weight of 1. The result is very similar to your example:

You could create an Entry widget in the textbox using text.window_create(). You could customize the border of the Entry widget, and you would be able to type text inside it. To make it look more like part of the textbox, you should register events so when the user presses Right and the caret is one character left of the Entry, give the Entry focus using focus_set. You could do the same with the Left.

Related

Why cant i move my drop-down list on Python Ktinker

I wish to move my drop down menu to the upper left.
But when i try to padx and pady nothing is happening.
global text
self.text = tk.Text(root, bg='black', foreground="white", height="15")
self.text.pack(padx=0, pady=75)
self.text.delete('1.0', tk.END)
self.text.insert(tk.END, "Opps, not yet connect OR no files to be read....")
self.variable = StringVar(root)
self.variable.set("Temperature") # default value
self.w = OptionMenu(root, self.variable, "Temperature", "Mazda", "three")
self.w.pack()
As default elements are centered and you need anchor='w' to move element to the left (west)
import tkinter as tk
root = tk.Tk()
txt = tk.Text(root, bg='black')
txt.pack(pady=75)
om_var = tk.StringVar(root, value='Hello')
om = tk.OptionMenu(root, om_var, 'Hello', 'World')
om.pack(anchor='nw') # north, west - top, left
root.mainloop()
Or you can use fill="x" (or fill="both") to resize to full width
om.pack(fill='x')
But there is also other problem - in Text you used pady=75 so you created margin between Text and OptionMenu and you would need pady=(75,0) to remove margin below Text
txt.pack(pady=(75,0))
import tkinter as tk
root = tk.Tk()
txt = tk.Text(root, bg='black')
txt.pack(pady=(75,0))
om_var = tk.StringVar(root, value='Hello')
om = tk.OptionMenu(root, om_var, 'Hello', 'World')
om.pack(fill='x')
root.mainloop()
I solved it by using place(), instead of pack().

Make button on opposite side of tkinter GUI

When I put in my code for this name picker, the gui opens and the two buttons are on top of each other. I understand why this is happening but I do not know how to move it.
This is what it looks like
This is what I want it to look like
Code:
from tkinter import *
import tkinter
import random
names =['Sledge','Thatcher','Ash','Thermite','Twitch','Montagne','Glaz','Fuze','Blitz','IQ','Buck','Blackbeard','Capitão','Hibana']
name = ["Smoke","Mute","Castle","Pulse","Doc","Rook","Kapkan","Tachanka","Jäger","Bandit","Frost","Valkyrie","Caveira","Echo"]
def pickName():
nameLabel.configure(text=random.choice(names))
def pickName1():
nameLabel.configure(text=random.choice(name))
root = tkinter.Tk()
root.title("Operator Picker")
root.geometry("400x100")
nameLabel = tkinter.Label(root, text="", font=('Helvetica', 32))
nameLabel.pack()
Grid()
pickButton1 = tkinter.Button(text="Pick Attack", command=pickName)
pickButton1.pack()
pickButton1.place(bordermode=OUTSIDE,height=100, width= 100)
pickButton2 = tkinter.Button(text="Pick Defend", command=pickName1)
pickButton2.pack()
pickButton2.place(bordermode=OUTSIDE,height=100, width= 100)
root.mainloop()
You don't need to pack and place your buttons, you can just pack them. If you want them on opposite sides, try this
pickButton1 = tkinter.Button(root, text="Pick Attack", command=pickName, height=100, width=100)
pickButton1.pack(side=tkinter.LEFT)
pickButton2 = tkinter.Button(root, text="Pick Defend", command=pickName1, height=100, width=100)
pickButton2.pack(side=tkinter.RIGHT)
Edit:
When you define the width and height of an object containing text, it is measured in lines and characters instead of pixels, if you want those exact sizes, you need to add frames
f1 = tkinter.Frame(root, height=100, width=100) #defines frame size in pixels
f1.pack(side=tkinter.LEFT) #packs on the left
f1.pack_propagate(0) #tells frame not to let children control size
pickButton1 = tkinter.Button(f1, command=pickName, text="Pick Attack")
pickButton1.pack(fill=tkinter.BOTH, expand=1) #takes up all available space
f2 = tkinter.Frame(root, height=100, width=100)
f2.pack(side=tkinter.RIGHT)
f2.pack_propagate(0)
pickButton2 = tkinter.Button(f2, command=pickName1, text="Pick Defend")
pickButton2.pack(fill=tkinter.BOTH, expand=1)

I want to print the entry text from textbox to console. Below is my code

I am trying to make a GUI using python tkinter.
I want to print the entry text from textbox to console after the analyzebutton is pressed.
here is my code
root = Tk()
root.title('Title')
MiddleFrame = Frame(root)
BottomFrame = Frame(root)
TopFrame.pack(side = TOP)
MiddleFrame.pack()
BottomFrame.pack(side = BOTTOM)
TextArea = Text()
ScrollBar = Scrollbar(root)
ScrollBar.config(command = TextArea.yview)
TextArea.config(height = 25, width = 70,
background = "white", yscrollcommand = ScrollBar.set)
TextArea.grid(padx = 18, pady = 18)
ScrollBar.pack(side = RIGHT, fill = Y)
padx = 10
pady = 10
TextArea.pack(padx = padx, pady = pady)
AnalyzeButton = Button(BottomFrame, text = "Analyze", fg = "white", bg = "blue", command = callback)
AnalyzeButton.pack(fill = X, padx = padx, pady = pady)
def callback():
text_input = Text.get()
print(text_input)
root.mainloop()
thanks in advance
Use get method of Text. Use the widget not the class-Text. Here is what you need to do:-
text_input = TextArea.get("1.0","end-1c")
You have several problems in your code. I will break it down so you understand what is going on here.
Fist I noticed you have tried to pack TopFrame but you have not actually defined TopFrame yet. So I added TopFrame = Frame(root) to your code.
Next we have a common mistake people encounter when trying to use grid() and pack() on the same window/frame. This is not allowed by the geometry manager. So you will need to decide on either grid() or pack() for all your needs in each window/frame. For now I changed TextArea.grid() to TextArea.pack() to get your code to work.
Next your button command was referencing a function that was after the command. This does not work outside of a class so you will need to move your callback() function above your AnalyzeButton.
Next we need to fix the indention on your callback() function. You must remember indention is very important in python and you should take care to keep your indention clean and consistent.
The last thing we needed to fix to get everything working as you were intending is to change:
text_input = Text.get()
To:
text_input = TextArea.get(1.0, END)
You were trying to call get() on the method that created the text widget and not the widget instance.
You also need to define from what part of the text widget you want to start reading data and how far you want to read through the text widget. this is done by applying 2 positions points with 1.0, END or "1.0", "end-1c" as tkinter allows for a few ways to apply these points. This will say 1.0 start at the first line at the first position on that line and END will say read until the last line of the textbox.
There may be other issues but I only fixed the problems preventing the code from working as intended. Your code modified to work below:
from tkinter import *
root = Tk()
root.title('Title')
TopFrame = Frame(root) # was missing from your code
MiddleFrame = Frame(root)
BottomFrame = Frame(root)
TopFrame.pack(side = TOP)
MiddleFrame.pack()
BottomFrame.pack(side = BOTTOM)
TextArea = Text()
ScrollBar = Scrollbar(root)
ScrollBar.config(command = TextArea.yview)
TextArea.config(height = 25, width = 70,
background = "white", yscrollcommand = ScrollBar.set)
TextArea.pack() # can't use pack and grid on the same window/frame. Changed this to pack()
ScrollBar.pack(side = RIGHT, fill = Y)
padx = 10
pady = 10
TextArea.pack(padx = padx, pady = pady)
# this function needs to be before the command that references it.
def callback():
# fixed indention
text_input = TextArea.get(1.0, END) # you need to reference that widget name not the tkinter method used to create the widget.
print(text_input)
AnalyzeButton = Button(BottomFrame, text = "Analyze", fg = "white", bg = "blue", command = callback)
AnalyzeButton.pack(fill = X, padx = padx, pady = pady)
root.mainloop()

Focus Events (or lack thereof)

I am having a hard time understanding the focus events for Entry and Textbox fields in Python version 3 using Tk. I eventually need to validate an Entry box on lost focus if I click a radio option or a button.
If you run the code below then (which serves only to demonstrate Focus issues not the validation i require elsewhere), place the cursor in either of the top row Entry boxes and click between the other widgets, the only time FocusIn and Focus out events occur are on the widgets that accept input ie Text/Entry boxes.
Clicking the button or the radio options, the cursor remains in the Entry or Textbox widgets. Why when i have clearly focused on a radio option or the button.
I have tried .bind FocusIn/Out events and still no joy. if anyone has an explanation I would be intrigued to know why and possibly how i can overcome it.
from tkinter import *
root = Tk()
root.title("My Widgets")
root.update_idletasks()
root.geometry("350x200+10+300")
root.attributes("-toolwindow",1)
root.resizable(width=FALSE, height=FALSE)
root.config(bg="blue")
# function below output to the console and label the focus results
def Validate(a,b,c,d,e,f,g,h):
text = g + ' on ' + h
lblOutputVar.set(text)
print(f,g,h)
return True
var = IntVar()
lblOutputVar = StringVar()
vcmd=(root.register(Validate),'%d','%i','%P','%s','%S','%v','%V','%W')
entryOne = Entry(root, name = 'entryBoxOne')
entryOne.config(validate = 'all',vcmd=vcmd)
entryOne.grid(row=1, column=1,padx=(0,0),pady=(10,10),ipady=(1), sticky=E+W)
entryTwo = Entry(root, name = 'entryBoxTwo')
entryTwo.config(validate = 'all',vcmd=vcmd)
entryTwo.grid(row=1, column=2,padx=(10,0),pady=(10,10),ipady=(1), sticky=E+W)
txtBox = Text(root, name = 'textBox', width=10, height=1, takefocus = 0)
txtBox.grid(row=5, column=1, sticky=E+W)
aButton = Button(root, text = 'Click Me!', takefocus=1)
aButton.grid(row=5, column=2)
lblOutput = Label(root, name = 'labelOutput', width=20, height=2, textvariable=lblOutputVar)
lblOutput.grid(row=10, column=1, columnspan =2, pady=(5,0), sticky=E+W)
radioOne = Radiobutton(root, anchor = 'w', text = 'One', variable = var, value = 1, takefocus = 1)
radioOne.grid(row=2, column=1, sticky=E+W)
radioTwo = Radiobutton(root, anchor = 'w', text = 'Two', variable = var, value = 2, takefocus = 1)``
radioTwo.grid(row=3, column=1, sticky=E+W)
root.mainloop()
The explanation is simply that tkinter buttons and radiobuttons aren't given focus when you click on them. If you want that to happen, you need to set up a binding to explicitly give them the focus.
Your other option is to use a ttk radiobutton which does get focus. It's unfortunate that the two different radiobuttons have different behavior.

Drawing on Tkinter grid

I couldn't find a way how to Draw line using grid. I want to have a line going from North to South seperating left and right frames.
self.left= Frame(self.tk, bg="black")
self.left.grid(column=0, row = 0, pady=5 ,padx=10, sticky=N)
self.center = Frame (self.tk ,bg= "black")
self.center.grid(column=1, row = 0, pady=5,padx=10, sticky=N)
self.right= Frame(self.tk, bg="black")
self.right.grid(column=2, row = 0, pady=5,padx=10, sticky=N)
I want something like
self.w.create_rectangle(self.centerwidth/2-2, 0, centerwidth/2+2, self.windowheigh, fill="#00CC00", outline = "#00CC00")
If you want to separate the left frame from the right one, you can use a separator from ttk module (http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-Separator.html)
Here is an example:
# python3
import tkinter as tk
from tkinter.ttk import Separator, Style
# for python2 :
# import Tkinter as tk
# from ttk import Separator
fen = tk.Tk()
left = tk.Frame(fen, bg="black",width=100, height=100)
# to prevent the frame from adapting to its content :
left.pack_propagate(False)
tk.Label(left, text="Left frame", fg="white", bg="black", anchor="center", justify="center").pack()
left.grid(column=0, row = 0, pady=5 ,padx=10, sticky="n")
sep = Separator(fen, orient="vertical")
sep.grid(column=1, row=0, sticky="ns")
# edit: To change the color of the separator, you need to use a style
sty = Style(fen)
sty.configure("TSeparator", background="red")
right= tk.Frame(fen, bg="black",width=100, height=100)
right.pack_propagate(False)
tk.Label(right, text="Right frame", fg="white", bg="black").pack()
right.grid(column=2, row = 0, pady=5,padx=10, sticky="n")
fen.mainloop()
I don't know what you want exactly, but you can create a line like this.
from Tkinter import *
master = Tk()
w = Canvas(master, width=200, height=100)
w.pack()
w.create_line(100, 0, 100, 100)
#first 2 args are starting point of line and next 2 are ending point of line.
mainloop()
For adding other options, refer to canvas widget of tkinter

Categories