deactivate the current sheet before going to another sheet - vba

I am getting error while swapping with two sheets.
I open one sheet and paste some data in this,after that I call a function which opens another sheet.but when I again paste data in the first sheet it throws error.
For y = 1 To size
Set src = Workbooks.Open("C:Template\Mapping.xlsx")
Worksheets("Sheet1").Activate
Worksheets("Sheet1").Range("B" & rowCntr).Value = "abc"
newValue= getNewValue()
rowCntr=rowCntr+1
Next
public Function getNewValue()
Dim newV=123
Set src = Workbooks.Open("C:Template\Mapping - Development v1.0.xlsx")
getNewValue=newV
End Function
For the first time it works properly but after calling the function getNewValue() it throws error "Subscript out of range" at Worksheets("Sheet1").Range("B" & rowCntr).Value = "abc" line.
Please help.

Your code example is incomplete. Noteably, it doesn't define what src is, but that is exactly what the error is: I must assume that srcis a global variable and you set src in both your main function and in function getNewValue.
When getNewValue returns, src now points to another workbook in which your ranges don't exist.
Further I am not sure whether opening the workbook again and again results in it being reloaded, reset or that multiple copies will be opened. I suggest you open them only once, e.g.:
Dim src as Object
Dim src2 As Object
Function main (size As Integer)
Dim y As Integer
Dim rowCntr As Integer
Set src = Workbooks.Open("C:Template\Mapping.xlsx")
Set src2 = Workbooks.Open("C:Template\Mapping - Development v1.0.xlsx")
For y = 1 To size
src.Worksheets("Sheet1").Activate
src.Worksheets("Sheet1").Range("B" & rowCntr).Value = "abc"
newValue= getNewValue()
rowCntr=rowCntr+1
Next
End Function
Public Function getNewValue()
Dim newV
newV = 123
'...whatever you want to do...
getNewValue = newV
End Function

no need for selection/activation, use objects (workbook, range) reference instead, like follows
Set src = Workbooks.Open("C:Template\Mapping.xlsx") '<~~ open workbook outside the loop since it doesn't depend on it
For y = 1 To size
src.Worksheets("Sheet1").Range("B" & rowCntr).Value = "abc" '<~~ use "src" workbook reference to point to it whatever may be the currently active workbook
newValue= getNewValue()
rowCntr=rowCntr+1
Next

Related

LibreOffice Calc: Can I get the cell address from VLOOKUP?

