I would like to hide multiple columns inside an excel worksheet. This works pretty fine using:
ActiveSheet.Range("R10:CO10").EntireColumn.Hidden = True
"R10" is the first and fix column to hide. The second column and all columns between to hide will be dynamically determined depending on it´s date value.
Sample Coding:
Private Sub Worksheet_Activate()
Dim c As Range
Dim start As String
Dim ende As String
start = "R10"
ende = "CO10"
Dim d As Date
d = Date
For Each c In Range("R10:HU10")
If c = (d - 8) Then
ende = **how to assign???**
End If
If c = (d - 7) Then
Application.Goto c, True
End If
Next c
'ActiveSheet.Range(**"start:ende"**).EntireColumn.Hidden = True
End Sub
Row 10 holds date values and I would like to hide all columns which dates are older than 7 days and I can´t find any hints about hiding multiple columns using variables or with column identifier or the number of the column etc.
The use of variables ends up in runtime error 1004.
As Scott pointed out, my first answer was not complete. You can use the following function:
Function GetColChars(col As Integer) As String
Dim coldown As Integer 'Column Countdown
Dim colrem As Integer 'Coumn Value Remaining
Dim colname As String 'Temporary String value for column name
Const alphanums = 26
Const aposition = 64
coldown = col
colname = ""
While coldown > 0
colrem = coldown Mod alphanums
If colrem = 0 Then colrem = 26
newchar = Chr(64 + colrem)
colname = newchar & colname
coldown = Int((coldown - 1) / alphanums)
Wend
GetColChars = colname
End Function
Then call the function to get the column letters:
ende = GetColChars(c.column)
I have tested Scotts solution approach and finally got it working. In that case that some other people will struggle with the same problems, getting a working solution, here is my solution:
Private Sub Worksheet_Activate()
Dim lastDateRangeColumn As Range
Dim givenDateRange As Range
Set givenDateRange = ActiveSheet.Range("R10:HU10")
Dim firstDateRangeColumn As Range
Set firstDateRangeColumn = ActiveSheet.Range("R10")
Dim todaysDate As Date: todaysDate = Date
For Each tempDateRangeColumn In givenDateRange
If tempDateRangeColumn < (todaysDate - 7) Then
Set lastDateRangeColumn = ActiveSheet.Range(tempDateRangeColumn.Address)
End If
If tempDateRangeColumn = (todaysDate - 7) Then
Application.Goto tempDateRangeColumn, True
End If
Next tempDateRangeColumn
Dim firstColumnNumber As Long
Dim lastColumnNumber As Long
firstColumnNumber = Range(firstDateRangeColumn.Address).Column
lastColumnNumber = Range(lastDateRangeColumn.Address).Column
Dim rangeToBeHidden As Range
Set rangeToBeHidden = Range(Cells(1, firstColumnNumber), Cells(1, lastColumnNumber))
rangeToBeHidden.EntireColumn.Hidden = True
End Sub
Related
I have a sheet where the first column holds the dates which can be in any date format. I am required to pass the date in the string format of MMM-yy into a function to get the cell address, but I am ending up getting either Error 2042 or type mismatch as I am trying to compare string & date. Given the scenario how do I solve the type-casting issue? My function is shared below:
Function getcellAddress(ByVal col As String, ByVal row As String) As Range
Dim r, c As Variant
Dim maxRowCount As Integer
With ActiveSheet
r = Application.Match(row, Format(.Columns("A"), "MMM-yy"), 0)
c = Application.Match(col, .Rows(1), 0)
'add new record when company not found
If IsError(r) And IsAllOther = False Then
r = 65636
c = 256
End If
Set getcellAddress = .Cells(r, c)
End With
End Function
And here's how I am calling this function in a Sub Procedure:
Dim lookUp As String
lookUp = getcellAddress("A", "May-21").Offset(-1, 0).Address
Sample Date Column has dates like
A
1 Jan-21
2 Feb-21
3 Mar-21
4 Apr-21
5 May-21
The expected Output needs to be A5.
Once you change the dates as I mentioned in your previous question, try this simple code to achieve what you want. Change as applicable.
Option Explicit
Sub Sample()
Dim r As Range
Set r = getcellAddress("Sep-21", "A")
If Not r Is Nothing Then
MsgBox r.Address
Else
MsgBox "Not Found"
End If
End Sub
Function getcellAddress(searchString As String, Col As String) As Range
Dim CurrentRow As Variant
CurrentRow = Application.Match(searchString, Columns(Col), 0)
If Not IsError(CurrentRow) Then
Set getcellAddress = Range(Col & CurrentRow)
End If
End Function
I'm a newbie in the programming world and I'm currently facing a challenge on VBA.
I've built a monthly calendar spreadsheet, and below every day number there is an empty space to be filled depending on some conditions.
I want to fill these spaces with a list of names, depending if the person has the value of Active or not. Another imposed condition is if the date of the calendar is a holliday the cell will remain an empty space, therefore I did a list of hollidays to test this condition.
Here goes the code i made so far:
Sub teste()
line_fill = 5
line_names = 3
column_names = 17
column_active = 18
For i = 6 To 10
Dim values As Worksheets("Planilha1").Cells(5, i))
Dim test As Worksheets("Planilha1").Cells(line_fill - 1, i)
Dim names As Worksheets("Planilha1").Cells(line_names, column_active)
Dim active As Worksheets("Planilha1").Cells(line_names, column_names)
If IsEmpty(test) And test.value <> WorksheetFunction.VLookup(test.value, Sheet1.Range("M4:M100"), 1, False) Then
If names.value = "Ativo" Then
values = active
line_names = line_names + 1
i = i + 1
Next i
End Sub
Image of the spreadsheet
Link to the spreadsheet I'm using
Please try to step through the code with F8 so you understand what I did and try to adjust it to fit your needs.
This is the setup I used to code it:
And this is the code:
Option Explicit
Public Sub CopyValuesInCalendar()
Dim targetSheet As Worksheet
Dim calendarRange As Range
Dim holidaysRange As Range
Dim teamRange As Range
Dim evalDayCell As Range
Dim teamFilteredList As Variant
Dim holidayLastRow As Long
Dim teamLastRow As Long
Dim counter As Long
Set targetSheet = ThisWorkbook.Worksheets("Planilha1")
targetSheet.AutoFilterMode = False
Set calendarRange = targetSheet.Range("D4:J13")
holidayLastRow = targetSheet.Cells(targetSheet.Rows.Count, 12).End(xlUp).Row
teamLastRow = targetSheet.Cells(targetSheet.Rows.Count, 16).End(xlUp).Row
Set holidaysRange = targetSheet.Range("L4:N" & holidayLastRow)
Set teamRange = targetSheet.Range("P3:Q" & teamLastRow)
teamFilteredList = GetActiveTeamMembers(teamRange)
For Each evalDayCell In calendarRange.Cells
If IsNumeric(evalDayCell.Value) And evalDayCell.Value <> vbNullString Then
If Not IsHoliday(evalDayCell.Value, holidaysRange) Then
If counter > UBound(teamFilteredList) Then
counter = 1
Else
counter = counter + 1
End If
evalDayCell.Offset(1, 0).Value = GetTeamMemberName(counter, teamFilteredList)
End If
End If
Next evalDayCell
End Sub
Private Function IsHoliday(ByVal dayNum As Long, ByVal holidayRange As Range) As Boolean
Dim evalCell As Range
For Each evalCell In holidayRange.Columns(1).Cells
If evalCell.Value = dayNum Then
IsHoliday = True
End If
Next evalCell
End Function
Private Function GetActiveTeamMembers(ByVal teamRange As Range) As Variant
Dim evalCell As Range
Dim counter As Long
Dim tempList() As Variant
For Each evalCell In teamRange.Columns(1).Cells
If evalCell.Offset(0, 1).Value = "Ativo" Then
ReDim Preserve tempList(counter)
tempList(counter) = evalCell.Value
counter = counter + 1
End If
Next evalCell
GetActiveTeamMembers = tempList
End Function
Private Function GetTeamMemberName(ByVal counter As Long, ByVal teamFilteredList As Variant) As String
GetTeamMemberName = teamFilteredList(counter - 1)
End Function
Let me know if it helps.
I am trying to get my codes to go through each DateTime column and search for cells that contain "00:00" as hours and minutes. If the value exists, remove 00:00 and only leave the date. For the cells that don't contain that value, leave the cells as they are. For example, if "3/22/2017 00:00", then format it to "3/22/2017". Otherwise, if "3/22/2017 09:16", leave it alone. Thank you in advance!
dataGrid.DataSource = dataSet.Tables(0)
dataGrid.DataBind()
ws.Cells(1, 1).LoadFromDataTable(dataGrid.DataSource, True)
Dim data = dataGrid.DataSource
Dim columnCount = data.Columns.Count
For i = 0 To columnCount - 1
If data.Columns(i).DataType Is GetType(DateTime) Then
If Not data.Columns(i).ToString.Contains("00:00") Then
ws.Column(i + 1).Style.Numberformat.Format = "mm/dd/yyyy hh:mm"
Else
ws.Column(i + 1).Style.Numberformat.Format = "mm/dd/yyyy"
End If
End If
Next
For your solution to work, you would need to set the style on each individual cell. This is an inefficient solution as a style would be created for each cell. Is could be mitigated somewhat by defining two different styles and assigning those references to the cell as needed.
A simpler solution is use the DataGridView.CellFormatting Event to set the format when the cell is painted.
Evidently, the DateTime values have a time component less than one minute because the default formatting would have yield the desired result if this was not the case. The code below sets the format based on whether the time component is less than one minute.
Private Shared tsLimit As New TimeSpan(0, 1, 0) ' 1 minute
Private Shared dtType As Type = GetType(DateTime)
Private Sub dataGrid_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles dataGrid.CellFormatting
Dim dgv As DataGridView = CType(sender, DataGridView)
Dim dt As DataTable = TryCast(dgv.DataSource, DataTable)
If dt IsNot Nothing Then
Dim sourceColumn As DataColumn = dt.Columns.Item(dgv.Columns.Item(e.ColumnIndex).DataPropertyName)
If sourceColumn IsNot Nothing AndAlso sourceColumn.DataType Is dtType AndAlso e.Value IsNot Nothing AndAlso Not e.Value Is DBNull.Value Then
Dim d As DateTime = CDate(e.Value)
If d.TimeOfDay < tsLimit AndAlso d.Hour <> 0 Then
e.CellStyle.Format = "mm/dd/yyyy"
Else
e.CellStyle.Format = "mm/dd/yyyy hh:mm"
End If
End If
End If
End Sub
This can be accomplished by:
Setting a default format for all DateTime columns
Only overriding the default format for values that meet your criteria.
Here's a simple helper method that handles multiple DateTime columns:
Sub SetDateTimeStyles(ByRef data As DataTable, ByRef ws As ExcelWorksheet)
' Track DateTime columns to override default column style
Dim dateTimeColumns = New List(Of Integer)()
' Set column format
Dim columnCount = data.Columns.Count
For i = 0 To columnCount - 1
If data.Columns(i).DataType Is GetType(DateTime) Then
Dim epPlusColumn = i + 1
ws.Column(epPlusColumn).Style.Numberformat.Format = "mm/dd/yyyy hh:mm"
dateTimeColumns.Add(epPlusColumn)
End If
Next
' Header row exists; set to 1 if no header row
Dim rowOffset = 2
Dim rowCount = data.Rows.Count
' Only set cell format when hour and minute are **both** zero
For i = 0 To rowCount - 1
For Each dateTimeColumn In dateTimeColumns
Dim value As DateTime = data(i)(dateTimeColumn - 1)
If value.Hour = 0 AndAlso value.Minute = 0 AndAlso value.Second = 0 Then
ws.Cells(i + rowOffset, dateTimeColumn) _
.Style.Numberformat.Format = "mm/dd/yyyy"
End If
Next
Next
End Sub
And call it when creating the Excel file:
dataGrid.DataSource = dataSet.Tables(0)
dataGrid.DataBind()
ws.Cells(1, 1).LoadFromDataTable(dataGrid.DataSource, True)
Dim data As DataTable = dataGrid.DataSource
SetDateTimeStyles(data, ws)
Result:
I have a userform whose image is below.
What i need is when i open the userform, there should be sequential number against voucher # textbox.
for example.
Column B has values BPV/1, BPV/2, BPV/3.
What i need is when i run the userform, the voucher # textbox should show the next serial number i.e. BPV/4 and so on...
Below is my code.
Private Sub UserForm_Initialize()
Dim NextNum As Long, prefix As String
Dim i As Long
prefix = "BPV/"
NextNum = Application.WorksheetFunction.Max(Worksheets("Sheet1").Columns(2))
i = NextNum + 1
Me.TextBox2.Enabled = False
Me.TextBox2.Value = prefix & i
End Sub
Kindly review the code and advise how to achieve it.
Thanks
Salman Khan
In order to find the Max value in Column B , that consists of Strings, I am reading the strings into an array on type Long (in case you have very large numbers), using the Mid function. Afterwards, I can find the Max value in the array of numbers.
Conveting using the Mid function is done with the following line:
myArr(lRow) = CLng(Mid(.Cells(lRow, 2), 5))
the value 5 is calculated by Len(prefix) +1
Code
Option Explicit
Private Sub UserForm_Initialize()
Dim NextNum As Long, prefix As String
Dim LastRow As Long, lRow As Long
Dim myArr() As Long
prefix = "BPV/"
With Sheets("Sheet1")
'find last row with data in Column B
LastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
ReDim myArr(2 To LastRow)
' read all cells contents and convert them to array of numbers
' start from 2nd row , 1st row has headers
For lRow = 2 To LastRow
If Mid(.Cells(lRow, 2), 5) <> "" Then
myArr(lRow) = CLng(Mid(.Cells(lRow, 2), 5))
End If
Next lRow
' find maximum value in array
NextNum = WorksheetFunction.Max(myArr)
End With
Me.TextBox2.Enabled = False
Me.TextBox2.Value = prefix & NextNum + 1
End Sub
You could enter this FormulaArray in Sheet1 let's say in A1:
=MAX(VALUE(SUBSTITUTE(B:B,"BPV/","")))
Then have this line pointing to that cell:
NextNum = Worksheets("Sheet1").Range("A1").value2
FormulaArrays are entered pressing* [Ctrl] + [Shift] + [Enter] simultaneously, you shall see { and } around the formula if entered correctly
This solutions uses the Application.Evaluate Method (Excel) to obtain the Last Voucher number at once avoiding the use of For...Next. It also uses constants (Const) to hold the Prefix and the MAX formula.
Private Sub UserForm_Initialize_EEM_Publish()
Const kPrefix As String = "BPV/"
Const kFml As String = "=MAX(IFERROR(1" & _
"*VALUE(SUBSTITUTE(#rTrg,""#Prefix"",""""))" & _
"*(SEARCH(""#Prefix"",#rTrg)),0))"
Dim rTrg As Range, sFml As String
Dim lNextNum As Long, l As Long
Rem Get Last Voucher Number
With ThisWorkbook.Worksheets("Sheet1").Columns("B")
Set rTrg = .Cells(1).Resize(.Cells(.Rows.Count).End(xlUp).Row)
End With
sFml = kFml
sFml = Replace(sFml, "#Prefix", kPrefix)
sFml = Replace(sFml, "#rTrg", rTrg.Address(, , , 1))
lNextNum = Application.Evaluate(sFml)
Rem Set Next Voucher Number
l = 1 + lNextNum
Me.TextBox2.Enabled = False
Me.TextBox2.Value = sPrefix & i
End Sub
i have a problem with my macro. I know its alot of code (sry for that) but i think it could be helpfull. So the basic thing i want to do is, take the value of the combobox and search for it in another worksheet to get the price written in the next column.
easy so far, but the name im searching for is not unique in the database. the one im searching for is only defined by beeing part of the correct named range (i.e. EngineMercedesDiesel)
Function getprice(Matrix As Range, name As String)
Dim i As Integer
Dim row As Variant
Dim col As Variant
Dim price As Variant
'loop to finde inside the range the name im looking for
For i = 1 To Matrix.Rows.Count
If Matrix.Cells(i, 1).Value = name Then
row = Matrix.Cells(i, 1).Address(RowAbsolute:=True)
col = Matrix.Cells(i, 1).Address(ColumnAbsolute:=True)
price = Tabelle2.Cells(row, col + 1).Value
Exit For
Next
getprice = price
End Function
Private Sub cbschaltung_Change()
Dim go As Range
Dim handle As String
'from here it builds the name i.e. EngineMercedesDiesel an there is a Named range with the same titel outside VBA
teil = Range("A4").Value
hersteller = Range("B3").Value
handle = cbschaltung.Value
If checkboxel.Value = True Then
c = checkboxel.Caption
Set go = teil & hersteller & c 'storing to the variable go, here ocures the error
Tabelle3.Range("C4").Value = getprice(go, handle)
ElseIf checkboxmech.Value = True Then
c = checkboxmech.Caption
Set go = teil & hersteller & c
Tabelle3.Range("C4").Value = getprice(go, handle)
End If
End Sub
I hop you can help me and (hopefully) you have a easy answer for me
ok i did it finally !
ElseIf checkboxmech.Value = True Then
c = checkboxmech.Caption
mname = teil & hersteller & c
Set go = Worksheets("Gruppendatenbank").Range(mname)
Tabelle3.Range("C4").Value = getprice(go, handle)
it was immportant to define mname as variant datatype and define also the worksheet of my range.
thank for the help
statusupdate: solved !