I asked a question on Stack Overflow a few days ago asking for a solution for copying email support forms and pasting the data into the appropriate text fields on a form. I got an answer which solved my problem - until I went to go use the tool and realized a problem.
I am using this code:
'Service Plan Description
For i = 0 To lines.Count - 1
If lines(i).StartsWith("Service Plan Desc. :") Then
StartLine = i
Exit For
End If
Next
tbx_ServicePlanDescription.Text = lines(StartLine).Split(":"c)(1).Trim 'Put sorted data into textbox
And when I copy the following text into the clipboard to test the Service Plan textbox:
Maint:AbloEnterprise S/W AddOn (5)
It only pastes 'Maint' in the textbox because the code purposely removes the colons.
So my question is: What would be a way to overcome this?
I used the Split(Char[], Int32) method to limit how many parts the split would split the string into, as suggested in the comments, like this:
tbx_ServicePlanDescription.Text = lines(StartLine).Split({":"c}, 2)(1).Trim()
Related
I've been working on a database project for my database classes but I am stuck at the most ridiculous thing; clearing a ComboBox of values in one of my forms. I've been trying to figure out how to do this for hours, but I cannot do it. The ComboBox has a control source linking it to an attribute which is a data type of Date/Time, formatted as short time (hh:ss)
I've tried a few things, but nothing really works, like:
ComboBox1.Items.Clear()
but that won't work because the Items property doesn't even exist in Access's version of VB, I run Access 2019 which has VB for Apps 7.1. Most things on the Internet suggest this approach.
I've also tried a rather quirky method:
index = Combo39.ListIndex
Dim indexc As Integer
indexc = 0
If index = -1 Then
'do nothing because its already empty
Else
Do
Combo39.RemoveItem (indexc)
If indexc = index Then
Exit Do
End If
indexc = indexc + 1
Loop
End If
This code basically loops until the number of times the loop has cycled is the same as the index number of the combo box. I am not sure why, but it doesn't work. It does appear to remove some things, but not everything. It's as if the loop breaks early.
I am in huge need of help, I've run completely dry on how to do this one simple thing. I would greatly appreciate help, thank you.
As your combobox seems to have a list of values as its rowsourcet, all you need is to clear this:
Me!Combo39.RowSource = ""
I'm trying to save the values of data that have been input into my form. There are a total of about 50 different fields to save across 5 different agents, so I loaded the data into arrays.
I've tried saving the fields in a loop, but it doesn't seem to work in a loop, only if each field has a separate line, which is a lot of code and messy. The Ag1Name, Ag2Name and Ag3Name are the names of my textboxes that the user enters to populate the form.
Sub LoadAndSaveData()
NumberofAgents = 3
Dim AgentName(3) as String
AgentName(1) = Ag1Name.Value
AgentName(2) = Ag2Name.Value
AgentName(3) = Ag3Name.Value
For Count = 1 To NumberOfAgents
With ActiveDocument.CustomDocumentProperties
.Add Name:="AgentName" & Count, LinkToContent:=False, Value:=AgentName(Count), Type:=msoPropertyTypeString
End With
Next Count
End Sub
The data doesn't get saved to the Custom Document Properties when the code is set up in a loop like the above. Since there are so many values to save and all the data is already in arrays, I would much prefer to use a loop rather than write out a separate line of code for all ~50 of the values. It does seem to work when each field is saved in a separate line of code.
I think this would probably get what you want. You don't really need to count the document properties first, only increment with the ones you want to update. Hopefully the only document properties you want contain the name AgentName in it.
ReDim AgentName(0) As String
Dim P As Long
For Each c In ThisDocument.CustomDocumentProperties
If InStr(1, c.Name, "AgentName", vbTextCompare) > 0 Then
ReDim Preserve AgentName(P)
AgentName(P) = c.Value
P = P + 1
End If
Next c
As a guest I cannot post a comment here, but the code you gave works OK here.
However, there is a problem with creating legacy custom document properties programmatically, because doing that does not mark the document as "changed". When you close the document, Word does not necessarily save it and you lose the Properties and their values.
However, if you actually open up the Custom Document Property dialog, Word does then mark the document as "changed" and the Properties are saved.
So it is possible that the difference between your two scenarios is not the code, but that in one scenario you have actually opened the dialog box to check the values before closing the document and in the other you have not.
If that is the case, here, I was able to change this behaviour by adding the line
ActiveDocument.Saved = False
after setting the property values.
If you do not actually need the values to be Document Properties, it might be better either to use Document Variables, which are slightly easier to use since you can add them and modify them with exactly the same code, or perhaps by storing them in A Custom XML Part, which is harder work but can be useful if you need to extract the values somewhere where Word is not available.
You can make this even easier by looping the controls on the UserForm, testing whether the control name contains "Ag" and, if it does, create the Custom Document Property with the control's value - all in one step.
For example, the following code sample loops the controls in the UserForm. It tests whether the controls Name starts with "Ag". If it does, the CustomDocumentProperty is added with that control's value.
Sub LoadAndSaveData()
Dim ctl As MSForms.control
Dim controlName As String
For Each ctl In Me.Controls
controlName = ctl.Name
If Left(controlName, 2) = "Ag" Then
With ActiveDocument.CustomDocumentProperties
.Add Name:=controlName, LinkToContent:=False, value:=ctl.value, Type:=msoPropertyTypeString
End With
End If
Next
End Sub
I feel a little stupid... I just realized that the reason that the code wasn't working was that the variable NumberofAgents was not being calculated correctly elsewhere in my code. I've got it working now. Thanks for your thoughts!
I am writing a program that reads questions from a CSV file for the user to answer. Once i read from the question CSV file, i store my questions in a list of Question objects. My GUI then displays each question to the user
Public Sub displayQuestion(ByVal x As Integer)
QuizForm.questionLabel.Text = allQuestions(x).qText
End Sub
and they are able to cycle through them via next/previous buttons. Each Question object has an associated string variable representing the question text.
Some questions are simple sentences such as
'Which of the following statements is the MOST valid goal for a test team?'
However, some questions are in the following format:
Which of the following statements are TRUE?
A. Software testing may be required to meet legal or contractual
requirements.
B. Software testing is mainly needed to improve the quality of the
developer’s work.
C. Rigorous testing and fixing of defects found can help reduce the risk of
problems occurring in an operational environment.
D. Rigorous testing is sometimes used to prove that all failures have been
found.
The trouble is, when reading a question text from the CSV file, it must be on one line. This then leads to questions structured like the second example above being displayed on my GUI like this:
Which isn't very user-friendly.
Id like it to be presented like this:
I understand how i would do this by hardcoding vbnewLine into the text, but the questions are all loaded dynamically at run-time.
Any suggestions to how i my go about this?
Just add a vbNewLine at the end of your subroutine:
Public Sub displayQuestion(ByVal x As Integer)
QuizForm.questionLabel.Text = allQuestions(x).qText & vbNewLine()
End Sub
Don't make it harder on yourself then need be. Append a new line at the end of your Question String, nothing wrong with this.
There are a few posts open on this topic however none seem to fully do what I need. I have done a little bit of programming however I have never done anything with VBA. Every day I receive a series of emails varying from 10 to 50 all containing a subject line starting with [Tk#*******] New Request ( * = 7 digit number)
Then inside the body text there is a form that looks like this:
Body Text
I then have an excel sheet set up with 'Username' in 'C', 'Company' in 'G', 'valid until' in 'H' and 'Ticket' in 'I'. I would like to extract first the 7 digit ticket number from the subject and put it in the excel 'Ticket' field, then just the 'smithjoh' part from the login field and place it in 'Username', then the External company listed to 'Company' and finally the Expiration date into 'valid until'.
First I would like to know if this is possible to do as it is extracting specific sections of the data and if so if someone could help me out with making this work that'd be most appreciated. I have attempted to do it myself however lack of experience has left me clueless therefor there is nothing to work with unfortunately. If this could be made it would help me out a lot as it would automate a very tedious manual task.
Thanks,
Mark
Ok, if you are grabbing the body and title without issue then you just need to do string manipulations. Read them into a variable each. Assuming that your subject is litterally "TK#******* New Request" then this should get you started. Basically repeat this logic for each part you want to pull out. Once you have the values in variables you can then put those values into cells.
Dim sSubject as string
Dim sBody as string
Dim sTicket as string
Dim sLogin as string
Dim lLoginPos as long
Dim iLoginLength as integer
sTicket = Mid(sSubject,4,7) 'start 4th char and grab 7 ... if you actually have the brackets in the subject then do 5,7
lLoginPos = InStr(sBody, "emea") + 5 'if they aren't all emea you will need to key off the "Req on behalf name" and add more to the result the result will be the e in emea so add 5 to get past that to the login.
iLoginLength = InStr(sBody, "Req on behalf mail") - lLoginPos ' you might need to subtract an additional 1 or 2 if your result isn't perfect. Not sure what the blank white spaces in your screenshot will do here.
sLogin = Mid(sBody,lLoginPos,iLoginLength) ' grabs that username.
With Sheets("Sheet1")
cells(1,3) = sLogin ' puts that into Row 1 Colum 3 (C) Cells is R1C1 ... backwards from the normal way you think of excel
End With
Use other string variables for all the other parts you want to grab and just repeat the logic of finding the starting place and ending place and then using mid to put it into a variable.
Give it a shot filling out the rest and if you get stuck, post your code up to that point and let us know what line is giving you trouble. Don't forget to turn on your locals window and use your F8 key to step through the code one line at a time so that you can see exactly what is going on. This is especially useful with string manipulations.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have a list of data, distributed with a non-homogeneous pattern, on 3 columns. The challenge is to write a vba code "smart enough" to copy and paste all these numbers on one column, putting them in order, one below the other one: 1, 2, 3, 4, 4.1, 4.2 etc.. without missing any of them.
Could someone help me in this task? Because I see a lot of complexity and I have no idea how to manage it. Thank you!
As I understand it, you're looking to order this in a specific way that isn't necessarily how Excel would sort by default. The values look like version numbers or nested task IDs.
Stack Overflow isn't really a "solve your problem for you" kind of place, but I can definitely get you started. Here's what you'll need to do:
Get all the values, preferably into a Collections object. Make sure to omit blank cells.
Convert each value into a new format which a) is sortable, and b) can be reverted to the original format. For example, let's say these are version numbers, and any given number can be as high as 999, and there can be up to 4 items (e.g. 123.10.15.9 is valid, as is 9.5). Convert these to the form 000000000000 (that's 12 0s). You can do this by using Split() to divide the values using the "." delimiter, then padding the value out. This might look something like this:
.
'Converts 1 => 001000000000
' 1.1 => 001001000000
' 2.4.7 => 002004007000
' 65.339.1 => 065339001000
Function ConvertToSortableVersionNumber(value As String) As String
'Add all the parts of the value (. delimited) to a collection
Dim vnPart As Variant
Dim error As Boolean: error = False
Dim Parts As Collection
Set Parts = New Collection
For Each vnPart In Split(value, ".")
'Make sure this can actually be formatted as needed.
If Len(vnPart) > 3 Then
error = True
Exit For
End If
'Add this part to the Parts collection
Parts.Add vnPart
Next vnPart
'Now make sure there are 4 parts total
If Parts.Count > 4 Then error = True
'Check for errors
If error Then
'There is an error. Handle it somehow
End If
'If there are less than 4 items in the collection , add some
While Parts.Count < 4
Parts.Add ("000")
Wend
'Now, assemble the return value
Dim retVal As String
Dim item As Variant
For Each item In Parts
retVal = retVal & Right(String(3, "0") & item, 3)
Next item
'All set!
ConvertToSortableVersionNumber = retVal
End Function
Sort the collection (this page has a good example of sorting a collection in memory).
Create an array with new values converting back to the original format (much easier since the inputs will be highly standardized).
Write the array to a new range--and you're done!
Take a stab at it. I think you'll find that Stack Overflow is much more helpful once you can show the work you've already done, what you've tried, and what specifically is giving you trouble.
Good luck!
If you have 2010 or later the following formula will do it:
=IFERROR(SUBSTITUTE(SUBSTITUTE(AGGREGATE(15,6,--SUBSTITUTE($A$1:$C$10,".","000")*--(1 & REPT("0",9-LEN(SUBSTITUTE($A$1:$C$10,".","000")))),ROW(1:1)),"0000",""),"000","."),"")
If you have 2007 or earlier than it will need to be an array formula:
=IFERROR(SUBSTITUTE(SUBSTITUTE(SMALL(IF($A$1:$C$10<>"",--SUBSTITUTE($A$1:$C$10,".","000")*--(1 & REPT("0",9-LEN(SUBSTITUTE($A$1:$C$10,".","000"))))),ROW(1:1)),"0000",""),"000","."),"")
Being an array formula it must be confirmed with Ctrl-Shift-Enter instead of Enter when leaving edit mode.
Column E is the first formula and Column F is the second.