Get selected column in virtual wxListCtrl Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
csc81
In need of some credit
In need of some credit
Posts: 5
Joined: Mon Feb 02, 2009 4:44 pm
Contact:

Get selected column in virtual wxListCtrl

Post by csc81 »

wx-Version: 2.8.9.0 - GTK


Hi :)

I'm having a virtual wxListCtrl in report mode (wxLC_REPORT and wxLC_VIRTUAL). The list has 5 columns and approximately 1000000 rows.

The problem: I would like to get the column number of the item (not the header) the user clicked on. I tried the following code which is part of my overloaded wxListCtrl.

...
void MyListCtrl::OnSelected(wxListEvent& event) {
long col = event.getColumn(); // PROBLEM: Always returned 0!!
wxLogMessage(wxT("Currently selected item: col=%ld"), col);
}
...

Is this even possible with wxListCtrl?
-- Experience is what you get if you don't get what you want.
JimFairway
wxWorld Domination!
wxWorld Domination!
Posts: 1059
Joined: Sun Dec 30, 2007 6:40 pm
Location: Canada

Post by JimFairway »

Hi,

According to the docs, the column is only valid for column events.
http://docs.wxwidgets.org/stable/wx_wxl ... tgetcolumn

wxListItem::GetColumn says it's useful for report mode, so you should be able it get the column by getting the item first.
See http://docs.wxwidgets.org/stable/wx_wxl ... mgetcolumn

Hope that helps,

Jim

ps. Welcome to the forum, it's best to use the code tags to improve the readability of your posts.
OS: Vista SP1, wxWidgets 2.8.7.
csc81
In need of some credit
In need of some credit
Posts: 5
Joined: Mon Feb 02, 2009 4:44 pm
Contact:

Post by csc81 »

Hi Jim :)

Thanks for your quick reply. The links you sent were quite useful and now I understand why it does not work the way I tried.

If I got it right, you proposed to get the item first and then the column from the item. I thought about it but have no idea how this can solve my problem.

Actually, what I want the user to do is:

The user selects one row in the wxListCtrl. This row has several columns. Then the user clicks right - lets say to the third column in this row. A popup window opens and then the user can select "Copy" from the popup menu. Then, finally, the content from the cell where the user clicked on should be copied to the clipboard (The wxListCtrl only contains text).

I have already implemented the popup menu and the clipboard mechanism. What I would need now is a way to get the text from the cell where the user clicked on.
-- Experience is what you get if you don't get what you want.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

You could try iterating over the column widths and compare it with the x-position of the mouse click:

Code: Select all

void myListCtrl::OnItemRightClick(wxListEvent& event)
{
  int column;
  int x=0;
  for(column=0; column<GetColumnCount(); column++) {
    x+=GetColumnWidth(column);
    if(x>=event.GetPoint().x) break;
   }
   wxLogDebug( wxT("column clicked: %d"), column);
}
The docs say that GetPoint() is only valid for drag events, but i tested it on MSW and it also works here. But this may not be guaranteed on other platforms.
Use the source, Luke!
csc81
In need of some credit
In need of some credit
Posts: 5
Joined: Mon Feb 02, 2009 4:44 pm
Contact:

Post by csc81 »

Hej!

Thanks, that's a cool idea. I tried out your piece of code in my program and it works if there is no horizontal scrollbar in the wxListCtrl.

Now, the problem is that

Code: Select all

event.GetPosition().x
only gives the distance from the x-position of the wxListCtrl to the mouse pointers x position. So if someone scrolls to the right, the x-position of the wxListCtrl does not change of course. In this case the calculated column number becomes wrong.

So far, I tried to get the amount of pixels the user scrolled with

Code: Select all

GetScrollPos(wxHORIZONTAL)
(which is part of the wxWindow class). Unfortunately, this method only returns "scroll units" and not pixels.

Is there a way to compute the amount of pixels from this "scroll units"?

Or is there maybe a much easier way to get the correct distance-value?

My code so far:

Code: Select all

void ProblemListCtrl::OnContextMenu(wxContextMenuEvent& event) {
	wxPoint point = event.GetPosition();
	int column;
	int x=0;
	
	for(column=0; column<GetColumnCount(); column++) {
		x+=this->GetColumnWidth(column);
		
		// FIXME: point.x does not contain scrolled region :(
		if(x >= point.x ) break;
	}

	...
}
-- Experience is what you get if you don't get what you want.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

i tested it and the value returned from GetScrollPos() seemed to be in pixels. What platform are you on?

In my test i just replaced the line

Code: Select all

int x=0;
with

Code: Select all

int x = -GetScrollPos(wxHORIZONTAL);
Use the source, Luke!
csc81
In need of some credit
In need of some credit
Posts: 5
Joined: Mon Feb 02, 2009 4:44 pm
Contact:

Post by csc81 »

Hi!

Hm, this is strange :?

My system is: Linux / wxGTK.
'wx-config --basename --version --libs' returns:

2.8.9
wx_gtk2
-L/home/schmica/Applications//lib -pthread -lwx_gtk2_richtext-2.8 -lwx_gtk2_aui-2.8 -lwx_gtk2_xrc-2.8 -lwx_gtk2_qa-2.8 -lwx_gtk2_html-2.8 -lwx_gtk2_adv-2.8 -lwx_gtk2_core-2.8 -lwx_base_xml-2.8 -lwx_base_net-2.8 -lwx_base-2.8

