How to determine the column from a mouse event in wx.ListCtrl

Hi again,

I am trying to find the column in a wx.ListCtrl (report mode, obviously)
to provide the right context menu to the user. There is
wx.ListCtrl.HitTestSubItem which should do this according to this
thread: http://markmail.org/message/pd5mlozlvlemy7n4

The documentation
http://www.wxpython.org/docs/api/wx.ListCtrl-class.html#HitTestSubItem
is a bit unclear, as it is the only place where subitems are mentioned
in comparison to columns. Apart from that, the wrapped HitTest method
does not compute the column, it is marked as a TODO here:
http://trac.wxwidgets.org/browser/wxWidgets/branches/WX_2_8_BRANCH/src/generic/listctrl.cpp?rev=63218#L5570

This is why I always get some kind of random number for the column value
in the tuple. I ended up using the code from the mailing list discussion
above, but it turned out that this does not work in all cases: With
scrolling, computing the column manually is off by the amount scrolled.

I ended up accounting for the scrollbar position, by calling
GetScrollPos and GetScrollPixelsPerUnit on the MainWindow of the list
control (see attached code). These should be implementation details of
the ListCtrl, therefore I dislike this approach. Is there a more
official way to find out the column from a mouse event?

Thanks, Torsten

demo_list.py (1.81 KB)

···

--
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landschoff@dynamore.de
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director: Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

The list control can be hard to deal with due to its complexity and
non-obvious way of doing things. I personally try to use
ObjectListView whenever possible instead of the list control.
Fortunately for you, I still have some old code that I use that shows
how to access the column number.

All you need to do is access the event object's "m_col" property in
your event handler:

event.m_col

I can't remember if the m_col is zero-based or not, so watch out for
off-by-one errors.

···

On Jul 14, 7:58 am, Torsten Landschoff <torsten.landsch...@dynamore.de> wrote:

Hi again,

I am trying to find the column in a wx.ListCtrl (report mode, obviously)
to provide the right context menu to the user. There is
wx.ListCtrl.HitTestSubItem which should do this according to this
thread:http://markmail.org/message/pd5mlozlvlemy7n4

The documentationhttp://www.wxpython.org/docs/api/wx.ListCtrl-class.html#HitTestSubItem
is a bit unclear, as it is the only place where subitems are mentioned
in comparison to columns. Apart from that, the wrapped HitTest method
does not compute the column, it is marked as a TODO here:wxTrac has been migrated to GitHub Issues - wxWidgets

This is why I always get some kind of random number for the column value
in the tuple. I ended up using the code from the mailing list discussion
above, but it turned out that this does not work in all cases: With
scrolling, computing the column manually is off by the amount scrolled.

I ended up accounting for the scrollbar position, by calling
GetScrollPos and GetScrollPixelsPerUnit on the MainWindow of the list
control (see attached code). These should be implementation details of
the ListCtrl, therefore I dislike this approach. Is there a more
official way to find out the column from a mouse event?

Thanks, Torsten

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

Hi Mike,

The list control can be hard to deal with due to its complexity and
non-obvious way of doing things. I personally try to use
ObjectListView whenever possible instead of the list control.
Fortunately for you, I still have some old code that I use that shows
how to access the column number.

All you need to do is access the event object's "m_col" property in
your event handler:

event.m_col

I can't remember if the m_col is zero-based or not, so watch out for
off-by-one errors.

Thanks for your reply, Mike! I looked into m_col of the ListEvent, and
it turns out that this is always zero here. As it seems that it worked
for you, I digged deeper. It turns out that the MSW implementation of
wxWidgets actually implements subitem indices. It also explains where
the wording of the documentation comes from: The Windows API calls the
columns subitems: Microsoft Learn: Build skills that open doors in your career
28v=VS.85%29.aspx

For event processing, the controls library actually passes NMLISTVIEW
structures: Microsoft Learn: Build skills that open doors in your career
29.aspx

These also contain the subitem indices and are used in wxWidgets for
example for the LVN_COLUMNCLICK event - here:
http://trac.wxwidgets.org/browser/wxWidgets/branches/WX_2_8_BRANCH/src/msw/listctrl.cpp?rev=57021#L2073

I was unable to track how and if m_col is initialized for mouse clicks
on columns of an item. But it seems that the generic ListCtrl (which is
used for the GTK+ backend on Linux) does not initialize m_col in any
case.

Thanks for the pointer to the ObjectListView. I checked the source to
find out how it does subitem lookup. Turns out that it uses the
HitTestSubItem which is not implemented for Linux/GTK+:

(look for line 1663).

So subitem indexing works on Windows (I presume) and wx uses the native
control there. On Linux/GTK+ a generic implementation of the list
control is used which lacks this feature.

Greetings, Torsten

···

