Good Afternoon
I have an Excel File this is what it looks.
and I have a VB.Net Program that looks like this.
Now after clicking the Print Transmittal Form the data from Datagridview will transfer into the Excel Format that I created but theres something wrong and here is the output.
The data overwrite this part.
How can I prevent that? Instead of over writing the cells the overwritten part will move down based on how many data on datagridview.
Here is my code.
If DataGridView1.Rows.Count = 0 Then
MsgBox("Nothing to Export")
Else
Dim ExcelApp As Object, ExcelBook As Object
Dim ExcelSheet As Object
Dim rowIndex As Integer = 1
Dim total As Double = 0
ExcelApp = CreateObject("Excel.Application")
ExcelBook = ExcelApp.Workbooks.Open("c:\SR Transmittal.xlsx")
ExcelSheet = ExcelBook.WorkSheets("Transmittal Form")
rowIndex += 11
With ExcelSheet
For i As Integer = 0 To DataGridView1.Rows.Count - 1
Dim columnIndex As Integer = 0
Do Until columnIndex
ExcelSheet.Cells(i + 12, columnIndex + 2).Value = DataGridView1.Item("ItemCode", i).Value.ToString
ExcelSheet.Cells(i + 12, columnIndex + 3).Value = DataGridView1.Item("Description", i).Value.ToString
ExcelSheet.Cells(i + 12, columnIndex + 4).Value = DataGridView1.Item("RequestedQty", i).Value.ToString
ExcelSheet.Cells(i + 12, columnIndex + 5).Value = DataGridView1.Item("UOM", i).Value.ToString
ExcelSheet.Cells(i + 12, columnIndex + 6).Value = DataGridView1.Item("UnitPrice", i).Value.ToString
ExcelSheet.Cells(i + 12, columnIndex + 7).Value = DataGridView1.Item("Total", i).Value.ToString
ExcelSheet.Cells(i + 12, columnIndex + 8).Value = DataGridView1.Item("Remarks", i).Value.ToString
.cells(i + 12, columnIndex + 4).NumberFormat = "#,##0.00"
.cells(i + 12, columnIndex + 6).NumberFormat = "#,##0.00"
.cells(i + 12, columnIndex + 7).NumberFormat = "#,##0.00"
columnIndex += rowIndex
.Columns("A:Z").EntireColumn.AutoFit()
.Columns("A:Z").EntireColumn.Font.Size = 9
Loop
Next
End With
ExcelApp.Visible = True
ExcelSheet = Nothing
ExcelBook = Nothing
ExcelApp = Nothing
End If
TYSM for help
Recently worked on something similar, I achieved it by inserting a new row prior to poplulating with data. For you it would look something like:
For i As Integer = 0 To DataGridView1.Rows.Count - 1
oSheet.Range(oSheet.Cells(i + 12, 2), oSheet.Cells(i + 12, 8)).Insert(Shift:=Excel.XlDirection.xlDown)
'... add row data
Also, FWIW, is the use of columnIndex and its Do Until entirely redundant? The loop will only ever run once (prior to having 12 (rowIndex) added to it?
Related
I would like to be able to copy around 30k rows (to be exact, just some elements of the rows) from sheet A to sheet B, starting the destination from row nr 36155. Sometimes, we copy the row more than once, depending on the number in the G column. This is the macro I've written:
Sub copy()
ActiveSheet.DisplayPageBreaks = False
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculate
Dim k As Long, k1 As Long, i As Integer
k = 36155
k1 = 30000
For i = 1 To k1
For j = 1 To Sheets("A").Range("G" & i + 2).Value
Sheets("B").Range("A" & k).Value = Sheets("A").Range("A" & i + 2).Value
Sheets("B").Range("B" & k).Value = Sheets("A").Range("B" & i + 2).Value
Sheets("B").Range("C" & k).Value = j
Sheets("B").Range("D" & k).Value = Sheets("A").Range("C" & i + 2).Value
Sheets("B").Range("E" & k).Value = Sheets("A").Range("D" & i + 2).Value
Sheets("B").Range("F" & k).Value = Sheets("A").Range("E" & i + 2).Value
Sheets("B").Range("G" & k).Value = Sheets("A").Range("F" & i + 2).Value
Sheets("B").Range("H" & k).Value = Sheets("A").Range("I" & i + 2).Value + (j - 1) * Sheets("A").Range("H" & i + 2).Value
Sheets("B").Range("I" & k).Value = Sheets("A").Range("J" & i + 2).Value
k = k + 1
Next j
Next i
Application.EnableEvents = True
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Unfortunately, this macro takes a lot of time to run (around 10 minutes). I have a feeling that, there may be a better way to do that.. Do you have any ideas, how can we enchance the macro?
Try this using variant arrays: could be even faster if you can use a B array containing more than 1 row. This version takes 17 seconds on my PC.
Sub Copy2()
ActiveSheet.DisplayPageBreaks = False
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculate
'
Dim k As Long, k1 As Long, i As Long, j As Long
Dim varAdata As Variant
Dim varBdata() As Variant
'
Dim dT As Double
'
dT = Now()
'
k = 36155
k1 = 30000
'
' get sheet A data into variant array
'
varAdata = Worksheets("A").Range("A1:J1").Resize(k1 + 2).Value2
'
For i = 1 To k1
'For j = 1 To Sheets("A").Range("G" & i + 2).Value
For j = 1 To varAdata(i + 2, 7)
'
' create empty row of data for sheet B and fill from variant array of A data
'
ReDim varBdata(1 to 1,1 to 9) As Variant
'Sheets("B").Range("A" & k).Value = Sheets("A").Range("A" & i + 2).Value
varBdata(1, 1) = varAdata(i + 2, 1)
varBdata(1, 2) = varAdata(i + 2, 2)
varBdata(1, 3) = j
varBdata(1, 4) = varAdata(i + 2, 3)
varBdata(1, 5) = varAdata(i + 2, 4)
varBdata(1, 6) = varAdata(i + 2, 5)
varBdata(1, 7) = varAdata(i + 2, 6)
varBdata(1, 8) = varAdata(i + 2, 9) + (j - 1) * varAdata(i + 2, 8)
varBdata(1, 9) = varAdata(i + 2, 10)
'
' write to sheet B
'
Sheets("B").Range("A1:I1").Offset(k - 1).Value2 = varBdata
k = k + 1
Next j
Next i
'
Application.EnableEvents = True
Application.CutCopyMode = False
Application.ScreenUpdating = True
MsgBox (Now() - dT)
End Sub
I would suggest you read your data into a recordset as shown here, then loop the recordset.
Try the following (untested).
Sub copy()
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculate
.Calculation = xlCalculationManual
End With
Dim k As Long, i As Integer
k = 36155
' read data into a recordset
Dim rst As Object
Set rst = GetRecordset(ThisWorkbook.Sheets("A").UsedRange) 'feel free to hard-code your range here
With rst
While Not .EOF
For j = 1 To !FieldG
' !FieldG accesses the Datafield with the header "FieldG". Change this to the header you actually got in Column G, like "!MyColumnG" or ![columnG with blanks]
Sheets("B").Cells(k, 1).Value = !FieldA
' ... your code
k = k + 1
Next j
.movenext
Wend
End With
With Application
.EnableEvents = True
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub
Also add the following Function into your VBA Module.
Function GetRecordset(rng As Range) As Object
'Recordset ohne Connection:
'https://usefulgyaan.wordpress.com/2013/07/11/vba-trick-of-the-week-range-to-recordset-without-making-connection/
Dim xlXML As Object
Dim rst As Object
Set rst = CreateObject("ADODB.Recordset")
Set xlXML = CreateObject("MSXML2.DOMDocument")
xlXML.LoadXML rng.Value(xlRangeValueMSPersistXML)
rst.Open xlXML
Set GetRecordset = rst
End Function
Note:
- using a recordset gives you additional options like filtering data
- with a recordset, your not dependent on the column-order of your input-data, meaning you don't have to adjust your macro if you decide to add another column to sheet A (as long as you keep the headers the same)
Hope this helps.
Good Morning
I have a program in VB.Net that exports a file from Datagridview into Excel file
and it looks like this.
My goal here is how can I lock some columns? based on the Image above? Lock all columns except the column that has a color yellow? I mean all the columns except the yellow are uneditable.
Here is my code in exporting excel
Try
If DataGridView1.Rows.Count = 0 Then
MsgBox("Nothing to Export")
Else
Dim ExcelApp As Object, ExcelBook As Object
Dim ExcelSheet As Object
Dim i As Integer
Dim J As Integer
Dim rowIndex As Integer = 1
Dim total As Double = 0
Dim indexTotal As Integer
ExcelApp = CreateObject("Excel.Application")
ExcelBook = ExcelApp.WorkBooks.Add
ExcelSheet = ExcelBook.WorkSheets(1)
With ExcelSheet
rowIndex += 2
For Each column As DataGridViewColumn In DataGridView1.Columns
.cells(rowIndex, column.Index + 1) = column.HeaderText
Next
.Range(.Cells(rowIndex, 1), .Cells(rowIndex, DataGridView1.Columns.Count)).Font.Bold = True
rowIndex += 1
For i = 0 To Me.DataGridView1.RowCount - 1
.cells(rowIndex, 1) = Me.DataGridView1.Rows(i).Cells("ItemCode").Value
For J = 1 To DataGridView1.Columns.Count - 1
If IsNumeric(DataGridView1.Rows(i).Cells(J).Value) Then
.cells(rowIndex, J + 1).NumberFormat = "#,##0.00"
.cells(rowIndex, J + 1) = DataGridView1.Rows(i).Cells(J).Value
Else
.cells(rowIndex, J + 1) = DataGridView1.Rows(i).Cells(J).Value
End If
'You can test also by index for example : if J = indexofTotalColumn then
If DataGridView1.Columns(J).Name = "Total" Then
total += DataGridView1.Rows(i).Cells(J).Value
indexTotal = J
End If
Next
rowIndex += 1
.Columns("A:Z").EntireColumn.AutoFit()
.Columns("L").ColumnWidth = 0
.cells(5).Locked = False
Next
.Protect("fakepwd")
End With
ExcelApp.Visible = True
ExcelSheet = Nothing
ExcelBook = Nothing
ExcelApp = Nothing
End If
Catch
End Try
TYSM for help
Set the Locked property of the cell to false, where J+1 is the desired column number.
For example to unlock column 5 :
For J = 1 To DataGridView1.Columns.Count - 1
If J=5 then
.cells(rowIndex, J + 1).Locked=False
End if
If IsNumeric(DataGridView1.Rows(i).Cells(J).Value) Then
..........
In the code, once you are done populating data in sheet, protect the sheet
Next
.Protect ("fakepwd")
End With
I am new to VBA and sitting with a sum, which includes three if loops. The code looks like this
Dim strKonto As String
Dim str?r As String
Dim strUdbetaling As String
Dim counter As Integer
Dim yearkbottom As Integer
Dim yearktop As Integer
For i = 1 To 50 'wsRefor.Cells(Rows.Count, 2).End(xlUp).Row
For k = 1 To 20 '200
yearkbottom = (wsRefor.Cells(k + 3, 1) - 2007) + 1
yearktop = (yearkbottom - 2007) + 4000
For j = yearkbottom To yearktop
strKonto = Right(wsArk7.Cells(j + 4, 2), 4)
str?r = wsArk7.Cells(j + 4, 1)
strUdbetaling = Left(wsArk7.Cells(j + 4, 2), 1)
counter = Val(str?r) - 2007
If wsRefor.Cells(i + 1, 2) = strKonto Then
If wsRefor.Cells(1, k + 3) = str?r Then
If strUdbetaling = 2 Then
wsRefor.Cells(i + 1, k + 3) = wsRefor.Cells(i + 1, k + 3) + wsArk7.Cells(j + 4, k + 2 - counter * 12)
End If
End If
End If
Next j
Next k
Next i
For the j-loop I tried to make the boundaries dynamic to make the calculations a little slower. That is, I am sure all values which the j loop finds are not spread over the entire range of j, but rather within the range defined above using k.
However, when I make this alteration I get an 1004 "Application-defined or Object-defined error".
Anyone able to spot the mistake, or alternatively to suggest any methods of speeding up the sum?
Best,
ID
EDIT: I found out what the problem was. The j counter took on zero at some point in the new boundaries, and when that happens (or when it is negative) the mistake I got comes up.
Thanks for the help!
Try below one. I have tried to do some fine tuning.
Dim strKonto As String
Dim strr As String
Dim strUdbetaling As String
Dim counter As Integer
Dim yearkbottom As Integer
Dim yearktop As Integer
Dim arryearkbottom(20) 'Declaring a Static Array of Size 21,(Starts from 0 index)
Dim arryearktop(20) 'Declaring a Static Array of Size 21,(Starts from 0 index)
'Initial Values
screenUpdateState = Application.ScreenUpdating
statusBarState = Application.DisplayStatusBar
calcState = Application.Calculation
eventsState = Application.EnableEvents
'Turning off the values for performance
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
'Reading all the values from sheet to Arrays
For i = 1 To 20
arryearkbottom(i) = (wsRefor.Cells(i + 3, 1) - 2007) + 1
arryearktop(i) = (arryearkbottom(i) - 2007) + 4000
Next
For i = 1 To 50 'wsRefor.Cells(Rows.Count, 2).End(xlUp).Row
For k = 1 To 20 '200
'yearkbottom = (wsRefor.Cells(k + 3, 1) - 2007) + 1
'yearktop = (yearkbottom - 2007) + 4000
For j = arryearkbottom(k) To arryearktop(k)
strKonto = Right(wsArk7.Cells(j + 4, 2), 4)
strr = wsArk7.Cells(j + 4, 1)
strUdbetaling = Left(wsArk7.Cells(j + 4, 2), 1)
counter = Val(strr) - 2007
If wsRefor.Cells(i + 1, 2) = strKonto Then
If wsRefor.Cells(1, k + 3) = strr Then
If strUdbetaling = 2 Then
wsRefor.Cells(i + 1, k + 3) = wsRefor.Cells(i + 1, k + 3) + wsArk7.Cells(j + 4, k + 2 - counter * 12)
End If
End If
End If
Next j
Next k
Next i
'Setting to Initial values
Application.ScreenUpdating = screenUpdateState
Application.DisplayStatusBar = statusBarState
Application.Calculation = calcState
Application.EnableEvents = eventsState
Solution2:
Dim strKonto As String
Dim strr As String
Dim strUdbetaling As String
Dim counter As Integer
Dim yearkbottom As Integer
Dim yearktop As Integer
Dim rngwsRefor As Range
Dim rngwsArk7 As Range
'Initial Values
screenUpdateState = Application.ScreenUpdating
statusBarState = Application.DisplayStatusBar
calcState = Application.Calculation
eventsState = Application.EnableEvents
'Turning off the values for performance
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
'Reading Entire sheet values to range
Set rngwsRefor = wsRefor.Cells
Set rngwsArk7 = wsArk7.Cells
For i = 1 To 50 'wsRefor.Cells(Rows.Count, 2).End(xlUp).Row
For k = 1 To 20 '200
yearkbottom = (rngwsRefor(k + 3, 1).Value - 2007) + 1
yearktop = (yearkbottom - 2007) + 4000
For j = yearkbottom To yearktop
strKonto = Right(rngwsArk7(j + 4, 2).Value, 4)
strr = rngwsArk7(j + 4, 1).Value
strUdbetaling = Left(rngwsArk7(j + 4, 2).Value, 1)
counter = Val(strr) - 2007
If rngwsRefor(i + 1, 2).Value = strKonto Then
If rngwsRefor(1, k + 3).Value = strr Then
If strUdbetaling = 2 Then
rngwsRefor(i + 1, k + 3).Value = rngwsRefor(i + 1, k + 3).Value + rngwsArk7.Cells(j + 4, k + 2 - counter * 12).Value
End If
End If
End If
Next j
Next k
Next i
'Setting to Initial values
Application.ScreenUpdating = screenUpdateState
Application.DisplayStatusBar = statusBarState
Application.Calculation = calcState
Application.EnableEvents = eventsState
Good Afternoon to all
I populate data in Datagridview from mySQL like this.
Datagridview Data
the next thing I do is that I have an Export Button and if I Click that it will Export the Data from Datagridview in Excel like this
Extracted in Excel
My Question is How can I Find the Last Data in Column "Total" and Put the Sum below that? As of now the Image shows only two rows in excel but someday it will populate, I just want to Sum up all the data in the Column "Total" and Display the Output in below the last Data. I hope you help me. :(
TYSM
by the way here is my code
If DataGridView1.Rows.Count = 0 Then
MsgBox("Nothing to Export")
Else
Dim ExcelApp As Object, ExcelBook As Object
Dim ExcelSheet As Object
Dim i As Integer
Dim j As Integer
Dim exl As Excel.Application
Dim NewWorksheet As Microsoft.Office.Interop.Excel.Worksheet
Dim myRange As Microsoft.Office.Interop.Excel.Range
ExcelApp = CreateObject("Excel.Application")
ExcelBook = ExcelApp.WorkBooks.Add
ExcelSheet = ExcelBook.WorkSheets(1)
exl = New Excel.Application
exl.Visible = True
With ExcelSheet
For Each column As DataGridViewColumn In DataGridView1.Columns
.cells(1, column.Index + 1) = column.HeaderText
Next
For i = 1 To Me.DataGridView1.RowCount
.cells(i + 1, 1) = Me.DataGridView1.Rows(i - 1).Cells("ItemCode").Value
For j = 1 To DataGridView1.Columns.Count - 1
.cells(i + 1, j + 1) = DataGridView1.Rows(i - 1).Cells(j).Value
.Cells(4, 13) = "Grand Total"
.Cells(4, 14).Formula = "=SUM(Sheet1!$J2:$J1048576)"
Next
Next
End With
NewWorksheet = DirectCast(ExcelBook.Sheets(1), Microsoft.Office.Interop.Excel.Worksheet)
myRange = NewWorksheet.Range("A:K")
myRange.Font.Bold = True
myRange.Font.Size = 9
myRange.Font.FontStyle = "Calibri"
ExcelSheet.Rows.Item(1).EntireColumn.AutoFit()
ExcelApp.Visible = True
ExcelSheet = Nothing
ExcelBook = Nothing
ExcelApp = Nothing
End If
Excel coordinates work by (column, row)
Dim rowIndex As Integer = 1
For i = 1 To Me.DataGridView1.RowCount
.cells(1, i + 1) = Me.DataGridView1.Rows(i - 1).Cells("ItemCode").Value
rowIndex += 1
For j = 1 To DataGridView1.Columns.Count - 1
.cells(j + 1, i + 1) = DataGridView1.Rows(i - 1).Cells(j).Value
Next
Next
.Cells(9, rowIndex + 1) = "Grand Total"
.Cells(10, rowIndex + 1).Formula = "=SUM(Sheet1!J2:J" & rowIndex.ToString().Trim() & ")"
Hello Everyone Good Morning.
I have a Program in VB.Net that will Populate Data from Mysql into the Datagridview.
I have also a button called Export and It will Export Datagridview Data in Excel Format like this.
But my our Prof. likes this Format.
How can I achieve this?
Put a Center Header
Put a .00 at the End of the Number of a Number Column
Find the Last Cell in a Column and Sum It.
I hope someone would help me.
Here is my code in Export
If DataGridView1.Rows.Count = 0 Then
MsgBox("Nothing to Export")
Else
Dim ExcelApp As Object, ExcelBook As Object
Dim ExcelSheet As Object
Dim i As Integer
Dim j As Integer
ExcelApp = CreateObject("Excel.Application")
ExcelBook = ExcelApp.WorkBooks.Add
ExcelSheet = ExcelBook.WorkSheets(1)
With ExcelSheet
For Each column As DataGridViewColumn In DataGridView1.Columns
.cells(1, column.Index + 1) = column.HeaderText
Next
For i = 1 To Me.DataGridView1.RowCount
.cells(i + 1, 1) = Me.DataGridView1.Rows(i - 1).Cells("ItemCode").Value
For j = 1 To DataGridView1.Columns.Count - 1
.cells(i + 1, j + 1) = DataGridView1.Rows(i - 1).Cells(j).Value
Next
Next
End With
ExcelApp.Visible = True
ExcelSheet = Nothing
ExcelBook = Nothing
ExcelApp = Nothing
End If
Try this code :
If DataGridView1.Rows.Count = 0 Then
MsgBox("Nothing to Export")
Else
Dim ExcelApp As Object, ExcelBook As Object
Dim ExcelSheet As Object
Dim i As Integer
Dim j As Integer
Dim rowIndex As Integer = 1
Dim total As Double = 0
Dim indexTotal As Integer
ExcelApp = CreateObject("Excel.Application")
ExcelBook = ExcelApp.WorkBooks.Add
ExcelSheet = ExcelBook.WorkSheets(1)
With ExcelSheet
With .Range(.Cells(rowIndex, 1), .Cells(rowIndex, DataGridView1.Columns.Count))
.HorizontalAlignment = Excel.Constants.xlCenter
.VerticalAlignment = Excel.Constants.xlCenter
.MergeCells = True
.Value = "PURCHASE REQUISITION"
.Font.Bold = True
End With
rowIndex += 2
For Each column As DataGridViewColumn In DataGridView1.Columns
.cells(rowIndex, column.Index + 1) = column.HeaderText
Next
.Range(.Cells(rowIndex, 1), .Cells(rowIndex, DataGridView1.Columns.Count)).Font.Bold = True
rowIndex += 1
For i = 0 To Me.DataGridView1.RowCount - 1
.cells(rowIndex, 1) = Me.DataGridView1.Rows(i).Cells("ItemCode").Value
For j = 1 To DataGridView1.Columns.Count - 1
If IsNumeric(DataGridView1.Rows(i).Cells(j).Value) Then
.cells(rowIndex, j + 1).NumberFormat = "#,##0.00"
.cells(rowIndex, j + 1) = DataGridView1.Rows(i).Cells(j).Value
Else
.cells(rowIndex, j + 1) = DataGridView1.Rows(i).Cells(j).Value
End If
'You can test also by index for example : if j = indexofTotalColumn then
If DataGridView1.Columns(j).Name = "Total" Then
total += DataGridView1.Rows(i).Cells(j).Value
indexTotal = j
End If
Next
rowIndex += 1
Next
.cells(rowIndex, indexTotal) = "Grand Total"
.cells(rowIndex, indexTotal + 1).NumberFormat = "#,##0.00"
.cells(rowIndex, indexTotal + 1) = total
.Range(.Cells(rowIndex, indexTotal), .Cells(rowIndex, indexTotal + 1)).Font.Bold = True
End With
ExcelApp.Visible = True
ExcelSheet = Nothing
ExcelBook = Nothing
ExcelApp = Nothing
End If