Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resizing columns automatically to fit the frame if they would be smaller in total than the available space #227

Open
DoomOfMax97 opened this issue May 21, 2024 · 6 comments

Comments

@DoomOfMax97
Copy link

DoomOfMax97 commented May 21, 2024

Hello,

I have been trying a lot but I can't seem to make this happen reliably,
do you have any tips/ideas?

@DoomOfMax97 DoomOfMax97 changed the title Resizing columns automatically to fitt frame if they would be smaller in total than the available space Resizing columns automatically to fit the frame if they would be smaller in total than the available space May 21, 2024
@ragardner
Copy link
Owner

ragardner commented May 22, 2024

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?

@DoomOfMax97
Copy link
Author

DoomOfMax97 commented May 24, 2024

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:

  1. Calculate a weight for each column based on the largest of the first n cells of the current column.
  2. 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?

@ragardner
Copy link
Owner

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

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

@DoomOfMax97
Copy link
Author

DoomOfMax97 commented May 26, 2024

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)

ragardner added a commit that referenced this issue May 27, 2024
### Version 7.2.2
#### Added:
- Add functions to address [227](#227):
    - `get_column_text_width`
    - `get_row_text_height`
    - `visible_columns` - `@property`
    - `visible_rows` - `@property`

#### Changed:
- Internal parameter names:
    - `only_set_if_too_small` -> ` only_if_too_small`
- Internal function parameters:
    - `set_col_width`
    - `set_row_height`
@ragardner
Copy link
Owner

Hello,

Thanks for adding your code,

In version 7.2.2 I have added a few functions you may find useful:

Cheers

@DoomOfMax97
Copy link
Author

No worries,

looks good, will give them a try.

Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants