How to Paste Data in Columns and Rows in this way - excel

i have some label data to print in columns and rows format based on the user defined input Value. their are 3 main inputs based conditions:
1) No of starting label to skip 2) No of label per Row 3) No of Rows Per page
I have one data sheet which has data in column A and No of copies to be printed in column B. i am attaching examples images with different input and output in page i expect to be printed. Also giving link to code which could be relevant for my purpose.
Data Sheet
Print Sheet
My codes are limited to 3 columns with unlimited rows and without skip
Here Can you tweak these codes for Userform : Make it small and efficient are codes for dynamic userfrom textbox creation given by #Brian M Stafford but not sure how to implement for this purpose
Public Sub GenerateLabels()
Dim CopyRowValue As String
Dim SecondDataCol, ThirdDataCol, FirstDataCol As Long
Dim SecondDataRow, ThirdDataRow, FirstDataRow As Long
Set shdata = ThisWorkbook.Sheets("Database")
Set shgenerate = ThisWorkbook.Sheets("LabelGenerate")
Set shDesignFormat = ThisWorkbook.Sheets("LabelDesignFormatBeforePrint")
FirstDataCol = shgenerate.Cells(1, shgenerate.Columns.Count).End(xlToLeft).Column
SecondDataCol = shgenerate.Cells(1, shgenerate.Columns.Count).End(xlToLeft).Column
ThirdDataCol = shgenerate.Cells(1, shgenerate.Columns.Count).End(xlToLeft).Column
FirstDataRow = shgenerate.Cells(shgenerate.Rows.Count, "A").End(xlUp).Row
SecondDataRow = shgenerate.Cells(shgenerate.Rows.Count, "C").End(xlUp).Row
ThirdDataRow = shgenerate.Cells(shgenerate.Rows.Count, "E").End(xlUp).Row
'======== Copy From Data Sheet============
Last_Row = Sheets("Database").Range("A" & Rows.Count).End(xlUp).Row
For r = 2 To Last_Row
shdata.Cells(x, "A").Copy
shDesignFormat.Range("B3").Paste 'pasting data to design sheet before print (to format data)
CopyRowValue = Worksheets("Database").Cells(r, "B").value
For r2 = 1 To CopyRowValue
'=====Paste to Generate Sheet ====
'Cells(FirstDataRow + 1, FirstDataCol + 1).Offset(0, 0).Select
If IsEmpty(shgenerate.Cells(FirstDataRow + 0, FirstDataCol + 0).Offset(0, 0).value) = True Then
shDesignFormat.Range("B3").Copy _
Destination:=shgenerate.Cells(FirstDataRow + 0, FirstDataCol + 0).Offset(0, 0)
ElseIf IsEmpty(shgenerate.Cells(SecondDataRow + 0, SecondDataCol + 2).Offset(0, 0).value) = True Then 'offset used to find empty cell if design layout changed
shDesignFormat.Range("B3").Copy _
Destination:=shgenerate.Cells(SecondDataRow + 0, SecondDataCol + 2).Offset(0, 0)
ElseIf IsEmpty(shgenerate.Cells(ThirdDataRow + 0, ThirdDataCol + 4).Offset(0, 0).value) = True Then
shDesignFormat.Range("B3").Copy _
Destination:=shgenerate.Cells(ThirdDataRow + 0, ThirdDataCol + 4).Offset(0, 0)
SecondDataRow = SecondDataRow + 2
ThirdDataRow = ThirdDataRow + 2
FirstDataRow = FirstDataRow + 2
End If
Next r2
Next r
Application.CutCopyMode = False
End Sub