On Wed, 2010-07-14 at 07:11 -0700, Mike Driscoll wrote:

--
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landschoff@dynamore.de
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director: Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

Torsten Landschoff wrote:

Hi Mike,

The list control can be hard to deal with due to its complexity and
non-obvious way of doing things. I personally try to use
ObjectListView whenever possible instead of the list control.
Fortunately for you, I still have some old code that I use that shows
how to access the column number.

All you need to do is access the event object's "m_col" property in
your event handler:

event.m_col

I can't remember if the m_col is zero-based or not, so watch out for
off-by-one errors.
    
Thanks for your reply, Mike! I looked into m_col of the ListEvent, and
it turns out that this is always zero here. As it seems that it worked
for you, I digged deeper. It turns out that the MSW implementation of
wxWidgets actually implements subitem indices. It also explains where
the wording of the documentation comes from: The Windows API calls the
columns subitems: Microsoft Learn: Build skills that open doors in your career
28v=VS.85%29.aspx

For event processing, the controls library actually passes NMLISTVIEW
structures: Microsoft Learn: Build skills that open doors in your career
29.aspx

These also contain the subitem indices and are used in wxWidgets for
example for the LVN_COLUMNCLICK event - here:
wxTrac has been migrated to GitHub Issues - wxWidgets

I was unable to track how and if m_col is initialized for mouse clicks
on columns of an item. But it seems that the generic ListCtrl (which is
used for the GTK+ backend on Linux) does not initialize m_col in any
case.

Thanks for the pointer to the ObjectListView. I checked the source to
find out how it does subitem lookup. Turns out that it uses the
HitTestSubItem which is not implemented for Linux/GTK+:

ObjectListView download | SourceForge.net
(look for line 1663).

So subitem indexing works on Windows (I presume) and wx uses the native
control there. On Linux/GTK+ a generic implementation of the list
control is used which lacks this feature.

Greetings, Torsten

All interesting information.

Note that HitTestSubItem method in ObjectListView (line 1298) would also work on Linux
(was that implicit in your message or not ?). It loops through the columns, and gets the subitem
index by using their width.

Raphael

···

On Wed, 2010-07-14 at 07:11 -0700, Mike Driscoll wrote:

I have to admit that I did not notice that the ObjectListView overrides
HitTestSubItem. So it should in fact work on Linux, but looking at the
code I have to doubt it: It uses the result of GetScrollPos on the list
control, which returns some scaled value here, not pixels.

In fact, GetScrollPos on the list control just proxies for GetScrollPos
on the main window of the list inside wxWidgets, which is scaled by the
scroll pixels per unit (happens to be 15 pixels/unit here).

I just adapted the ObjectListView demo and ran a few tests and in fact
the hit test returns the wrong column when scrolling horizontally. Most
of the time, there will be no horizontal scroll bar though when used as
in the example, as there is a column that resizes itself to remove the
scroll bar.

Greetings, Torsten

···

Am Mittwoch, den 14.07.2010, 14:16 -0700 schrieb Raphael Mayoraz:

All interesting information.

Note that HitTestSubItem method in ObjectListView (line 1298) would also
work on Linux
(was that implicit in your message or not ?). It loops through the
columns, and gets the subitem
index by using their width.

--
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landschoff@dynamore.de
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director: Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

Hopefully the author of ObjectListView is watching this thread and
will be able to patch a fix into the code. Or Robin might have some
ideas on how to make the normal Listctrl work.

Cross your fingers!

An alternative may be the UltimateListCtrl, which was added in 2.8.11.
I didn't mention it last time because I don't think it's had extensive
testing on Linux. However, it's pure Python, not SWIGGed C++, so it
should be easier to hack...theoretically anyway.

···

On Jul 15, 1:30 am, Torsten Landschoff <torsten.landsch...@dynamore.de> wrote:

Am Mittwoch, den 14.07.2010, 14:16 -0700 schrieb Raphael Mayoraz:

> All interesting information.

> Note that HitTestSubItem method in ObjectListView (line 1298) would also
> work on Linux
> (was that implicit in your message or not ?). It loops through the
> columns, and gets the subitem
> index by using their width.

I have to admit that I did not notice that the ObjectListView overrides
HitTestSubItem. So it should in fact work on Linux, but looking at the
code I have to doubt it: It uses the result of GetScrollPos on the list
control, which returns some scaled value here, not pixels.

In fact, GetScrollPos on the list control just proxies for GetScrollPos
on the main window of the list inside wxWidgets, which is scaled by the
scroll pixels per unit (happens to be 15 pixels/unit here).

I just adapted the ObjectListView demo and ran a few tests and in fact
the hit test returns the wrong column when scrolling horizontally. Most
of the time, there will be no horizontal scroll bar though when used as
in the example, as there is a column that resizes itself to remove the
scroll bar.

Greetings, Torsten

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org