Color lines seperately in tkinter? - python

I'm trying to write a music program that would display Chordpro files in python. Similar to this image, I want the chords, comments, and lyrics to each have different colours. I've tried these widgets:
I tried separating chords, comments and lyrics into multiple strings that could overlap on a canvas (with a different colour for each string) to make the full song, but sadly whitespace overrides previously rendered text, so I could only see the last layer.
Label/Message doesn't have functionality for multiple colours unless make a label for each line, which is very tedious, considering I want the font size to be adjustable too.
Text is editable, which I don't want.
Is there some kind of module or other tkinter widget that would allow separately coloured lines?

Just draw the separate lines at different y positions (heights) on the canvas. It's the first two parameters of the create_text() function. E.g.
self.canvas = Canvas(root, width=800, height=650, bg = '#afeeee')
self.canvas.create_text(100,10,fill="darkblue",font="Times 20 italic bold",
text="Greensleeves are my...")
So here, change 10 to the line position you want etc. Code copied from Python: how to add text inside a canvas?

Related

Setting entry text box size in Tkinter python

I am attempting to create a form that requires some entry options to be more than one line long. This does not seem possible with the .Entry() function.
This issue is that I dont see anywhere in the documentation how to restrict the size of the text entry box (particularly, number of lines, or height)
To be clear, I am not trying to set the placement height, or text size, I am trying to restrict the number of lines where text can be entered (so the form is a predictable size) this is necessary because for each item I am using .place() to put them at certain pixel locations, and thus .pack() is not a viable solution for my problems either
Some reference material:
Documentation for entry widget
Use the text widget instead. It has a height option
Note: place requires integers that represent pixels, however, within the options of the text box, the width option requires integers that represent number of characters, and the height option requires an integer that represents number of lines. If you attempt to use height=20 expecting 20 pixels, you will be unpleasantly surprised. If you use width = 5, height = 5 it will not be square.
For reference, the default text size and font is an average of 8 pixels wide per character in the text widget, and 6 pixels per character in the default for the entry widget, so if you wanted a form to stretch a certain number of pixels, use width = round(pixel_length /6)
you can combine this with screen width and placement of the corner of forms to fill across the page or to near the end if you like

Change color of single word in Tk label widget

I would like to change the font color of a single word in a Tkinter label widget.
I understand that something similar to what I would like to be done can be achieved with a Text widget.. for example making the word "YELLOW" show in yellow:
self.text.tag_config("tag_yel", fg=clr_yellow)
self.text.highligh_pattern("YELLOW", "tag_yel")
But my text is static and all I want is to change the word "YELLOW" to show as yellow font and "RED" in red font and I cannot seem to figure out how to change text color without changing it all with label.config(fg=clr).
Any help would be appreciated
You cannot do what you want. A label supports only a single foreground color and a single background color. The solution is to use a text or canvas widget., or to use two separate labels.

wrap text in an entry widget in tkinter

I want to create an interactive text box in a tkinter GUI, the text box should get the text to wrap to the next line after the length of 30 characters, like it would do using the wraplength=30 attribute in a label widget. I am trying to get it to work using an Entry widget, this is what I am aiming for (apart from the wraplength attribute needs to be changed to something that works in an Entry widget:
ent = Entry(root, width=30, wraplength=30)
I also need to be able to make the Entry widget taller than one line, is there a way i can do that, for example making it vertically fill a frame (similarly to expand=True making it horizontally fill a frame).
Thank you!
I believe that Entry widgets are single line only, you may want to try Text widget
https://tkdocs.com/tutorial/morewidgets.html#text
The entry widget doesn't support wrapping. If you want to have multiple lines -- even if it's one long line that's wrapped -- you'll need to use either a Text, Label, or Message widget. Only the Text widget supports user input, the other two are strictly for display.
As for making the entry widget taller, you can do that with a geometry manager. For example, you can use the sticky option of grid or the fill and expand options of pack. This will make the widget taller, but the text will still just appear as a single line.
but text can't use (show="")

Tkinter : Getting screen text unit width. (Not pixels)

I'm using Tkinter to design a UI for an application. I'm using grid geometry and while specifying button width (or any widget width), I realized that width should be specified in text units and not pixels. Since I want to make it platform independent and screen size independent Is there any method to get max text unit width ? So that I can do math on basis of that.
For example:
I've 10 buttons in a row, which should be of equal width. If I hard code a width value specific to current screen value, it would not work on diff screen wise.
Thanks.
Using the tkinter.font package you can create Tk font objects to define a font and call the measure method to obtain the screen width of text using that font.
import tkinter as tk
import tkinter.font as tkfont
root = tk.Tk()
font = tkfont.Font(family="Consolas", size=10, weight="normal")
m_len = font.measure("m")
For monospace fonts, any character will do. For proportional text, if you give the whole string you get the screen length of the string. Otherwise you typically get the size of m or n as either a maximum or an average character width.
However, buttons are typically all the same size on many UI styles. Varying the button sizes is likely to look quite poor. You can specify a negative width to set a minimum width for the widget which can be helpful.
If you want to make a GUI that is "platform independent and screen size independent", you definitely do not want to be measuring sizes yourself. Unless, by saying you want something platform independent, you're saying you want a button to be X pixels regardless of pixel density or screen resolution (which seems like a very bad idea).
The whole reason tkinter supports measuring in character units, along with options for widgets to stretch and shrink, is to support platform independence. When you start working at the pixel level, you will have many, many problems when you run the code on other platforms, or on other displays, or with other fonts.
That being said, the measure method of a font can tell you exactly how many pixels a given string will require in a given font. If you want to know how wide "one character" is, you can use the measure method on the string "0", which is what tkinter uses as a base when computing widths based on characters.
If you want buttons to be exactly the same size, using character widths will give you that, because it isn't the width of 10 actual characters in that widget, but ten average character widths. In that case, "10 characters" will be the same for every widget, no matter what the contents of that widget.
You must be having a root variable like-
import tkinter as tk
root = tk.Tk()
You can use root.winfo_sccreenwidth() for width
width = root.winfo_screenwidth() #width of screen
height = root.winfo_screenheight() # height of screen
I am not sure about any way to get the screenwidth in text units, it may not even be possible.
A solution would be to be able to specify the button width in pixels, you can do this by following a simple example given here.
What you do is - put the Button widget inside a frame and specify the height and width for the frame , and then make frame not propagate the size using grid_propagate(False) for the frame and then making the button expand upto the frame (maybe by using grid sticky="we" )

Two lines of text in a single grid row

Does anybody know if it's possible to put two lines of text in a single row using grid in TKinter?
If I make the font small enough, can I distribute the text in two lines?
>>> import Tkinter as tk
>>> root = tk.Tk()
>>> tk.Label(master=root, text="Line1\nLine2").grid(row=0)
>>> root.mainloop()
Worked for me and produced an image like this:
You can put multiple items in one cell but it is highly unusual, may have surprising behavior, and there are better ways to accomplish the same effect.
For example, the grid is invisible so you can have as many rows as you want to achieve any look you can imagine. Also, the definition of "item" is pretty loose -- you can create a frame, and in that frame put two labels, and that frame can go in a single row using grid to give the appearance of two lines of text in a single grid row. You can also use a text widget which lets you put as many lines of text that you want.

Categories