I have a python tkinter treeview that has a header font size of 12 and an row font size of 8. I have one item in the treeview. In one of the columns (lets say column 3) of the item, i have a text string that is significantly longer than the width of the column. If I use a word wrap function to warp the text string after 90 characters, the text string creates 22 rows of text in the item's column - all at font size 8.
How can I use style, height, and rowheight to set the treeview widget so that the full text in the column is displayed in the treeview and the bottom of the treeview aligns with the bottom of column 3 of the item - so that there's no white space between the bottom of the item and the bottom of the treeview? I've tried using metrics with my font to calculate the linespace and then set rowheight to linespace. But nothing seems to work.
header_font = tkfont.Font(family='TimesNewRoman', size=12)
row_font = tkfont.Font(family='TkFixedFont', size=8)
row_font.metrics()['linespace']
style = ttk.Style()
treeview.height=1
style.configure("Treeview.Heading", font=header_font, rowheight=int(12*2.5))
style.configure("Treeview", font=row_font, rowheight=(row_font.metrics()['linespace']*2.5))
Note: The treeview is in a frame using pack.
I can get the text to wordwrap using textwrap.wrap. For one item, this would result in 22 lines of text from the single string. For another item, this may result if 21 lines, etc. Note: I'm only displaying one item at a time in the treeview because of the length of the textstring. And I can set the font using a style to get it displayed in 8 point.
What I can't figure out is how to get the size of the treeview and/or frame to cut off at the bottom of the item/column so that I have no whitespace between the bottom of the item/column and the bottom of the treeview/frame, and the border around the item/columns is the bottom border of the treeview/frame.
If I set rowheight to the number of rows created from the textwrap, sometimes the bottom will cut off before the last row(s) for the item is displayed, sometimes in the middle of the row. And if I try to add a factor to the rowheight, it may be on for one row and off for other column heights.
Note: I will be loading textstrings of different length into the longest column so that's why I need to figure out a formula that will set the bottom of the treeview/frame to be the bottom of the content area/item area/column with the biggest height.
Related
What I really want is for the imported money numbers to be formatted with red font for negative, black for positive, with a dollar sign ($) in front.
I can't seem to find anyone else struggling with this. I have a hard time imagining I'm the only one who might want to display money columns in a tkinter treeview.
Anyway, if you have any suggestions for how I can accomplish this, please let me know.
ChatGPT suggested the following:
import tkinter as tk
import tkinter.ttk as ttk
# Create the main window
root = tk.Tk()
# Create a ttk.Treeview widget
tree = ttk.Treeview(root)
tree.pack()
# Insert some rows into the Treeview widget
tree.insert('', 'end', text='Row 1', values=('10.50', '20.00'))
tree.insert('', 'end', text='Row 2', values=('15.00', '25.00'))
tree.insert('', 'end', text='Row 3', values=('20.00', '30.00'))
# Define a formatting function for the cells
def format_currency(value):
return '${:,.2f}'.format(float(value))
# Set the formatting function for the cells in the second column
tree.tag_configure('currency', foreground='red',
font='Arial 14 bold', format=format_currency)
tree.tag_bind('currency', '<1>', lambda e: e.widget.item(e.item, tags=[]))
# Set the tag for the cells in the second column
for item in tree.get_children():
tree.item(item, tags=['currency'], text=1)
# Run the main loop
root.mainloop()
but there is no such parameter "format" for tree.tag_configure. The error I get when trying to run this code is: "TclError: unknown option "-format""
I was expecting the values in the second column to be formatted according to the format_currency function. I don't think ChatGPT quite got the format I want for the currency values, but at this point, it seems the priority is getting any format to be applied.
With Tkinter in Python, is it possible to format a column in a treeview control as currency with red font for negative values?
No, it is not possible. You can't control the color of individual cells in a treeview widget.
I would like to display a list of about 2500 fonts with 2 columns. Column 1 with the font name and column 2 with a sample text styled with the font named in column 1 for that row.
I am trying to use tkinter treeview to do this. I saw a similar question asked here but the answer that was given only applied to column headers.
I am also open to suggestions for other widget structures to accomplish this.
for font_name in font_list:
# create a tag for each font name in the list
# the name of the font is the name of the tag
my_treeview.tag_configure(font_name, font=font_name)
# insert items into the treeview using the font_name tags
my_treeview.insert(
'',
tk.END,
values=(font_name, sample_text),
tags=[font_name]
)
# the caveat here is that both columns will be in the new font
I created a table using plotly to calculate some financials, I would like to show the whole table in the graph interface (not just a few rows):
As you can see in the image, only 11 of my 30 rows are shown. I would like to show all the data of the table (all 30 rows with no scrollbar).
The code for the table is the following:
fig6 = go.Figure(data=[go.Table(
header=dict(values=list(df_table.columns),
fill_color='#d3d3d3',
align='left'),
cells=dict(values=[df_table['date'],
df_table['P/E_Ratio'],
df_table['Stock Price']],
fill_color='white',
align='left'))
])
As Juan correctly stated, adding height to fig6.update_layout() will do the trick. If you are however looking for a more dynamic workaround, you can use this function to calculate the height when input with a dataframe-
def calc_table_height(df, base=208, height_per_row=20, char_limit=30, height_padding=16.5):
'''
df: The dataframe with only the columns you want to plot
base: The base height of the table (header without any rows)
height_per_row: The height that one row requires
char_limit: If the length of a value crosses this limit, the row's height needs to be expanded to fit the value
height_padding: Extra height in a row when a length of value exceeds char_limit
'''
total_height = 0 + base
for x in range(df.shape[0]):
total_height += height_per_row
for y in range(df.shape[1]):
if len(str(df.iloc[x][y])) > char_limit:
total_height += height_padding
return total_height
You might have to play around with the other features if you have a different font_size than the default, or if you change the margin from the default. Also, the char_limit argument of the function is the other weakpoint as some characters take up more space than others, capital characters take up more space, and a single word if long can force a row to be extended. It should also be increased if the number or columns are less and vice versa. The function is written taking 4 table columns into consideration.
You would have to add fig6.update_layout(height=calc_table_height(df_table)) to make it work.
Suppose a column has two colors: white and green.
Task: Use openpyxl to select green cells.
I have read the official documentation Working with styles, but fail to figure out how to do it.
There are many minor questions: for example, how to figure out the code of current color?
Bellow is one possibility to set the (backgroud) color of a cell.
In this example, we use the openpyxl.styles.fills.PatternFill class.
It applies an uniform fill using a pattern (here, it is the "solid" pattern),
with a foreground color (green), and a background color (not visible
with the solid pattern, but visible with another like 'gray125').
You can also the the openpyxl.styles.fills.GradientFill class
to produce a gradient fill…
import openpyxl.styles
wb = load_workbook(xls_path)
ws = wb.active
cell = ws["A1"]
cell.fill = openpyxl.styles.PatternFill('solid', openpyxl.styles.colors.GREEN)
So, to get the color of the fill pattern, you can read the fill.fgColor
(or fill.bgColor for background) property.
You get an instance of openpyxl.style.Color class.
Call the rgb property (it’s a descriptor) to get the RGB color as string.
Note: this value has 4 component: the Alpha color (transparency) and the classic RGB colors.
color = cell.fill.fgColor
assert isinstance(color, openpyxl.styles.Color)
assert color.rgb == "0000FF00" # Green
But, all that won’t help you. Because columns have styles too.
A worksheet contains a collection of column_dimensions.
Each column_dimensions contains the properties (styles, etc.)
for one or several columns (the notion of column groups).
The min and max attributes of a column_dimensions give
the column indexes (start and end index of the group, starting at 1).
cd = ws.column_dimensions["A"]
assert cd.min == 1 and cd.max == 1
Like a cells, you can set the fill pattern of a columns:
cd.fill = openpyxl.styles.PatternFill('solid', openpyxl.styles.colors.GREEN)
Note: the cell style has higher priority over column style.
In other words, if you set the column style to white, but the cell style to green,
the user will see a green cell.
The columns of my QTableWidget do not fill in the space of the table, so that an empty space is left on the right hand-side. How to make the columns of my QTableWidget assume the maximum space so as to fill in this space?
The headers of the table have methods for controlling this:
header = table.horizontalHeader()
header.setStretchLastSection(True)
or:
header.setResizeMode(QHeaderView.Stretch)
I don't know of any method to set this property to the QTableWidget's content. However, I could use the following to get the columns to resize:
def resizeEvent(self, event):
self.setColumnWidth(0, event.size().width())
This resizes the first column only. To resize all columns, one should get all children item and apply column width / number of items.