wxPython 4.0.2

Roland King:

So the replacement for NewID is to reserve an ID, or more, from NewControlID.
It won’t conflict with legacy code which uses NewID [...]
What sequence of events makes you think that NewControlId is not a viable replacement for NewID?

I can't very well use NewId in code originally written prior to last week (a.k.a. "legacy code") if it doesn't exist any more.
If wx.NewId is going out, then I have to do something about the >100 occurrences of wx.NewId in the code I'm maintaining. Timers and custom events, mostly.

So the question I was looking for an answer to is this: Can I simply search-replace NewId into NewControlId? And my conclusion was no, that will not work, because the id's will go back into the pool when the first wx thing using them is destroyed, and the second time I create a wx thing using the same id, it's a bug because that id is not actually reserved any more.

For example:

EVT_SYNC_ID = wx.NewId()
class MyFrame(wx.Frame):
     def __init__(self, ...):
        self._sync_timer = wx.Timer(self, EVT_SYNC_ID)
        self.Bind(wx.EVT_TIMER, self.OnSyncTimer, id=EVT_SYNC_ID)

I can't replace wx.NewId with wx.Window.NewControlId here, because when the first MyFrame instance is destroyed, and the timer with it, then EVT_SYNC_ID will be unreserved, and when the second instance is created, it will be using a rogue unreserved id.

NewId is not strictly needed here, there is a rewrite to avoid any explicit allocation:

class MyFrame(wx.Frame):
     def __init__(self, ...):
        self._sync_timer = wx.Timer(self, -1)
        self.Bind(wx.EVT_TIMER, self.OnSyncTimer, id=self._sync_timer.GetId())

I don't like to rewrite working code, but it may come to that.

Wrt. the other typical use, custom events, I think they are safe because in this case the id is never actually passed to wx.Window.__init__ or similar, they're only passed to wx.PyEvent.SetEventType and wx.Window.Connect, and I don't see them unreserving anything.

regards, Anders

Since timers have a GetId method then they can be used as the source argument for Bind. So another style of rewrite could be this, which IMO is a little cleaner:

class MyFrame(wx.Frame):

 def __init__(self, ...): 

    self._sync_timer = wx.Timer(self, -1) 

    self.Bind(wx.EVT_TIMER, self.OnSyncTimer, self._sync_timer) 

But there is a change on the way (4.0.3 in a day or two) that will provide a better replacement for wx.NewId, so your migration pain will be alleviated a little more with that. See my forthcoming message in this thread for more info about that.

···

On Monday, June 25, 2018 at 8:44:50 AM UTC-7, Anders Munch wrote:

So the question I was looking for an answer to is this: Can I simply search-replace NewId into NewControlId? And my conclusion was no, that will not work, because the id’s will go back into the pool when the first wx thing using them is destroyed, and the second time I create a wx thing using the same id, it’s a bug because that id is not actually reserved any more.

For example:

EVT_SYNC_ID = wx.NewId()

class MyFrame(wx.Frame):

 def __init__(self, ...):

    self._sync_timer = wx.Timer(self, EVT_SYNC_ID)

    self.Bind(wx.EVT_TIMER, self.OnSyncTimer, id=EVT_SYNC_ID)

I can’t replace wx.NewId with wx.Window.NewControlId here, because when the first MyFrame instance is destroyed, and the timer with it, then EVT_SYNC_ID will be unreserved, and when the second instance is created, it will be using a rogue unreserved id.

NewId is not strictly needed here, there is a rewrite to avoid any explicit allocation:

class MyFrame(wx.Frame):

 def __init__(self, ...):

    self._sync_timer = wx.Timer(self, -1)

    self.Bind(wx.EVT_TIMER, self.OnSyncTimer, id=self._sync_timer.GetId())

Robin

I just looked at the wx source to see if it really was dumb enough to release window ids which it didn’t assign itself and … it actually is … which was an unfortunate design choice.

http://docs.wxwidgets.org/3.1/overview_windowids.html

That led me to wxWindowIDRef and it was clear you needed to create and hold one of those with the id if you wanted to use it in wx windows and not have it released for you (ie you effectively manually keep a refcount to it) and then I just saw Robin’s mail this morning saying he’d implemented wxNewID to do exactly that.

Still don’t see a lot of use cases for not just using wxID_ANY (the only one came to my mind was if you wanted a contiguous range to bind) but that certainly seems to address the issue. I assume if you do allocate yourself a range and want to use them for window ids you’ll have to create a window id ref for them, ie do what the wxNewID does.

···

On 25 Jun 2018, at 23:44, Anders Munch ajm@flonidan.dk wrote:

Roland King:

So the replacement for NewID is to reserve an ID, or more, from NewControlID.
It won’t conflict with legacy code which uses NewID […]
What sequence of events makes you think that NewControlId is not a viable replacement for NewID?

I can’t very well use NewId in code originally written prior to last week (a.k.a. “legacy code”) if it doesn’t exist any more.
If wx.NewId is going out, then I have to do something about the >100 occurrences of wx.NewId in the code I’m maintaining. Timers and custom events, mostly.

So the question I was looking for an answer to is this: Can I simply search-replace NewId into NewControlId? And my conclusion was no, that will not work, because the id’s will go back into the pool when the first wx thing using them is destroyed, and the second time I create a wx thing using the same id, it’s a bug because that id is not actually reserved any more.

For example:

EVT_SYNC_ID = wx.NewId()
class MyFrame(wx.Frame):
def init(self, …):
self._sync_timer = wx.Timer(self, EVT_SYNC_ID)
self.Bind(wx.EVT_TIMER, self.OnSyncTimer, id=EVT_SYNC_ID)

I can’t replace wx.NewId with wx.Window.NewControlId here, because when the first MyFrame instance is destroyed, and the timer with it, then EVT_SYNC_ID will be unreserved, and when the second instance is created, it will be using a rogue unreserved id.

NewId is not strictly needed here, there is a rewrite to avoid any explicit allocation:

class MyFrame(wx.Frame):
def init(self, …):
self._sync_timer = wx.Timer(self, -1)
self.Bind(wx.EVT_TIMER, self.OnSyncTimer, id=self._sync_timer.GetId())

I don’t like to rewrite working code, but it may come to that.

Wrt. the other typical use, custom events, I think they are safe because in this case the id is never actually passed to wx.Window.init or similar, they’re only passed to wx.PyEvent.SetEventType and wx.Window.Connect, and I don’t see them unreserving anything.

regards, Anders


You received this message because you are subscribed to the Google Groups “wxPython-users” group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.