I'm using VLOOKUP, in Calc, like this:
VLOOKUP(B11,G2:J7,4,0)
Normally when any of us uses this, we want to get the value in the cell this function finds. In this case, rather than the value, I'd like to get a string with the cell address in it instead or the row and column of that cell. For instance, if I have a double precision floating point value of 30.14 in cell J5 and that's the answer, rather than having it return 30.14, I want it to return something like "J5" or 9,4 or some other way for me to read the result in a macro.
I've tried using =ADDRESS() and =CELL("address", ) but I'm getting errors (=CELL() gives me '#REF!').
EDIT: I'm using this routine as a wrapper around VLOOKUP with a table of floating point numbers (which is why it returns a DOUBLE instead of getting the cell value as a STRING or something else). All I have to do is pass it the column I want to get the data from:
Function getLookup(valColumn as Integer) as Double
oDoc = ThisComponent
oSheet = oDoc.Sheets (workSheet)
rangeInfo = lookupTopLeft + ":" + lookupBottomRight
cellRange = oSheet.getCellRangeByName(rangeInfo)
oCell = oSheet.GetCellByPosition(dataCellColumn, dataCellRow)
searchValue = oCell.getString()
Mode = 0
svc = createUnoService( "com.sun.star.sheet.FunctionAccess" )
args = Array(searchValue, cellRange, valColumn, Mode)
getLookup = svc.callFunction("VLOOKUP", args)
End Function
Note I'm using some local variables in this. They're private, for the module only, so I don't have to change cell references in multiple places while I'm working on designing my spreadsheet. "lookupTopLeft" and "lookupBottomRight" are "G2" and "J7", the top left and bottom right cells for the data I'm working with. "dataCellColumn", and "dataCellRow" are the column and row coordinates for the source for the key I'm using in VLOOKUP.
(#JohnSUN, I think this may be modified from an answer you provided somewhere.)
I'd like to be able to do a similar wrapper routine that would return the column and row of a cell instead of the value in the cell.
One of many possible options:
Option Explicit
Const lookupTopLeft = "G2"
Const lookupBottomRight = "J7"
Const dataCellColumn = 1
Const dataCellRow = 10
Const workSheet = 0
Function getCellByLookup(valColumn As Integer) As Variant
Dim oSheet As Variant, cellRange As Variant, oCell As Variant
Dim oColumnToSearch As Variant
Dim oSearchDescriptor As Variant
Dim searchValue As String
Dim nRow As Long
oSheet = ThisComponent.getSheets().getByIndex(workSheet)
cellRange = oSheet.getCellRangeByName(lookupTopLeft + ":" + lookupBottomRight)
searchValue = oSheet.GetCellByPosition(dataCellColumn, dataCellRow).getString()
Rem If we are looking not for a value, but for a cell,
Rem then using VLOOKUP is unnecessary, a simple Find is enough
oColumnToSearch = cellRange.getCellRangeByPosition(0, 0, 0, _
cellRange.getRows().getCount()-1) ' Resize full range to one first column
Rem Set search params
oSearchDescriptor = oColumnToSearch.createSearchDescriptor()
oSearchDescriptor.setSearchString(searchValue)
oSearchDescriptor.SearchType = 1 ' Search in Values!
Rem Try to find searchValue in oColumnToSearch
oCell = oColumnToSearch.findFirst(oSearchDescriptor)
If Not IsNull(oCell) Then ' Only if the value was found
nRow = oCell.getRangeAddress().StartRow
Rem Offset oCell to valColumn
oCell = cellRange.getColumns().getByIndex(valColumn-1).GetCellByPosition(0,nRow)
getCellByLookup = Replace(oCell.AbsoluteName, "$", "")
Else ' If the value from B11 is not found - warn about it
getCellByLookup = "Not found"
EndIf
End Function

Why is assigning the Value property of cell causing code to end aburptly?

Private Sub FillRow(programCell As Range, storedProgramCell As Range)
Dim counter As Integer
For counter = 3 To 9
Dim cellOffset As Integer
cellOffset = counter - 3
Dim currentStoredCell As Range
Set currentStoredCell = storedProgramCell.Offset(0, cellOffset)
Dim value As String
value = currentStoredCell.value
Dim currentTargetCell As Range
Set currentTargetCell = programCell.Offset(0, cellOffset)
MsgBox currentStoredCell.value 'Works correctly, prints correct value
currentTargetCell.value = value
Next counter
End Sub
The line:
currentTargetCell.value = value
causes the code to stop executing, with no error.
I added the expression to my watch list, then stepped through the routine. The expression was seen as a Boolean:
This makes me think the expression is being viewed as a comparison, and the program abruptly ends since the returned Boolean is not being stored or used anywhere. I wouldn't doubt if I were wrong though.
I'm new to VBA, struggling to debug my program, so please forgive me if this is a petty mistake. I couldn't find any sources online that explains this problem.
Replace your subroutine with following code:
Private Sub FillRow(Dst As Range, Src As Range)
Dim x As Integer
Dim v As Variant
Dim Srcx As Range
Dim Dstx As Range
Debug.Print "FillRow"
Debug.Print Src.Address
Debug.Print Dst.Address
Debug.Print "Loop"
For x = 0 To 6
Debug.Print x
Set Srcx = Src.Offset(0, x)
Debug.Print Srcx.Address
v = Srcx.Value
Debug.Print TypeName(v)
Set Dstx = Dst.Offset(0, x)
Debug.Print Dstx.Address
Dstx.Value = v
Next
Debug.Print "Completed"
End Sub
Run and post in your question Immediate window output.
Value is a reserved word, even if vba does not raise an error on this name, you should not use it. Name it something else. Also, try setting it as a variant.

Knowing the assigned name of a cell instead of the "A1" name

Context:
I have several lists in my sheet (1 column wide, 1-10 rows long). When I right click a cell in these lists, I can do several options, that all work well. I have given a name to the cell at the top of each of these lists (ex. Cell A1 has been given the name cell_1, B10 is names cell_2, etc).
I would like to know if the cell I am right clicking on is the one at the top of the list; is it named "cell_(number)"? If it is not, it checks the cell on top of that one. Does it have a name that starts with "cell_"? If not, check the one on top, etc. Until I can figure out the user clicked on an element of WHICH list.
TL;DR The actual question
I can use ActiveCell.Address, which gives me something like "A1" whether or not I have assigned a name to that cell. ActiveCell.Name gives "Sheet1!A1", so it's not much better. Any idea how to get it to return the name I have assigned instead?
Create a UDF to test the application names, it's less efficient but contains error handling within the function itself:
Sub SO()
'// Example how to call function
Debug.Print GetCellName(Range("A1"))
End Sub
Function GetCellName(myCell As Excel.Range) As Variant
Dim nameCheck As Variant
For Each nameCheck In Application.Names
If Replace(Replace(Replace(nameCheck, "=", ""), "'", ""), "!", "") = _
CStr(myCell.Parent.Name & myCell.Address) Then
GetCellName = CStr(nameCheck.Name)
Exit Function
End If
Next
GetCellName = CVErr(Excel.xlErrName)
End Function
Note you can also use this function in a worksheet cell like so:
=GetCellName(A1)
Perhaps this would work. This function returns the names assigned to a cell (or bigger range for that matter). If there's more than one name, it returns it as an array for array formula...or the user can supply an index to return only the desired name position
Public Function CellIsInRangeNames(sheetname As String, checkRange As Range, Optional itemNumber As Variant) As Variant
Dim oNM As Name
Dim oSht As Worksheet
Dim isect As Range
Dim namesCollection() As Variant
Set oSht = Worksheets(sheetname)
Dim i As Integer
i = -1
For Each oNM In oSht.Names
Set isect = Application.Intersect(Range(oNM.Name), checkRange)
If Not isect Is Nothing Then
i = i + 1
ReDim Preserve namesCollection(0 To i)
namesCollection(i) = CStr(oNM.Name)
End If
Next oNM
If i = -1 Then
'didn't find any
CellIsInRangeNames = xlErrName
ElseIf Not IsMissing(itemNumber) Then
'user wanted this instance only
If (itemNumber - 1 > UBound(namesCollection)) Or (itemNumber - 1 < LBound(namesCollection)) Then
CellIsInRangeNames = xlErrValue
Else
CellIsInRangeNames = namesCollection(itemNumber - 1)
End If
Else 'here's the list as an array
CellIsInRangeNames = namesCollection
End If
End Function

Skip iteration of loop if certain value exists

I have the following code below that iterates through rows of a specific range and if a value is present (code not seen), creates copies of the entire pages. My concern is at the bottom of the code in the iteration of r1. It originally only had one conditional statement...
If BiDiRowValid(r1)
and I wanted to add a second conditional statement, which I did...
and Range("MAIN_BIDI_PINMC") <> "No BiDi"
but when I run the code and the MAIN_BIDI_PINMC range = "No BiDi", it errors out and doesn't get past that line. FYI: IsBiDiRowValid() is a function that checks to see that the specific r1 is not empty, and then continues. Right after that subroutine finishes and exits, my code errors with a "Type Mismatch error". I also added the ElseIf line at the bottom, I have not gotten to that code because the top errors out, but I just want to make sure I am writing this iteration correctly, and if anything else needs to be done. Basically, if "NoBiDi" is found in the range, I want it to skip all of this code and go to the next r1... which is what I think I have written... Thanks in advance!
Private Sub start_new()
Dim MC_List As Range
Dim r1 As Range
Dim biDiPinName As Range
Dim Pin As String
Dim mc As String
Dim mType As String
Dim tabName As String
Dim rowNumber As Integer
Dim pinmcSplit() As String
Dim NoBidi As String
On Error GoTo start_biDi_tr_new_Error
Set MC_List = Range("MAIN_PINMC_TABLE")
Set biDiPinName = Range("MAIN_PIN2_NAME")
For Each r1 In MC_List.Rows
If IsBiDiRowValid(r1) And WorksheetFunction.CountIf(Worksheets("MAIN").Range("MAIN_BIDI_PINMC", "No Bidi") = 0 Then
tabName = r1.Cells(1, 8)
pinmcSplit = Split(tabName, "_")
Pin = pinmcSplit(0)
mc = pinmcSplit(1)
mType = r1.Cells(1, 3)
ElseIf WorksheetFunction.CountIf(Worksheets("MAIN").Range("MAIN_BIDI_PINMC"), "No Bidi") = 1 Then
End If
Next
You are getting that error because Range("MAIN_BIDI_PINMC") is not a single cell. To check for a value in multiple cells you can use Application.Worksheetfunction.Countif
EDIT
Post discussion in chat, the user wanted to loop through each cell.
Dim aCell As Range
For Each r1 In MC_List.Rows
If IsBiDiRowValid(r1) Then
For Each aCell In Worksheets("MAIN").Range("MAIN_BIDI_PINMC")
If aCell.Value <> "No Bidi" Then
tabName = r1.Cells(1, 8)
pinmcSplit = Split(tabName, "_")
Pin = pinmcSplit(0)
mc = pinmcSplit(1)
mType = r1.Cells(1, 3)
End If
Next
ElseIf aCell.Value = "No Bidi" Then
'~~> Do Something
End If
Next

Excel - VBA Object does not support this property or method - Paste - Excel

the line that is giving me trouble is ""Sheets(CStr(WS_M.Cells(n, START_C))).Cells(n, START_C).Paste""
this is supposed to find the tab name in column 3 and go to that tab and paste the tab name in that tab.
Const START_C = 3
Const MAX_TRAN = 1000
Const START_R = 2
Const MASTER = "MASTER"
Sub MOVEDATACORRECTLY()
Dim WS_M As Worksheet
Dim thisWB As Workbook
Set thisWB = ActiveWorkbook
Set WS_M = Worksheets(MASTER)
For M = START_R To (START_R + MAX_TRAN)
If WS_M.Cells(M, (START_C + 1)) = "" Then Exit For
Next M
M = M - 1
For n = START_R To M
WS_M.Cells(n, START_C).Copy
Sheets(CStr(WS_M.Cells(n, START_C))).Cells(n, START_C).Paste
Next n
End Sub
Try this instead:
For n = START_R To M
WS_M.Cells(n, START_C).Copy
Sheets(CStr(WS_M.Cells(n, START_C))).Cells(n, START_C).Select
ActiveSheet.Paste
Next n
If you look at the documentation for the Excel Range object, Paste is not in the list of members. There is PasteSpecial, however. I haven't experimented with that, but that might also work.
For copying a range of cells in Excel, using Copy method makes the VBA program easier to crash / or to give inpredictable results.
Suppose during the your procedure copies data from system clipboard and user was trying to store some other to system clipboard!
Not always, but from users this kind of mistake might happened.
So I always prefer to use a better approach, something like Swaping the range on the fly. Here's a small demonstration:
Public Sub Sample_Copy_without_Clipboard()
Dim dRange As Range, iRange As Range
Set iRange = Range("A1:B3")
Set dRange = Range("D1:E3")
dRange.Value = iRange.Value
End Sub
Note: This method works only with unformatted textual data. If not then either use Tim's suggestion or DanM's answer.