Calc sheet selection change event and mouse

Hello everyone,

When a cell is clicked on once with a mouse, and the predefined SelectionChanged event is fired, the mouse seems to be stuck in a “selection mode”. In other words, unless I click on that same cell once again, cells will continue to be selected on the mouse’s path as it’s being moved around the spreadsheet. The questions, which I’d like to ask are as follows:

  1. What can be done to eliminate the necessity for the second click?
  2. When I do click that same cell once again, to remove the “selection mode”, the SelectionChanged event fires three more times. Why so many?

Thank you in advance.

Can you clarify a bit. Are you in code, say, looking at the XInterface from the event object passed to the handler, or are you looking at the UI and actually seeing a mouse drag without ctrl or shift pressed doing multiselection? Is this happening always, or only when you have your event handler added to the sheet events?

I’m looking at UI and literally see the light blue rectangle appearing. I do not have any keyboard key pressed at all.

But it pretty much has almost the same visual effect as if I were to press shift + arrow key. With the exception that when I release the shift key, and press arrow key once again, the selection disappears and a cell immediately next to the previously selected appears.

It is only happening when the event handler is added to the sheet event. Otherwise the software works perfectly fine.

I tried using flags to exit sub in case the event is fired, but it did not help, as the event repeats more than twice and I just cannot think of any instance when the flag should be cleared. Furthermore, when I attempted to programmatically set a selection, the code generated error and shut LO down completely. Error handling helped somewhat but not in all cases.

Definitely post an example that clarifies what you really want to accomplish. I can replicate the scenario. Using

Sub SomeChange(event As Variant)
	MsgBox("Hello")
End Sub

set as the change event handler, you can see that you seem to be in block selection mode, and if you move your mouse cursor across a cell boundary the event fires again.

But try this message box example and instead of clicking on the OK button use F4 to close the box a couple of times. The behavior seems to change.

What I was attempting to do was to highlight row and column of cell selected (code included below.) I chose to completely ignore the aforementioned multiple events repeating themselves, for now. But even that brings its own array of issues. So far it pseudo works, but there are issues to be resolved yet:

  1. The events firing. I have found a code by @JohnSUN where he is using MouseClickHandler added to the current controller. I’m sure it will be a better solution than mine. Although I would love to still understand why the predefined event exhibits this behavior. Also, I see that the member list of the controller service has a selection change listener function. I’ll try to attempt using this as well. Hopefully I’ll get it to work. (Way easier to copy what someone else has done already, but by now I will hopefully be able to figure this out as well)

*** Update ***
Using MouseClickHandler completely eliminates the multiple event calling.

  1. When pressing Ctrl-Z, it shuts me out of LO entirely.

  2. When selecting with a mouse, and dragging across several rows, the behaviour is not entirely as desired. But I’m hoping that with the MouseClickHandler it will be resolved.

This is what I came up with so far:

Sub Test(oEvent)
On Error Resume Next

Const cRed = 230
Const cGreen = 230
Const cBlue = 230

oEvent.getSpreadsheet.cellBackColor = -1

With oEvent
	.Rows.CellBackColor = RGB(cRed, cGreen, cBlue)
	With .cellAddress
		oEvent.getSpreadsheet.getCellRangeByPosition(.column,0,.column,oEvent.getSpreadsheet.Rows.Count -1).cellBackColor = RGB(cRed, cGreen, cBlue)
	End With
End With

End Sub

Once a year I have to edit some big CSV’s. This will be nice for that, since nuking the background color doesn’t matter. Honestly, I am very surprised that it works so snappy, if a little jittery.

Thanks for the heads-up on MouseClickHandler.

To get the full cross effect that I think you want, you could try:

Sub Test(oEvent)
	Dim BackColor As Variant
	Dim Sheet As Object
	Dim Rows As Object
	Dim Columns As Object
	Dim CellRangeAddress As New com.sun.star.table.CellRangeAddress

	If Not oEvent.supportsService("com.sun.star.sheet.SheetCellRange") Then Exit Sub

	Const cRed = 230
	Const cGreen = 230
	Const cBlue = 230
	
	BackColor = RGB(cRed, cGreen, cBlue)
	Sheet = oEvent.getSpreadsheet()
	CellRangeAddress = oEvent.RangeAddress
	Rows = oEvent.Rows
	Columns = Sheet.getCellRangeByPosition( _
		CellRangeAddress.StartColumn, 0, _
		CellRangeAddress.EndColumn, Sheet.Rows.Count -1 _
		)
	
	'Nuke back background colors
	Sheet.cellBackColor = -1

	'Set new background colors
	Rows.CellBackColor = BackColor
	Columns.cellBackColor = BackColor
		
End Sub

My style is to set variables rather than using With statements. No critique meant.

Nothing says UNO quite like an object supporting the SheetCellRange service whose RangeAddress property returns a CellRangeAddress.

Thank you for that suggestion. I ran it, and it works pretty much just like the one I came up with last night, using the MouseClickHandle Event. I’ll post mine below, hopefully it will help someone else in the future. But essentially both solutions resolve issues 1 and 3. As far as #2 is concerned, I am thinking that if it will not be possible to be resolved, then maybe I can define a keyboard event which will watch for “ctrl-z” and ignore it.

