Hide a column programmatically in MS-Access - ms-access

I want to hide or show a column based on variable data from a users selection. How do you set a column to hidden in MS-Access 2003?
For Example,
After user change event...
For Each ctl In Me.FormNameHere.Form.Controls
If (TypeName(ctl) = "Textbox") Then
If InStr(GetTextList(), ctl.Name) > 0 Then
ctl.hidden = True
Else
ctl.hidden = False
End If
End If
Next ctl
What is the best approach to this type of challenge?
Is there a more obvious solution?

Controls do not have a "hidden" property (no objects in Access have a hidden property). They do have a .Visible property.
For future reference, I suggest you familiarize yourself with the Object Browser in the VBE -- open the VBE and hit F2. You can then restrict your search to the individual libraries used in your project. It does take a while to get to the point where you understand the object model, though.
Also, you can rely on Intellisense to learn the properties/methods of an object, so in the code of the form you're working with, you can type "Me.MyTextBox." and the Intellisense dropdown will show you all the properties and methods of that particular control. It doesn't work for a generic control variable (as in your code) because different control types have different properties.
And, of course, the properties sheet gives the names of the properties, even though in code they don't always use the same orthography (usually they are the same with spaces removed).
Also, there are differences in how you might want to do this depending on whether it's a regular form or a datasheet form. In a datasheet, your controls also have .ColumnHidden and .ColumnWidth properties (setting those in any view other than datasheet view has no effect, and neither of those properties are available in the standard property sheet, but changes to them are retained when you save the form).

I answered a similar question to this not long ago to do with hiding columns on a datasheet. However you seem to want to hide textboxes arranged in a column on a form, is that correct?
Iterating over all the controls in the form could be slow if you have many controls. If you really need to use textboxes like that, then you could try group the 'columns' together then hide the groups. Another approach would be to use a listbox or datasheet to represent the data, where you can alter the layout of the columns directly.

I found the ColumnHidden property does the trick.
For Each ctl In Me.FormNameHere.Form.Controls
If (TypeName(ctl) = "Textbox") Then
If InStr(GetTextList(), ctl.Name) > 0 Then
ctl.Columnhidden = True
Else
ctl.Columnhidden = False
End If
End If
Next ctl
I got a hint from this related question.

A one-liner approach is using:
forms(fname).Controls(ctrlname).columnhidden = false
where
fname is name of your form
ctrlname is name of your control

Related

MS Access: Easiest way to implement a "check all" box in a form with a datasheet subform