Looking at your code, my first thought was it could be simplified. Once I did this, I began modifying to add needed requirements. The main task was keeping track of the current location. The code ended up like this:
Option Explicit
Public Sub GenerateLabels(ByVal LabelsToSkip As Integer, ByVal LabelsPerRow As Integer, ByVal RowsPerPage As Integer)
Dim shdata As Worksheet
Dim shgenerate As Worksheet
Dim shDesignFormat As Worksheet
Dim curRow As Long
Dim curCol As Long
Dim RowsPerPageCount As Long
Dim r As Long
Dim r2 As Long
Set shdata = ThisWorkbook.Sheets("Database")
Set shgenerate = ThisWorkbook.Sheets("LabelGenerate")
Set shDesignFormat = ThisWorkbook.Sheets("LabelDesignFormatBeforePrint")
shgenerate.UsedRange.ClearContents
curRow = 1
curCol = 1
RowsPerPageCount = 1
For r = 2 To shdata.Range("A" & Rows.Count).End(xlUp).Row
'======== Copy From Data Sheet============
shdata.Cells(r, "A").Copy
shDesignFormat.Range("B3").PasteSpecial 'pasting data to design sheet before print (to format data)
For r2 = 1 To shdata.Cells(r, "B").Value + LabelsToSkip
'=====Paste to Generate Sheet ====
If curCol > LabelsPerRow * 2 Then '* 2 for double spacing
curCol = 1
If RowsPerPage > 0 And (RowsPerPageCount + 1) Mod (RowsPerPage + 1) = 0 Then
curRow = curRow + 10 'new page
RowsPerPageCount = 1
Else
curRow = curRow + 2
RowsPerPageCount = RowsPerPageCount + 1
End If
End If
If r2 > LabelsToSkip Then
LabelsToSkip = 0
shDesignFormat.Range("B3").Copy Destination:=shgenerate.Cells(curRow, curCol)
End If
curCol = curCol + 2
Next r2
Next r
Application.CutCopyMode = False
End Sub
I recommend using Option Explicit and declaring all variables that you need.

Related

My Paste function isn't working and I don't know why

I am trying to copy the entry forms I select from the master list to a different worksheet. The idea is that it goes down a condensed list of names without details. Looks at what I have selected. Copies the selected entry form and pastes it in a new place to generate a list that only contains the entry forms I need. I can't tell if the loop is working properly because the paste function at the end isn't working.
Sub BidList()
'Sets unique terms used throught this code
Dim wQuick As Worksheet, wMaster As Worksheet
Dim BlankFound As Boolean
Dim x As Long, n As Long, y As Long
Dim firstrow As Long, pasterow As Long, lastrow As Long, PasteCell As String, MyRange As String
'Turns off Screen updating to save memory
Application.ScreenUpdating = False
'Store an initial value for "x" effectively starting the macro at C4 after the +1 in the next step
x = 3
n = 0
y = 0
Set wQuick = ThisWorkbook.Sheets("Quick Reference")
Set wMaster = ThisWorkbook.Sheets("MASTER")
BlankFound = False
'Loop until x equals 600
Do While BlankFound = False
x = x + 1
n = n + 1
If Trim(wQuick.Cells(x, "B").Value) = "" Then Exit Do
'If there is a 1 in the Boolean column then ...
If Trim(wQuick.Cells(x, "C").Value) = "1" Then
'Move the y value so that the template is pasted in the appropriate place
y = y + 1
'Copy the appropriate form from wMaster
firstrow = (n * 9) + 18
lastrow = (n * 9) + 27
Let MyRange = "A" & firstrow & ":" & "K" & lastrow
wMaster.Range(MyRange).Copy
'Select the next place for the form to be pasted on wQuick
pasterow = (y * 9) - 5
Let PasteCell = "F" & "," & pasterow
wQuick.Cells(PasteCell).Paste
End If
Loop
Application.ScreenUpdating = True
End Sub
Please avoid copy-paste in Excel, better use a for-loop like the following:
# keep track of MyRange.Row and MyRange.Column
For Each cell in wMaster.Range(MyRange):
wQuick.Cells(<Starting point>).Offset(<take the cell coordinates, based on MyRange.Row and/or MyRange.Column>).Value = cell.Value
Next

Grouping rows in Excel with similar values

I have a table with the first column containing some numbers and I want to loop through and group the rows of my table based on the values in this first column so that they can be collapsible. So similar to what shift+alt+right does. As an example I would want to convert a table with rows like this
1
1
2
3
3
3
Into a table like this with each grouping being expandable and on the same level.
1
2
3
I have been trying to change the macro I found from https://superuser.com/questions/867796/excel-macro-to-group-rows-based-on-a-cell-value. My current macro is...
Dim LastRow As Integer
LastRow = ActiveSheet.UsedRange.Rows.Count
Dim StartRow As Integer
StartRow = 8
groupBegin = StartRow 'For the first group
For i = StartRow To LastRow
If Cells(i, 1).Value <> Cells(i + 1, 1).Value Then
groupEnd = i - 1
Rows(groupBegin & ":" & groupEnd).Select
Selection.Rows.Group
groupBegin = i + 1 'adding one to keep the group's first row
End If
Next i
Rows(groupBegin & ":" & LastRow).Select
Selection.Rows.Group
ActiveSheet.Outline.ShowLevels RowLevels:=1 'Minimize all the groups
This however groups all the rows together. Any guidance on how to achieve this would be appreciated.
Below is the code to do the task. Note that the code assumes the numbers are sorted and there is no blank space between the rows.
Sub Group_Similar_Rows()
Dim i As Long
Dim lRef_Number As Long
Dim lNumber As Long
Dim lCount As Long
Dim lStarting_Row As Long
Dim lDate_Column As Long
Dim wks As Worksheet
lStarting_Row = 1 ' Change this to the starting row of your data
lDate_Column = 1 ' Chnage this to the column index of your data
Set wks = ThisWorkbook.ActiveSheet
lRef_Number = wks.Cells(lStarting_Row, lDate_Column)
lCount = -1
For i = 0 To 100000 ' if your data entry is more than 100,000 increase this the value
If wks.Cells(lStarting_Row + i, lDate_Column) = "" And lCount <= 0 Then
Exit For
End If
lCount = 1 + lCount
lNumber = wks.Cells(lStarting_Row + i, lDate_Column)
If lNumber <> lRef_Number Then
lRef_Number = wks.Cells(lStarting_Row + i, lDate_Column)
If i > 1 Then
lCount = lCount - 1
End If
If lCount > 0 Then
lCount = 1 + lCount
wks.Rows(lStarting_Row + i - lCount & ":" & lStarting_Row + i - 2).Group
End If
lCount = 0
End If
Next i
End Sub
Below is picture showing what the result of running the code:
Example of my comment
dim i as long, j as long
for i = 10 to 1 Step -1
if not cells(i,1).value = cells(i-1,1).value then rows(i).insert
next i
for j = 1 to 10
if cells(j,1).value <> "" then rows(j).group
next j
untested, but should give the appropriate example.

VBA/Formula logic advice

