Home > Back-end >  Copy selected rows with checkboxes
Copy selected rows with checkboxes

Time:09-28

I run this code ( from this answer ) to copy rows with selected checkboxes to another sheet, surprisingly, it also prints out rows with unselected checkboxes. The logic seems to be right, but I don't know why the output is wrong...

Sub Copy_to_new_sheet()
    Dim Row1 As Long, ChkBx As CheckBox, WS1 As Worksheet, WS2 As Worksheet
    Set WS1 = Worksheets("Top100") 'Source worksheet
    Set WS2 = Worksheets("Top100_Extract") 'Destination worksheet
    WS1.Rows(1).Copy 'Copy header in row 1
    WS2.Rows(1).PasteSpecial xlPasteValues 'Paste header in destination worksheet
    
    Row1 = WS1.Range("A" & Rows.Count).End(xlUp).Row   1
    For Each ChkBx In ActiveWorkbook.Sheets("Top100").CheckBoxes 'The sheet with ckeckboxes must be selected (ActiveSheet)
        If ChkBx.Value = 1 Then
            Row1 = Row1   1
            'Assign value to cells in destination sheet
            WS2.Cells(Row1, "A").Resize(, 14) = Range("A" & _
            ChkBx.TopLeftCell.Row).Resize(, 14).Value
        End If
    Next
End Sub

CodePudding user response:

Here's an approach which will work both for linked cells (the best and simplest way to ensure you're copying the correct cell) and also for cases where you need to check TopLeftCell to determine the row, and allows for some "drift" of the checkbox into the cell above.

Sub Copy_to_new_sheet()
    Const NUM_COLS As Long = 14    'use const for fixed values
    Dim Row1 As Long, ChkBx As CheckBox, WS1 As Worksheet, WS2 As Worksheet, wb As Workbook, c As Range
    
    Set wb = ActiveWorkbook                   'best to be explicit
    Set WS1 = wb.Worksheets("Top100")         'Source worksheet
    Set WS2 = wb.Worksheets("Top100_Extract") 'Destination worksheet

    WS2.Rows(1).Value = WS1.Rows(1).Value     'copy header data

    Row1 = WS1.Range("A" & Rows.Count).End(xlUp).Row   1 'first destination row
    
    For Each ChkBx In WS1.CheckBoxes
        If ChkBx.Value = 1 Then
            Set c = CheckBoxCell(ChkBx)
            WS2.Cells(Row1, "A").Resize(, NUM_COLS) = _
               c.EntireRow.Cells(1).Resize(1, NUM_COLS).Value
            Row1 = Row1   1
        End If
    Next
End Sub

'What cell is a checkbox linked to or "over"?
'Allows for a bit of drift when checking TopLeftCell
Function CheckBoxCell(ChkBx As Object) As Range
    Dim lnk, overlap
    
    lnk = ChkBx.LinkedCell
    If Len(lnk) > 0 Then 'does the checkbox have a linked cell? (##safest method##)
        Set CheckBoxCell = ChkBx.Parent.Range(lnk) 'use the linked cell
    Else
        'no linked cell, so get the TopLeftCell
        Set CheckBoxCell = ChkBx.TopLeftCell
        'how much of the checkbox is actually in that cell?
        overlap = CheckBoxCell.Height - (ChkBx.Top - CheckBoxCell.Top)
        'if less than 20% of the checkbox is in the TopLeftCell, use the next cell down
        If overlap / ChkBx.Height < 0.2 Then Set CheckBoxCell = CheckBoxCell.Offset(1)
    End If
    Debug.Print ChkBx.Parent.Name, ChkBx.Name, CheckBoxCell.Address
End Function

CodePudding user response:

Several things, too long for a comment:
a) If you copy code from an answer of SO, it is nice to reference it (same code can be found here: https://stackoverflow.com/a/73830937/7599798)
b) As far as I understand, the variable Row1 should hold the next free row of the destination sheet (WS2), but you calculate it by checking the source sheet (WS1)
So likely, that row should look like

Row1 = WS2.Range("A" & Rows.Count).End(xlUp).Row   1

c) My advice would be to name those variables like wsSource and wsDest and rowDest to make the meaning more obvious.
d) When copying the row, you are specifying the destination worksheet, but not the source worksheet, therefore the code will copy the data from the active sheet which is not necessarily the source sheet:

WS2.Cells(Row1, "A").Resize(, 14).Value = WS1.Range("A" & _
        ChkBx.TopLeftCell.Row).Resize(, 14).Value

e) If you run the code multiple times, the selected rows will be copied again and again. Not sure if this is intended.


Nothing explains why all rows are copied. As far as I remember, the OP of the linked question had another question asking how to create those checkboxes, but I can't find it anymore. If you did the same (creating the checkboxes via code): Are you sure that you don't have multiple checkboxes on top of each other? An unchecked box could hide a checked box that is exactly at the same position.

What you should do is to debug the code (execute is step by step) or set a breakpoint inside the If and look to the content of the chkBox (name, value, topLeftRow...).

  • Related