I have a form whose main purpose is to contain a datasheet subform (the form provides a common visual theme across the pages as well as navigation buttons and sometimes selection criteria for the subform).
One of my subforms has a check box.
The user behavior will be to:
Open this form
Filter the datasheet according to some specification
Do something off-line involving, e.g., the ten visible line items
Check the field (yes/no field) on those ten line items to indicate that it's been done
What I'd like is for the user to be able to check one box that then checks all the visible boxes.
The challenge is that it must only be the visible ones, i.e. dependent on what filters are in place.
I tried to create a checkbox in the main form labeled "Check All" which runs code something like:
me.sfrmReport.Control.reported.value = me.chkCheckAll.value
But unfortunately, this only checked the active row, not all of them. I know I could run a query on the underlying table, but it would need to replicate the user filters.
In fact, what might be even cooler would be a "Check highlighted" box that checks the highlighted rows only.
But I think "Check all" would be better.
I tried to find this, but my searching skills failed me. I'd have thought this was something somewhat common, but perhaps I'm thinking about this incorrectly. I do note that there's a sum function which automatically sums just the filtered/visible rows in a datasheet, so the notion of interacting with just the visible rows is at least somewhat standard.
Well, the check all box certainly should not be on a "row". So one would assume that say beside the combo box, you place a check all box. (can't imagine that the button or code would be place on the row(s)).
So, say beside the combo box in your screen shot, you have a button called check all.
The code behind that button would/could be:
dim rst as dao.RecordSet
set rst = me.MySubForm.Form.RecordSetClone
rst.movefirst
do while rst.EOF = false
rst.edit
rst!ResultReported = true
rst.update
rst.moveNext
loop
me.MySubForm.Form.Refresh
So above will operate directly against the sub forms data source (current filtered recordset).
I "think" from your screen shot, the top part of the form (with combo) is the main form, and the sub form you have displayed is the sub form.
So, of course you will have to replace the name of the controls I used above, and also the field name for the check box.
So the format to get that recordset is:
me.MySubFormControlName.Form.RecordSetClone
and to fire off a refresh of the sub form after the code runs is of course.
me.MySubFormControlName.Form.Refresh
Note that intel-sense should work and help you. if the code does not compile, then don't try and run it until it compiles.

Referencing a subform as variable in a module

I've been using a module to take the name of a form and a control as variables to change a property of a control on a form. For example:
Sub mySub(formName As String, controlName As String)
Forms(formName).Controls(controlName).ForeColor = Colour.RedDark
End Sub
I'd like to do this for a property on a control on a subform as well, but can't quite figure out the syntax to also refer to the subform as a variable too.
I thought it might be something like:
Forms(mainFormName).Form(subFormName).Controls(controlName).ForeColor = Colour.RedDark
...but this isn't working (Object doesn't support this property or method).
My Access 2010 does not recognize a control property named ForeColour; but ForeColor is valid. (I don't know whether there is a locale issue involved here but my locale is US English.)
Other than that, I think you're trying to access ForeColor through the .Form(subFormName) property. Instead of that, reference the subform control, and from there the target control in its contained subform.
In this working example, Form12 contains a subform control named Child0. The subform control contains a form named fsub2 which in turn contains a text box named txtMemo_field. But note the name of the subform (the form name not the control which contains it) does not appear in this statement:
Forms("Form12").Controls("Child0").Controls("txtMemo_field").ForeColor = vbBlue

Referring to specific record's Controls on subform

I have a subform which makes a lot of use of conditional formatting to grey-out cells which cannot contain data, and highlight cells which have been adjusted by the user. The subform is a Datasheet.
This all works fine, except for the lag in applying the formatting, which sometimes even won't update until the user mouses over the cells.
What I would like to try is applying the formatting in VBA, rather than using the in-built conditional formatting, as I would rather the form takes a couple of seconds longer to load but with all formatting applied once it does, than to have the delay I'm currently getting.
So what I'm stuck on, is how to tie back a control on the subform to a specific record in the view that's populating it. For example, I can use the following code:
Dim ctrl As Control
For Each ctrl In Me.Controls
MsgBox ctrl.Name & " : " & ctrl.Value
Next ctrl
Which might display, for instance, "RowNumber : 010", so I could identify what record that control relates to, but when it says "TotalUSD : 1,234,567.89", I would have no way of knowing which record that related to, and therefore whether or not formatting should be applied.
Is there a better way of doing this, I guess ideally by being able to link each ctrl to its corresponding record in the Form.Recordset?
UPDATE
Below screenshot shows the conditional formatting as it is currently implemented, and what I am trying to achieve using VBA instead of conditional formatting.
I do not have in depth information about your implementation so here is a general suggestion that I have used in my implementations.
You should add some kind of distinguishing column to your table. For example I once had a form that showed projects and employees. The distinguishing column contained a boolean value "True" for each project, "False" for each employee. Based on that information I was able to format accordingly.
My suggestion: Add an integer distinguishing column to your recordset table. The value "0" would be a plain column, "1" would be for greyed out, "2" for user input.
In the Form_Load Event you would have to iterate through all your controls and set the formatting.

Getting data from Word doc form controls

I'm building a form in a Word .docm (macro enabled Word 2013 doc) with the aim of programming an Access database to import data from completed forms. I've placed textBox and comboBox controls to receive user input, but I can't get the data back out.
The examples I've seen use the Document.FormFields collection like so (in Word):
Dim fld as FormField
for each fld in ActiveDocument.FormFields
Debug.Print fld.Name & " - " & fld.Result.Text
next
However in my doc Document.FormFields is empty, but Document.Fields has 19 elements, which happens to be the number of controls in my form. That's great, except that I can't seem to get the name or value of any of the controls using a Field object. Field.Result.Text is always blank, and there is no Field.Name attribute.
So what's the difference between Field objects and FormField objects, and why are my controls showing up in Fields when all the examples I've seen use FormFields?
Am I using the wrong form controls? There are three types (I hope I'm not the only one who thinks this is ridiculous) legacy controls, ActiveX controls, and content controls. I'm using the ActiveX type.
A few things...
In MS Word terms, a 'field' doesn't have to be a form field. E.g., an auto-updated date, linked graphic, page number, etc., are all types of 'field' (or at least, were until the most recent versions of Word).
For compatibility reasons, it can be better to avoid the ActiveX controls. E.g., the Mac version of Word doesn't support them.
For best compatibility I would personally stick to the traditional form controls. Instances are named according to their bookmark name, which is settable by right clicking the control and selecting Properties. In VBA, their data is then got via the FormFields collection; if you want the value for a specific field, use
Value = ActiveDocument.FormFields("MyFieldName").Result
If all you want is to use the current fields you have, you can get the value or name from the OLEFormat.Object:
Application.ActiveDocument.Fields.Item(1).OLEFormat.Object.Value
Or
Application.ActiveDocument.Fields.Item(1).OLEFormat.Object.Name
However, I would agree with Chris in recommending that you avoid the ActiveX controls. As Microsoft says, there are a lot of reasons that they aren't the best choice for Word forms, except in very specific cases.
Using the "legacy" formfields and
//key
Application.ActiveDocument.FormFields(1).Range.Fields(1).Code
//value
Application.ActiveDocument.FormFields(1).Result
Is the solution I came up with.
I've seen companies use the bookmarks, default values, status / help texts for different purposes as well. Not that I would recommend it, but maybe they are working around an issue I'm not aware of.
I feel like .range is a bit of a hack, but considering it's the range of only the form field, unless form fields or fields can have nested fields, it should be ok.

View Form Creation Code in Access VBA?

Is it possible to view the form creation code in Access VBA? I don't mean the event listener code that is viewable in the VBE from View>Code in the form's Design View. I mean the code that is used to create the components, and add them to the form. I would like to programatically set Form properties; doing this from the Properties dialog is quite slow (and annoying).
Yes, it's possible to create a form to design.
Vba include CreateControl Method (see MSDN Office-11 Control )
And you can add to this controls any event procedure like OnClick, OnFocus, etc. (see MSDN Office-11 Event
You can manipulate the width, height, etc.. properties as simple as me.control.width
I developed some time ago a form that could customized OnResize event to create different views depend of screen resolution and use all of this.
In theory you could get the form definition from the system table where it is stored (MSysObjects), but it isn't in a format that is practical to work against.
In theory you could avoid using the graphical designer to layout your form and create all the controls/set their properties dynamically in the form_load event. However, this wouldn't be much of a time-saver.
Assuming the gist of the question is whether there is an XML like declarative way to define a form layout similar to WPF. The answer is no.
All (?) the properties can be set through VBA for both the form and the controls.
Sub FormInDesignView()
Dim frm As Form
Dim ctl As Control
Set frm = Screen.ActiveForm
frm.Caption = "New"
For Each ctl In frm.Controls
ctl.Name = "txt" & ctl.Name
ctl.ForeColor = vbRed
Next
End Sub
No, it is not directly possible to do what you want. But if you insisted, you could use the undocumented Application.SaveAsText/LoadFromText commands and process the resulting text file.
Why you think this is a useful way to work in Access, I haven't a clue -- it's completely antithetical to the purpose and design of Access. Give up on your habits from other development tools and learn the Access way of doing things. You'll be a lot happier and productive in the long run.