my VBA dynamically writes several tables depending on criteria and works quite well.
For example here is adding a row, formatting it and advancing to the next row.
oDoc.Tables(t).Rows.Add 'add a row below control number
oDoc.Tables(t).Rows(i).Range.ParagraphFormat.Alignment = wdAlignParagraphCenter
oDoc.Tables(t).Rows(i).Shading.BackgroundPatternColor = oTableHeaderColor
i = i + 1 'advance to row below control number row.
oDoc.Tables(t).Cell(i, 2).Range.Text = "Check Definition"
I do it in this manner because I just don't know how many rows any given table is - so I create the rows as I need them, might be clumsy but it works.
What I need to do is add a check-able checkbox to rows with text like this.
Planned: ☐
I've tried several ways that just don't seem to work. as far as I can tell it's because i'm not creating the table then selecting it. I've tried recording a macro and that just shows the bit about selection first.
Here's what I've got, it pops an error.
oDoc.Tables(t).Cell(i, 2).Range.Text = "Planned: " & oDoc.Tables(t).Cell(i, 1).Range.ContentControls.Add(wdContentControlCheckBox)
I get "requested member of the collection doesn't exist.
If I try to put it on two lines it will just overwrite cell 1. with the checkbox and I can't seem to position it to the end of the cell first. Any ideas? I've tried insertbefore and that works but I have to insert several checkboxes in the same cell.
Any ideas?
thank you.
Getting text + checkbox + other text + second checkbox into one cell is tricky.
This may be one of the few cases, where you actually have to use the Selection object.
This works for me in Word:
Dim oDoc As Word.Document
Set oDoc = ThisDocument
Const t = 1
Const i = 1
Dim rng As Word.Range
Dim iCheck As Long
Dim sLabel As String
Set rng = oDoc.Tables(t).Cell(i, 2).Range
rng.Select
With Selection
.Collapse Direction:=wdCollapseStart
For iCheck = 1 To 3
sLabel = Choose(iCheck, "Planned: ", " Done: ", " Perhaps: ")
.TypeText Text:=sLabel
.Range.ContentControls.Add wdContentControlCheckBox
' move cursor after checkbox
.MoveRight Unit:=wdCharacter, Count:=2
Next iCheck
End With
In Access, use oWord.Selection instead (or what you have as reference to Word).
The following works for a single checkbox, but I didn't manage to create a second one after additional text.
Dim rng As Word.Range
Set rng = oDoc.Tables(t).Cell(i, 2).Range
rng.Text = "Planned: "
' set range to end of cell
rng.Collapse Direction:=wdCollapseEnd
' I'm not entirely sure why this is needed, but without the checkbox goes into the next cell
rng.MoveEnd Unit:=wdCharacter, Count:=-1
rng.ContentControls.Add (wdContentControlCheckBox)
Related
I have a csv file that I need to have converted to an xlsx file (not a problem)...in the process of doing that I format my data. I want to delete all rows where I have an empty cell. Column C had text data and Column D has numeric data.
I have tried :
If (.Sheets(1).Columns.Cells("D")) = "" Then
msgbox("HI")
End If
I've tried .text as well as .value I can't seem to get into the actual cells to determine if it's empty so as to delete the row.
You need a little more structure to achieve your goal. You can't check every cell in Column D just by using .Cells("D") = "" as the Cells expects both row and column indicators to be provided.
Perhaps you could try looping over your data in Column C and/or D and where there's an empty cell, delete the whole row.
Const xlUp = -4162 ' Excel variables are not defined in vbscript
Dim oBook : Set oBook = ThisWorkbook
Dim oSheet : Set oSheet = oBook.Sheets(1)
Dim iLastRow, iRow
iLastRow = oSheet.Cells(oSheet.Rows.Count, 3).End(xlUp).Row
For iRow = iLastRow to 2 Step -1 'assumes a header row otherwise use 1 instead of 2
If oSheet.Range("C" & iRow) = "" Then
oSheet.Range("C" & iRow).EntireRow.Delete ' delete row if blank
End If
Next
Edit after comment:
Changed the loop to run from iLastRow to 2 instead of 2 to iLastRow. When deleting rows, you should always move from the bottom up, as when you delete a row, the next one jumps up and is then skipped over!
I am trying to set values into text boxes by referring to them as strings
The text box names all follow a format:
eg. txt_N1 or txt_N2
I want to be able to go through the text boxes by incrementing the integer of the text box name, which would look like "txt_N" & CStr(intRow).
I am not sure how I am meant to go about doing this.
Below is what I've got so far
intRow = 1 'The 1st Row
recVat.MoveFirst 'Go to the 1st record in the recordset
'Loop through the records
Do Until intRow = 4 Or recVat.EOF
'Set the text boxes in the VAT Summary
strNet = "txt_N" & CStr(intRow)
Me!strNet = recVat![SumOfnet_t]
'Move to the Next Record
recVat.MoveNext
intRow = intRow + 1
Loop
Just don't use the bang notation, but the normal notation, and this should be rather easy:
Me.Controls(strNet).Value = recVat![SumOfnet_t]
I'm currently struggling how to set up validation rules for forms in either Datasheet or Form view that trigger immediately upon going to either another field within the record or to another record entirely.
My form is designed to add records to one destination table where the primary key column needs to match a value of a specific field in any record of a source table. The rest of the fields in the form (and destination table) are for general user input (some DateTime fields, some text, some decimal).
I can get Access to display a standard error dialogue when a user attempts to free-enter a value not on the list immediately after selection of another field or record. The error displayed is
The text you entered isn't an item in the list.
Select an item from the list, or enter text that matches one of the listed items"
And if I reselect a lookup value already selected and go to the next record, I get
The changes you requested to the table were not successful because they would create duplicate values in the index, primary key, or relationship. Change the data in the field or fields that contain duplicate data, remove the index, or redefine the index to permit duplicate entries and try again.
However, I'd like that error (or similar) to appear immediately if going to another field within the same record. In other words, I want it to tell me that it's a duplicate before allowing the user to fill out the rest of the current record in the form or table.
I would like the selection list be restricted to values not previously present in the destination table. Obviously if editing an already-created entry, you should be able to keep the value you had previously (i.e. that value wouldn't be excluded from the dropdown list).
Alternatively there would be a selection dialogue that would appear if an otherwise valid value was duplicated.
Duplicate Value
You've already used that value. Would you like to change this record or the previously-entered record.
⪡ This One ⪢ < Previous >
If "Previous" is selected, it would jump up to the same field in the indicated record, providing a dropdown list for re-selection (and once done would jump back to the "current" record and autoselect the temporarily duplicated value.
I'll edit this post in a bit with my table design details, as well as source setups for the form.
"Solved" this in VBA.
Private Sub MyControl_AfterUpdate()
newval = Me.MyControl.Value
oldval = Me.MyControl.OldValue
If newval = oldval Then Exit Sub ' everything's okay
Dim rs As Object
Set rs = Me.Form.Recordset
whereclause = "MyControl = '" & newval & "'"
qry = "SELECT COUNT(*) as c FROM MyQuery WHERE " & whereclause
qrs = CurrentDb.OpenRecordset(qry)
If qrs.Count = 1 Then cnt = qrs(0).Value
If cnt >= 1 Then
selval = MsgBox("Would you like to keep your selection for this record?" & vbCrLf & "[yes = change previous record's MyField; no = change MyField for this record]", vbYesNo Or VbMsgBoxStyle.vbExclamation Or vbSystemModal Or vbDefaultButton2 Or vbMsgBoxSetForeground, "Duplicate MyField selection encountered")
If selval = vbYes Then
' set focus to the other entry, preserving selection here
thissel = Me.MyControl.ListIndex
Me.MyControl.Value = "temp" ' if a string is okay & so we can jump away from this record
thisloc = Me.Form.CurrentRecord ' record number
rs.Findfirst (whereclause)
thatloc = Me.Form.CurrentRecord
Debug.Print (thisloc & "now ; was" & thatloc)
Me.MyControl.Value = "invalid"
DoCmd.GoToRecord , , acGoTo, thisloc ' jump to the new row
Me.MyControl.Value = newval
DoCmd.GoToRecord , , acGoTo, thatloc ' jump to the one to change
If thissel <= 0 Then thissel = 1 ' may not be useful, given the error handling below
On Error Resume Next
Me.MyControl.ListIndex = thissel - 1
On Error GoTo 0
Me.MyControl.Dropdown
ElseIf selval = vbNo Then
Me.MyControl.Value = Me.MyControl.OldValue
Me.MyControl.Undo ' for some reason this doesn't clear the "dirty" bit, resulting in the edit pencil showing up for the row.
Me.MyControl.SetFocus
End If
Else
Debug.Print ("There were no matches! Das ist gut")
End If
End Sub
Residual Issue(s)
Selecting "Yes" from the dialogue and then hitting escape puts the invalid "invalid" string into the box, which ignores any requirement to restrict the final selection to one in the list (ie Limit to List = 1). Ideally this would "roll back" the two rows.
Maybe I should change this to an OnExit Event so it doesn't trigger before I even leave the cell? Not sure if the primary key violation would happen before this triggers though. OnChange triggers much too frequently (every time you down-arrow through the list).
Hi I'm using Access 2007 and i am doing a program to enter stock items.
I am using a form and i need to make sure that when the user inputs the barcode of the product the system checks in the table if this exists. If it does exists, i need to load data for this existing item into the 3 additional fields in the same form, otherwise to continue creating the new record.
Now i am trying to use set tempvar in the beforeupdate however i cannot get it right.
any suggestions please.
field name : [barcode]
table to look into is "cartridge static data"
additional fields to fill if barcode exists are : [cartridge] , [end user] , [phone no]
Appreciate any help
regards
Tony
I would insert a combo box using the Access wizzard.
Select the data from "cartridge static data" i.e. [barcode] [cartridge] [end user] [phone no]
Do not hide the first row, and make sure you can see the data width in the wizard as you build it.
When completed go to the combo [data] [row source] and click the three {…}
Check what is displayed ~ for example sort by Barcode, remove nulls etc.
If you have the column widths wrong you can change those in the [format tab].
Column headers default to No which may need changing or you may be happy with that.
Under [other] name check you have a sane name e.g. cbo_barcode_search
Now attach this code to the AfterUpdate property of the Combo Box:
Sub cbo_barcode_search_AfterUpdate ()
Dim rs As DAO.Recordset
If Not IsNull(Me.cbo_barcode_search) Then
'Save before move.
If Me.Dirty Then
Me.Dirty = False
End If
'Search in the clone set.
Set rs = Me.RecordsetClone
rs.FindFirst "[BarCode] = " & Me.cbo_barcode_search
'rs.FindFirst "[BarCode] = """ & Me.cbo_barcode_search & """" 'for text
If rs.NoMatch Then
'Trigger new form or add the just typed data into your form as required
‘e.g. me.field1 = cbo_barcode_search.column(0) ' Barcode
Else
'Display the found record in the form.
' Usually use Me.Bookmark = rs.Bookmark but your question suggests this is not what you want so
'NOTE: First column data is column(0) NOT column(1)
me.field1 = cbo_barcode_search.column(0) ' Barcode
me.field2 = cbo_barcode_search.column(1) ' Cartridge
me.field3 = cbo_barcode_search.column(2) ' end user
me.field4 = cbo_barcode_search.column(3) ' phone no
End If
Set rs = Nothing
End If
End Sub
You will need to modify this to match your field names (eg me.field1 is probably me.barcode but it may be me.str_barcode ~ I don't know what you used.
Hope this gets you on the right track. Paul
I want to populate a combo box with the results of a query in Access. I'm just not seeing how to do it. As far as I understand, one must first create a record set, read the query results into the record set, then write the record set to the combo box's row source property. Is this correct? is there a simple example somewhere that I can follow? I haven't found one in any of the other threads.
Here's my attempt so far:
Dim RS As Recordset
Dim myDB As Database
Set RS = myDB.OpenRecordset("SourcesNotDisposed", dbOpenDynaset)
Do While Not RS.EOF
With Me.cmbSN
RowSource.AddItem
End With
Loop
With this code, I'm getting an "Object required" error at the RowSource line. cmbSN has data properties:
Row source Type = Table/Query
Bound Column = 0
Limit to List = Yes
Allow value list edits = Yes
Inherit value list = Yes
Show only row source = No
The query only has one visible column called "Serial Number"
Thanks in advance
Thanks for all the suggestions everyone. I've worked it out and found a very simple solution. With the combo box's Row Source Type property set to Table/Query, all I needed to do was set the Row Source property to a valid SQL string. e.g.:
strSQL = "SELECT Sources.[Serial Number] FROM Sources " & _
"WHERE (((Sources.Nuclide)='Cf-252') " & _
"AND ((Sources.[Location / Status])<>'Disposed')) " & _
"ORDER BY Sources.[Serial Number];"
Me.cmbItem.RowSource = strSQL
Me.cmbItem.Requery
Below code insert table fields into combo box. Add this code under onEnter event of combo
Private Sub CM_Enter()
'CM is combobox name
Dim strItem1 As String
Dim strItem2 As String
On Error Resume Next
Dim i As Integer 'Index for loop
With Me.CM
.RowSourceType = "Value List" 'Set rowsource type as Value list
.RowSource = "" 'Clean combo contents
End With
'Loop through field names of table and add them to your combo:
For i = 1 To CurrentDb.TableDefs("table1").Fields.Count - 1
Me.CM.AddItem (CurrentDb.TableDefs("table1").Fields(i - 1).Name)
Next i
'/***Delete unwanted items from the combo
strItem1 = "col1"
strItem2 = "col2"
'CM.RemoveItem strItem1
'CM.RemoveItem strItem2
End Sub
I think you might need to do a 'first read a record' before starting the loop.
Try using a RS.MoveFirst before the Do-While loop?
I think you may also need to do a .MoveNext inside your loop, just before the Loop statement; it's been a long while since I did anything like this in VBA, but it looks to me like it'll just add the same item over and over until it runs out of memory? I don't think the AddItem moves the record pointer to the next record by itself.
You may also need to check what happens if you MoveNext off the end of the record set...
HTH :)