Currently I have a textbox that will display some text based on the search criteria. The text that is displayed will be the name of a table. Is it possible for me to make it so that if I click on the name of the table in the textbox, it will open the table for me?
In the click event of the textbox:
DoCmd.OpenTable Me.MyTextbox
Edit re comment, this is a sketch and will not work if the table name has spaces.
Private Sub Text0_Click()
i = Me.Text0.SelStart
j = InStr(i, Me.Text0, " ")
k = InStrRev(Me.Text0, " ", i)
tbl = Mid(Me.Text0, k, j - k)
DoCmd.OpenTable tbl
End Sub
Or better, capture the construction in a listbox by row, rather than in a textbox.
Based on you code sample, you can say:
Public Sub SearchTables(SearchString As String)
Dim tdf As DAO.TableDef
Dim sTable As String
Dim sField As String
Dim sMsg As String
sMsg = ""
For Each tdf In CurrentDb.TableDefs
sTable = tdf.Name
sField = SearchTable(sTable, SearchString)
If sField <> vbNullString Then
sMsg = sMsg & ";" & sTable & ";" & sField
End If
Next
'listbox0
'Row source type: Value List
'Column count: 2
'You will get a two column listbox with table in one column
'and field in another
Forms!Search!listbox0.RowSource = Mid(sMsg, 2)
End Sub
Then in the click event for listbox0:
Private Sub listbox0_Click()
DoCmd.OpenTable Me.listbox0
End Sub
Do you mean specifically clicking on the text that is the name...
so if the text were "John 12345 THE TABLE" you want just THE TABLE to open?
Not enough information to give a solid answer, but if you wanted to just get THE TABLE from the above text then you could use screen coordinates based on where you click in relation to the position of text. It would be far easier to do it another way...
If the format of your text is like this:
Table = NAMEOFTABLE Field = NAMEOFSEARCH Table = NAMEOFTABLE2 Field = NAMEOFSEARCH2
You could use this code:
Private Sub Text0_Click()
i = Me.Text0.SelStart
If i > 0 Then
startTable = InStrRev(Me.Text0, "Table = ", i)
startField = InStr(startTable + 8, Me.Text0, "Field = ")
If startTable > 0 And i < InStr(startTable + 8, Me.Text0, "Field = ") Then
DoCmd.OpenTable Mid(Me.Text0, startTable + 8, startField - startTable - 9)
End If
End If
End Sub
If you click on the name of any table, it will open that table.
Here a little explanation: using current position of the cursor, I'm searching backwards for the "Table = " string, and from there I'm searching for the next string "Field = ". All we have to do is to check if the cursor is before next field.
Related
I am creating a dynamic search-as-you-type that filters a list of data as the user types in a text box.
Private Sub TxtSearch_Change()
Dim CursorPosition As Long
Dim strSearch As String
Dim sqlSearch As String
CursorPosition = TxtSearch.SelStart
Me.Dirty = False 'set the dirty property to false to save the current value
strSearch = ""
If Not IsNull(Me.TxtSearch.Value) Then
strSearch = Me.TxtSearch.Value
End If
searchLength = Len(strSearch)
If searchLength < CursorPosition Then
For i = 1 To (CursorPosition- searchLength)
strSearch = strSearch + " "
Next
End If
'Check if a keyword has been entered or not
If strSearch = "" Then
Me.TxtSearch.SetFocus
sqlShowAll = "SELECT * FROM qrySearch"
Forms![frmSearch]!fsubTest.Form.RecordSource = sqlShowAll
Else
sqlSelect = "SELECT * FROM qrySearch WHERE ("
sqlLastName = "(LastName Like ""*" & strSearch & "*"")"
sqlFirstName = " OR (FirstName Like ""*" & strSearch & "*"")"
sqlFullName = " OR (FullName Like ""*" & strSearch & "*"")"
sqlEnd = ")"
sqlAllNames = sqlLastName & sqlFirstName & sqlFullName
sqlSearch = sqlSelect & sqlAllNames & sqlEnd
Forms![frmSearch]!fsubTest.Form.RecordSource = sqlSearch
End If
TxtSearch.SelStart = CursorPosition
End Sub
Access truncates trailing spaces in text fields. Is there a way to get around this? I have already implemented a for loop to restore the trailing space for search purposes, but I'd like to save the trailing space so that as the user continues typing the space has not disappeared. For example, I could enter "Jane " and search for "Jane " but when returned to the text box, I would see "Jane" so I could never type "Jane Doe" but only "JaneDoe".
Here's the code I use to accomplish what you're looking for. I have the search box "Searchfor" as where I type, and "SearchResults" as a combobox with the data. There's also a text box "SrchText" which is used by the query "QRY_SearchAll." That query is a series of "Like "" & [Forms]![FRM_SearchMulti]![SrchText] & """ for each field I want displayed in the combo box, see picture.
Private Sub SearchFor_Change()
'Create a string (text) variable
Dim vSearchString As String
'Populate the string variable with the text entered in the Text Box SearchFor
vSearchString = SearchFor.Text
'Pass the value contained in the string variable to the hidden text box SrchText,
'that is used as the sear4ch criteria for the Query QRY_SearchAll
SrchText = vSearchString
'Requery the List Box to show the latest results for the text entered in Text Box SearchFor
Me.SearchResults.Requery
'Tests for a trailing space and exits the sub routine at this point
'so as to preserve the trailing space, which would be lost if focus was shifted from Text Box SearchFor
If Len(Me.SrchText) <> 0 And InStr(Len(SrchText), SrchText, " ", vbTextCompare) Then
'Set the focus on the first item in the list box
Me.SearchResults = Me.SearchResults.ItemData(1)
Me.SearchResults.SetFocus
'Requery the form to refresh the content of any unbound text box that might be feeding off the record source of the List Box
DoCmd.Requery
'Returns the cursor to the the end of the text in Text Box SearchFor,
'and restores trailing space lost when focus is shifted to the list box
Me.SearchFor = vSearchString
Me.SearchFor.SetFocus
Me.SearchFor.SelStart = Me.SearchFor.SelLength
Exit Sub
End If
'Set the focus on the first item in the list box
Me.SearchResults = Me.SearchResults.ItemData(1)
Me.SearchResults.SetFocus
'Requery the form to refresh the content of any unbound text box that might be feeding off the record source of the List Box
DoCmd.Requery
'Returns the cursor to the the end of the text in Text Box SearchFor
Me.SearchFor.SetFocus
If Not IsNull(Len(Me.SearchFor)) Then
Me.SearchFor.SelStart = Len(Me.SearchFor)
End If
End Sub
One warning about this sytem: It uses requery instead of refresh. This is fine for a reasonable number of records on a reasonbly fast system. I found that when I tried to use this same code for data on an ancient Sharepoint server, I'd be hitting a 10 second delay after each letter I type. So if you're dealing with a lot of records or a slow server, you may want to change 'requery' to 'refresh.'
I've been working on a spread sheet to allow my team to manage our workload more effectively, whilst the business is developing a new tool. Anyway, what the sheet does is inject information, then at the click of a button, it populates an OFT email template so that the info can be sent out.
Problem is, we rely heavily on bullet lists for our emails, and I'm really struggling to find a way of adding bullets effectively from an ActiveX Textbox.
At the moment, I have a button which adds the follow to a text box:
[bullets]
* Bullet 1
* Bullet 2
* Bullet 3
[/bullets]
I then have Replace statements that look for strings and it replaces them with the appropriate HTML tags. Here's the code:
' Add HTML formatting to text updates so it displays correctly in the email.
LatestUpdate.Text = Replace(LatestUpdate, "[bullets]", "<ul>")
LatestUpdate.Text = Replace(LatestUpdate, "[/bullets]", "</ul>")
LatestUpdate.Text = Replace(LatestUpdate, "* ", "<li>")
LatestUpdate.Text = Replace(LatestUpdate, vbCrLf, "<br>")
The problem I'm having, is that non-technical people are using this document, so I would really like to have it in such a way were they don't have to look at the markup, but can simple add bullets straight from the textbox.
I was originally thinking about replacing "* " with "< li >" however, that doesn't add the correct < ul > tags, so it's not actually a bullet list within the email.
Can anyone help in simplifying this process for the end users please? I'm really stuck.
The holy grail would be to enable rich text formatting on the textbox, but I don't believe that's possible from all the research I've done?
TIA.
Based on your last comment, what you are looking for is not just a bullet point in your textbox but indentation as well. So here is an attempt at it:
First add the below in your <textbox>_KeyUp function:
Private Sub txtBulletPoints_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim STRING_LENGTH As Long: STRING_LENGTH = 49
Dim aLine() As String
Dim aLineSpace() As String
Dim iC As Integer
Dim sText As String
Dim bUpdate As Boolean
' Only do this if there is a string to work with
If Len(Me.txtBulletPoints.Text) > 0 Then
' Set initial values
aLine = Split(Me.txtBulletPoints.Text, vbCrLf)
bUpdate = False
' First lets indent the last line if we need to
If Left(aLine(UBound(aLine)), 2) = "- " Then
For iC = LBound(aLine) To UBound(aLine)
If iC = UBound(aLine) Then
sText = sText & vbTab & aLine(iC)
Else
sText = sText & aLine(iC) & vbCrLf
End If
Next
Me.txtBulletPoints.Text = sText
End If
' Now the tricky bit. Check if we have reached the end of the
' line so that we can indent the text into the next line
If (Len(aLine(UBound(aLine))) >= STRING_LENGTH) And (InStr(1, aLine(UBound(aLine)), vbTab) = 1) Then
For iC = LBound(aLine) To UBound(aLine)
If iC = UBound(aLine) Then
aLineSpace = Split(aLine(iC), " ")
' As we have to indent the last bullet point line, call the finction to do that
sText = sText & SetIndentsInString(aLine(iC), STRING_LENGTH)
Else
sText = sText & aLine(iC) & vbCrLf
End If
Next
Me.txtBulletPoints.Text = sText
End If
End If
End Sub
Now add the below UDF where your form code is (essentially at the same place where your <textbox>_KeyUp function is):
Function SetIndentsInString(ByVal sString As String, ByVal iIndentLen As Long) As String
Dim iC As Long
Dim iLastTab As Long: iLastTab = 0
Dim aSpace() As String
Dim aTab() As String
Dim sCurString As String
' Check if the string is the same as what it was last
' time (sLastString is a private module variable initialised
' to "" when the form is activated)
If Replace(sString, vbTab, "") = Replace(sLastString, vbTab, "") Then
' Its the same string so lets return it as is
SetIndentsInString = sString
Else
' Its not the same string so set initial values
sLastString = sString
SetIndentsInString = ""
' Loop to see how many lines we have based on number of TABs in the string
Do While InStr(iLastTab + 1, sString, vbTab) > 0
iLastTab = iLastTab + InStr(iLastTab + 1, sString, vbTab)
Loop
' If there is only 1 TAB, simply indent the line
If iLastTab = 1 Then
aSpace = Split(sString, " ")
SetIndentsInString = Mid(sString, 1, Len(sString) - Len(aSpace(UBound(aSpace)))) & vbTab & " " & aSpace(UBound(aSpace))
Else
' More then 1 TAB.. damn!. Ok well lets work it
aTab = Split(sString, vbTab)
sCurString = aTab(UBound(aTab))
' Check if the last line of our bullet point has more characters then allowed in a line
If Len(sCurString) >= iIndentLen Then
' It does. Now loop through all the lines in our bullet point and set the last character in a new line with indent
aSpace = Split(sCurString, " ")
For iC = LBound(aTab) To UBound(aTab)
If iC = UBound(aTab) Then
SetIndentsInString = SetIndentsInString & Mid(sCurString, 1, Len(sCurString) - Len(aSpace(UBound(aSpace)))) & vbTab & " " & aSpace(UBound(aSpace))
Else
SetIndentsInString = SetIndentsInString & aTab(iC) & vbTab
End If
Next
Else
' It doesnt. Loop through and send the string back
SetIndentsInString = sString
End If
End If
End If
End Function
Now in the same module, make the following declaration at the top:
Private sLastString As String
Essentially the above will act like a bullet point as it would be in a Rich Text box. Things to remember is that you will have to set STRING_LENGTH to the number of characters your textbox will take in a given bullet point line (you will have to play around with that). Below is a screen print of how it worked for me
How do I select multiple items in the list box, then refer to the Items I have selected?
You will need to use a variation of the following steps:
create a list box on a form
populate the list box using the row source.
go to the other tab and change the multiselect property to extended
I then used the following VBA
Option Compare Database
Private Item_IDs as string
Private Sub List_item_id_Click()
Dim i As Integer, count As Integer
Dim Item_IDs As String
count = 1
For i = 0 To Me.List_item_id.ListCount - 1
If Me.List_item_id.Selected(i) = True Then
Item_IDs = Item_IDs & ", " & Me.List_item_id.ItemData(i)
count = count + 1
End If
Next i
Item_IDs = Mid(Item_IDs, 3)
Debug.Print Item_IDs
End Sub
Now every time I click on a value in the list, it will return the a comma separated value string (Item_IDs) of the things I have selected. Use CTRL+G in the VBA window to open the immediate window and see the fruits of your labors.
Something like . . .
Private Sub OKButton_Click()
Dim Msg As String
Dim i As Integer
Msg = "You selected" & vbNewLine
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
Msg = Msg & ListBox1.List(i) & vbNewLine
End If
Next i
MsgBox Msg
Unload UserForm1
End Sub
I have a combobox that builds it's list upon first usage. I know that the way I want "NotInList" to behave isn't conventional - I don't want to waste adding the item to a table separate from the needed entry, but I'd like to still warn about an item that hasn't been used yet, so that the user has to think twice before accepting the entry.
Once the user adds the item, it will automatically appear in the list next time because the data source for the combo box is as follows:
SELECT tbl_SP.PROGRAM
FROM tbl_SP
GROUP BY tbl_SP.PROGRAM
HAVING (((tbl_SP.PROGRAM) Is Not Null And (tbl_SP.PROGRAM)<>""));
I tried this:
Private Sub cmbPROGRAM_NotInList(NewData As String, Response As Integer)
If MsgBox("'" & Chr(34) & NewData & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & NewData & "?") = vbYes Then
Response = acDataErrAdded
End If
End Sub
but of course, Access wants the item to actually exist before it will release the error. And...if I set LimitToList to "No" then the user doesn't get a warning.
How can I achieve this behavior?
Ok, I tried this which works fine if the user selects YES, but becomes more complicated when the user selects "NO"
Public Function ReturnsRecords(strSQL As String) As Boolean
Dim d As DAO.Database
Dim arr(1 To 3) As DAO.Recordset
'Dim rs As DAO.Recordset
'assume 3 items in array above
Set d = CurrentDb
Set arr(1) = d.OpenRecordset(strSQL)
' MsgBox "Record Count is " & arr(1).RecordCount
If arr(1).RecordCount > 0 Then
ReturnsRecords = True
Else
ReturnsRecords = False
End If
Set d = Nothing
End Function
Private Sub cmbPROGRAM_BeforeUpdate(Cancel As Integer)
Dim strSQL As String
strSQL = "Select * from LU_PROGRAM where PROGRAM ='" & Me.cmbPROGRAM & "'"
If ReturnsRecords(strSQL) = False Then
If MsgBox("'" & Chr(34) & Me.cmbPROGRAM & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & Me.cmbPROGRAM & "?") = vbNo Then
Cancel = True
' how do I reset this? Me.cmbPROGRAM.Text = Null
End If
End If
End Sub
How do I clear the combobox if the user selects NO? If I select me.undo, that will undo all of the entries, but I just want to clear the combobox.
Incidentally, the form is totally unbound and doesn't accept an entry until the user selects "Save"
First, I'm not quite sure what you wish to achieve ...
Then, educate the users to press Escape to cancel. This is mandatory wisdom when operating an Access application.
For your code to work, you can't change the content of a control in the BeforeUpdate event. So try the AfterUpdate event with either:
Me!cmbPROGRAM.Text = ""
or:
Me!cmbPROGRAM.Value = Null
I am trying to make a form which searches for the value inside all of the tables in the database (there are more than 1 table). The result will be displayed as the name of the table which this appears in. If someone can help me that will be nice.
In short, I have a form with a textbox and button. I enter the search string (for example 183939) and click on the button. It searches the value (183939) inside all the fields in the tables in the database, and if the value is found, then it displays the name of the table that it appears in. Thanks for the help.
I think this is a bad idea because it could take a very long time, and provide confusing results due to also searching system tables... but the following function will return an array of all table names containing the search term or nothing if it wasn't found. Calling example is such: theTables = containingTable("hello") where theTables is a variant. A limitation is that this will fail for multi-valued fields.
Function containingTables(term As String)
Dim db As Database
Dim tds As TableDefs
Dim td As TableDef
Set db = CurrentDb
Set tds = db.TableDefs
For Each td In tds
For Each f In td.Fields
On Error Resume Next
If DCount("[" & f.Name & "]", "[" & td.Name & "]", "[" & f.Name & "] LIKE '*" & term & "*'") Then
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description
Err.Clear
On Error GoTo 0
Else
containingTables = containingTables & td.Name & ","
Exit For
End If
End If
Next
Next
Set tds = Nothing
Set db = Nothing
'Alternate Version
if Len(containgingTables) then containingTables = Left(containingTables, Len(containingTables) - 1)
'Original Version
'if Len(containgingTables) then containingTables = Split(Left(containingTables, Len(containingTables) - 1), ",")
End Function
To display the results with the alternate version, just use: Msgbox(containingTables(searchTerm)) where searchTerm is whatever you are searching.
Me as well i don't know why you would want to do something like that...
I think the solution posted by Daniel Cook is correct, i just took a slightly different approach. Do you need to match the exact value like I do? Anyway, here's my code:
Function searchTables(term as String)
Dim T As TableDef
Dim Rs As Recordset
Dim Result() As String
Dim Counter
Counter = 0
For Each T In CurrentDb.TableDefs
If (Left(T.Name, 4) <> "USys") And (T.Attributes = 0) Then
Set Rs = T.OpenRecordset
While Not Rs.EOF
For Each Field In Rs.Fields
If Rs(Field.Name) = term Then
Counter = Counter + 1
ReDim Preserve Result(Counter)
Result(Counter) = T.Name & "," & Field.Name
End If
Next
Rs.MoveNext
Wend
Rs.Close
End If
Next
If Counter = 0 Then
searchTables = Null
Else
searchTables = Result
End If
End Function
You should filter out duplicated values, in case the function matches multiple times the same filed in the same table.