Seeking help!
Hi,
I am almost done on a project and there's a part I don't understand
I have a + and a - button to add amounts from it's left cell to a total cell on the right (reads 54 in the example) (shown in the link down below)
Also, the amount of times the + is pressed is also calculated on the far most cell (2 for this example)
From the following code I made:
Range("L8").FormulaLocal = "=" & Replace(Range("L8").FormulaLocal, "=", "") & "+" & Range("G8")
The problem is that with the same code, using subtraction, I don't want to see it in the formula bar as it ends up as:
=29+29+29-29-29+29... (2nd image)
I only want to keep the positives. Is there something in the above mentioned code that I can change that will not show the subtraction though and not erase the whole formula that is there already
Thanks!
Part of my excel sheet for better understanding:
What I don't want to see in my formula bar:
First, shouldn't the value in your screenshot be 58, not 54?
Next, does the cell really need to contain a formula? As #teylyn mentioned, just do the calculation in VBA and set the cell's value. E.g. for the + button:
Range("L8").Value = Range("L8").Value + Range("G8").Value
Finally, if you really need to keep the formula, and you know that the value in cell G8 (the value being added or subtracted) never changes between clicks of the + and - buttons, you could first increment the counter (which I assume is cell M8), and then use its value to build the formula.
That might look something like the following, although you'd want to add some error trapping. Also, if you can ensure the counter will never be negative, you could eliminate the ElseIf portion:
Public Sub MinusButton_Click()
Range("M8").Value = Range("M8").Value - 1
Range("L8").FormulaLocal = GetCellFormula
End Sub
Public Sub PlusButton_Click()
Range("M8").Value = Range("M8").Value + 1
Range("L8").FormulaLocal = GetCellFormula
End Sub
Private Function GetCellFormula()
Dim strFormula As String
Dim intNum As Integer
strFormula = "="
If Range("M8").Value > 0 Then
For intNum = 1 To Range("M8").Value
strFormula = strFormula & Range("G8").Value & "+"
Next intNum
ElseIf Range("M8").Value < 0 Then
For intNum = Range("M8").Value To 1 Step -1
strFormula = strFormula & Range("G8").Value & "-"
Next intNum
End If
strFormula = Left(strFormula, Len(strFormula) - 1) 'strip trailing symbol
GetCellFormula = strFormula
End Function
Otherwise, if the value in cell G8 may change, your only option may be to do some (potentially) complicated parsing of the existing formula. If that's the case, please give it a try first, and post a new SO Question if you have any issues.
Related
So I created a macro that muliplies a cell value with 100 (10^2). If the cell is simply a value it justs multiplies the cell value with 100, however if it's a formula it puts the formula in brackets and adds a 100* to the beginning
As you can't undo a macro easily but I need it, I tried to create an "undo" macro.
The Cell Value-Undo is quite easy, however for the formulas I struggle to delete the outer brackets.
An example process would be:
Original: =1+1 becomes =100*(1+1) and the undo should return to =1+1 (without brackets).
This is my code for the multiplication:
Private Sub MultiplySelectionBy100(Control As IRibbonControl)
Dim Cell As Range
For Each Cell In Selection
If Len(Cell.Value) > 0 And Application.IsNumber(Cell.Value) Then
If Cell.HasFormula Then
Cell.Formula = Replace(Cell.Formula, "=", "=100*(") & ")"
Else
Cell.Value = 100 * Cell.Value
End If
End If
Next
Application.OnUndo "Undo something", "UnDoSomething"
End Sub
For the UNDO, this is what I have so far:
Public Sub UnDoSomething()
Dim Cell As Range
Dim bet As String
For Each Cell In Selection
If Len(Cell.Value) > 0 And Application.IsNumber(Cell.Value) Then
If Cell.HasFormula Then
Cell.Formula = Replace(Cell.Formula, "=100*(", "=") 'This is not running
Cell.Formula = Replace(Cell.Formula, Chr(41), Chr(0))
Else
Cell.Value = 100 / Cell.Value
End If
End If
Next
End Sub
I don't know how to attach multiple replace functions but it gives me an error every time (mostly because I delete a opening bracket but the closing bracket remains).
I also can't delete all brackets as there may be more brackets inside the formula.
Maybe you have an idea...
Your main problem is that the first replace command will set the formula invalid because the closing ")" is still there, and Excel (not VBA) doesn't allow an invalid formula, so you get a runtime error (1004).
You should use an intermediate variable to handle the string manipulation of the formula, and only if that is done completely, assign the formula back to the cell. Using intermediate variables is always a good idea if you are dealing with formulas in VBA - you can check with the debugger if the formula looks really as expected before you write it back to the cell.
You need to be careful with your second replace-statement: This will remove all closing parenthesis characters, even if it has nothing to do with your "Undo". You should (a) check if you really want to remove it and (b) remove only the last closing parenthesis.
Dim f As String
f = cell.Formula
If Left(f, 6) = "=100*(" Then
f = Replace(cell.Formula, "=100*(", "=")
f = Left(f, Len(f) - 1)
cell.Formula = f
End If
Or, maybe easier
If Left(f, 6) = "=100*(" Then
f = "=" & Mid(f, 7, Len(f) - 7)
cell.Formula = f
End If
For work, I have to generate some QR code with info in it.
Therefore, I checked on internet and found this "already made" QR code generator :
https://github.com/JonasHeidelberg/barcode-vba-macro-only
It's very nice, and works quite well.
I'm trying to integrate it into my VBA sheet to do data treatment before using the code to create the final QR code. (Nothing complex)
here is how it looks like :
The 4 cells "B4 to B6" get the entry data which are encoded or not, depending on the checkboxes, then the result it written in the column D.
Each cell content is stacked in a variable, and this variable is given to eat to the QR code generator :
Public Function GenerateQRCode()
Dim CurrentWS As String
UserDataRange = "B6:B9" 'The cells in which the data to be encoded are stored
InputDataRange = "D6:D9" 'the cells with the encoded (or not) values
InputCell = "A4" 'the cell where the text to be encoded in the QR code has to be put
'encode the text depending on hte value of the cell behind the chek boxes
For Each cell In Range(UserDataRange)
If cell.Offset(0, 1) = True Then
EncodedText = EncodeDecode.Base64EncodeString(cell.Value)
cell.Offset(0, 2).Value = EncodedText
ElseIf cell.Offset(0, 1) = False Then
cell.Offset(0, 2).Value = cell.Value
End If
Next
Range(InputCell).ClearContents
DataToEncode = ""
'puts the text in the input line with dashes between each value
For Each cell In Range(InputDataRange)
pouet = Range(InputDataRange).Address
If DataToEncode = "" Then
DataToEncode = cell.Value & Chr(10)
Else
If cell.Address = Mid(Range(InputDataRange).Address, InStr(1, Range(InputDataRange).Address, ":") + 1, _
Len(Range(InputDataRange).Address) - (InStr(1, Range(InputDataRange).Address, ":") - 1)) Then
DataToEncode = DataToEncode & cell.Value
Else
DataToEncode = DataToEncode & cell.Value & Chr(10)
End If
End If
Next
Range(InputCell).Value = DataToEncode
End Function
My concern is that "whatever cell I modify in the whole workbook, it lunches the QR code generator."
I wanted to give a condition at the beginning of the code like If cell A4 is modified, lunch the code, but I don't even achieve to understand what makes the code start and how the data are gathered...
My best guess is that this is the beginning of the code :
Public Function EncodeBarcode(ShIx As Integer, xAddr As String, _
code As String, pbctype%, Optional pgraficky%, _
Optional pparams%, Optional pzones%) As String
Dim s$, bctype%, graficky%, params%, zones%
Dim oo As Object
Call Init
If IsMissing(pzones) Then zones = 2 Else zones = pzones
If IsMissing(pparams) Then params = 0 Else params = pparams
If IsMissing(pgraficky) Then graficky = 1 Else graficky = pgraficky
If IsMissing(pbctype) Then bctype = 0 Else bctype = pbctype
But how is it started? O.o
I thought a line like Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, cancel As Boolean) followed by a control of the value of "target" was mandatory...
Here, it looks like magic to me :(
How does xAddr gets the address of the cell I clicked? Magic again...
I would like the execution of the code to happen only when I click the button I created. (it generate some infinite loops and excel shuts down :/ )
Or, if not possible, I would like it to be executed only when the data in the cell A4 are modified.
Thank's for your help :)
This is because the CELL function function is volatile it recalculates on every calculation (not only on calculation in cells it depends on). That means EncodeBarcode() calculates on every calculation too (because it is using the CELL() function in its parameters).
A Volatile Function is one that causes recalculation of the formula in the cell where it resides every time Excel recalculates.
This occurs regardless of whether the precedent data and formulas on which the formula depends have changed, or whether the formula also contains non-volatile functions.
If you remove the CELL() function and replace it with hard values
=EncodeBarcode(1;"B4";A4;51;1;0;2)
it doesn't re-calculate the barcode on every cell change. But it does only re-calculate the barcode if the cell it depends on changes (it this example cell A4).
I have a longstanding formatting frustration. I often do this manually but doing it manually takes forever, and there has to be a way to do this with either a VBA macro, conditional formatting or a clever number format.
Below is my desired result. It has the following properties:
The largest number in the column (in this case the last number in the column, $103,420) is centered within the cell.
The largest number in the cell is not, however, center aligned, it is right indented until the value is centered.
All other numbers in the column are also right indented an equal amount. This is desirable because it lines up the ones place, tens place etc. in each number.
Negative numbers are denoted surrounded by parentheses.
The dollar sign is adjacent to the leftmost number.
Commas are included properly for numbers greater than 999.
This result was achieved by:
Applying the following number format:$#,##0_);($#,##0)_);$0_);#_)
Manually adjusting the right indent of the cell on the largest number to determine when it is roughly centered. If more space must be on one side or the other, the larger space is left on the left side of the number.
I attempted to apply a number format similar to the one used in response to this question.
Specifically my attempt at using this was to center align all cells using the following number format: $?,??0;($?,??0);
That produces the following close but not quite result below.
Thoughts on how I can address this? I'm imagining a macro that identifies the largest number in the selection, gets the number of digits in that number, the font size, the width of the column, does some computation yielding the desired right indent and then applies the right indent. I'm just not sure how to do that kind of computation.
'Select your data range, and run formatCells_Accounting(). The number formatting in the selected cells will widen to the cell with the longest value. Note, the macro does not work on values greater than 10^14 (not sure why.)
Sub formatCells_Accounting()
Dim rg As Range
Set rg = Selection
maxVal = Application.WorksheetFunction.Max(rg)
minVal = Application.WorksheetFunction.Min(rg)
If Abs(minVal) > maxVal Then
longest_ = minVal
Else
longest_ = maxVal
End If
lenLongest = Len(CStr(Round(longest_, 0)))
rg.NumberFormat = "_($" & addCommasToFormat(lenLongest) & "_);" & _
"_(($" & addCommasToFormat(lenLongest) & ");" & _
"_($" & addCommasToFormat(lenLongest - 1) & "0_);" & _
"_(#_)"
End Sub
Function addCommasToFormat(ByVal lenLongest) As String
str_ = String(lenLongest, "?")
new_str_ = ""
For i = 1 To Len(str_)
If i Mod 3 = 1 And i <> 1 Then
new_str_ = new_str_ & ",?"
Else
new_str_ = new_str_ & "?"
End If
Next
addCommasToFormat = StrReverse(new_str_)
End Function
Chris - your answer doesn't do what I was hoping for (your answer leaves space between the dollar sign and the "last" digit for numbers shorter than the longest number in the set)
However, your code was a helpful starting point for this solution I've come up with. The result is shown in the image below along with the inherent downside to this solution - running a formula on the numbers in the column after they've been formatted in this way results in a weird number format.
The only solution I can come up with that doesn't have the problem this solution does is, one that relies on estimating an indent, and applying it. That solution only works so long as the column width is not adjusted going forwards. If it is adjusted the macro would have to be re-run. Additionally, because the indent can only be increased by an increment of 1 (and nothing less), a macro that applied an indent would typically result in the largest number in the column not being exactly centered. Not a huge deal but my current solution doesn't have either of these problems and in my use case, these formats are being applied as the last step in the process of formatting a spreadsheet so additional calculations aren't likely to happen and if they do, the macro can simply be re-run as needed.
'Select your data range, and run formatCells_Accounting(). The number formatting in the selected cells will widen to the cell with the longest value. Note, the macro does not work on values greater than 10^14 (not sure why.)
Sub formatCells_Accounting()
Dim rg, thisColRange, rCell As Range
Dim maxVal, minVal, valueLen, longest_, lenLongest As Long
Set rg = Selection
'Center aligns all selected cells
rg.HorizontalAlignment = xlCenter
'Loops through each column in the selected range so that each column can have it's own max value
For Each thisColRange In rg.Columns
maxVal = Application.WorksheetFunction.Max(thisColRange)
minVal = Application.WorksheetFunction.Min(thisColRange)
'The longest number in the range may be the most negative
'This if section accounts for this scenario
If Abs(minVal) > maxVal Then
longest_ = minVal
Else
longest_ = maxVal
End If
'Gets the length of the longest value rounded to the ones place (aka length not including decimals)
lenLongest = Len(CStr(Round(Abs(longest_), 0)))
'Creates a number format for every cell
For Each rCell In thisColRange.Cells
'Gets the length of the value in the current cell
valueLen = Len(CStr(Round(Abs(rCell.Value), 0)))
rCell.NumberFormat = "_(" & addCommasDollarsToFormat(lenLongest, valueLen, rCell.Value) & "_);" & _
"_(" & addCommasDollarsToFormat(lenLongest, valueLen, rCell.Value) & ")_);" & _
"_(" & Left(addCommasDollarsToFormat(lenLongest, 1, rCell.Value), Len(addCommasDollarsToFormat(lenLongest, 1, rCell.Value)) - 1) & "0_);" & _
"_(#_)"
Next
Next
End Sub
Function addCommasDollarsToFormat(ByVal lenLongest, ByVal valueLen, ByVal cellVal) As String
Dim new_str_ As String
Dim i, j As Long
'Initializes empty strings
new_str_ = ""
nearlyFinishedString = ""
'Adds ? and , through the length of the value currently being formatted
For i = 1 To valueLen
If i Mod 3 = 1 And i <> 1 Then
new_str_ = new_str_ & ",?"
Else
new_str_ = new_str_ & "?"
End If
Next
If cellVal < 0 Then
new_str_ = new_str_ & "$("
Else
new_str_ = new_str_ & "$"
End If
For j = i To lenLongest
If j Mod 3 = 1 Then
new_str_ = new_str_ & ",?"
Else
new_str_ = new_str_ & "?"
End If
Next
addCommasDollarsToFormat = StrReverse(new_str_)
End Function
Solution visualized with the downside of the solution shown below it.
i am trying to insert a reference number into a cell in excel using vba. I want a prefix text of 'V0000' followed by an auto incremented number starting from 836.
so for each row that gets inserted I will have V0000836
Then V0000837
etc
A large portion of my code creates a new row and inserts data into it automatically one after the other, but instead of posting my whole code I am just wanting to focus on this one line of code which inserts value into column AA of my spreadsheet. I am using the following but it just gives me V00001 each time. can someone show me how I can get my code to do what I want it to.
ws2.Range("AA" & DestRow).Value = "V0000836" & Value + 1
Consider an alternative that does not remove numerical (mathematical) functionality from the cell's value.
ws2.Range("AA" & DestRow).numberformat = "\V0000000"
ws2.Range("AA" & DestRow).Value = 836 + 1
If you require the formatted (displayed) alphanumeric designation you can retrieve it like this.
Dim str as string, num as long
str = ws2.Range("AA" & DestRow).text '◄ V0000837
num = ws2.Range("AA" & DestRow).value '◄ 837
Using VBA, you can do this by incrementing the number each time the loop goes round and then prefixing the V0000 to the front like so:
Dim i As Integer
Dim cell As Range, rng As Range
Set rng = Range("A1:A10")
i = 836
For Each cell In rng
cell.Value = "V000" & i
i = i + 1
Next cell
can i do this =(For i=1 to 100, print i)
is there a way to put a FOR statement inside a cell WITHOUT USING VBA?
You can use an array to get the numbers 1 through 100, but you're limited on what you can do with them. You can't, for instance, concatenate in an array formula (which your pseudo code suggests). But you could SUM, AVERAGE or many other operations.
{=SUM(ROW(1:100))}
{=AVERAGE(ROW(1:100))}
{=MAX(ROW(1:100))}
The braces means enter with control+shift+enter, not just enter.
The VBA for this isn't fancy at all :-)
Option Explicit
Sub SimpleForLoop()
Dim i As Integer
For i = 1 To 100 Step 1
With ActiveWorkbook.Sheets(1).Cells(1, 1)
.Value = .Value + i
End With
Next
End Sub
The simple code above puts the value 5050 in cell A1.
If you want to concatenate a string instead, slap this code into your for-loop:
With ActiveWorkbook.Sheets(1).Cells(2, 1)
If .Value = "" Then
.Value = CStr(i)
Else
.Value = .Value & "," & CStr(i)
End If
End With
Which will print the following into cell A2:
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100