Hide Rows / Autofilter Listener - OpenOffice Basic - listener

I need to dev Listener to detect changes of isVisible setting for a rows in calc.
Even better it would be for me to have autofilter changes listener - this is also beyond my skills. I would be appreciative for any or both solutions help.
XEventListener nor XModifyListener dont detects this changes.
Maybe try to use XChangesListener XChangesNotifier? <- anyway, i had problem to implement it for tests too
Sub add_eventsListener
Dim ePrefix As String, eService As String
ePrefix = "event_"
eService = "com.sun.star.document.XEventListener"
If IsNull(mEventHandler) Then
mEventHandler = CreateUnoListener(ePrefix, eService)
ThisComponent.addEventListener(mEventHandler)
EndIf
End Sub
Sub event_notifyEvent(oEvent)
msgbox "event: " & oEvent.EventName
End Sub
Sub add_modifyListener(ByRef Sheet)
Dim ePrefix As String : Dim eService As String
Dim cell as Object
ePrefix = "event_"
eService = "com.sun.star.util.XModifyListener"
cell = Sheet.getCellrangeByName("A2:A9")
If IsNull(mModifyHandler) Then
mModifyHandler = CreateUnoListener(ePrefix, eService)
cell.AddModifyListener(mModifyHandler)
EndIf
End Sub
Sub event_modified(oEvent)
'If oEvent.Source.CellAddress.Column <> 0 Then Exit Sub
Msgbox "changes made"
End Sub
where mEventHandler and mModifyHandler are global
Sub add_autofilter(ByRef Sheet)
On Error GoTo Err
Dim Range As New com.sun.star.table.CellRangeAddress
Dim FilterOn As Boolean, dRange As Object, cell As Object, row%
FilterOn = False
cell = Sheet.getCellRangeByName("A1")
row = getLastRow(Sheet)
On Error Resume Next
dRange = ThisComponent.DatabaseRanges.getByName("Symbols")
FilterOn = dRange.AutoFilter
On Error GoTo 0 : On Error GoTo Err
If FilterOn Then Exit Sub
With Range
.Sheet = 0
.StartColumn = 0
.StartRow = 0
.EndColumn = 0
.EndRow = row
End With
'Range = Sheet.getCellRangeByPosition(0, 0, 0, row)
ThisComponent.DatabaseRanges.addNewByName("Symbols", Range)
ThisComponent.DatabaseRanges.getByName("Symbols").AutoFilter = True
Exit Sub
Err:
End Sub
Function getLastRow(ByRef Sheet) As Integer
Dim cursor
cursor = Sheet.createCursor()
cursor.gotoEndOfUsedArea(false)
getLastRow = cursor.getRangeAddress().EndRow
End Function

While I am waiting for rational solution, I found a workaround - If no autofilter listener will be possible, Ill have to stay with that:
add formula in some cell: (old solution, check EDIT below)
"=IF(NOW()>0;ROWS_FILTERED();0)"
Function ROWS_FILTERED() As Integer
If Freezed Then Exit Function
Dim i%, rows%, Sheet As Object : Sheet = ThisComponent.Sheets(0)
rows = getLastRow(Sheet)
For i = 1 to getLastRow(Sheet) 'row 0 is for labels
If Sheet.Rows(i).IsVisible = True Then
rows = rows - 1
End If
Next i
ROWS_FILTERED = rows
End Function
And if you make changes where computations are not expected, just assign True to Global Freezed for that time
EDIT:
eureka! I have found this shiny formula that works and updating without workaround:
Eureka! Mimo że nie osiągnąłem rezultatu z czystego BASIC'a, znalazłem genialną formułę, która się odnosi bezpośrednio do autofiltra!! i updateuje bez obejścia:
"=SUBTOTAL(3;A2:A" & getLastRow(Sheet) + 1 & ")"
dont forget to include getLastRow(ByRef Sheet) function to your code

Related

