I have a ttk.Separator widget and I would like it to be all black. I used ttk.Style() as follows
import Tkinter as TK
import ttk
self.line_style = ttk.Style()
self.line_style.configure("Line.TSeparator", background="#000000")
self.line = ttk.Separator(self.tk, orient=TK.VERTICAL, style="Line.TSeparator")
self.line.place(x = 1250,y = 0, height = self.tk.winfo_screenheight(), width = 8)
And the separator is black, 8 pixels wide, but it has a 1 pixel white line on the left side. Plase, do you know how could I get rid of it?
Unfortunately you can't get rid of the 1 pixel white line, the only available option to configure for a ttk Separator is the background option.
You can see this by finding the layout of the Separator and then listing all of its configuration options as follows
s = ttk.Style()
print(s.layout('TSeparator')) # [('Separator.separator', {'sticky': 'nswe'})]
print(s.element_options('Separator.separator')) # ('-orient', '-background')
If you set the background color to something other than black you'd see that this 1 pixel border is not always white but somehow related to chosen background color, either a lighter or darker shade.
The most viable workaround is to simply insert a styled Frame (ttk or regular tkinter) of the desired width instead of using a separator
I know that this is an old post but I had the same issue and figured out a work around. When I create a 1 pixel high tkinter.Frame and stretch it out along the x-axis, I get something that looks like a ttk.Separator. Example:
import tkinter as tk
root = tk.Tk()
separator = tk.Frame(root, bg="blue", height=1, bd=0)
separator.pack(fill="x")
root.mainloop()
The colour of the separator is controlled by its bg keyword.
Related
Hy, I hope you are all doing well. I am building a Eye chart software in python tkinter which consists of Opto Charts.
In Opto Charts all alphabet comes directly below each other. But when I try to add labels in tkinter, it forms V shape as with each row font size is decreasing.
I want to occupy the label all the available space.
I managed to do that using mainFrame.rowconfigure(0, weight=1) but it only makes the label to full width not the text inside it. I have attached a screenshot for how it looks.
In the screenshot you can see the labels are set to full length of screen but text is in V shape as font size is decreasing from top to bottom.
Is there a way to anchor the text to full width also. In others words each alphabet should come directly below the above one.
I hope I was clear, If you need to know anything else let me know.
If an image or bitmap is being displayed in the label then the value is in screen units; for text it is in characters.
To occupy same space for different size of font, try to use image mode and use an empty image.
import tkinter as tk
from tkinter.font import Font
texts = ('EDFHT', 'FPYUI', 'TOZQW', 'LPEDA', 'PECFD')
sizes = (28, 24, 20, 16, 12)
root = tk.Tk()
factor = 2
tkfont = Font(font=("Courier New", max(sizes), 'bold'))
width, height = tkfont.measure("W")*factor, tkfont.metrics("linespace")*factor
image = tk.PhotoImage(data='')
for row, (text, size) in enumerate(zip(texts, sizes)):
for column, t in enumerate(text):
label = tk.Label(root, text=t, font=("Courier New", size, 'bold'), image=image, width=width, height=height, compound=tk.CENTER)
label.grid(row=row, column=column)
root.mainloop()
I need to create semi-transparent 1x1 images which I can zoom on the canvas.
Currently, I have a directory full of prerendered transparent images for each possible alpha value, however I would like to avoid that.
Also, I cannot use anything outside of the standard library - this is for a school project and the computers don't have admin access (cannot use PIP).
Using PhotoImage, you can create a blank image and place pixels in the desired coordinates, however when specifying the color used, I can't figure out how to pass in alpha values. The Tcl Tk documentation (https://www.tcl.tk/man/tcl8.7/TkCmd/photo.htm#M53) states you can specify alpha values in colors.
From my understanding, a red color with an alpha value of 0.5 would look like this: #ff0000#0.5
Here's the code I have right now:
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width = 500, height = 500, bg = "black", highlightthickness = 0)
canvas.pack()
image = tk.PhotoImage(width = 1, height = 1)
image.put("#ff0000#0.5", (0, 0))
image = image.zoom(30)
canvas.create_image(
0,
0,
image = image,
anchor = "nw"
)
root.mainloop()
Can I place transparent pixels/regions using the put method in Tkinter's PhotoImage? I cannot use PIL.
transparent = "#000000" # color that will be considered as "transparent"
if color != transparent:
image.put(color, (0, 0))
I apologize in advance if my question is a duplicate however I have not found an answer to this question.
I'm learning Tkinter and I'm struggling with understanding the relation between a label's font type, it's size and it's width and the length of the string in it.
Specifically, what my problem is:
I have created a widget: a 800x640 canvas on which I want to place other
widgets.
On this canvas I want to place a label with some text which has the following
attributes: font: Helvetica, font size: 20, text = "main application". I want
to place this label widget at the very most top left corner of the
widget(meaning at point 0,0 with respect to the canvas). I want the label to
be 200 in width meaning it's background to take almost 1/3 of the canvas's
size(after I manage to do this I plan to add 2 more labels as well). I guess
the height of the label is determined by the font size in this case 20. I
placed the label at coordinate y=20 and this coordinate seems to be ok.
I did some googling and found out that the width parameter of the label widget is not the actual width but something related to the font and size of the label's text: something like if I understood correctly: if the width is 6 than the label will be wide enough to contain 6 characters of, in my case verdana size 20. But I was not able to figure out what width and what x coordinate I should give my label so it starts at the x point of the canvas. Here is the code that I wrote:
from tkinter import *
from tkinter.ttk import *
from tkinter import messagebox
from tkinter import Menu
# Define the application class where we will implement our widgets
class Application(Frame):
def __init__(self, master):
super(Application, self).__init__(master)
# CANVAS COLOUR DEFAULTS TO THE COLOUR OF THE WORKING WINDOW
canvas = Canvas(master, width=800, height = 640, bg="gray") # IF YOU DO .PACK() HERE IT WILL RETURN NONE AND THEN YOU WILL HAVE PROBLEMS BECAUSE .PACK() RETURNS A 'NONE' TYPE OBJECT
canvas.place(relx=0.5, rely=0.5, anchor=CENTER)
# The 'menu' of the application. The selection labels
main_application_label = Label(master, text="main_application", font=("Helvetica", 20))
main_application_window = canvas.create_window(103,20, window=main_application_label)
main_application = Tk()
main_application.title("main_application")
app = Application(main_application)
app_width = 800
app_height = 640
screen_width = main_application.winfo_screenwidth()
screen_height = main_application.winfo_screenheight()
x_coord = (screen_width/2) - (app_width/2)
y_coord = (screen_height/2) - (app_height/2)
main_application.geometry("%dx%d+%d+%d" % (app_width, app_height, x_coord, y_coord))
main_application.mainloop()
I have managed to somehow get the label at around point 0,0(by giving more values till I got it right) but the actual width of the label is not 200 pixels(~1/3 of the canvas). Please help me understand what values to the width parameter I should give so that my label's background is 1/3 of the canvas's size and if possible explain the relation between character font and width parameter so I can do that for any widgets regardless of their text's length. Thank you for reading my post!
Edit: What I wanted to do was to place 3 widgets(labels in this case but it doesn't matter) on the canvas. I did not understand what the 'anchor' option does and that was confusing me because I was expecting the center of the widget to be placed at the given coordinates all times but as I was changing anchor the placement of the center of the widget was changing and that was confusing me. It's all clear now thanks to #Bryan Oakley. Thanks.
If you want the upper left corner of the text to be at (0,0), you don't have to adjust the coordinates based on the width. You can use the anchor option when creating the canvas object:
main_application_window = canvas.create_window(0, 0, anchor="nw",
window=main_application_label)
If you really need to compute the actual size of the string, you can create a Font object and then use the measure method to find the actual width of a string in the given font.
from tkinter.font import Font
font = Font(family="Helvetica", size=20)
string_width = font.measure("main_application")
string_height = font.metrics("linespace")
This gives you the size of the rendered string. If you're using a label widget you'll also need to take into account the amount of padding and borders that the widget uses.
When you create items on a canvas, you can specify the width and height. For example, this makes the widget 200 pixels wide:
main_application_window = canvas.create_window(0, 0, anchor="nw", width=200,
window=main_application_label, width=400)
import tkinter as tk
root = tk.Tk()
root.title("window")
yellow_header = tk.Label(root, text = 'Header', bg = 'light yellow')
yellow_header.pack(side = tk.TOP, anchor = tk.N, expand = 1, fill = tk.X)
yellow_header2 = tk.Label(root, text = 'paragraph', bg = 'light yellow')
yellow_header2.pack(side = tk.TOP, anchor = tk.N, expand = 1, fill = tk.X)
root.mainloop()
For the above code I am trying to have both these labels anchored to the top and directly below one another. Although the first label (yellow_header) anchors to the top, where as the second label (yellow_header2) when expanded move towards the centre. How can I fix this?
Thank you in advance!
Don't use expand=1. From effbot:
The expand option tells the manager to assign additional space to the widget box. If the parent widget is made larger than necessary to hold all packed widgets, any exceeding space will be distributed among all widgets that have the expand option set to a non-zero value.
With expand=1, when you make the window larger, the space is distributed between the two labels. So even though you only tell them to fill it in the X direction, they are given the space in both directions. The second label is placed directly under the space that is available to the first label, which is half of the window.
I've tried to explain and visualize the difference between expand and fill in this answer.
P.S. You don't need anchor=tk.N either. When the space available to the widget and the size of the widget are the same, the anchor option makes no difference. Also, side=tk.TOP is the default so you could decide to omit that too, leaving you with only fill=tk.X.
Looking at the docs I see:
The Text widget is used to display text in multiple lines.
and this seems to work:
import tkinter as tk
root = tk.Tk()
root.title("window")
yellow_header = tk.Label(root, text = 'Header\nParagraph', bg = 'light yellow')
yellow_header.pack(side = tk.TOP, anchor = tk.N, expand = 1, fill = tk.X)
That might be a bit OS specific and perhaps the proper way would be:
import os
...
yellow_header = tk.Label(root, text = 'Header' + os.linesep + 'Paragraph', bg = 'light yellow')
When increasing the length of the first string the second still remains in the center.
I noticed that the width argument for the Tkinter entry widget is in characters, not pixels.
Is it possible to adjust the width in pixels?
You can also use the Place geometry manager:
entry.place(x=10, y=10, width=100) #width in pixels
You cannot specify the width in pixels using the '-width' option, but there are ways to accomplish the same thing. For example, you could pack an entry in a frame that has no border, turn off geometry propagation on the frame, then set the width of the frame in pixels.
You can use "ipadx" and "ipady" while packing the "Entry" widget.
You can also use it with "grid".
import tkinter as tk
root = tk.Tk
e = tk.Entry()
e.pack(ipadx=100, ipady=15)
tk.mainloop()