Clearing cells in excel and 6 checkboxes - vba

I have a button in Excel with a VBA script attached to it to clear certain cells on a sheet.
Is there a cleaner code to achieve the same result?
Also for my checkboxes for some reason 1 piece of code clears all 6 boxes, is this right?
The checkboxes are activeX boxes I added through the developer view.
Sub ClearForm()
Range("I9:I10").Select
Selection.ClearContents
Range("I13:I17").Select
Selection.ClearContents
Range("H20").Select
Selection.ClearContents
Range("C5").Select
Selection.ClearContents
Range("C9:C10").Select
Selection.ClearContents
Range("C13:C18").Select
Selection.ClearContents
Dim OleObj As OLEObject
For Each OleObj In ActiveSheet.OLEObjects
If OleObj.progID = "Forms.CheckBox.1" Then
OleObj.Object = False
End If
Next OleObj
End Sub

Well for one thing you can have a string of ranges and do it all at once.
Range("I9:I10, I13:I17, H20, C5, C9:C10, C13:C18").Select
Selection.ClearContents
as for your check-boxen, if by "clear" you mean "Removes" or "Deletes" then yes it makes sense, if on the other hand all you want to do is clear a checkbox then I think this is what you need in the loop:
OleObj.Object.Value = False

To answer your first question:
Range.Select is unecessary and actually slows execution down a bit. You can directly call .ClearContents on the range object itself. I imagine you did the Range.Select bit because of macro recorder. Whilst a useful tool to learn about Excel object model, also bear in mind that it does churn out some ugly bits ;-)
As you are performing the same set of commands several times, it is also generally better practice to encapsulate the steps into their own sub to a) have a neater 'main' procedure and b) easily enable to you adapt the process, should you later wish it.
However, this second point is definitely optional if this is a minor and unlikely to change part of your code, as the actual 'step' is just a single call to Range.ClearContents. Indeed, if it is literally intended to only clear 5 cells, I would probably just keep it like you do in the sub. I show the alternative below just for reference for more complex bits in the future.
Finally, if the group of ranges you wish to clear or do things to could change, it is also considered good practice to define a set of the ranges and enumerate the set (aka "looping through") rather than specifying identical commands for each range itself. Most objects will be handled through a Collection or an array. However for ranges, a range can contain many ranges of contiguous and non-contiguous cells. Each group of contiguous cells is referenced by using the .Areas property of the range object, which returns a range of the area. I also demonstrate this below.
Note that as another answerer has shown, Range.ClearContents can operate on multiple Areas at once so looping through Areas is not necessary in this case (it is for many other operations).
For example:
Sub ClearForm()
Dim rng As Range
For Each rng in Range("I9:I10,I13:I17,...etc...").Areas
clearRange rng
Next rng
...Rest of code...
End Sub
Private Sub clearRange(rng As Range)
rng.ClearContents
End Sub
With respect to your second question: the 6 checkboxes are cleared because you loop through all activex objects on the sheet in the last part of your code and set their Value property to False, which for a checkbox unchecks it.

Related

Link Excel Chart Axis Scale to Values in Cells