One scroll unit returned by

Code: Select all

GetScrollPos(wxHORIZONTAL)
approximately corresponds to 15 pixels. Of course I could calculate from this value to the pixel count but this would be more a hack than a solution.

I also tried to find a correlation to the scroll thumb

Code: Select all

GetScrollThumb(wxHORIZONTAL)
but this method always returns 0.

So do I maybe have care about the scrollbar of the wxListCtrl by myself?
-- Experience is what you get if you don't get what you want.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

One scroll unit returned by

Code: Select all

GetScrollPos(wxHORIZONTAL)
approximately corresponds to 15 pixels. Of course I could calculate from this value to the pixel count but this would be more a hack than a solution.
the Linux version uses the generic listctrl, while MSW has a native one.

I checked the source and the generic version has a hardcoded value of 15, so your observation was correct.

Code: Select all

static const int SCROLL_UNIT_X = 15;
Unfortunately in the wxListCtrl interface these values are not exposed. So you probably have to use a little hack here.
Use the source, Luke!
csc81
In need of some credit
In need of some credit
Posts: 5
Joined: Mon Feb 02, 2009 4:44 pm
Contact:

Post by csc81 »

Hm okej, if there is no official way to solve the problem at the moment it at least doesn't feel so bad to make a hack here :wink: Maybe a better way will be provided in future releases of wx...

Thank you very much for your help!
-- Experience is what you get if you don't get what you want.
shawnee
Experienced Solver
Experienced Solver
Posts: 78
Joined: Tue Jan 16, 2018 1:05 am

Re:

Post by shawnee »

doublemax wrote:You could try iterating over the column widths and compare it with the x-position of the mouse click:

Code: Select all

void myListCtrl::OnItemRightClick(wxListEvent& event)
{
  int column;
  int x=0;
  for(column=0; column<GetColumnCount(); column++) {
    x+=GetColumnWidth(column);
    if(x>=event.GetPoint().x) break;
   }
   wxLogDebug( wxT("column clicked: %d"), column);
}
The docs say that GetPoint() is only valid for drag events, but i tested it on MSW and it also works here. But this may not be guaranteed on other platforms.
Hi doublemax,
Does event.GetPoint().x really work? In my codes, it always 0.
I checked the header file in v3.1, GetPoint() returns the value of m_pointDrag. It seems not mouse clicking position.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Re:

Post by doublemax »

shawnee wrote:Does event.GetPoint().x really work? In my codes, it always 0.
I checked the header file in v3.1, GetPoint() returns the value of m_pointDrag. It seems not mouse clicking position.
Like i wrote:
The docs say that GetPoint() is only valid for drag events, but i tested it on MSW and it also works here. But this may not be guaranteed on other platforms.
If it doesn't work under GTK, use ScreenToClient( ::wxGetMousePosition() )
Use the source, Luke!
shawnee
Experienced Solver
Experienced Solver
Posts: 78
Joined: Tue Jan 16, 2018 1:05 am

Re: Re:

Post by shawnee »

doublemax wrote:
shawnee wrote:Does event.GetPoint().x really work? In my codes, it always 0.
I checked the header file in v3.1, GetPoint() returns the value of m_pointDrag. It seems not mouse clicking position.
Like i wrote:
The docs say that GetPoint() is only valid for drag events, but i tested it on MSW and it also works here. But this may not be guaranteed on other platforms.
If it doesn't work under GTK, use ScreenToClient( ::wxGetMousePosition() )
I used ScreenToClient( ::wxGetMousePosition() ), then done. Thank you!
shawnee
Experienced Solver
Experienced Solver
Posts: 78
Joined: Tue Jan 16, 2018 1:05 am

Re: Get selected column in virtual wxListCtrl

Post by shawnee »

I found this trick is not effective under Win7! :-(
stevie_wonder
In need of some credit
In need of some credit
Posts: 1
Joined: Wed Mar 22, 2023 8:48 am

Re: Get selected column in virtual wxListCtrl

Post by stevie_wonder »

Just to complete a lot of the input made on this page. My cross platform code.

Code: Select all

int ListControl_GetColumnFromPosition(wxListCtrl* pList, int PositionX)
{
	int column = 0;
	if (pList == NULL) return -2;
	int x = -(pList->GetScrollPos(wxHORIZONTAL));
	for (column = 0; column < pList->GetColumnCount(); column++) {
		x += pList->GetColumnWidth(column);
		if (x >= PositionX) break;
	}
	if (!(column < pList->GetColumnCount())) return -1;
	return column;
}

void MainFrame::OnMouseDown(wxMouseEvent& event)
{
	int col = -1;
	if (theLiscontrol)
	{
	int CurrentX = 0;
#ifndef __unix__
	CurrentX = event.GetX();
#else
	CurrentX = ScreenToClient(::wxGetMousePosition()).x;
#endif
	col = ListControl_GetColumnFromPosition(theLiscontrol, CurrentX);
	}
	event.Skip();
}

void MainFrame::CreateComponents()
{
	if (theListcontrol) theListcontrol->Bind(wxEVT_LEFT_DCLICK, wxMouseEventHandler(MainFrame::OnMouseDown), this);
}
Last edited by DavidHart on Wed Mar 22, 2023 10:05 am, edited 1 time in total.
Reason: Added code-tags
Post Reply