I'm making a small app that handles pricing and quotes for cloud services.
On one of my forms, I work out some pricing info in the 'me.shown' bit.
The prices for various items are read in from a mysql database on app launch, so i've already got all that info.
My price working out code is as follows:
calc_vmCPUprice = vmcpuprice * cpuslider.Value
calc_vmHDDprice = vmhddprice * hddslider.Value
calc_vmRAMprice = vmRAMprice * memoryslider.Value
If requirebackup.Checked = True Then
calc_backupsetupfee = vmbackupsetupfeecost
calc_backupfee = vmbackupcostperGB * sliderbackup.Value
End If
If supportcheck.Checked = True Then
calc_supportfee = vmsupportfee
End If
vmmonthlycost = calc_vmCPUprice + calc_vmHDDprice + calc_vmRAMprice + calc_backupfee + calc_backupsetupfee + calc_supportfee
vm_monthlycost.Text = "£" & vmmonthlycost
I need to make my program re-calculate the 'vmmonthlycost' variable each time an item is changed.
So for example if you change the slider for cpu (cpuslider.value) then the price will obviously change as the 'calc_vmCPUprice' variable will now be different.
I dont want to copy and paste the calculation code into the change event of each item, as this will be messy and any future changes will need to be mirrored across all items etc.
What would you guys recommend as the best way of achieving this recalculation of price?
I would ideally like to take that bit of code and seperate it then call it from each change event, but as I tinker with vb as a hobbyist more than anything else, my knowledge is still limited.
Thanks in advance!!
Related
For the next part of this project that I've been working on to speed up follow up emails to clients for the office, I'm looking to grab a specific attachment from a specified filepath based on the items that the user selected on the userform. These emails will always be sending the exact same files so the less time the user has to spend manually attaching files, the better it will be. My first assumption right off the bat was that I'd need a loop to do this, so I began to do my groundwork, but now I'm generally stuck.
The first loop grabs what the user selected from the userform:
For i = 0 To List1.ListCount - 1
If List1.Selected(i) Then
Counter = Counter + 1
msg = msg & "<font style = 'background: yellow'>" & List1.List(i) & "<br />"
Else: If Counter = 0 Then End
End If
Next
And the second loop attaches the files based on the selections above:
For i = 0 To List1.ListCount - 1
If List1.Selected(i) Then
Counter = Counter + 1
.Attachments.Add List1.List(i)
Else: If Counter = 0 Then End
End If
Next
The attachments process just fine.However, the program ends up displaying the highlighted body of the message as the filepath I tried to associate with the list item:
' test files
List1.List(0) = "C:\Users\jmarkman\Dropbox\Python Practice\ex1.py"
List1.List(1) = "C:\Users\jmarkman\Dropbox\Python Practice\ex2.py"
List1.List(2) = "C:\Users\jmarkman\Dropbox\Python Practice\ex3.py"
List1.List(3) = "C:\Users\jmarkman\Dropbox\Python Practice\ex4.py"
List1.List(4) = "C:\Users\jmarkman\Dropbox\Python Practice\ex5.py"
List1.List(5) = "C:\Users\jmarkman\Dropbox\Python Practice\ex6.py"
So my question is, how do I associate these file paths with corresponding items in the listbox within the userform? I'm pretty sure that although it worked, the process changed the list items since I assigned them a different value.
I'm not sure how complex or simple this might end up being, so your time and patience are well appreciated.
People have said that one can learn best just by doing and making mistakes, but let me tell you that not having someone you can at least talk to about where to start making mistakes is incredibly frustrating. I hope anyone else who, like me, was on the cusp of solving this problem is able to look here and have their own "a-ha!" moment.
When I first asked this question, I was on the right path with choosing to put all of my filepath locations within an array and I was further along the right path by using a loop to go through it. I declared the myAttach array with a range as I did at first, but unlike whatever example I saw during my google research, I kept my second attachment loop the same but simply changed out List1.List(i) for myAttach(i). That made the script's wheels turn and performed all the functions I needed it to.
The long and short of it was that I made an array that matched the quantity and order of the items in the userform and re-used the loop I made for picking the subjectivities, I was able to associate the choices in the userform to those in the array by having the second loop go through the array. Each listing in the array had a filepath associated with it.
' example
myAttach(0) = "[filepath]"
myAttach(1) = "[filepath]"
myAttach(2) = "[filepath]"
myAttach(3) = "[filepath]"
' ... and so on ...
It helped to visualize the array and the list items as two side-by-side columns; the first item in the list is parallel to the first item in the array, and can therefore be recognized by the second loop. If a mental image isn't forthcoming, try inputting some data into two or more Excel columns to witness the relationship or review Matricies.
A caveat of this line-up approach, I found out shortly after while continuing research to figure out exactly what I did right this time would be if I had to have the items in the list in a specific order (i.e., alphabetical), but fortunately the list items are phrases and complete sentences and don't require sorting.
Happy learning and programming!
I'm pretty new to programming, so this may be a pretty basic question. But, I need help to shorten this really repetitive code.
I'm working on a card game that has about 2 hundred different creatures, two decks (your and the enemy's), and 10 slots in each deck (meaning 10 creatures per deck).
In the deck builder part of my UI, when you actually add a creature to your deck, it does this:
If CritName = "Monarch" Then
YourCreature1PictureDB.Image = DHBattleSim.My.Resources.Monarch_Icon
YourCreature1Group.BackColor = Color.Transparent
End If
If the creature is "Ariel", then it'd be
If CritName = "Ariel" Then
YourCreature1PictureDB.Image = DHBattleSim.My.Resources.Ariel_Icon
YourCreature1Group.BackColor = Color.Transparent
End If
etc. Now, imagine there being two hundred of those statements, each for a different creature. THEN I need to copy that huge chunk of code, and change all of the 1's to 2's, and again, changing the 2's to 3's, etc. After I finish the 10's, I'd have to copy ALL OF THAT and change all of the "YourCreature" phrases to "EnemyCreature". So obviously this is extremely repetitive and tedious.
I know about the Find and Replace feature, but I'd rather shorten the code itself so that I don't have to resort to using that.
You can use code like this
Dim resources As Object = DHBattleSim.My.Resources.ResourceManager
YourCreature1PictureDB.Image = resources.GetObject(yourVariable & "_Icon")
This,
YourCreature1Group.BackColor = Color.Transparent
can follow; in your original code it doesn't need to appear in every if, if it is always set to Transparent.
create a sub for setting the image:
Public Sub SetCreatureImage(critName As String)
YourCreature1PictureDB.Image = DHBattleSim.My.Resources.ResourceManager.GetObject(critName + "_Icon")
YourCreature1Group.BackColor = Color.Transparent
End Sub
Can I use Win API methods such as LVM_INSERTITEM and LVM_SETITEM for adding items in ListView control?
I want to load listview data fast, I think objListView.ListItems.add is slow for larger amount of rows to be added into the listview.
Currently I use following code to Add ListItems:
Dim tmpLI as ListItem
Set tmpLI = ListView1.ListItems.Add text:="Item" & iCounter
tmpLI.SubItems(1) = objRs("StudentCode")
tmpLI.SubItems(2) = objRs("StudentName")
tmpLI.SubItems(3) = objRs("MotherName")
tmpLI.SubItems(4) = objRs("FatherName")
tmpLI.SubItems(5) = objRs("PhoneNo")
etc.
tmpLI.SubItems(15) = objRs("Description")
[iCounter is a Loop Variable, objRs is ADODB Recordset]
You can do that, but it probably won't speed things up too much. You will probably find that use of a With block will give you a better result, though. Like this:
With ListView1.ListItems
.Add text:="Item" & iCounter
.SubItems(1) = objRs("StudentCode")
.SubItems(2) = objRs("StudentName")
.SubItems(3) = objRs("MotherName")
.SubItems(4) = objRs("FatherName")
.SubItems(5) = objRs("PhoneNo")
etc.
.SubItems(15) = objRs("Description")
End With
The reason that this is faster is that you only need to resolve the object reference once, at the top of the With block, instead of once for each line of code.
You might also get noticeable improvement with using objRs.Fields(0), objRs.Fields(1), etc. The runtime has to resolve the field name string to the offset of the Collection, which is an extra step. The compiler doesn't know about the database, so it can't do that at compile time. When you remove the extra step, you remove performance overhead. Whether it's enough to make a difference might be worth testing.
I have a form in MS Access that I'm trying to create for insurance claims. I have all the fields that I need to be filled in but what I'd like to be able to do is enable or disable those fields depending on certain actions of the users. So the flow of the form is like this: I have a Frame at the top with two radio buttons, one for a single-claim incident and one for a multi-claim incident. If the user clicks the single-claim button everything continues with no problem. If the user clicks the multi-claim incident button, a combo box appears to the side with a dropdown list of MultiClaim_Incident_ID numbers that they need to select from. What I'm trying to do is if the user selects the Multi-Claim Incident button AND does not select an Incident ID number from the dropdown down list (i.e. leaves it at default value) then the rest of the form is disabled until corrected as well as clear all the fields...
It seems like it should be pretty straightforward but I can't seem to get it to work, I'm not sure if my logic is flawed or what. Here's an abridged version of my VBA code:
Private Sub Form_Load()
Me.SM_Frame.Value = 1
Me.MultiClaim_Drpdwn.Value = Null
End Sub
Private Sub SM_Frame_AfterUpdate()
If SM_Frame.Value = 1 Then
Me.MultiClaim_Incident_ID_Label.Visible = False
Me.MultiClaim_Drpdwn.Visible = False
ElseIf SM_Frame.Value = 2 Then
Me.MultiClaim_Incident_ID_Label.Visible = True
Me.MultiClaim_Drpdwn.Visible = True
ElseIf SM_Frame.Value = 2 & MultiClaim_Drpdwn.Value = Null Then
Me.Incident_Date = Null
Me.Incident_Date.Enabled = False
Me.Claimant_Name.Value = ""
Me.Claimant_Name.Enabled = False
//PATTERN CONTINUES FOR REST OF FIELDS//
MsgBox ("CLEAR EVERYTHING!!")
ElseIf SM_Frame.Value = 1 Then
Me.Incident_Date.Value = ""
Me.Incident_Date.Enabled = True
Me.Claimant_Name.Value = ""
Me.Claimant_Name.Enabled = True
//PATTERN CONTINUES FOR REST OF FIELDS//
MsgBox ("Everything can continue as is")
End If
End Sub
Let me just say that getting sequences like these right is NOT straightforward AT ALL! So don't feel bad about not getting it right on the first try. I have to create things like that about once a month and still need a lot of tries until it works in all situations.
Try to seperate to concerns:
You already have SM_Frame_AfterUpdate(). Do in it what you must to handle changing from Value 1 to 2, namely making the Combobox visible, but STOP there. You dont know what will happen to the fields with information from SM_Frame alone, you need to wait for MultiClaim_Drpdwn. Also, do what is needed to go from 2 to 1, namely hide the Combobox.
Next, create an AfterUpdate-handler MultiClaim_Drpdwn_AfterUpdate(). Use THAT to deal with the fields (enable/disable, set empty) according to its value.
Once you have that in place, you only have some edge cases remaining. For example, you want the fields to behave like MultiClaim_Drpdwn_AfterUpdate() states right after you change the SM_Frame. Thats easy once you understand that you can just happily CALL MultiClaim_Drpdwn_AfterUpdate() from within SM_Frame_AfterUpdate(), best done at the very end. These eventhandlers are still just normal functions, already public and available for anyone. This will make things chain nicely when you come from the radiobutton or not when you come from the Combobox.
In an "elseif" series, once a condition is true, the rest is ignored.
So, your
ElseIf SM_Frame.Value = 2 & MultiClaim_Drpdwn.Value = Null Then
is never reached, because you've got
ElseIf SM_Frame.Value = 2 Then
before.
In the same idea, the "ElseIf SM_Frame.Value = 1 Then" after the MsgBox is totally useless, because it's hidden by "If SM_Frame.Value = 1 Then"
Try to use the step-by-step debug mode to see that.
For the life of me, I just cannot seem to get this to work. Here is the situation: I am trying to add the already existing customer custom field (already had a definition, but no value) to an estimate that I am currently creating via QBSDK 12. So far, I can add the estimate, the custom fields to the line items, but not the custom fields belonging to the customer in the estimate header area (reserved for customer information).
Here is my attempted code for the header (doesn't work):
If Not (DE.sconProof(x) Is Nothing) Or Not (DE.sconProof(x) = "") Then
Dim DataExtModRq As IDataExtMod
DataExtModRq = requestMsgSet.AppendDataExtModRq
' DataExtModRq.ORListTxn.TxnDataExt.TxnID.SetValue(sEstID)
DataExtModRq.OwnerID.SetValue("0")
DataExtModRq.DataExtName.SetValue("Proof Required")
DataExtModRq.ORListTxn.TxnDataExt.TxnDataExtType.SetValue(ENTxnDataExtType.tdetEstimate)
DataExtModRq.ORListTxn.ListDataExt.ListObjRef.FullName.SetValue(DE.sconCompany(x))
DataExtModRq.DataExtValue.SetValue(DE.sconProof(x))
End If
Here is my working code for line items within the estimate (Does work):
If Not DE.sitemDateNeeded(i) = "" Then
Dim DataExt53 As IDataExt
DataExt53 = EstimateLineAdder.EstimateLineAdd.DataExtList.Append()
'Set field value for OwnerID
DataExt53.OwnerID.SetValue("0")
DataExt53.DataExtName.SetValue("In Hands By")
'Set field value for DataExtValue
DataExt53.DataExtValue.SetValue(DE.sitemDateNeeded(i))
End If
If Not DE.sitemSPC(i) = "" Then
Dim DataExt54 As IDataExt
DataExt54 = EstimateLineAdder.EstimateLineAdd.DataExtList.Append
DataExt54.DataExtName.SetValue("SPC")
DataExt54.DataExtValue.SetValue(DE.sitemSPC(i))
End If
The error message say's I am missing the TxnID but I am not modifying the estimate, I am creating a new one. I have tried the "IDataExt" as well but that doesn't work any better. If I need to save the newly created estimate, and then go back and add the TxnID, that would be really weird, and I'm not sure of a simple way to do that. I should be able to add data to the custom field in the header portion of the estimate without going through so much "hoopla". Please help me if you know the answer.
I figured it out...
If Not (DE.sconProof(x) Is Nothing) Or Not (DE.sconProof(x) = "") Then
Dim DataExtModRq As IDataExtMod
DataExtModRq = requestMsgSet.AppendDataExtModRq
DataExtModRq.DataExtName.SetValue("Proof Required")
DataExtModRq.DataExtValue.SetValue(DE.sconProof(x))
DataExtModRq.OwnerID.SetValue("0")
'DataExtModRq.ORListTxn.TxnDataExt.TxnDataExtType.SetValue(ENTxnDataExtType.tdetEstimate)
DataExtModRq.ORListTxn.ListDataExt.ListDataExtType.SetValue(ENListDataExtType.ldetCustomer)
DataExtModRq.ORListTxn.ListDataExt.ListObjRef.FullName.SetValue(DE.sconCompany(x))
'DataExtModRq.ORListTxn.TxnDataExt.TxnID.SetValue(sTxnID)
End If