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

wxPython 4.2.0 ultimatelistctrl issue with floats in Rect() #2240

Closed
finchyfinch opened this issue Aug 18, 2022 · 6 comments · Fixed by #2415 · May be fixed by #2576
Closed

wxPython 4.2.0 ultimatelistctrl issue with floats in Rect() #2240

finchyfinch opened this issue Aug 18, 2022 · 6 comments · Fixed by #2415 · May be fixed by #2576

Comments

@finchyfinch
Copy link

Hi There,

WX Version: 4.2.0 msw (phoenix) wxWidgets 3.2.0, Python Version: 3.10.6 (tags/v3.10.6:9c7b4bd, Aug 1 2022, 21:53:49) [MSC v.1932 64 bit (AMD64)].

Using ultimatelistctrl in VirtualList setup. Finding it wont accept a ulc.ULC_FORMAT_CENTER for column definitions. Generates the following error;

Traceback (most recent call last):
File "C:\Python310\lib\site-packages\wx\lib\agw\ultimatelistctrl.py", line 5284, in OnPaint
self.DrawTextFormatted(dc, text, wx.Rect(xAligned+EXTRA_WIDTH, int(HEADER_OFFSET_Y), int(cw-EXTRA_WIDTH), int(h-4)))
TypeError: Rect(): arguments did not match any overloaded call:
overload 1: too many arguments
overload 2: argument 1 has unexpected type 'float'
overload 3: argument 1 has unexpected type 'float'
overload 4: argument 1 has unexpected type 'float'
overload 5: argument 1 has unexpected type 'float'
overload 6: argument 1 has unexpected type 'float'

To fix it I need to make the vars within the Rect() in the following line in def OnPaint(self, event): an integer;

From:
self.DrawTextFormatted(dc, text, wx.Rect(xAligned+EXTRA_WIDTH, HEADER_OFFSET_Y, cw-EXTRA_WIDTH, h-4))

To:

self.DrawTextFormatted(dc, text, wx.Rect(int(xAligned+EXTRA_WIDTH), int(HEADER_OFFSET_Y), int(cw-EXTRA_WIDTH), int(h-4)))

Then all is good.

@da-dada
Copy link

da-dada commented Aug 21, 2022

Python is dynamic but strongly typed language and an int is an int and a float is a float, no magic here, and that rigidity should have been pursued long ago (I'm sure that will peeve a lot of people)
but better they straighten that out than removing the dynamics: I love to use attributes on the fly, and the pressure to introduce declarations/public etc is huge

@finchyfinch
Copy link
Author

Just as some further clarification, the issue arises due to this section within ultimatelistctrl.py in the OnPaint function;
elif align == ULC_FORMAT_CENTER:
xAligned = x + wcheck + (cw - wLabel)/2

As I am using ULC_FORMAT_CENTER, its calculation is creating a float in xAligned and then that variable is being used further down in the Rect(). The /2 just needs to be changed to a //2 and all is well. For now as my workaround I am distributing a local copy of the custom control with the necessary patch until a future update / release is made.

@da-dada
Copy link

da-dada commented Aug 22, 2022

in the docu of Rect it clearly says int and that goes into another language, but the note on // (python 310) warns clearly that the result type may not be int
it's these imponderables that must be avoided, not so much within python but certainly at the API (I think)

@MGILSON72
Copy link

MGILSON72 commented Oct 4, 2022

I've hit a related issue that does not pertain to formatting, should a new issue be created for this?

File "...\venv\lib\site-packages\wx\lib\agw\ultimatelistctrl.py", line 5606, in HandleColumnCheck
rect = wx.Rect(theX + HEADER_OFFSET_X, HEADER_OFFSET_Y + (h - 4 - iy)/2, ix, iy)
TypeError: Rect(): arguments did not match any overloaded call:
overload 1: too many arguments
overload 2: argument 2 has unexpected type 'float'
overload 3: argument 1 has unexpected type 'int'
overload 4: argument 1 has unexpected type 'int'
overload 5: argument 1 has unexpected type 'int'
overload 6: argument 1 has unexpected type 'int'

Simple program to reproduce the issue:

import wx
import wx.lib.agw.ultimatelistctrl as ULC


class MainFrame(wx.Frame):

    def __init__(self):
        super().__init__(None, title="Test Rect Issue")
        self.SetSize((1250, 573))

        frame_sizer = wx.BoxSizer(wx.VERTICAL)

        self.panel = wx.Panel(self, wx.ID_ANY)
        panel_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, 'Test Rect Call'), wx.VERTICAL)
        panel_sizer.Add((0, 0), 0, 0, 0)
        panel_list_ctrl = UlcListCtrl(self.panel)
        panel_sizer.Add(panel_list_ctrl, 0, wx.ALL | wx.EXPAND, 3)
        self.panel.SetSizer(panel_sizer)

        frame_sizer.Add(self.panel, 0, wx.ALL | wx.EXPAND, 0)

        self.SetSizer(frame_sizer)
        frame_sizer.Fit(self)
        self.Layout()
        self.Center()

        # Display the frame
        self.Show()


class UlcListCtrl(ULC.UltimateListCtrl):

    def __init__(self, parent: wx.Panel, **kwargs):
        self.parent = parent

        kwargs['agwStyle'] = (
            wx.LC_REPORT | ULC.ULC_VRULES | ULC.ULC_HRULES | ULC.ULC_USER_ROW_HEIGHT | ULC.ULC_AUTO_CHECK_CHILD)

        super().__init__(parent, size=(400, 200), **kwargs)

        self.SetUserLineHeight(18)
        self._create_columns()

    def _create_columns(self) -> None:
        columns = [('', -1, 1), ('Col 1', 100, 0), ('Col 2', 100, 0), ('Col3', -3, 0)]
        for index, (column_name, width, kind) in enumerate(columns):
            column_item = self._create_list_item(column_name, kind)
            self.InsertColumnInfo(index, column_item)
            self.SetColumnWidth(index, width)

    @staticmethod
    def _create_list_item(column_name: str, kind: int) -> ULC.UltimateListItem:
        item = ULC.UltimateListItem()
        item.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_CHECK)
        item.SetAlign(ULC.ULC_FORMAT_LEFT)
        item.SetKind(kind)
        item.SetText(column_name)
        return item


if __name__ == '__main__':
    app = wx.App()
    frame = MainFrame()
    frame.Show()
    app.MainLoop()

As mentioned by @finchyfinch if you wrap all of the arguments to the wx.Rect method with an int the issue is resolved in python 3.10 or if you add floor division (//) it resolves the issue as well.

wx.Rect(int(theX + HEADER_OFFSET_X), int(HEADER_OFFSET_Y + (h - 4 - iy)/2), int(ix), int(iy))

or

wx.Rect(theX + HEADER_OFFSET_X, HEADER_OFFSET_Y + (h - 4 - iy)//2, ix, iy)

@RobinD42
Copy link
Member

This issue has been mentioned on Discuss wxPython. There might be relevant details there:

https://discuss.wxpython.org/t/questions-about-plans-for-4-2-1-release/36294/2

@RobinD42
Copy link
Member

This issue has been mentioned on Discuss wxPython. There might be relevant details there:

https://discuss.wxpython.org/t/facing-an-error-in-ultimatelistctrl-py-file-for-python-3-10-10/36696/2

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