I have a VBA/Formula logic issue which I hope to pick your brains on.
Step 1
User completes a data table from Column C Row 2 onward which tells a macro how many times to duplicate the row by per Column B Row 2.
I have a formula which then populates Column A Row 2 with the column header:
=IF(COUNTA($B2:$D2)=0,"",INDEX($B$1:$G$1,MATCH(FALSE,INDEX(ISBLANK($B2:$G2),0),0)))
The above formula will only populate the first column Name which is great if we are not duplicating the rows. However, the issue is that I need to populate the column header of the row that has been duplicated so it looks at the column after the first one of that row.
Step 2
This is what the finished data table should look like:
Example
Any advice would be appreciated.
Option Explicit
Const TitleRow As Integer = 1
Const StartGenColumn As Integer = 47 ' AU
Sub GenerateRows()
Dim SrcRow As Integer, DestRow As Integer, SrcCol As Integer
Dim NumCoreColumns As Integer, LastGenColumn As Integer
Dim SrcWS As Worksheet, DestWS As Worksheet
Dim i As Integer
NumCoreColumns = StartGenColumn - 1
' find the last column
LastGenColumn = ActiveSheet.Cells(TitleRow, ActiveSheet.Columns.Count).End(xlToLeft).Column
' check if it has the totals
If InStr(ActiveSheet.Cells(TitleRow + 1, LastGenColumn).Formula, "SUM") Then
LastGenColumn = LastGenColumn - 1
Else
' put in a total so that we can tell when we've finished processing
ActiveSheet.Cells(TitleRow + 1, LastGenColumn + 1).Formula = "=SUM(" & ColLetter(StartGenColumn) & (TitleRow + 1) & _
":" & ColLetter(LastGenColumn) & (TitleRow + 1) & ")"
' fill down
ActiveSheet.Range(Cells(TitleRow + 1, LastGenColumn + 1), Cells(ActiveSheet.Rows.Count, LastGenColumn + 1)).FillDown
End If
Set SrcWS = ActiveSheet
If LastGenColumn > StartGenColumn Then
' create the new worksheet
Worksheets.Add
Set DestWS = ActiveSheet
Application.ScreenUpdating = False
' populate the titles
SrcWS.Range(SrcWS.Cells(TitleRow, 1), SrcWS.Cells(TitleRow, NumCoreColumns)).Copy
' always at top of new sheet
DestWS.Range(DestWS.Cells(1, 1), DestWS.Cells(1, NumCoreColumns)).PasteSpecial xlPasteAll
SrcRow = TitleRow + 1
DestRow = 2
' while we still have something to do
Do While SrcWS.Cells(SrcRow, LastGenColumn + 1) <> "" And SrcWS.Cells(SrcRow, LastGenColumn + 1) > 0
' copy the core data
SrcWS.Range(SrcWS.Cells(SrcRow, 1), SrcWS.Cells(SrcRow, NumCoreColumns)).Copy
' what to we need to generate
For SrcCol = StartGenColumn To LastGenColumn
For i = 1 To SrcWS.Cells(SrcRow, SrcCol).Value
DestWS.Range(DestWS.Cells(DestRow, 1), DestWS.Cells(DestRow, NumCoreColumns)).PasteSpecial xlPasteAll
' copy in the title and colour
DestWS.Cells(DestRow, 1).Value = SrcWS.Cells(TitleRow, SrcCol).Value
DestWS.Cells(DestRow, 1).Interior.Color = SrcWS.Cells(TitleRow, SrcCol).Interior.Color
DestRow = DestRow + 1
Next i
Next SrcCol
SrcRow = SrcRow + 1
Loop
Application.CutCopyMode = False
DestWS.Cells(1, 1).EntireColumn.AutoFit
Application.ScreenUpdating = True
End If
End Sub
Private Function ColLetter(Col As Integer) As String
Dim Arr
Arr = Split(Cells(1, Col).Address(True, False), "$")
ColLetter = Arr(0)
End Function

How to duplicate preferred columns data in Conditionally one sheet to multiple sheets