Nevertheless, I took yours, and I adjusted it slightly. When you use it as such, and click just on one cell, you’ll see that the event fires up four times for each click. I’d love to understand the reasoning behind this.

Sub Test(oEvent)
	Dim BackColor As Variant
	Dim Sheet As Object
	Dim Rows As Object
	Dim Columns As Object
	Dim CellRangeAddress As New com.sun.star.table.CellRangeAddress
	Dim i As Byte
	
	If Not oEvent.supportsService("com.sun.star.sheet.SheetCellRange") Then Exit Sub

	Const cRed = 230
	Const cGreen = 230
	Const cBlue = 230
	
	BackColor = RGB(cRed, cGreen, cBlue)
	Sheet = oEvent.getSpreadsheet()
	CellRangeAddress = oEvent.RangeAddress
	Rows = oEvent.Rows
	Columns = Sheet.getCellRangeByPosition( _
		CellRangeAddress.StartColumn, 0, _
		CellRangeAddress.EndColumn, Sheet.Rows.Count -1 _
		)
	
	'Nuke back background colors
	Sheet.cellBackColor = -1

	'Set new background colors
	Rows.CellBackColor = BackColor
	Columns.cellBackColor = BackColor

	Do
		If Sheet.getCellByPosition(0,i).String = "" Then
			Sheet.getCellByPosition(0,i).String = "Event Fired " & i+1
			Exit Do
		Else
			 i = i + 1
		End If
	Loop

End Sub

This is the one I have come up with, with very similar results. Actually, maybe a little bit less jittery, as there aren’t as many events firing up. As far as critique is concerned, I am here to learn. Therefore, any suggestions/corrections/advise is truly appreciated :+1:. Again, this works with the MouseClickHandler:

Sub Test2(oEvent)

	Const cRed = 230
	Const cGreen = 230
	Const cBlue = 230
	
	Dim oDoc As Object
	Dim oSheet As Object
	Dim oSelection As Object
	Dim vBackgroundColor As Variant
	
	oDoc = ThisComponent	
	oSheet = oDoc.Sheets(0)
	vBackgroundColor = RGB(cRed, cGreen, cBlue)
	
	oSheet.cellBackColor = -1
	
	If oDoc.CurrentSelection.Rows.Count > 1 Then
		oSelection = oSheet.getCellRangeByName(split(split(oDoc.CurrentSelection.AbsoluteName,":")(0),".")(1))
	Else
		oSelection = oDoc.currentSelection
	End If
		
	with oSelection
		.Rows.cellBackColor = vBackgroundColor
		.getSpreadsheet.getCellRangeByPosition(.CellAddress.Column,0,.CellAddress.Column,.getSpreadsheet.Rows.Count -1).cellBackColor = vBackgroundColor
	End With
		
End Sub

I definitely prefer the MouseClickEvent! As for my example, I thought you wanted a “big, fat cross” in both directions when selecting multiple cells. Maybe that’s just what I wanted :slight_smile:. That was the only reason I thought about using the CellRangeAddress.StartColumn and CellRangeAddress.EndColumn. I’m guessing you added the getImplementationName check from JohnSUN’s example…without it I seem to have problems, say, if I click a chart.

Since UNO for LO doesn’t pass event metadata into the event handler, finding out why a handler is firing multiple times may be a lost cause. For user defined functions it seems clearer; they recalculate because of necessary ‘inefficiencies’ in the sheet update algorithm.

In LO 7.2.2.2 it looks like ctrl+z works for me with the MouseClickHandler version. Of course I have to press it a few times because it is undoing the cell background changes as well as whatever I did before, but it doesn’t crash. With the Selection Changed event it seems like ctrl+z may be firing a Selection Changed event itself, so it gets into a recursion and crashes when the stack space runs out. Just a speculation.

Hello Joshua,

Sorry for the late reply, but it has been an extremely busy week. I only get to learn programming when I “steal” some time and make it mine. Nevertheless, I did not add the getImplementationName yet, but I’ll do it right now. In all honesty I did not even consider anything else but cells being clicked on.

As far as the ctrl+z is concerned, I’m still getting kicked out of LO for whatever reason. I’ll try to set up error handling and see if there are any error codes coming up this way. Or maybe there is a bug in the newest version.

Version: 7.3.0.3 (x64) / LibreOffice Community
Build ID: 0f246aa12d0eee4a0f7adcefbf7c878fc2238db3
CPU threads: 16; OS: Windows 10.0 Build 22000; UI render: Skia/Raster; VCL: win
Locale: en-CA (en_CA); UI: en-US
Calc: threaded

Have you looked at any keyboard customization? I cannot duplicate. Have you a file demonstrating this you can share?

As for the multiple events, see → Sheet Event Selection Change runs Macro 4 times

Good evening @Ratslinger

As I have copied my routines to a fresh file, so that I can upload it, I ran another test. It actually works perfectly now. No idea why it didn’t want to work in the old one. ctrl-z is completely functioning and it does not kick me out anymore.

As per the multiple events fired, I came up with precisely the same conclusion. Keyboard fires up only one, whereas the mouse spits out four of them.

Thanks to you and @joshua4 for all your help. I’m uploading the example, as maybe someone in the future can use it.
Spreadsheet_CrossHair.ods (10.5 KB)

1 Like