ColumnFromXY() undefined over empty rows of a listbox

I find this odd: when passing x,y coords (as obtained in MouseMove or MouseDown events in a listbox) to ColumnFromXY, you get -1 for the column index unless the cursor is over non-empty rows. To me, if your mouse is in a column that is visible, whether its rows are filled or not, you should be able to obtain the corresponding column index. Indeed, the y parameter in ColumnFromXY(x,y) is superfluous in my opinion. Should x only matter?

In fact, if you want both behaviors, passing y>0 could return what ColumnFromXY does now, but passing y=-1 could ignore whether rows are filled or not, and always return the correct column index.

Ditto for RowFromXY().

@Peter Stys —ColumnFromXY and RowFromXY are made to return either an existing index (i.e. one that can be used without raising an OutOfBoundException) or -1 in case of failure. Both your point of view and this one are valid to me.

Empty rows, or non-existent rows? If you haven’t AddRow, it’s not an empty row - there is no row. There’s literally nothing there, so you get -1 for RowFromXY. Can’t explain why ColumnFromXY wouldn’t be able to determine the column, sorry.

However it should still be possible. You will need to collect all the column widths, factor in the ScrollPositionX, and difference the MouseX. Take some time to twiddle the math, it’s a little more than I want to figure out in the forum post editor :stuck_out_tongue:

Intelligent programming ?

Totally unrelated to the Row “problem”: in that case, you get the Column “location” (even if no Row). I think it is a good idea.

Now, we have to ask ourselves: “What would we say if this was not the case” ? (returns -1 ? .Index only returns a Row number or -1, we do not have anything for Column number: we do not add Columns, only Rows).

It may sense to me (and I like it).

I’m not sure what the use case is for caring about the column when the mouse is over an area that does not contain a row, but it seems to me that instead of having to do the math yourself, you could pass the Y coordinate as lstObject.Top + 2 or something instead of the real Y coordinate. As long as there is a visible row, seems like it should work. Would not work on an empty list though.

Boo, that’s simpler and less math-y. :stuck_out_tongue:
I like it, but it’s important to remember that it will still fail if there are 0 rows at all :frowning:

[quote=467904:@Tim Parnell]Boo, that’s simpler and less math-y. :stuck_out_tongue:
I like it, but it’s important to remember that it will still fail if there are 0 rows at all :([/quote]

Which is what I said. I haven’t tested it though. If you have headers, it may also be necessary to offset the top of the listbox past the header height so that you are on a visible row.

I didn’t post any code because I have not tested how it behaves. But seems it shouldn’t be that hard to make listbox extension methods that call the normal RowFromXY or ColumnFromXY when neither value is -1, and computes the row or column to return when given -1 as the OP stated. Then depending on if you care about the column on empty lists too, may need the math approach vs my quick estimate method.

[quote=467910:@Douglas Handy]Which is what I said. I haven’t tested it though. If you have headers, it may also be necessary to offset the top of the listbox past the header height so that you are on a visible row.
[/quote]

And depending on how close you are cutting it you may also need to check if it has a boarder…

In any case going by column widths and ScrollPositionX is not that hard… I needed to do that in my subclass for other reasons than making ColumnFromXY work with no data .

Back when i first wrote it (over 9 years ago!) I had to figure out ways to get at all the particulars of listbox layout/spacing etc…that the listbox did not give direct access to… had to figure out lots of nit picking details to get things to look right!

-Karen

The problem arose as follows: I have a listbox with say 6 columns, it is displayed with gridlines like a spreadsheet, so shows say 30 rows. I only have data that fill 10 rows, so 20 rows are empty (they don’t exist, I get it, but they display in the grid nonetheless). Contextual menu to copy 1 column to the clipboard. I need to know which column the user R-clicked in. So now user must R-click over non-empty rows, R-clicking in the column lower down fails because col index returns -1. Not intuitive.

I realize that one can do some manual gymnastics to work around this but IMHO this should be built in.
My comment re RowFromXY didn’t make sense in retrospect, so ignore.

Then file a feature request in feedback. In the meantime, just make an extension method so you can get the behavior today.

Out of curiosity, I decided to test what happens with the piDog DataView control which I use more and more now instead of a standard listbox. It is not sub-classed from Listbox; it is pure Xojo code on top of a canvas so that it can offer LOTS of features beyond a standard listbox. Too many to mention here.

But I wanted to see if you could just drop it in as a replacement and get the values you want. And the answer is not quite a drop in replacement, depending on what you want the UI to do. But close.

ColumnFromXY() does work, even when not over a valid row position (verified by requesting row/col in a mouse down event not over a valid row). It even correctly accounts for things like hidden columns or rows, variable row heights, locked left side columns, etc that a standard listbox cannot support.

The caveat for your use case is the context menu event does not fire when not over a valid row. Whether or not you have it “paint empty rows”. (Unlike a standard listbox, there is a property where you can control this. If you don’t paint empty rows, you don’t see gridlines or row colors or whatever when rows do not exist.)

So if you wanted to also allow a context menu in non-valid locations, I think you would need to use a MouseDown event, check if a right click, then request the ColumnFromXY() value and just show your own context menu. Or maybe you could just raise the DataView’s ConstructContextMenu event – just thought of that as I write this, but did not test it.

Thx Doug, this problem also occurs with the canned listbox: I subclass and just continuously store the MouseMove coords in properties; at Contextual time, I take the last MouseMove coords as the effective MouseDown coords.

In that case, I recommend you try the DataView demo. You have TONS of options not available in a standard listbox. I opted for the source version so that I could also make custom tweaks, but most of the tweaks I used to make are now supported by Jim out of the box. (Jim, the author, is very receptive to feature requests too.)

No vested promotional interest here; just a happy user.

https://forum.xojo.com/57531-find-listbox-column-in-mouse-move-event/p1#p467253

As a user (Newbie), I do not click in an empty area …

As a developer, I click in an empty area to know what happens (and something happens if I add code to so something or any selected Row is deselected). I never do that a second time because I already know what will happens (or I want to deselect the selected Rows, then I click).

What is not intuitive here ?

OK, the documentation is a bit scarce and the ListBox is a Control with so many features (implemented and missing) :wink:

And, I nearly forgot, we are not always at 100%, so, sometimes we need a little help from our friends (Where’s Ringo ?). :slight_smile:

if the mouse is over a column, I should be able to obtain the col’s index, whether a cell has data in it or not. If it is displayed, a column is a column.

Thx for all the tips on how to work around.

Perhaps when still showing gridlines for non-existent rows that may be true. If Excel is your baseline, then it does in fact show a context menu popup over “unused” cells. But I’d argue it needs to because of its context menu options, like Paste. The options are acting more on the cell than the column (unless you right click the column header in Excel).

In my personal opinion, if rows and gridlines are not painted where not present, then having nothing happen on a context click in an unused area seems intuitive enough to me. Perhaps intuitive is in the eye of the beholder.