In My office five Employee is working for example In my office Employ Entry Exit sheet is dere..
This is Main Sheet
Now my requirement
category wise data copy to this sheet to other sheet but it's do it automatically
Like Example
enter image description here
I hope I am interpreting your question correctly, but please let me know if I have misinterpreted your request.
Try the following code on your sheet:
Sub AutoCopyByName()
Dim Names() As String
Dim i As Long, NumRows As Long, NameRow() As Long
Dim j As Integer, NumNames As Integer
j = 0
NumSites = 0
'''''''''''''''''''''''''''''''''''''''''''
'''COUNT NUMBER OF ROWS WITH INFORMATION'''
'''''''''''''''''''''''''''''''''''''''''''
i = 2 'Standard Counter (counts all non-blank cells)
NumRows = 1 'Number of rows with information
Do While WorksheetFunction.IsText(Sheets("data").Range("A" & i))
If Sheets("data").Range("A" & i) <> " " Then NumRows = NumRows + 1
i = i + 1
Loop
'''''''''''''''''''''''''''
'''COUNT NUMBER OF NAMES'''
'''''''''''''''''''''''''''
For i = 3 To NumRows + 1
If Sheets("data").Cells(i, 1) <> Sheets("data").Cells(i - 1, 1) Then NumNames = NumNames + 1 'Works
Next i
''''''''''''''''''
'''REDIM ARRAYS'''
''''''''''''''''''
ReDim Names(NumNames)
ReDim NameRow(NumNames)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''FINDING THE LOCATION OF EACH NAME IN THE SHEET AND STORING IT IN NameRow ARRAY'''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
For i = 2 To NumRows + 1
If Sheets("data").Cells(i, 1) <> Sheets("data").Cells(i - 1, 1) Then
Names(j) = Sheets("data").Cells(i, 1).Value
NameRow(j) = i
j = j + 1
End If
Next i
'''''''''''''''''''''''''''''''''''''''''
'''COPY ENTRIES PER NAME TO EACH SHEET'''
'''''''''''''''''''''''''''''''''''''''''
For i = 0 To NumNames - 1
Worksheets.Add
Worksheets(1).Name = Names(i)
Worksheets("data").Rows(1).Copy
Worksheets(Names(i)).Paste
Worksheets("data").Activate
Worksheets("data").Range(Cells(NameRow(i), 1), Cells(NameRow(i + 1) - 1, 1)).EntireRow.Copy
Worksheets(Names(i)).Activate
Worksheets(Names(i)).Range("A2").Select
Worksheets(Names(i)).Paste
Next i
End Sub
I've used the following as my input sheet

How to receive all combinations of all columns?

I am trying to get all row combinations of all columns (say 8 columns). The following vba macro can do that but I get an error that says data overload:
Option Explicit
Const sTitle As String = "shg Cartesian Product"
Sub CartesianProduct()
' shg 2012, 2013
' Choose one from col A, one from col B, ...
Dim rInp As Range
Dim avInp As Variant ' ragged input list
Dim nCol As Long ' # columns in list
Dim rOut As Range ' output range
Dim iCol As Long ' column index
Dim iRow As Long ' row index
Dim aiCum() As Long ' cum count of arrangements from right to left
Dim aiCnt() As Long ' count of items in each column
Dim iArr As Long ' arrangement number
Dim avOut As Variant ' output buffer
Application.ScreenUpdating = False
Set rInp = Range("rgnInp")
If VarType(rInp.Value) = vbEmpty Then
MsgBox Prompt:="No input!", _
Buttons:=vbOKOnly, _
Title:=sTitle
Exit Sub
End If
Set rInp = rInp.CurrentRegion
If rInp.Columns.Count < 2 Or rInp.Rows.Count < 2 Then
MsgBox Prompt:="Must have more than one row and more than one columns!", _
Buttons:=vbOKOnly, _
Title:=sTitle
Exit Sub
End If
With rInp
.Style = "Input"
avInp = .Value
nCol = .Columns.Count
Set rOut = .Resize(1).Offset(.Rows.Count + 1)
Range(rOut.Offset(-1, -1), Cells(Rows.Count, Columns.Count)).Clear
End With
ReDim aiCum(1 To nCol + 1)
ReDim aiCnt(1 To nCol)
aiCum(nCol + 1) = 1
For iCol = nCol To 1 Step -1
For iRow = 1 To UBound(avInp, 1)
If IsEmpty(avInp(iRow, iCol)) Then Exit For
aiCnt(iCol) = aiCnt(iCol) + 1
Next iRow
aiCum(iCol) = aiCnt(iCol) * aiCum(iCol + 1) <------ This is where it says error is
Next iCol
If aiCum(1) > Rows.Count - rOut.Row + 1 Then
MsgBox Prompt:=Format(aiCum(1), "#,##0") & _
" is too many rows!", _
Buttons:=vbOKOnly, Title:=sTitle
Exit Sub
End If
ReDim avOut(1 To aiCum(1), 1 To nCol)
For iArr = 1 To aiCum(1)
For iCol = 1 To nCol
avOut(iArr, iCol) = avInp((Int((iArr - 1) * aiCnt(iCol) / aiCum(iCol))) Mod aiCnt(iCol) + 1, iCol)
Next iCol
Next iArr
With rOut.Resize(aiCum(1), nCol)
.NumberFormat = "#"
.Value = avOut
.Style = "Code"
.Cells(1, 0).Value = 1
.Cells(2, 0).Value = 2
.Cells(1, 0).Resize(2).AutoFill .Columns(0)
End With
ActiveWindow.FreezePanes = False
rOut.EntireColumn.AutoFit
ActiveSheet.UsedRange
Beep
End Sub
Is there away to adjust for this? I also want it to not bring back the same values for a row. So lets say that two columns had the exact same data. If column A has lets say Ice cream, cake, and cookies and so does Column B, I don't want Row 1 to have cookies in column B if it is already picked in Column A.

Resources