In the following Python code I try to change the colour of rows in the Treeview table. It doesn't work. I try with tag.configure but...
As you can see what the function do is extract data from a sql database and put it in a Treeview table, depending line the colour should be different but it doesn't work... anu help?
from tkinter import *
from tkinter import ttk
import sqlite3
root=Tk()
FrameTabla=Frame(root)
FrameTabla.pack()
def mostrar_items():
miConexion=sqlite3.connect("database")
miCursor=miConexion.cursor()
miCursor.execute("SELECT * FROM DATABASE ORDER BY USERID DESC")
lista=miCursor.fetchall()
for i in lista:
if lista.index(i) % 2 == 0:
Tabla.insert('', 0, text=i[0], values=(i[1], i[2]), tags=('par',))
else:
Tabla.insert('', 0, text=i[0], values=(i[1], i[2]), tags=('impar',))
miConexion.close()
Tabla=ttk.Treeview(FrameTabla, heigh=20, columns=("Nombre", "Apellido"))
Tabla.grid(row=0, column=0, columnspan=3)
Tabla.tag_configure('par',background='white',foreground='black')
Tabla.tag_configure('impar',background='black',foreground='white')
Tabla.heading('#0', text = 'UserID', anchor = CENTER)
Tabla.heading('Nombre', text = 'Nombre', anchor = CENTER)
Tabla.heading('Apellido', text = 'Apellido', anchor = CENTER)
Tabla.column('#0', width=120, anchor= CENTER)
Tabla.column('Nombre', anchor = CENTER)
Tabla.column('Apellido', anchor = CENTER)
ScrollVert=Scrollbar(FrameTabla, command=Tabla.yview)
ScrollVert.grid(row=0, column=4, sticky='nsew')
mostrar_items()
root.mainloop()
Further to this issue I have seen a number of responses to getting the Treeview row colour to work but if your problem resides with the Style Theme Files and you are using Windows 10 then you will spend a great deal of time going around in circles not ever getting it to work which I did and which is why I have provided these additional comments.
1 - there are setup issues with the Theme Files in relation to Treeview colour displays. Defined as a bug that has been / will be fixed in future releases.
2 - start point is to update the Theme File you are using in your program albeit I have seen an option to introduce some additional code to override the file issues. I found this harder to apply(and I didn't really understand what it was doing) than changing the Theme Files directly.
3 - The address for the Theme Files for me is:
C:\Users\xxxx\AppData\Local\Programs\Python\Python39\tcl\tk8.6\ttk
All the Theme files are named xxxxxTheme e.g clamTheme, vistaTheme etc. The change needed was something I found on a python 'reported' bug site. Below is the before change values which seem to be consistent in each Theme file:
ttk::style map Treeview \
-background [list disabled SystemButtonFace \
{!disabled !selected} SystemWindow \
selected SystemHighlight] \
-foreground [list disabled SystemGrayText \
{!disabled !selected} SystemWindowText \
selected SystemHighlightText]
After Changes follow - in essence you need to remove the disabled references
# Treeview:
ttk::style map Treeview \
-background [list selected SystemHighlight] \
-foreground [list selected SystemHighlightText] \
;
This resolves the issue immediately you apply it but you need to ensure that you then use the Theme that you have amended, also make sure that you take a copy of the original theme file pre the changes as python wont run if you mess it up.
A couple of lines follow to setup use of the style that you have amended, in this case vista.
style = ttk.Style()
style.theme_use('vista')
Happy to post a complete example of using the 'odd' and 'even' tag approach to alternating row colours for Treeview if needed but I think if you got to the point of the style and tags not working for colours then you were very close to completing on this anyway.
Related
I am creating a code editor as my project, and I think it is nice to have vertical lines under tabs so its easier for the coder. I want to draw a vertical line below tabs (I think the image below will be better to understand what I want, Just a screenshot from vs code):
Here you can see that there is a vertical line under def and I think these are pretty useful for me so that I won't make any indentation errors while I am coding. Now I want exactly a feature like this in my code editor. To simplify things I will upload a sample code below.
from tkinter import *
root = Tk()
txt = Text(root) # What changes do I have to make to this text widget so the lines appear like it does in the image
txt.pack()
root.mainloop()
The text widget doesn't directly support this. You can fake it by using ascii line drawing characters, but it would probably be a lot of work. It should be doable, though.
You can do this if you base your IDE on a canvas rather than a Text widget, but the text-editing ability of the canvas text item would be very cumbersome compared to the text widget.
All of that being said, with a little creativity you can get something close to what you want with tags. The idea is to add a tag to the character that you want to appear as a line. If you set the tag to have a different color than the text, it will look like a vertical line. The problem, however, is that you don't have much control over the width of the line. You might have some luck using the bgstipple option, which allows you to apply a bitmap to the region.
Here's an example to illustrate the idea.
import tkinter as tk
import tempfile
def add_markup(text, start=None, end="end"):
text.mark_set("current", start or "1.0")
text.tag_remove("markup", "current", end)
while text.compare("current", "<", end):
if text.get("current") == " ":
text.tag_add("markup", "current", "current+1c")
text.mark_set("current", "current+4c")
else:
text.mark_set("current", f"current +1l linestart")
root = tk.Tk()
text = tk.Text(root)
text.tag_configure("markup", background='#f0f0f0', bgstipple='#line.xbm', fgstipple='#line.xbm')
text.pack(fill="both", expand=True)
text.bind(
"<Any-KeyRelease>",
lambda event: add_markup(event.widget, "insert linestart", "insert lineend")
)
def load_this_file(text):
with open(__file__, "r") as f:
text.insert("1.0", f.read())
load_this_file(text)
add_markup(text)
root.mainloop()
This is what it looks like on my machine:
I found the possibility to make a stippled line in Python tkinter. (Seen here: Canvas Line Objects)
It states that I need a bitmap file and define stipple=bitmap_file
I tried this in:
# Import the required libraries
from tkinter import *
# Create an instance of tkinter frame or window
win=Tk()
# Set the size of the tkinter window
win.geometry("700x350")
# Create a canvas widget
canvas=Canvas(win, width=500, height=300)
canvas.pack()
# Add a line in canvas widget
canvas.create_line(100,200,200,35, stipple='#CheckedLine.bmp', fill='red', width=5)
win.mainloop()
However, the console then says:
_tkinter.TclError: error reading bitmap file "CheckedLine.bmp"
Can someone help?
The page linked to in the OP, also links to a detailed description of what they meant by a "bitmap", they never mention it to be a file but rather a bitmap.
stipple
To draw a stippled line, set this option to a bitmap that specifies
the stippling pattern, such as stipple='gray25'. See Section 5.7,
“Bitmaps” for the possible values.
Section 5.7 details about the files to be used -:
The graphic above shows Button widgets bearing the standard bitmaps.
From left to right, they are 'error', 'gray75', 'gray50', 'gray25',
'gray12', 'hourglass', 'info', 'questhead', 'question', and 'warning'.
You can use your own bitmaps. Any file in .xbm (X bit map) format will
work. In place of a standard bitmap name, use the string '#' followed
by the pathname of the .xbm file.
For more information on the .xbm format this may be useful.
Some image viewers/converters, e.g., XnView, FFmpeg and IrfanView,
support XBM. A 48×48 XBM can be converted to Ikon and eventually
X-Face with Netpbm tools.
ImageMagick supports converting images both to and from XBM. GIMP
may be used to create or modify images using the XBM format, and also
supports converting images to and from the XBM format.
NOTE:
Incase, you use the standard bitmaps as listed above and in the link provided, they render to look like this -:
Just starting to try to use python-pptx, and have fallen at the first. Linux Mint 20.1, python 3.85, LibreOffice 6.4.
This is basically the 'Hello World' from the documentation.
from pptx import Presentation
from pptx.util import Inches, Pt
prs = Presentation()
blank_slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(blank_slide_layout)
left = top = width = height = Inches(1)
txBox = slide.shapes.add_textbox(left, top, width, height)
tf = txBox.text_frame
print('before text ', txBox.left, txBox.top, txBox.width, txBox.height)
tf.text = "This is a long line of text inside a textbox"
print('after text ', txBox.left, txBox.top, txBox.width, txBox.height)
prs.save('test.pptx')
The text is more than a single line for the textbox. Printing out its bounds before and after text insertion shows that as far as python-pptx is concerned, the textbox width hasn't changed.
When the resulting presentation is viewed in LibreOffice, instead of wrapping the text within its boundaries, the textbox has expanded symmetrically around the mid point, pushing the start of the text off the lefthand edge of the page.
I was hoping the LibreOffice was only incompatible with powerpoint for rare edge cases, but text in text boxes is the meat and bread of presentations.
When I upload it to google slides, the text wraps within the left and right text box boundaries, but spills out of the bottom edge. The textbox shows up as 1" x 1" in the right place.
If I use onedrive.live.com, the text is left justified in the box and spills out of the righthand side without wrapping, and the textbox is shown as being 1" x 1" in the right place.
If I use onlinedocumentviewer.com, the display is the same as onedrive, though I can't get to see the text box.
Unfortunately I can't test the behaviour on a native powerpoint installation.
Maybe there's an autosize or fixed flag, which left unset leaves each viewer defaulting it in its own idiosyncratic way? How do we control text boxes / frames when targetting LibreOffice?
I possibly have a workaround to break up my text into single lines and use one per text box, but I'd rather understand the whether it can be done the proper way.
After some floundering around in the docs, I stumbled across the text_frame .word_wrap property. Setting to True gets the text to wrap in LibreOffice. While I was there, setting text_frame.auto_size = MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE reduces font size to get it all to fit in the box.
Is there a list of properties like .word_wrap in one place anywhere?
I am creating an app using Python Tkinter in which I give the users an option to insert an image into a text widget. I know that when you insert an image, and you don't specify the name attribute, tkinter automatically generates one. There is also a way to get a tuple of all the names in the text widget using the text.image_names() method. All the methods I have looked at, that relate to text widget images only take the image's index as an attribute. However, I don't know the image's index.
It would be nice if anyone could tell me if there is a method where I give the function the image's name is an attribute, and get the index in return.
You can use Text.index() on the image name to get the image index in "line.column" format.
Below is an example:
import tkinter as tk
root = tk.Tk()
text = tk.Text(root, width=80, height=20)
text.pack()
text.insert('end', 'This is line 1\n')
text.insert('end', 'Embed an image ')
img = tk.PhotoImage(file='sample.png')
text.image_create('end', image=img, name='img1')
text.insert('end', ' in a line')
print('Image with name "img1" is at index', text.index('img1'))
root.mainloop()
You will get Image with name "img1" is at index 2.15 in the console.
For a webapp I need a way to prevent that a browser falls back to another font if my web font doesn't include a character. It seems the only way to do this is to add another font to the fontstack which includes "all" possible characters 1.
There are already existing fallback fonts, but those are more debug helpers as they show the codepoint as number, therefore they are much to heavy (>2MB).
The fallback font for my usecase should just show something like a box to signal a missing character.
My idea was to generate a simple font with only one glyph and apply a feature file which will replace all glyphs with this one.
My script for fontforge:
import fontforge
import fontTools.feaLib.builder as feaLibBuilder
from fontTools.ttLib import TTFont
font_name = 'maeh.ttf'
font = fontforge.font()
glyph = font.createChar(33, "theone")
pen = glyph.glyphPen()
pen.moveTo((100,100))
pen.lineTo((100,500))
pen.lineTo((500,500))
pen.lineTo((500,100))
pen.closePath()
for i in range(34, 99):
glyph = font.createChar(i)
glyph.width=10
font.cidConvertTo('Adobe', 'Identity', 0) # doesn't make a difference
font.generate(font_name)
font = TTFont(font_name)
feaLibBuilder.addOpenTypeFeatures(font, 'fallback.fea')
font.save("fea_"+font_name)
My feature file:
languagesystem DFLT dflt;
#all=[\00035-\00039];
##all=[A-Z] this works
feature liga {
sub #all by theone;
} liga;
But the above results in a
KeyError: ('cid00037', 'SingleSubst[0]', 'Lookup[0]', 'LookupList')
with changing numbers for cid00037.
If I use the out commented A-Z from the Feature file it works, so this approach doesn't seem to be completely wrong.
Why can't fonttools find the glyphs if I specify the range in CID notation?
Is there another way to crate a class for the OpenType feature file which includes all glyphs?
While working on the above problem, somebody hinted me to the Adobe NotDef font, which is pretty much what I was looking for. For some reason I wasn't able to convert the .otf of the Adobe NotDef to woff or woff2 with fontforge. Also all the online tools to create the web font files like fontsquirrel failed. To create the woff file I used sfnt2woff from the woff-tools package. For the woff2 file I used https://github.com/google/woff2.