I am creating a form where the input of one field is used for calculations in VBA to return a value that is inserted in another text field. I am fine up to here.
Problem is, dealing with Power numbers tend to get quite high, so my code divides Watts into Kilowatts or Megawatts depending on the value.
If the number is divided by 1,000 into kW, I would like the format of the field to be "#.##0,00 kW". If it is divided by 1,000,000 into Megawatts, the format should be "#.##0,00 MW".
Any suggestions on how to do this?
My code looks something like this (previous part is irrelevant):
Dim Module As String, Power As Integer, Technology As String, TechLong As String, NumberOfCells As Integer
Module = ActiveDocument.FormFields("ModType").Result
Power = Mid(Module, 4, 3)
Technology = Mid(Module, 9, 1)
NumberOfCells = Mid(Module, 10, 2)
' Project information
Dim NumModules As Long, ProjectSize As Long, PowerField As FormField
NumModules = ActiveDocument.FormFields("ModNum").Result
ProjectSize = NumModules * Power
Set PowerField = ActiveDocument.FormFields("TotalPower")
If ProjectSize < 1000000 Then
'Change W to kW
PowerField.Result = ProjectSize / 1000
Else
'Change W to MW
PowerField.Result = ProjectSize / 1000000
End If
Thanks!
My suggestion is to break the number and power label into two separate form fields. Deactivate the "Fillin enabled" property of the power label so that the user can't change it.
Even though the user can't change the content of the "label", your code can.
This approach allows you to leave the number formatting of the power amount field alone. Changing the number format setting using your code would mean unprotecting then re-protecting the form document. It's always better to avoid that step if at all possible.
So assuming the form field for the power label is named PowerLabel your code could look like this:
PowerLabel = ActiveDocument.Formfields("PowerLabel")
If ProjectSize < 1000000 Then
'Change W to kW
PowerField.Result = ProjectSize / 1000
PowerLabel.Result = "Kw"
Else
'Change W to MW
PowerField.Result = ProjectSize / 1000000
PowerLabel.Result = "Mw"
End If
Related
I am trying to do some math through VBA, and came across this error which I haven't seen before. Some googling tells me that it has to do with Intelli-Sense options that aren't available for the object being applied to it. But as far as I can tell, it shouldn't be messing up anything here because I didn't use Intelli-Sense in the line the debugger is highlighting. I will post the full code below, any insight is very much appreciated!!
'Declare Variable
Dim L As Double
Dim Length As Double
Dim OrderFTG As Double
Dim UoM As String
Dim W As Double
Dim frm As Access.Form
Set frm = Forms!Frm_JobTicket
'Set L equal to Length from Tbl_JobTicketMould
L = DLookup("Length", "Tbl_JobTicketMould", "Access_ID =" & Forms!Frm_JobTicket!Part_Number)
'Convert Length to Feet
Length = (L \ 12)
'Find Unit of Measure for this part
UoM = DLookup("Unit_of_Measure", "Tbl_JobTicketUoM", "Access_ID =" & Forms!Frm_JobTicket!Part_Number)
'Mupltiply Length times Quantity to get Order Footage
OrderFTG = Int((Length * Me.Txt_Pcs_JobTicket))
'If UoM is PCS then insert that number. Otherwise set equal to Quantity Ordered divided by Length of piece(in FT)
If UoM = "PCS" Then Me.Txt_Pcs_JobTicket = Me.Quantity_Ordered Else: Me.Txt_Pcs_JobTicket = Abs(Int(Me.Quantity_Ordered \ Length))
'Define limits of the loop. Then runs through all Wrap SQ FTG fields and inputs calculation
For W = 1 To 3
'If UoM is PCS then calculate Order Footage to find Wrap Sqaure Footage. Otherwise take slit size in FT and multiply by Order Quantity and Scrap Rate
If UoM = "PCS" Then
frm("Txt_Wrap" & W & "SQFTG_JobTicket") = (((frm("Wrap_Slit" & W) \ 12) * OrderFTG) * (frm(RIP_Scrap_Rate + 1)))
Else: frm("Txt_Wrap" & W & "SQFTG_JobTicket") = (((frm("Wrap_Slit" & W) \ 12) * frm(Quantity_Ordered)) * (frm(RIP_Scrap_Rate + 1)))
End If
Next W
I am also having trouble with this line OrderFTG = Abs(Int((Length * Me.Txt_Pcs_JobTicket))) It keeps coming out to half of the required amount, the data tips for the Abs part of the evaluation will come out to 12,000 and OrderFTG then equals 6,000. I am not sure how that is happening as there is no division whatsoever even happening in that expression.
Thank you!
This simpler example demonstrates the problem I think you're dealing with.
I added a text box, txtScrap_Rate, to my form, opened it in Form View, and entered the number 27 into the text box.
So then I can retrieve that value with the frm(<control name>) approach you're using ... as long as I enclose the control name in quotes.
set frm = Forms!Form18b
? frm("txtScrap_Rate")
27
? frm("txtScrap_Rate") + 1 ' add one to Scrap Rate
28
Without the quotes, Access interprets txtScrap_Rate to be an undeclared variable instead of a control name.
? frm(txtScrap_Rate)
Null
' result is the same as giving it any undeclared variable name, such as this one:
? frm(Bogus)
Null
And, without the quotes, if I try to also do the plus one inside the parentheses ...
? frm(txtScrap_Rate + 1)
... I get the same 438 error as you:
Object doesn't support this property or method
I think you have this issue with RIP_Scrap_Rate in two places. Also I suspect you need to quote the control name in frm(Quantity_Ordered)
You would be wise to include Option Explicit in your module's Declarations section. Access will then alert you about anything it thinks is an undeclared variable but you think should be something else.
I have table "PriceList" in excel with below structure
Type Thickness width Height Price
iron 5 7 10 20
iron 10 10 15 24
iron 12 14 17 26
how can i find the price if some-one enters type iron, thickness 10, width 9, height 14 using vlookup or macro. i have tried using vlookup but its not works and later on i found on google that Vlookup only retrieve data with one parameter. Can i do this using macro like we do for selecting sheet data using queries
select * from [sheet1$] where col1=x
Please suggest??
Edit: i have calculated the above using this. Now i am calling this macro on sheet change event like below
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 41 Or Target.Column = 43 Or Target.Column = 45 Or Target.Column = 46 Then
Dim i As Currency
i = Calculate_CorePrice(cell(Target.Row, 46).Value, cell(Target.Row, 45).Value, cell(Target.Row, 41).Value, cell(Target.Row, 43).Value, "RWJ Doorset Schedule", "ED15")
cell(Target.Row, 134).Value = i
End If
End Sub
if i debug the function itself with hard-coded values, it is working but if i call the function as in above way, it does not return value and i am not able to debug sheet_change event.
How can i debug this event.
Assuming your columns are A, B, C, etc. You can use an Index/Match formula as an array (enter with CTRL+SHIFT+ENTER).
If the user enters the type, thickness, width, and height in W1, X1, Y1, and Z1, you can use:
=Index($E$2:$E$10,Match(W1&X1&Y1&Z1,$A$2:$A$10&$B$2:$B$10&$C$2:$C$10&$D$2:$D$10,0))
It's convoluted, but basically the Match part is you are looking for W1 in the range A2:A10, then whatever is in X1, you will search B2:B10, etc.
It seems I am just a bit late with my answer and #BruceWayne beat me to it. Still, I will add my solution as well as there is a nice little illustration to it:
Basically, it is the same proposal has been already proposed. Just use an array formula and the & sign to combine all criteria into one. In the end a criteria will look like this iron101015 (for example). And it will be compared to all the combinations in the table.
The best would be to loop through the data, using an if statement to check the data tables. (This could be placed in a sub or in a function depending on how you want the data to be retrieved)
Function GetPrice(Type As String, Thickness As Integer, Width As Integer, Height As Integer)
Dim ItemRow As Range, SearchColumn As Range
'Dim Price As Double 'Use variable if this were a sub
Set SearchColumn = Range(Cells(2,1),Cells(ActiveSheet.UsedRange.rows.count,1))
For Each ItemRow In SearchColumn
If ItemRow.Value = Type AND ItemRow.Offset(0,1).Value >= Thickness AND ItemRow.Offset(0,2).Value >= Width AND ItemRow.Offset(0,3).Value >= Height AND ItemRow.Offset(-1,1).Value < Thickness AND ItemRow.Offset(-1,2).Value < Width AND ItemRow.Offset(-1,3).Value < Height Then
'Price = ItemRow.Offset(0,4).Value
GetPrice = ItemRow.Offset(0,4).Value
Exit For
End If
Next ItemRow
End Function
Edit: Given your comment on another answer, I've adjusted the code to find the value as i believe you are looking for
I've been messing around with VBA in Excel a bit recently; and as a small project for myself, I'm trying to create a "draw names from a hat" sort of macro.
I began by generating a random number, and then choosing which entry from a Table (i.e. ListObject) would be selected using a case statement. The problem with this is that it only works of the number of Table entries is always the same.
So my question (probably a ridiculous one) is: is it possible at all to generate a dynamic 'Select Case' block, where the number of cases on the block is based on the number of entries in the Table?
Thanks.
-Sean
Edit: To clarify: what I am trying to do, exactly, is this:
I generate a random number, i, from 1 to n=10*(number of Table entries). After this, I want to display, in a cell, one of the table entries based on the random number.
Ideally, the code would work similarly to this:
if i = 1 to 10 then choose event 1
if i = 11 to 20 then choose event 2
if i = 21 to 30 then choose event 3
...
if i = (n-9) to n then choose event (n/10)
I hope this helps to clarify the goal of the code.
From our comments here is something you can use:
Sub random()
Dim used_rows As Integer
Dim random As Integer
Dim cell_array() As Integer
used_rows = Sheet1.UsedRange.Rows.Count
ReDim cell_array(used_rows)
For i = 1 To used_rows
cell_array(i - 1) = Cells(i, 1)
Next
random = Int(Rnd * (used_rows))
MsgBox cell_array(random)
End Sub
You can go ahead and change MsgBox to whatever you like, or set like Cell(1,4).Value = cell_array(random), or however you'd like to proceed. It will be based off the number of rows used. Though depending on how you implement your spreadsheet the code might have to be changed a bit.
Here's the update code from the suggestions from the comments. Also remember to use Randomize() in your form initialization or WorkBook Open functions.
Sub random()
Dim used_rows As Integer
Dim random As Integer
'Multiple ways to get the row count, this is just a simple one which will work for most implementations
used_rows = Sheet1.UsedRange.Rows.Count
random = Int(Rnd * (used_rows))
'I use the variable only for the reason that you might want to reference it later
MsgBox Cells(random, 1)
End Sub
This assumes that by "table" you mean "Table with a capital T", known in VBA as a ListObject:
Sub PickRandomTens()
Dim lo As Excel.ListObject
Dim ListRowsCount As Long
Dim RandomNumber As Long
Dim ListEvent As String
Dim Tens As Long
Set lo = ActiveSheet.ListObjects(1)
ListRowsCount = lo.DataBodyRange.Rows.Count
RandomNumber = Application.WorksheetFunction.RandBetween(10, ListRowsCount * 10)
ListEvent = lo.ListColumns("Data Column").DataBodyRange.Cells(Int(RandomNumber / 10))
MsgBox "Random number: " & RandomNumber & vbCrLf & _
"Event: " & ListEvent
End Sub
I execute a VBA code that takes a database, treats it and export it into a sheet. This is working fine. However, I have a sheet that produces graphs depending on the data in the particular sheet. The datas does not actualize. I have to enter the cell and click enter to actualize it. I'm pretty sure there is an easier way to do this. Calculation is set to automatic but that doesn't seem to change anything.
In my cell, I have my own vba function that needs to be updated once the report is done. When I click the cell and then enter, the result is updated but I would like this to be done automatically. I hope this is clearer !
Thanks in advance,
Etienne NOEL
HEre is the code of my function
Public Function number_of_appearances(term As String, sheet As String, column As Integer) As Integer
Application.Volatile
Dim number_of_rows As Integer
Dim appearances As Integer
Dim row As Integer
appearances = 0
row = 1
number_of_rows = Worksheets(sheet).UsedRange.Rows.Count
Do While row <= number_of_rows
If Worksheets(sheet).Cells(row, column).Value = term Then
appearances = appearances + 1
End If
row = row + 1
Loop
number_of_appearances = appearances
End Function
A cell example of a user of the function
=number_of_appearances('test';'sheet1'; 3)
Sounds like your UDF might not depend on any cells that change value when your DB is processed.
See This MSDN Link
Post your UDF (or just its header if you prefer) and an example of its use...
EDIT:
Yes, none of the parameters to the UDF are cell references, therefore the UDF is not triggered to recalculate when data on the shet changes.
You have two choices:
1. rewrite your UDF to include parameter(s) that reference cells that change value when the DB is processed
2. make your UDF volitile (include Application.Volatile in the UDF code) WARNING: this can be very inefficient, depending on how many time the UDF is used and how intensive its calculation is
EDIT 2:
Heres a refactor of your udf using the first option mentioned:
Public Function number_of_appearances(term As String, rng As Range) As Integer
Dim v As Variant
Dim i As Long, j As Long
Dim appearances As Long
v = Intersect(rng, rng.Worksheet.UsedRange)
For j = LBound(v, 2) To UBound(v, 2)
For i = LBound(v, 1) To UBound(v, 1)
If v(i, j) = term Then
appearances = appearances + 1
End If
Next i, j
number_of_appearances = appearances
End Function
use like
=number_of_appearances("test";Sheet1!C:C)
EDIT 3:
If all you are doing is counting number of occurances of a string in a range, consider using
=COUNTIF(Sheet1!C:C;"test")
I'm trying to make a macro that formats a chart in Excel 2003 where the data changes. Basically, I have a 20 X values and Y values at all times; however, the values are data specific (I'm making stock price charts that will change depending on the stock I'm analying). I'm trying to make my Y-Axis cross the X axis at the value in cell B8; is there anyway to do this with a macro? Because I can't link where the axes cross to a cell. Also, I want to change the axis minimum to cell B8 as well. Also I want the macro to adjust the cart to look logical automatically depending on the data I put in there (ie logical intervals).
The chart type here is a Scatter plot, where the desription is: "Scatter with Data Points Connected by Lines Without Markers". Thank you very much.
I don't think it's possible to dynamically link the intercept value to a cell - this is just based on the fact that the UI for selecting the intercept value requires an explicit value, rather than allowing you to select a cell.
Within VBA, however, once you have read the desired value from the cell, do
ActiveSheet.ChartObjects("Chart 1").Axes(xlValue).CrossesAt = value
(with your chart name)
This is approximately what you need (no time here to test and get the details exact):
ActiveChart.Axes(xlValue).CrossesAt = Range("B8").value
You might also have to set
ActiveChart.Axes(xlCategory).Crosses = xlAxisCrossesCustom
and play around a little with whether to use Value or Category.
"to adjust the cart to look logical automatically depending on the data I put in there (ie logical intervals)."
That one is a lot of fun. Here's a VBA function that does the hard part of calculating a pretty interval between the ticks.
Public Function prettyVal( _
xMin As Double, _
xMax As Double, _
minBins As Integer) _
As Double
'' returns an aesthetic interval size to _
use for a plot axis or histogram bin. _
marc#smpro.ca 2010-09-01
Dim pretties
pretties = Array(1, 2, 5, 10)
Dim maxBin As Double ''maximum size of bin
Dim xScale As Double ''scale factor
With WorksheetFunction
maxBin = (xMax - xMin) / minBins
xScale = 10 ^ Int(.Log10(maxBin))
prettyVal = xScale * .Lookup(maxBin / xScale, pretties)
End With
End Function
You'll want to use it in a worksheet. Use the floor and ceiling of the min and max with the pretty value for significance. This makes them also pretty. Something like this in the worksheet:
minimum plot value minVal 120
maximum plot value maxVal 980
minimum num of bins minBins 10
pretty bin size binsize 50 =prettyVal(minVal,maxVal,minBins)
low axis value minEdge 100 =FLOOR(minVal,binsize)
high axis value maxEdge 1000 =CEILING(maxVal,binsize)
number of bins numBins 18 =(maxEdge-minEdge)/binsize
Enjoy.