Insert vertical line below tabs in tkinter.text - python

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:

Related

How to change extracted specified range of text from Entry into another? (tkinter)

phqitemmaintit["text"][0:8] = Font(fg="Red")
Above is the extracted text but Font and fg method are not working.
How can I fix it to color text of Label?
Strings do not have fonts. You can't extract text and then add font information to it. At least, not in any way that python or tkinter can use it.
Font information is part of a widget, not part of the text. If you want to color part of a text string, the only supported way of doing that is with a Text widget, in which case you apply a tag to a range of characters and then configure that tag to have a color.
Here's an example:
import tkinter as tk
root = tk.Tk()
text = tk.Text(root, width=30, height=1)
text.pack(fill="both", expand=True)
text.tag_configure("red", foreground="red")
text.insert("end", "0123456789Hello, world")
text.tag_add("red", "1.0", "1.8")
root.mainloop()

Python-pptx compatibility with text boxes in LibreOffice

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?

In Python Tkinter, how do I get the index of an image embedded in a text widget using the name?

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.

Change colour in a row in Treeview

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.

How Could I replace Text in a PPP with Python pptx?

I want to replace the text in a textbox in Powerpoint with Python-pptx.
Everything I found online didn't work for me and the documentation isn't that helpful for me.
So I have a Textbox with the Text:
$$Name 1$$
$$Name 2$$
and I want to change the $$Name1 $$ to Tom.
How can I achieve that?
A TextFrame object defined in python-pptx helps in manipulating contents of a textbox. You can do something like:
from python-pptx import Presentation
"""open file"""
prs = Presentaion('pptfile.pptx')
"""get to the required slide"""
slide = prs.slides[0]
"""Find required text box"""
for shape in slide.shapes:
if not shape.has_text_frame:
continue
text_frame = shape.text_frame
if "Name 1" == text_frame.text:
text_frame.text = "Tom"
"""save the file"""
prs.save("pptfile.pptx")
Try this:
import pptx
input_pptx = "Input File Path"
prs = pptx.Presentation((input_pptx))
testString = "$$Name1 $$"
replaceString = 'Tom'
title_slide_layout = prs.slide_layouts[0]
slide = prs.slides.add_slide(title_slide_layout)
for slide in prs.slides:
for shape in slide.shapes:
if shape.has_text_frame:
if(shape.text.find(testString))!=-1:
shape.text = shape.text.replace(testString, replaceString)
if not shape.has_table:
continue
prs.save('C:/test.pptx')
Ok thank you. I just found out, that my PowerPoint example was totaly messed up. No everything works fine with a new PowerPoint blanked
In order to keep original formatting, we need to replace the text at the run level.
from pptx import Presentation
ppt = Presentation(file_path_of_pptx)
search_str = '$$Name1$$'
replace_str = 'Tom'
for slide in ppt.slides:
for shape in slide.shapes:
if shape.has_text_frame:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
print(run.text)
if(run.text.find(search_str))!=-1:
run.text = run.text.replace(search_str, replace_str)
ppt.save(file_path_of_new_pptx)
Since PowerPoint splits the text of a paragraph into seemingly random runs (and on top each run carries its own - possibly different - character formatting) you can not just look for the text in every run, because the text may actually be distributed over a couple of runs and in each of those you'll only find part of the text you are looking for.
Doing it at the paragraph level is possible, but you'll lose all character formatting of that paragraph, which might screw up your presentation quite a bit.
Using the text on paragraph level, doing the replacement and assigning that result to the paragraph's first run while removing the other runs from the paragraph is better, but will change the character formatting of all runs to that of the first one, again screwing around in places, where it shouldn't.
Therefore I wrote a rather comprehensive script that can be installed with
python -m pip install python-pptx-text-replacer
and that creates a command python-pptx-text-replacer that you can use to do those replacements from the command line, or you can use the class TextReplacer in that package in your own Python scripts. It is able to change text in tables, charts and wherever else some text might appear, while preserving any character formatting specified for that text.
Read the README.md at https://github.com/fschaeck/python-pptx-text-replacer for more detailed information on usage. And open an issue there if you got any problems with the code!
Also see my answer at python-pptx - How to replace keyword across multiple runs? for an example of how the script deals with character formatting...

Categories

Resources