I have an excel file in which I have a filled column A with numeric values, I would like to add the text "dt" to the values before the numeric value. Of course, text dt would be added in the entire column where values exist. Unfortunately, something in my code does not work
Imports System
Imports System.IO
Imports Excel
Imports System.IO.FileStream
Imports Microsoft.Office.Interop.Excel
Public Class Form1
Private Sub Button5_Click_1(sender As Object, e As EventArgs) Handles Button5.Click
Dim oExcel As New Microsoft.Office.Interop.Excel.Application
Dim oBook As Microsoft.Office.Interop.Excel.Workbook
Dim oSheet As Microsoft.Office.Interop.Excel.Worksheet
oBook = oExcel.Workbooks.Open("C:\Users\PC\Desktop\1.xlsx")
oSheet = oBook.Worksheets(1)
Dim rg21 = oSheet.Columns("A:A")
rg21.Select()
rg21.NumberFormat = "#"
rg21 = "dt" & rg21
oBook.Save()
oExcel.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(oBook)
System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcel)
oBook = Nothing
oExcel = Nothing
End Sub
End Class
I would use a loop. In Excel VBA:
Sub dural()
Dim r As Range
Set r = Columns(1).Cells.SpecialCells(2)
For Each rr In r
rr.Value = "dt" & rr.Value
Next rr
End Sub
Adapt this to VB.Net.
Simply loop through the cells with value in rg21.
This is the slow version of the loop, as far as you loop through all the 1.000.000+ cells in column A:
For Each rg In rg21.Cells
If Len(rg) Then
rg = "dt" & rg
End If
Next rg
If you want if faster it would be easier to loop only through the cells with values in the first column. Like the example from #Gary's Student:
Set r = Columns(1).Cells.SpecialCells(2)
Related
I am new to VBA and macros.
I got the repeated task of copy data from Excel and paste it in a particular location in the word document.
For example, my excel sheet has the data like this:
Col1
Col2
ID_1
I'm_One
ID_2
I'm_Two
ID_3
I'm_Three
Now i'm looking for a Word macro
Get text in Word table with cell position 3
Find the same text in Excel Col1
Get the value of Col2 from Excel
Paste the value of Col2 in word table with cell position 10
Repeat the same process for another table in Word document
[Update]
I have tried with multiple code snippets by google search but unable to construct the working macro.
Sub pull_from_Excel2()
'ref: https://www.macworld.com/article/211753/excelwordvisualbasic.html
Dim Month As String
ID_Range = "A2:A6" 'Select this as range like "A2:A16"
Offset_to_fetch = 1 'Select this to fetch comments etc. value starts with
Set xlSheet = GetObject("D:\Excel.xlsx")
'Snippets:
'Debug.Print VarType(xlSheet.Worksheets("Sheet1").Range("A3:A5").Value)
'8204
Dim Cell As Range, rng As Range
Debug.Print VarType(xlSheet.Worksheets("Sheet1").Range(ID_Range).Value2)
Set rng = xlSheet.Worksheets(1).Range(ID_Range)
For Each Cell In rng
Debug.Print Cell.Text
Next Cell
End Sub
I used this url to construct my skeleton code: https://www.macworld.com/article/211753/excelwordvisualbasic.html
When i try to get the values from the range of cells in excel, i got the following error for the code.
Set rng = xlSheet.Worksheets(1).Range(ID_Range).Value2
The above line gives "Object required" error when running.
Set rng = xlSheet.Worksheets(1).Range(ID_Range)
The above line gives "Type Mismatch" error when running.
Notes: For this error, I tried to use for each loop as this is array but the error is showing before executing the for loop.
Kindly assist.
I recommend to use Option Explicit and declare all your varibales properly. This way it is less likely that you end up with unseen errors.
To activate it for all new codes that you add in the future, you can activate it directly in Excel and Word. This is a good practice and will protect you from doing it wrong by notifying you of not declared variables:
In the VBA editor go to Tools › Options › Require Variable Declaration.
This will add Option Explicit to new modules only. In existing modules Option Explicit needs to be added manually as first line.
Further I highly recommend to name your variables according what they contain because otherwise it gets very confusing. You named your variable xlSheet but you load a workbook into it and not a worksheet.
The next issue is that your code is in Word and if you declare rng As Range then this is of type Word.Range and not Excel.Range and those are diffetent types so that is why you get a "Type Mismatch" error.
To solve this you either go in Word VBA to Extras › Refereces … and set a reference to the Excel library so you can declare your variable Dim xlRng As Excel.Range or if you don't set a reference you declare it as Object or Variant like in below example:
' This code is in Word!
Option Explicit
Public Sub pull_from_Excel2()
'declare constants
Const ID_Range As Sting = "A2:A6" 'Select this as range like "A2:A16"
Const Offset_to_fetch As Long = 1 'Select this to fetch comments etc. value starts with
Dim xlWorkbook As Object
Set xlWorkbook = GetObject("D:\Excel.xlsx") 'This expects the Excel to be already open! If not open you need to use CreateObject("Excel.Application")
Dim xlRng As Object
Set xlRng = xlWorkbook.Worksheets(1).Range(ID_Range)
Dim xlCell As Object
For Each xlCell In xlRng
Debug.Print xlCell.Text
Next xlCell
End Sub
Note if your workbook Set xlWorkbook = GetObject("D:\Excel.xlsx") is not open in Excel you need to use CreateObject("Excel.Application") and open it.
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
Dim xlWorkbook As Object
Set xlWorkbook = xlApp.Workbooks.Open(FileName:="D:\Excel.xlsx") 'will open the workbook
xlApp.Visible = True 'make it false to open Excel invisible in the background
'your code here …
'in the end close workbook and Excel (espaciall if you had it invisible!)
xlWorkbook.Close SaveChanges:=False
xlApp.Quit 'close Excel
Option Explicit
Sub UpdateTables()
Const XLSX = "D:\Excel.xlsx"
Dim xlApp, wb, ws
Dim rngSearch, rngFound
Dim iLastRow As Long, n As Integer
' open spreadsheet
'Set xlApp = New Excel.Application
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
Set wb = xlApp.Workbooks.Open(XLSX, 1, 1)
Set ws = wb.Sheets(1)
iLastRow = ws.Cells(ws.Rows.Count, "A").End(-4162).Row 'xlUp
Set rngSearch = ws.Range("A2:A" & iLastRow)
' update tables
Dim doc As Document, tbl As Table, s As String
Set doc = ThisDocument
For Each tbl In doc.Tables
s = tbl.Cell(1, 1).Range.Text
s = Left(s, Len(s) - 2)
Set rngFound = rngSearch.Find(s, LookIn:=-4163, LookAt:=1) ' xlValues, xlWhole
If rngFound Is Nothing Then
MsgBox "'" & s & "' not found in table " & tbl.Title, vbExclamation
Else
tbl.Range.Cells(3).Range.Text = rngFound.Offset(0, 1)
n = n + 1
End If
Next
wb.Close False
xlApp.Quit
MsgBox n & " tables updated", vbInformation
End Sub
I'm simply trying to "Cut" a range of cells from one sheet to another. I've never been able to make the ".Cut" work but the ".Copy" works with an error ("Run-time error '424': Object required"). I don't understand why ".Cut" doesn't work as simple as ".Copy" and what the error is.
Private Sub mti_line62_Click()
Dim infreq As Worksheet
Dim freq As Worksheet
Dim mti_player As Range
Dim line62 As Range
Set infreq = ThisWorkbook.Worksheets("INFREQ")
Set freq = ThisWorkbook.Worksheets("Frequent")
Set mti_player = infreq.Range("D" & Rows.Count).End(xlUp).Offset(1)
Set line62 = freq.Range("D62:Q62")
mti_player.PasteSpecial = freq.Range("D62:Q62").Copy
'mti_player.PasteSpecial = freq.Range("D62:Q62").Cut
'mti_player.PasteSpecial = line62.Copy
'freq.Range("D62:Q62").Clear
Application.CutCopyMode = False
infreq.Activate
End Sub
I did succeed to export data from a DataGridView to excel file by using a loop and writing cell by cell, but the problem is i have more than 2000 rows so the exporting process takes a lot of time.
My question is : Is there anything to change so i can minimize the exportation time ?
Thanks
'exporter
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
xlApp = New Excel.Application
xlBook = xlApp.Workbooks.Open(Filename:=Path.Combine(Application.StartupPath, "EMP_.xlsx"), IgnoreReadOnlyRecommended:=True, ReadOnly:=False, Editable:=True)
xlSheet = xlBook.Worksheets(1)
If DataGridView1.DataSource IsNot Nothing Then
Dim i, j As Integer
For i = 1 To DataGridView1.RowCount - 1
For j = 1 To DataGridView1.ColumnCount
xlSheet.Cells(i + 1, j) = DataGridView1.Rows(i - 1).Cells(j - 1).Value
Next
Next
xlApp.Visible = True
xlApp.UserControl = True
xlApp.Quit()
xlApp = Nothing
Else
MsgBox("Le tableau est vide")
End If
End Sub
Not sure if this is something might be open too. By chance if you could load your DataGridView via setting the DataSource of the DataGridView to a DataTable then the following would be an option.
Using SpreadSheetLight (installed via NuGet) you can use a function like the sample below. Pass in the following, full path and file name, sheet name, the DataTable from the DataGridView e.g. Dim dt As DataTable = CType(DataGridView1.DataSource,DataTable) and the last argument if True included column headers (DataColumn names) or False exclude column names.
SpreadSheetLight home page.
Public Sub SimpleExportRaw(
pFileName As String,
pSheetName As String,
pDataTable As DataTable,
pColumnHeaders As Boolean)
Using doc As New SLDocument()
doc.SelectWorksheet(pSheetName)
doc.ImportDataTable(1, SLConvert.ToColumnIndex("A"), pDataTable, pColumnHeaders)
doc.SaveAs(pFileName)
End Using
End Sub
I would like to count the lines that have values. I tried oSheet.Rows.Count but that doesn't work. Any idea about this?
My code is the following:
Dim oExcel As Object
Dim oBook As Object
Dim oSheet As Object
oExcel = CreateObject("Excel.Application")
oBook = oExcel.Workbooks.Add
oSheet = oBook.Worksheets("Sheet")
oSheet.Range("A" & max).Value = "0000111"
oSheet.Range("B1").Value ="Name"
oBook.SaveAs("C:\New folder\excel\" & datenw & ".xlsx")
oExcel.Quit()
As said in the comments, the following code should get you the count of rows that have values based on your Range:
Dim rowCount As Integer = oSheet.UsedRange.Rows.Count()
There is however a slight issue with your code I believe. This probably won't work:
oSheet = oBook.Worksheets("Sheet")
The reason it won't, is because "Sheet" doesn't exist on a new Workbook. "Sheet1" does, so this needs to be changed to:
oSheet = oBook.Worksheets("Sheet1")
'or
oSheet = oBook.Worksheets(1) 'remember Excel collections are one based not zero based
Lastly I would look at the way you are closing Excel as oExcel.Quit() is probably leaving an instance of Excel running. Have a look at this answer which links to Siddharth Rout's bit of code:
Private Sub ReleaseObject(ByVal obj As Object)
Try
Dim intRel As Integer = 0
Do
intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
Loop While intRel > 0
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
You also to make sure you release in the right order and release everything. This is usually in backwards order:
ReleaseObject(oSheet)
oBook.Close()
ReleaseObject(oBook)
oExcel.Quit()
ReleaseObject(oExcel)
However with all that said I would look at using the Microsoft.Office.Interop.Excel namespace directly rather than declaring objects:
Imports Microsoft.Office.Interop
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim oExcel As New Excel.Application
Dim oWorkbooks As Excel.Workbooks = oExcel.Workbooks
Dim oWorkbook As Excel.Workbook = oWorkbooks.Add()
Dim oSheets As Excel.Sheets = CType(oWorkbook.Sheets, Excel.Sheets)
Dim oWorksheet As Excel.Worksheet = CType(oSheets(1), Excel.Worksheet)
Dim oARange As Excel.Range = oWorksheet.Range("A" & max.ToString()) 'Not sure what max is but I took the assumption it's an Integer
oARange.Value = "0000111"
Dim oBRange As Excel.Range = oWorksheet.Range("B1")
oBRange.Value = "Name"
Dim oUsedRange As Excel.Range = oWorksheet.UsedRange()
Dim rowCount As Integer = oUsedRange.Rows.Count()
oWorkbook.SaveAs("C:\Test.xlsx")
ReleaseObject(oUsedRange)
ReleaseObject(oBRange)
ReleaseObject(oARange)
ReleaseObject(oWorksheet)
ReleaseObject(oSheets)
oWorkbook.Close()
ReleaseObject(oWorkbook)
ReleaseObject(oWorkbooks)
oExcel.Quit()
ReleaseObject(oExcel)
End Sub
Private Sub ReleaseObject(ByVal obj As Object)
Try
Dim intRel As Integer = 0
Do
intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
Loop While intRel > 0
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
End Class
I would also then look at turning Option Strict On:
Restricts implicit data type conversions to only widening conversions, disallows late binding, and disallows implicit typing that results in an Object type.
Define a row variable as Long, then start a loop which will end when it finds a blank value in column A:
Dim lRow as Long = 1
Do until oSheet.Range("A" & lRow).Value=""
' increment the loop variable
lRow+=1
Loop
' display the result in a message block
MsgBox(lRow-1)
I need to loop the read data from excel to vb.net and when I reach the last row/column "!##$%^&*()" the excel data will stop read. How can I do that?
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Form1
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
Dim xRange As Excel.Range
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub cmdGenerate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdGenerate.Click
'Dim row As String
Dim empty_cell_ctr As Integer = 0 '5
Dim end_of_xlsheet As Boolean = False
Dim sRow As Integer 'start row
Dim col_end As Integer 'col W
'
'loading excel(open and read)
xlApp = New Excel.ApplicationClass
xlWorkBook = xlApp.Workbooks.Open("c:\sample.xls")
xlWorkSheet = xlWorkBook.Worksheets("Timesheet")
xlApp.Visible = True
While Not end_of_xlsheet
If sRow = "'!##$%^&*()_+" Then
xRange = xRange.Cells(sRow, col_end)
end_of_xlsheet = False 'end of sheet
Continue While
End If
sRow += 1
End While
MessageBox.Show(sRow)
End Sub
End Class
You seem to be overthinking this, you can get all of the data in the spreadsheet by accessing the UsedRange property, and then load this into a 2D array variable by accessing the Value2 property of this object like so:
Dim application = New Excel.Application()
Dim workbook As Excel.Workbook = application.Workbooks.Open("C:\aaa\bbb.xlsx")
Dim worksheet As Excel.Worksheet = workbook.Sheets(1)
Dim usedRange = worksheet.UsedRange
Dim usedRangeAs2DArray As Object(,) = usedRange.Value2
workbook.Save()
workbook.Close()
application.Quit()
Marshal.ReleaseComObject(application)
You may use LIKE operator :)
'Not sure why you are trying to check Row number for set of characters...
Excel.Range range = sheet.UsedRange;
Int rows_count = range.Rows.Count;
For (int sRow = 1; sRow <= rows_count; sRow++)
If (sheet.Cells[sRow, col_end].value Like "*'!##$%^&*") Then
'-- input the data to where ever you want. It is best to store it into an array first..
xRange = sheet.Cells[i, col_end].value;
Break;
Else
sRow++;
End If
Please take a look the following reference for better understanding your options.
import data from Excel to VB.Net
read data from Excel to VB.Net