Skip to content

Icon support for all columns in Winforms Table#4164

Merged
freakboy3742 merged 15 commits intobeeware:mainfrom
Oliver-Leigh:winforms-table-multi-column-icons
Feb 17, 2026
Merged

Icon support for all columns in Winforms Table#4164
freakboy3742 merged 15 commits intobeeware:mainfrom
Oliver-Leigh:winforms-table-multi-column-icons

Conversation

@Oliver-Leigh
Copy link
Copy Markdown
Contributor

Previously, the Windows version of the Table widget only supported icons in the first column. This update extends the functionality by allowing icons in all columns.

The functionality works as follows:

  • Enable the display of icons in all columns using the built-in Extended List-View style LVS_EX_SUBITEMIMAGES (detailed at https://learn.microsoft.com/en-us/windows/win32/controls/extended-list-view-styles)
  • The ListView object is in virtual mode, so the icons are set by intercepting and handling the LVN_GETDISPINFO message. (The standard way of handling these messages in C++ is detailed at
    https://learn.microsoft.com/en-us/windows/win32/controls/use-virtual-list-view-controls)
  • The LVN_GETDISPINFO messages are intercepted by subclassing the ListView object with the SetWindowSubclass function.
  • The icons of the Table entries are set using a new function _set_subitem_icon.
  • The text property of the Table entries utilises the existing .NET implementation with the RetrieveVirtualItem function.
  • Cached items are now a pair (ListViewItem, icon_indices) where icon_indices is a tuple containing the indices if the associated icons in the WinForms ListView icon list (-1 is used to indicate there is no icon).

PR Checklist:

  • All new features have been tested
  • All new features have been documented
  • I have read the CONTRIBUTING.md file
  • I will abide by the code of conduct

@mhsmith
Copy link
Copy Markdown
Member

mhsmith commented Feb 4, 2026

The CI log is showing a native crash, so there must be something wrong with the way you've used the native APIs. I'll switch this PR to draft status; once all the tests are passing, please post a comment and we'll take a look at it.

@mhsmith mhsmith marked this pull request as draft February 4, 2026 12:31
@Oliver-Leigh
Copy link
Copy Markdown
Contributor Author

@mhsmith The tests are passing now.

@mhsmith mhsmith marked this pull request as ready for review February 6, 2026 09:42
@mhsmith
Copy link
Copy Markdown
Member

mhsmith commented Feb 6, 2026

Thanks, but it looks like you've done some kind of a rebase which has caused this PR to include all of #4161 as well. We prefer not to rebase PRs after someone else has already seen them, as it makes it difficult to keep track of changes.

Merging from the main branch will probably resolve the situation.

@rkm and me will be out of office for the next week and a half, so reviews may take longer than normal. Any other team member is welcome to pick this PR up.

@Oliver-Leigh Oliver-Leigh force-pushed the winforms-table-multi-column-icons branch from 1f93398 to 465c0da Compare February 6, 2026 10:46
Copy link
Copy Markdown
Contributor

@johnzhou721 johnzhou721 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Welcome to Toga, BeeWare, and open-source development in general! It's quite exciting to see very advanced code contributions like this, especially as a first-timer. I'm impressed by your sheer Win32 knowledge.

[Disclaimer: I'm not part of the core team.]

I'm not as familiar as the internals of Windows as you are (by the way: #2574 may be something you're interested in if you're this into Windows development) — and I haven't had the time to actually test this, but I do have a few suggestions.

Comment thread changes/4164.feature.md Outdated
Comment thread winforms/src/toga_winforms/widgets/table.py Outdated
Comment thread winforms/src/toga_winforms/widgets/table.py
Comment on lines +185 to +207
def _subclass_proc(
self,
hWnd: int,
uMsg: int,
wParam: int,
lParam: int,
uIdSubclass: int,
dwRefData: int,
) -> LRESULT:
# Remove the window subclass in the way recommended by Raymond Chen here:
# https://devblogs.microsoft.com/oldnewthing/20031111-00/?p=41883
if uMsg == WM_NCDESTROY:
RemoveWindowSubclass(hWnd, self.pfn_subclass, uIdSubclass)

if uMsg == WM_REFLECT_NOTIFY:
phdr = cast(lParam, POINTER(NMHDR)).contents
code = phdr.code
if hex(code) == hex(LVN_GETDISPINFOW):
disp_info = cast(lParam, POINTER(NMLVDISPINFOW)).contents
self._set_subitem_icon(disp_info.item)

# Call the original window procedure
return DefSubclassProc(HWND(hWnd), UINT(uMsg), LPARAM(wParam), LPARAM(lParam))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested on line 18, this may be worth moving to the libs module you create if manually doing this helper is warranted.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to leave this here. I think that window procedure callback functions are usually defined in the classes that they are used. Also, here the messages LVN_GETDISPINFOW are specific to a ListView object in virtual mode.

)
self.add_action_events()

def _enable_multi_icon_style(self):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is only called once. Would it be too tedious to inline it into where this is called?

P.S. same applies for _set_subitem_icon

@Oliver-Leigh
Copy link
Copy Markdown
Contributor Author

Thanks for the review and suggestions @johnzhou721 ! I'll look over them and make some changes

@rkm
Copy link
Copy Markdown

rkm commented Feb 9, 2026

@mhsmith I think you have the wrong user 🙂

@freakboy3742
Copy link
Copy Markdown
Member

@mhsmith I think you have the wrong user 🙂

Apologies for the stray ping - @mhsmith meant me :-)

@johnzhou721
Copy link
Copy Markdown
Contributor

johnzhou721 commented Feb 13, 2026

@Oliver-Leigh FYI -- by this point I'm satisfied with the overall structures of the things you've done. Feel free to ask the core team for a review [once tests are passing].

Copy link
Copy Markdown
Member

@freakboy3742 freakboy3742 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely testing the limits of my Win32 API knowledge, but I can't argue with success - and you've evidently picked up some edge case bugs in TextInput as well. Thanks for the PR! I've pushed one minor tweak to the changenote, and removed the documentation

If you're sufficiently familiar with Win32 APIs to get this working, could I tempt you to fill the one big gap in our Winforms backend? The Tree widget is the one notable widget we're missing on Winforms - we've held off because the "out of the box" Winforms tree doesn't allow multiple columns of data. I've been led to believe that this might be fixable with some Win32 magic, but that's well outside my comfort zone. If this is an area where you have expertise, a contribution would be hugely appreciated.

Comment thread changes/4164.feature.md Outdated
@@ -0,0 +1 @@
The Table widget on WinForms can now display icons in all columns. Previously, icons were only supported in the first column. Changes to the tests have also been made to test the new structure.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The Table widget on WinForms can now display icons in all columns. Previously, icons were only supported in the first column. Changes to the tests have also been made to test the new structure.
The Table widget on WinForms can now display icons in all columns. Previously, icons were only supported in the first column.

@freakboy3742 freakboy3742 merged commit 473a5f1 into beeware:main Feb 17, 2026
57 checks passed
@Oliver-Leigh
Copy link
Copy Markdown
Contributor Author

If you're sufficiently familiar with Win32 APIs to get this working, could I tempt you to fill the one big gap in our Winforms backend? The Tree widget is the one notable widget we're missing on Winforms - we've held off because the "out of the box" Winforms tree doesn't allow multiple columns of data. I've been led to believe that this might be fixable with some Win32 magic, but that's well outside my comfort zone. If this is an area where you have expertise, a contribution would be hugely appreciated.

It definitely looks possible! I’m not sure whether it can be a modified .NET approach (like here), or whether it has to be a full blown Win32 approach. I have a Win32 base proof of concept for the detailed list widget which I’ll be posting shortly. I’ll look into the tree widget once that’s done.

@freakboy3742
Copy link
Copy Markdown
Member

@Oliver-Leigh Awesome news - I look forward to seeing both widgets :-)

I'll freely admit that Windows support is an area where we (as a project) aren't strong. John has already mentioned #2574 and the WinUI3 backend; see #4204 for a summary of the bigger picture issues we're facing. Any expertise you've got in the area that you're willing to volunteer is gratefully accepted.

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

Successfully merging this pull request may close these issues.

5 participants