tksheet
tksheet copied to clipboard
Resizing columns automatically to fit the frame if they would be smaller in total than the available space
Hello,
I have been trying a lot but I can't seem to make this happen reliably, do you have any tips/ideas?
Hi there,
Have you tried the option auto_resize_columns= which resizes them to an int amount of pixels?
Or do you mean resizing them to fit the cell text rather than a width in pixels?
In my testing just now
self.set_options(auto_resize_columns=self.winfo_width(), redraw=True)
self.redraw(True, True)
seems to work for resizing a single column correctly, but not if you have multiple,
there could be an issue with my subclass though.
The idea is, at least that's what my code tried to do initially is:
- Calculate a weight for each column based on the largest of the first n cells of the current column.
- If winfo_width() < sum(weights): 2a. Set each column to size "weight", they won't fit, but have an efficient column width 2b. Multiply each weight by winfo_width()/sum(weights) and fudge the last one, so all columns get resized to fit the frame
Is there a good/an easier way to do this?
Sorry about the confusion with auto_resize... you can find the docs here: https://github.com/ragardner/tksheet/wiki/Version-7#auto-resize-column-widths-to-fit-the-window
Basically the value is for the minimum width in pixels of each individual column, so you could set this to 50 for example
About your question, I'm afraid I can only point to the relevant functions at the moment, especially the one below
- https://github.com/ragardner/tksheet/wiki/Version-7#set-or-get-a-specific-column-width
There is an internal function in the ColumnHeaders class, accessible from the Sheet() class, but considering the things above I might have to make changes to it in the future so maybe you don't want to use it,
self.CH.set_col_width(
col=column int,
width=None, # set to text size
only_set_if_too_small=False,
displayed_only=True, # if you have a lot of rows
return_new_width=True or False, # when True this will not set the column width but return the width it was going to be set to
)
Looking at the available Sheet() functions and their uses I think there is a lack of functionality, such as text measuring functionality for columns, getting the currently visible columns, etc. This would make work like yours a lot easier
I will have to add some more functions for dealing with row heights / column widths, they may not have the functionality you seek above but by using them maybe you'll get to what you want. I can't offer a timeframe on this work though sorry
I see, thank you for your help anyways. This is my current code, maybe it helps you in any way.
def resize_columns_to_fit(self, n=5):
minimum_scale_factor = 15
scrollbar_width = 17
if (self._headers is None
or self._is_shown is False
or self._show_mode == NO_DATA):
return
# Calculate the weight for each column based on the largest of the first n cells
weights = []
for col_idx in range(len(self._headers)):
# Get the first n cells in the current column
col_data = [len(str(self._data[row_idx][col_idx])) for row_idx in range(min(n, len(self._data)))]
# Include the header in the calculation
col_data.append(len(str(self._headers[col_idx])))
# Calculate the weight based on the largest item
max_width = max(col_data)
weights.append(max_width)
# Get the width of the sheet widget
root_window.update_idletasks() # Ensure the window is updated before getting its width
winfo_width = self._sheet.winfo_width()
total_weight = sum(weights)
# Proportionally adjust the weights to fit the widget width
if total_weight == 0:
scale_factor = minimum_scale_factor
else:
scale_factor = max(winfo_width / total_weight, minimum_scale_factor)
weights = [int(weight * scale_factor) for weight in weights]
# Adjust the last column to ensure the total width matches the widget width
if scale_factor > minimum_scale_factor:
weights[-1] += winfo_width - sum(weights)
if len(self._headers) == 1:
self._sheet.set_all_column_widths(weights[-1] - scrollbar_width)
return
# Set each column width
for col_idx, weight in enumerate(weights):
self._sheet.column_width(col_idx, weight)
Hello,
Thanks for adding your code,
In version 7.2.2 I have added a few functions you may find useful:
visible_rowse.g.start_row, end_row = self._sheet.visible_rows(it's a property)visible_columnse.g.start_column, end_column = self._sheet.visible_columns(it's a property)get_row_text_height- https://github.com/ragardner/tksheet/wiki/Version-7#get-a-rows-text-heightget_column_text_width- https://github.com/ragardner/tksheet/wiki/Version-7#get-a-columns-text-width
Cheers
No worries,
looks good, will give them a try.
Thank you
I can't seem to adjust the width of a column. sheet.get_column_widths() indicates that the widths have changed, but there is no change on the screen. I am not using autosizing. (This is without default_column_width, which does change the column widths on screen when it is not commented out.) This is what I have tried: self.mileage_table.column_width( column=5, width=400, redraw=True) Is my syntax correct?
Your syntax appears to be correct make sure you havent used auto_resize_columns or max_column_width and check you're using the latest version of the library
I tried using the function in the same way and all seems ok, I also had a quick look over the code involved and nothing seems wrong
If you want to post more code or if you can manage to reproduce the issue in a minimal example I could take a look
Kind regards
I moved the column_width code to after I populate the sheet with data and it resized correctly. Thanks for the really quick response!
What does the iterator in the below code look like? Can I resize all columns to a different value with it?
set_column_widths( column_widths: Iterator[int, float] | None = None, canvas_positions: bool = False, reset: bool = False, ) -> Sheet
any object you can iterate over, lists, tuples, generators
from itertools import repeat
.set_column_widths(repeat(400, 5))