How to hide columns in dynamic subranges before converttohtml in emailbody in Outlook?

I am doing a macro that is formatting a data base into a table, and then select ranges from this table in order to send to different persons depending of the range.
But depending of the range sometimes I can have several column empty, I would like to add in my loop that when creating the temporary workbook, to copy paste my subtable that I wanna send, a function or a part that check if the column is empty (I have headers) and if it's the case, hide the columns concerned only for this range and then convert to HTML in my body email the range without my empty column now hidden and after the loop keeps going through my whole table.
Thanks to a previous post, my VBA code is running smoothly but as soon as I add the part which is supposed to hide column, it's not working anymore, I guess, that I am not adding it in the right place but I don't know,
I tried to add it, just after RangeToEmail and in the function that is creating the tempWB, RangetoHTML but it's not working. (see both codes after)
The code I used on a static range and which is working, to hide the column is
Dim iFirstCol As Integer, iLastCol As Integer, i As Integer`
'variables to hold the first and last column numbers
iFirstCol = Range("A2").Column
iLastCol = Range("W2").Column
LastRow = Range(Range("A2"), Range("A2").End(xlDown))
'count backwards through columns
For i = iLastCol To iFirstCol Step -1
'if all cells are blank, hide the column
If WorksheetFunction.CountA(Range(Cells(1, i), Cells(LastRow, i))) = 0 Then
Columns(i).EntireColumn.Hidden = True
End If
Next i
and here is the code I use to go from my table to the different subtable and then through TemporaryWB convert to html in my email body
Option Explicit
Sub GetNames()
Dim NameArray() As String
Dim NameRange As Range
Dim C As Range
Dim Counter As Integer
Dim NameFilter As Variant
Dim RangeToEmail As Range
Dim EmailAddress() As String
'Email Stuff
Dim objOutlook As Object
Set objOutlook = CreateObject("Outlook.application")
Dim objEmail As Object
Set NameRange = Range(Range("H2"), Range("H2").End(xlDown))
ReDim NameArray(1 To Range(Range("H2"), Range("H2").End(xlDown)).Rows.Count) ReDim EmailAddress(1 To Range(Range("H2"), Range("H2").End(xlDown)).Rows.Count)
Counter = 0
For Each C In NameRange
Counter = Counter + 1
NameArray(Counter) = C.Value
EmailAddress(Counter) = C.Offset(, 3)
Next
NameArray = ArrayRemoveDups(NameArray)
EmailAddress = ArrayRemoveDups(EmailAddress)
Counter = 0
For Each NameFilter In NameArray
Counter = Counter + 1
ActiveSheet.Range("A1").AutoFilter Field:=8, Criteria1:=NameFilter Set RangeToEmail = ActiveSheet.ListObjects("DataTable").Range
Set objEmail = objOutlook.CreateItem(olMailItem)
With objEmail .To = EmailAddress(Counter)
.Subject = "TestSubject"
.HTMLBody = "Hello, <br><br>Please see the latest report:<br><br>" & RangetoHTML(RangeToEmail)
.Display
End With
Set objEmail = Nothing
Next
ActiveSheet.Range("A1").AutoFilter
End Sub
Function ArrayRemoveDups(MyArray As Variant) As Variant
Dim nFirst As Long, nLast As Long, i As Long
Dim item As String
Dim arrTemp() As String
Dim Coll As New Collection
'Get First and Last Array Positions
nFirst = LBound(MyArray)
nLast = UBound(MyArray)
ReDim arrTemp(nFirst To nLast)
'Convert Array to String
For i = nFirst To nLast
arrTemp(i) = CStr(MyArray(i))
Next i
'Populate Temporary Collection
On Error Resume Next
For i = nFirst To nLast
Coll.Add arrTemp(i), arrTemp(i)
Next i
Err.Clear
On Error GoTo 0
'Resize Array
nLast = Coll.Count + nFirst - 1
ReDim arrTemp(nFirst To nLast) '
Populate Array
For i = nFirst To nLast
arrTemp(i) = Coll(i - nFirst + 1)
Next i
'Output Array
ArrayRemoveDups = arrTemp
End Function
Function RangetoHTML(rng As Range)
Dim fso As Object
Dim ts As Object
Dim TempFile As String
Dim TempWB As Workbook
TempFile = Environ$("temp") & "/" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"
' Copy the range and create a workbook to receive the data.
rng.Copy
Set TempWB = Workbooks.Add(1)
With TempWB.Sheets(1)
.Cells(1).PasteSpecial Paste:=8
.Cells(1).PasteSpecial xlPasteValues, , False, False
.Cells(1).PasteSpecial xlPasteFormats, , False, False
.Cells(1).Select
Application.CutCopyMode = False
On Error Resume Next
.DrawingObjects.Visible = True
.DrawingObjects.Delete
On Error GoTo 0
End With
' Publish the sheet to an .htm file.
With TempWB.PublishObjects.Add( _ SourceType:=xlSourceRange, _ Filename:=TempFile, _ Sheet:=TempWB.Sheets(1).Name, _ Source:=TempWB.Sheets(1).UsedRange.Address, _ HtmlType:=xlHtmlStatic)
.Publish (True)
End With
' Read all data from the .htm file into the RangetoHTML subroutine.
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
RangetoHTML = ts.ReadAll
ts.Close RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", _ "align=left x:publishsource=")
' Close TempWB. TempWB.Close savechanges:=False
' Delete the htm file.
Kill TempFile
Set ts = Nothing
Set fso = Nothing
Set TempWB = Nothing
End Function
First LastRow is not declared as variable properly and therfore you didn't see that
LastRow = Range(Range("A2"), Range("A2").End(xlDown))
is actually writing an array of values into LastRow. Actually your first code cannot work properly. Make sure you use Option Explicit (I recommend always to activate Option Explicit: In the VBA editor go to Tools › Options › Require Variable Declaration).
The issue is probably if your empty columns have headers too then
WorksheetFunction.CountA(Range(Cells(1, i), Cells(LastRow, i)))
will never be 0 because you included your header row 1 Cells(1, i) in your range. So if you want to exclude the header you need to change it to start with row 2 like Cells(2, i).
Finally all this code applies to ActiveSheet which is not very reliable because the active sheet can change by a single mouse click. If you can specify the worksheet precisely by a name, do so. If it really has to run on multiple sheets (so you really want to use the active one) at least make sure the active sheet does not change during the code excecutes by reading it only once into a variable Set ws = ThisWorkbook.ActiveSheet.
I would use
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") 'name your sheet here!
'or if it really is the active sheet do
'Set ws = ThisWorkbook.ActiveSheet 'and make sure you only use `ws` from now!
'variables to hold the first and last column numbers
Dim iFirstCol As Long
iFirstCol = ws.Columns("A").Column
Dim iLastCol As Long
iLastCol = ws.Columns("W").Column
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlDown).Row
'count backwards through columns
Dim i As Long
For i = iLastCol To iFirstCol Step -1
'if all cells are blank, hide the column
If Application.WorksheetFunction.CountA(ws.Range(ws.Cells(2, i), ws.Cells(LastRow, i))) = 0 Then
ws.Columns(i).EntireColumn.Hidden = True
End If
Next i
Apply the same to the rest of your code to make it more reliable.

Not in List Error after replacing Chr(), yet added to list correctly

I have some combo boxes with code for adding new items to the source table with a form when it doesn't exist.
The code will replace Chr(47) / and Chr(92) \ with Chr(45) - if present. This is done because a file name is created using concatenation later.
The problem is if a character is replaced, I get an Access error that the item is not in the list. This does not happen if a character is not replaced. In both instances the correct items are added to the corresponding tables.
I have tried replacing the character before passing it to OpenArgs, AfterUpdate, on the form after it opens, etc. The error does not break so the program is working, I just want to eliminate a unnecessary pop-up message.
Any help is greatly appreciated.
Private Sub cboManual_NotInList(NewData As String, Response As Integer)
Dim MyMessage As String
Dim myButtons As Integer
Dim myTitle As String
Dim strSQL As String
On Error GoTo ErrHandler
MyMessage = "This Manual does not exist. Create it?"
myButtons = vbYesNo + vbDefaultButton1 + vbQuestion + vbApplicationModal
myTitle = "Add Manual?"
MyChoice = MsgBox(MyMessage, myButtons, myTitle)
If MyChoice = 6 Then
If Not DBAuthority = "Admin" And Not DBAuthority = "Data Entry" Then
Response = acDataErrContinue
MsgBox "Sorry, authorized access only", _
vbOKOnly, "Important Information"
Exit Sub
Else
Response = acDataErrAdded
CallerField = "Manual"
CallerForm = "NewDocument"
NewData = Replace(NewData, Chr(47), Chr(45))
NewData = Replace(NewData, Chr(92), Chr(45))
DoCmd.OpenForm "AddManual", windowmode:=acDialog, OpenArgs:=NewData
Me.cboManual.RowSource = Me.cboManual.RowSource
Me.cboManual.value = strAddManual
strManual = Me.cboManual.value
strAddManual = vbNullString
Me.cboSection.value = strAddSection
strSection = Me.cboSection.value
strAddSection = vbNullString
Me.cboEngine.value = strAddEngine
strEngine = Me.cboEngine.value
strAddEngine = vbNullString
End If
ElseIf MyChoice = 7 Then
Response = acDataErrContinue
MsgBox "Select Manual from list.", vbOKOnly, "Select Manual"
Me.cboManual.Undo
Me.cboManual.SetFocus
Exit Sub
End If
Exit Sub
ErrHandler:
If Err = 20 Then
Response = acDataErrContinue
ElseIf Err = 94 Then
Response = acDataErrContinue
Resume Next
ElseIf Err = 2237 Then
Response = acDataErrContinue
Resume Next
ElseIf Err = 0 Then
Response = acDataErrContinue
Else
MsgBox "cboManual.NotInList Err = " & Err.Number & " :" & Err.Description
Exit Sub
End If
Exit Sub
End Sub
Option one
Replace while typing
Select Case KeyCode
Case vbKeyDown
Me![cboNewPart].Dropdown
Case 220, 191 ' / and \
KeyCode = 189 ' with -
Case Else
End Select
Option two
after adding the new value to the table. do
me.combo.undo, me.combo.requery. me.combo.value = newValue
followed by acDataErrContinue
this way you won't get error message but the list will flicker a and it's purely a hack.
Try using a different variable name (other than NewData) to store the modified version of the value passed to the NewData argument, i.e.:
Dim NewString as String
NewString = NewData
NewString = Replace(NewString, Chr(47), Chr(45))
NewString = Replace(NewString, Chr(92), Chr(45))
DoCmd.OpenForm "AddManual", windowmode:=acDialog, OpenArgs:=NewString
Since VBA arguments are passed ByRef unless otherwise stated, any modification to the argument value will be modifying the original value passed to your cboManual_NotInList event handler.
Given the above, you could alternatively try changing the NewData argument to be passed by value (ByVal):
Private Sub cboManual_NotInList(ByVal NewData As String, Response As Integer)

Excel 2010: VBA convert custom function code to a module with macro shortcut

Info: Excel 2010
Notes: The code works exactly how I need, I am now wanting to automate it a little
I recently came across this code, it's for a custom function, however I can not create a button for it (like a macro), I would like to convert some of this code, however I don't know what to do or how to go about it. I want to have a shortcut/button on my ribbon.
https://stackoverflow.com/a/17337453/2337102
Function listUnique(rng As Range) As Variant
Dim row As Range
Dim elements() As String
Dim elementSize As Integer
Dim newElement As Boolean
Dim i As Integer
Dim distance As Integer
Dim result As String
elementSize = 0
newElement = True
For Each row In rng.Rows
If row.Value <> "" Then
newElement = True
For i = 1 To elementSize Step 1
If elements(i - 1) = row.Value Then
newElement = False
End If
Next i
If newElement Then
elementSize = elementSize + 1
ReDim Preserve elements(elementSize - 1)
elements(elementSize - 1) = row.Value
End If
End If
Next
distance = Range(Application.Caller.Address).row - rng.row
If distance < elementSize Then
result = elements(distance)
listUnique = result
Else
listUnique = ""
End If
End Function
Results with the ability to:
Just enter =listUnique(range) to a cell. The only parameter is range
that is an ordinary Excel range. For example: A$1:A$28 or H$8:H$30.
I would like the following:
Create a macro button with an a popup Inputbox to ask for a range.
Usage:
1) I am in the cell where I require the list to begin (BA9)
2) I click the custom module/macro button & popup box asks me the range (G$8:G$10000)
3) The result then autofills in column (BA)
Lastly, can the code be amended so that the restriction of "The first cell where you call the function must be in the same row where the range starts." be removed so that I can use a reference from another sheet within the same workbook.
I apologise if I should have gone direct to the coder, the thread that it was in is old & I thought given the amount of change I'm asking for it may be better suited in its own question.
Thank you in advance.
First approach: (you can use RemoveDuplicates method instead function listUnique)
Just assign this Sub to your custom button:
Sub testRemoveDuplicates()
Dim targetRange As Range
Dim actCell As Range
Dim res As Variant
Set actCell = ActiveCell
On Error Resume Next
Set targetRange = Application.InputBox("Please highlight the cell for TARGET", Type:=8)
On Error GoTo 0
If targetRange Is Nothing Then
MsgBox "User has pressed cancel"
Exit Sub
End If
targetRange.Copy
actCell.PasteSpecial xlPasteValues
actCell.RemoveDuplicates Columns:=1, Header:=xlNo
Application.CutCopyMode = False
End Sub
Second approach: (if you'd like to use function listUnique)
Here is another listUnique function. You can get list of unique elements usign Dictionary object (it is better suited for your purposes):
Function listUnique(rng As Range) As Variant
Dim row As Range
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
On Error Resume Next
For Each row In rng.Rows
If row.Value <> "" Then
dict.Add row.Value, row.Value
End If
Next
Dim res As Variant
ReDim res(1 To dict.Count)
res = dict.Items
Set dict = Nothing
listUnique = Application.Transpose(res)
End Function
then you can call it using following Sub (you can assign it to custom button):
Sub test()
Dim targetRange As Range
Dim actCell As Range
Dim res As Variant
Set actCell = ActiveCell
On Error Resume Next
Set targetRange = Application.InputBox("Please highlight the cell for TARGET", Type:=8)
On Error GoTo 0
If targetRange Is Nothing Then
MsgBox "User has pressed cancel"
Exit Sub
End If
res = listUnique(targetRange)
actCell.Resize(UBound(res)) = res
End Sub
Note: if you're going to call this listUnique function direct from worksheet (as UDF function), you should select destination range (in example D10:D20), with selected range enter formula =listUnique(A1:A10) in formula bar, and press CTRL+SHIFT+ENTER to evaluate it.

MS Access 2007 VBA - Reusable list box code

I have a MS Access 2007 application which has several forms where I've used the same list box design. I have two list boxes, one of which gets values from a table with a query like:
SELECT id, value FROM table
And the second which is initially empty. In between these two list boxes are add and remove buttons, which are disabled by default. Clicking a value in the first list box enables the add button, and clicking a value in the second list box enables the remove button. Clicking the add button adds the selected item to the second list, and clicking the remove button removes an item for the second list.
The code I have for the add button is as follows ("ALLLIST" refers to the list with the query values, "SELECTEDLIST" is the one that's initially empty) :
Dim selectedId, selectedValue, safeValue As String
Dim existing As Boolean
Dim index As Integer
existing = False
selectedId = Me.ALLLIST.Value
index = Me.ALLLIST.ListIndex
selectedValue = Me.ALLLIST.Column(1,index)
'Loop through the list of selected values and see if this one has already been added to the list
For i = 0 To (Me.SELECTEDLIST.ListCount)
If (Me.SELECTEDLIST.Column(0, i) = selectedId) Then
existing = True
End If
Next i
'Only add the value if it's not already on the list
If (existing) Then
MsgBox "This list can't contain duplicate values", vbOKOnly + vbInformation, "Error"
Else
safeValue = Replace(selectedValue & "", "'", "''")
Me.SELECTEDLIST.AddItem (selectedId & ";'" & safeValue & "'")
Me.SELECTEDLIST.Value = Null
Me.REMOVEBUTTON.Enabled = False
End If
And the code for the remove button is:
Dim numItems, index As Integer
index = Me.SELECTEDLIST.ListIndex
'Remove the selected item and move to the top of the list
Me.SELECTEDLIST.RemoveItem (index)
Me.SELECTEDLIST.Selected(0) = True
numItems = Me.SELECTEDLIST.ListCount
'Cosmetic feature, select the row above the one we're removing
If (index > 0) Then
Me.SELECTEDLIST.Selected(index - 1) = True
Else
Me.SELECTEDLIST.Selected(0) = True
End If
'If the list is empty now, disable the remove button
If (numItems = 0) Then
Me.ALLLIST.SetFocus
Me.REMOVEBUTTON.Enabled = False
Me.SELECTEDLIST.Selected(-1) = True
End If
What I would like to do is, rather than copy and paste this code all over the place, have this template stored somewhere and then in my form code write something like:
hookUpLists(allListName, selectedListName, addButtonName, removeButtonName)
How can I do this? Can I write a module to do this some how? I'm also open to any improvements I can make on the above code.
Thanks
Thanks for the hint on using class modules, HK1, I'd never used them before.
To solve the original question, I created a new class module "MultiSelectListBox", which has the following code:
Option Compare Database
Private WithEvents allList As ListBox
Private WithEvents selectedList As ListBox
Private WithEvents addBtn As CommandButton
Private WithEvents removeBtn As CommandButton
Private numColumns As Integer
Public Sub hookUpLists(numberOfColumns As Integer, allValuesList As ListBox, selectedValuesList As ListBox, addButton As CommandButton, _
removeButton As CommandButton)
'Grab all the controls passed in
Set allList = allValuesList
Set selectedList = selectedValuesList
Set addBtn = addButton
Set removeBtn = removeButton
numColumns = numberOfColumns
'Tell Access we want to handle the click events for the controls here
allList.OnClick = "[Event Procedure]"
selectedList.OnClick = "[Event Procedure]"
addBtn.OnClick = "[Event Procedure]"
removeBtn.OnClick = "[Event Procedure]"
End Sub
Private Sub allList_Click()
addBtn.Enabled = True
End Sub
Private Sub selectedList_Click()
removeBtn.Enabled = True
End Sub
Private Sub addBtn_Click()
Dim selectedId As String
Dim existing As Boolean
Dim index As Integer
existing = False
selectedId = allList.Value
index = allList.ListIndex
'Loop through the list of selected values and see if this one has already been added to the list
For i = 0 To (selectedList.ListCount)
If (selectedList.Column(0, i) = selectedId) Then
existing = True
End If
Next i
'Only add the value if it's not already on the list
If (existing) Then
MsgBox "This list can't contain duplicate values", vbOKOnly + vbInformation, "Error"
Exit Sub
End If
Dim item As String
item = selectedId & ";"
'Loop over all of the columns and add them to the second list box
For i = 1 To numColumns - 1
item = item & "'" & Replace(allList.Column(i, index) & "", "'", "''") & "'"
'Don't add a trailing semicolon
If (i <> numColumns - 1) Then
item = item & ";"
End If
Next i
selectedList.AddItem (item)
selectedList.Value = Null
removeBtn.Enabled = False
'Select the next row
If (index <> allList.ListCount - 1) Then
allList.Selected(index + 1) = True
allList.Value = allList.Column(0, index + 1)
End If
End Sub
Private Sub removeBtn_Click()
Dim numItems, index As Integer
index = selectedList.ListIndex
'Remove the selected item and move to the top of the list
selectedList.RemoveItem (index)
selectedList.Selected(0) = True
numItems = selectedList.ListCount
'Cosmetic feature, select the row above the one we're removing
If (index > 0) Then
selectedList.Selected(index - 1) = True
Else
selectedList.Selected(0) = True
End If
'If the list is empty now, disable the remove button
If (numItems = 0) Then
allList.SetFocus
removeBtn.Enabled = False
selectedList.Selected(-1) = True
End If
End Sub
Most of the above is identical to what I was already using, one important thing to note for anyone stumbling across this is the use of "WithEvents" when declaring the variables. This tells Access to look in the class module for event handlers. Finally, from my form I can do the following:
Private contactList As MultiSelectListBox
Private Sub Form_Open(Cancel As Integer)
Set contactList = New MultiSelectListBox
contactList.hookUpLists 3, Me.allContactsList, Me.selectedContactsList, Me.addContactBtn, Me.removeContactBtn
End Sub

Me.Recordset.AbsolutePosition can not move to current record in the form

i have a form with data sheet view i want to use this form as a list box (multi select extended), so when i click on each record/field in the form it uses (clear selection function) for unselected other records and just select record i have focused, now problem is when click on each field after running clear selection function it goes to the first record and did not moves cursor to current focused record.
it seems below code
Me.Recordset.AbsolutePosition = Pos1
does not work and will not be moved to current focused record.
the complete code is like below:
Private Sub P_Click()
On Error Resume Next
Dim ct As Control
Dim Cnt As Long, Rws As Long
Dim Pos1 As Long, Pos2 As Long
Pos1 = Me.Recordset.AbsolutePosition
Set ct = ActiveControl
' Clear other selections if Ctrl or Shift key
' is not simultaneously pressed.
If CtrlPressed = 0 And ShiftPressed = 0 Then
P_ClearSelections
Me.Recordset.AbsolutePosition = Pos1
Me.IsSelected = True
ct.SetFocus
GoTo ExitPoint
End If
If ShiftPressed > 0 Then
Rws = Me.SelHeight
If Rws > 1 Then
Pos2 = Me.SelTop - 1
For Cnt = Pos2 To Pos2 + Rws - 1
Me.Recordset.AbsolutePosition = Cnt
Me.IsSelected = True
Next
End If
GoTo ExitPoint
End If
Me.IsSelected = True
ExitPoint:
' Save the status
Me.Dirty = False
' Update display in SF_Selected
Me.Parent("SF_Selected").Requery
ActiveControl.SelLength = 0
Set ct = Nothing
On Error GoTo 0
End Sub
function clear selection is like below;
Public Sub P_ClearSelections()
On Error Resume Next
DoCmd.Echo False
' Clear all check boxes
CurrentDb.Execute "UPDATE tblItems " & _
"SET IsSelected = False;", dbFailOnError
Me.Requery
DoCmd.Echo True
On Error GoTo 0
End Sub
You are requerying the underlying recordset in your P_ClearSelections() procedure. From the Microsoft documentation:
There is also no assurance that a given record will have the same
AbsolutePosition if the Recordset object is requeried or reopened.
Bookmarks are still the recommended way of retaining and returning to
a given position and are the only way of positioning across all types
of Recordset objects.
MSDN AbsolutePosition
I suggest that you investigate the use of Bookmarks instead (and remove the On Error Resume Next statements).