I have this Gantt Chart and i'm looking at Planned Vs Actual dates.
the problem is that the chart wont sync the start/end date.
i'm trying to link the max/min values to the cell with VBA but it wont to it.
I tried to use this site:
https://peltiertech.com/link-excel-chart-axis-scale-to-values-in-cells/
but his code doesn't work for my chart.
here is a picture:
the dates MUST be the same, and change together if i change some values in the table on the right
any ideas?
thanks
Private Sub Worksheet_Change(ByVal Target As Range)
With ActiveSheet.ChartObjects("Chart 2").Chart
Select Case Target.Address
Case "$G$161"
.Axes(xlCategory).MaximumScale = Target.Value
Case "$F$163"
.Axes(xlCategory).MinimumScale = Target.Value
Case "$G$161"
.Axes(xlValue).MaximumScale = Target.Value
Case "$F$163"
.Axes(xlValue).MinimumScale = Target.Value
End Select
End With
End Sub
The code you have re-used is a simple demonstration program which allows the axes of a chart to be manipulated when one of 6 specific cells on the worksheet is changed. However, these changes are intended to be made by the user through the keyboard. Making a change in this way triggers the Worksheet_Change event and allows the changed cell to be identified. The code within the event routine modifies the chart's axes according to which specific worksheet cell has been changed.
Your issue, as David Ziemens noted in his comment, is that if a cell changes value because it is recalculated through a formula then this change does not trigger a Worksheet_Change event. (Of course, it is entirely possible that a manually entered change elsewhere on the worksheet will have triggered both a Worksheet_Change event and a recalculation causing a cell of interest to change its value via a formula. In this case, however, the Target argument will identify the cell that was manually changed rather than the one recalculated through a formula.)
Throw away the Select ... Case structure, that is really only useful in the context of the demonstration program you are trying to re-use. Instead, change the code so that it unconditionally updates all 4 of your chart properties directly from cells G161 and F163 (so use ws.Range("G161").Value and ws.Range("F163").Value instead of Target.Value for assigning the chart properties, where ws represents whichever worksheet these cells are located on - eg ActiveSheet or Worksheets("Sheet1") or whatever the worksheet is called). Wrap the assignment of the chart properties inside a Workbook_SheetChange sub rather than Worksheet_Change and your chart will update whenever the workbook recalculates.
This is not a very pure solution in that it does not detect whether cells F163 and G161 actually change when recalculation takes place. So it runs the risk that the 4 properties are being unnecessarily assigned with values that are unchanged. However, unless you have a very large workbook and you are pushing the limits of what your computer can handle, this won't matter from a practical point of view.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
With ActiveSheet.ChartObjects("Chart 2").Chart
ActiveSheet.ChartObjects("Chart 2").Activate
' for main axes
ActiveChart.Axes(xlValue).MaximumScale = Worksheets("Single
Tool").Range("$G$161").Value
ActiveChart.Axes(xlValue).MinimumScale = Worksheets("Single
Tool").Range("$F$163").Value
'for secondary axes
ActiveChart.Axes(xlValue, xlSecondary).MaximumScale = Worksheets("Single
Tool").Range("$G$161").Value
ActiveChart.Axes(xlValue, xlSecondary).MinimumScale = Worksheets("Single
Tool").Range("$F$163").Value
End With
End Sub
i found that this works best. thank you all

Range SpecialCells ClearContents clears whole sheet instead

I have a sheet in Excel 2010 which is setup as a pseudo form (I didn't create it, I'm just trying to fix it) so formatting suggests that the user can only enter in certain cells. Depending on certain functionality these areas need to be reset, i.e. cleared although formulae and standard/conditional formatting need to be kept. I have defined each of these cells/ranges as named ranges so I can easily loop through them using the following code: -
Public Sub ResetDetailSheet()
Dim nm As Name
With ThisWorkbook
For Each nm In .Names
If Left(nm.Name, 9) = "nmrDetail" Then
Range(nm.Name).SpecialCells(xlCellTypeConstants).ClearContents
End If
Next
End With
End Sub
For some reason instead of clearing the constants from the specific range it is clearing constants from the entire sheet so I am losing all titles/headings. Formulae and standard/conditional formatting are staying as expected.
What am I doing wrong?!?!
As a test using the immediate window I tried clearing a specific cell, e.g.
Range("G7").SpecialCells(xlCellTypeConstants).ClearContents
But this still cleared all constants from the entire sheet.
What am I missing? I don't understand. Maybe I'm being dumb.
Sorry, I can't upload an example. This place is pretty locked down.
Range({any single cell}).SpecialCells({whatever}) seems to work off the entire sheet.
Range({more than one cell}).SpecialCells({whatever}) seems to work off the specified cells.
So, make sure your range has more than a single cell before you clear it - if the range is only a single cell, then check if it .HasFormula; if that's the case then its .Value isn't a constant:
With ThisWorkbook
For Each nm In .Names
If Left(nm.Name, 9) = "nmrDetail" Then
If nm.RefersToRange.Count > 1 Then
nm.RefersToRange.SpecialCells(xlCellTypeConstants).ClearContents
ElseIf Not nm.RefersToRange.HasFormula Then
nm.RefersToRange.ClearContents
End If
End If
Next
End With
Note that I'm using Name.RefersToRange instead of fetching the range by name off the active sheet.

copy row to next free row on another spreadsheet on change

First off, I'm a noob when it comes to Macros and VBA, so please forgive me if I don't make sense.
I've got an Excel spreadsheet which is basically a list of users and their mobile phone numbers and some other bits (columns A-K are currently used) and it's ordered by rows.
What I need is a way of copying the whole row if I change a cell. So if I change the username, it copies the whole row of that user to the next blank row on a second sheet.
The purpose of this is to keep an audit trail allowing us to see who's previously used a number etc.
I found this: Copy row to another sheet in excel using VBA which is working as intended, but I can't for the life of me get it to a, copy the cells to the next free row, or b, not overwrite the existing entry.
This is the code I'm using:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim a As Range, rw As Range
For Each a In Selection.Areas
For Each rw In a.Rows
If rw.Row >= 2 Then
rw.EntireRow.Copy Sheet2.Cells(2 + (rw.Row - 2) * 3, 1)
End If
Next rw
Next a
End Sub
I'd really appreciate it if someone could help me customise it.
I'm using Excel 2010 on Win7.
Many thank in advance.
Typically the Intersect method is used to determine if the cell or cells receiving a change involve one or more columns that you are concerned with. You can add additional parameters; in this case, I've .Offset the Worksheet.UsedRange property down one row to make sure that row 1 is not involved.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Columns(1), Me.UsedRange.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False 'not really necessary in this case but never a bad idea within a Worksheet_Change
Dim a As Range
For Each a In Intersect(Target, Columns(1), Me.UsedRange.Offset(1, 0))
If CBool(Len(a.Value2)) Then _
a.EntireRow.Copy _
Destination:=Sheet2.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0) 'not really sure this is the correct destination
Next a
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
I've included a call to disable event handling for the duration of the Worksheet_Change event macro. While this is a critical step when the Worksheet_Change modifies values, it is not really important to incorporate here. However, it does not harm and is already in place in case you want to augment the Worksheet_Change to include something like a timestamp that would change the values on the worksheet.

how to prevent re sizing of buttons after release of auto filter in excel 2010 using vba

I have an excel sheet with some buttons (each doing different functions) i have created an auto filter macro as shown below but the problem is when i release the filter my all buttons get very small in their sizes (means they change their original size) although i selected the radio button (Do not move or size with cell) from each button's property.
Sub AutoFilter()
Range("A1:I1628").Select
Selection.AutoFilter
ActiveSheet.Range("$A$1:$I$1631").AutoFilter Field:=8, Criteria1:="="
Selection.Copy
Sheets("Blank Names").Select
Range("A1").Select
ActiveSheet.Paste
End Sub
I am badly in need of help, please assist me with this issue.plzzzzzz
My guess is that you need to set the object positioning of the button to "Don't move or size with cells" (as seen here, unfortunately I don't have enough reputation to post images yet).
If you have many different buttons in many different spreadsheets, this code should set the property for all of them (provided none of the worksheets are protected, etc.)
Sub test()
Dim ws As Worksheet, sh As Shape
For Each ws In Worksheets
For Each sh In ws.Shapes
If sh.Type = msoFormControl Then
sh.Placement = xlFreeFloating
End If
Next
Next
End Sub
I faced the same issue and couldn't find a solution anywhere in the internet. Then on manual testing, I found that the issue is with the format.
Please clear the format from the range of cells where you're trying to put autofilter
For example, I copied data from source file and pasted the as values and then I put the autofilter.

Call a function when only a specific Excel cell changes on Formula Recalculation

As far as i know, Worksheet_Calculate is called when the value of any cell in a worksheet changes on Formula recalculation.
Is there a way so that i need a function to be called only when a specific cell changes on Formula Recalculation
To make something happen when a specific cell is changed, you need to embed the relevant selection change event within the file Worksheet_Change(byval target as Range). We can re-calculate a worksheet when your cell changes as follows:
Private Sub Worksheet_Change(byval target as range)
If target.address = Range("YourCell").Address Then Application.Calculate
End Sub
Now what you want to do is switch off calculations the rest of the time. If you only want to switch off calculations on the single sheet (and not your whole file), you will need to turn calculations off when it is activated, and on when deactivated e.g.
Private Sub Worksheet_Activate
Application.Calculation = xlCalculationManual
End Sub
Private Sub Worksheet_Deactivate
Application.Calculation = xlCalculationAutomatic
End Sub
Of course, your requirements to re-calculate may be considerably more complex than the example above. Firstly, you may open the file whilst on the sheet in question in which case you should use the Workbook_Open event to detect your sheet, and set calculations accordingly
Then you may have several cells that may require some sort of calculation. Presumably the reason you want to switch off calculations is that the file is running too slowly. If so, and you are identifying all the input cells, you could enter the outputs using code. One method would be to enter the formulas using this guide to entering formulas in Excel Visual Basic. You could then replace the formula with the calculated value e.g. Range("YourCell") = Range("YourCell").Value...so stopping the number of formulas in the sheet constantly growing
Let me see if I interpret your question correctly. You want to know if it is possible to only kickoff a macro if a particular cell (or group of cells) is changed.
The answer is Yes. To tweak Ed's code a little.
Private Sub Worksheet_Change(byval target as range)
If Not Intersect(target.address, Range("YourCells")) is Nothing Then
MyMacro()
End If
End Sub
I think your use of "function" is throwing people off. That's why Ed's answer is so elaborate.
Ok. It is possible that you stated your question correctly and you just want to gain efficiency. In that case, Ed's answer solves your immediate problem, but will cause the spreadsheet NOT to calculate automatically when you change other cells.