Hide Controls in MS Access Based on Value Field - vba

I am trying to hide some controls in a form in MS Access. The idea is that a linked table has a type of question such as OpenResponse or OptionBox. Given this input I want to switch the type of input the user can input. Here is a sample of what I have:
Private Sub QuestionType_AfterUpdate()
Dim QType As String
Set QType = Me.QuestionType.Value
Select Case QType
Case OpenResponse
Forms("Survey").Controls(AnswerField).Visible = True
Forms("Survey").Controls(OptionTitle).Visible = False
Forms("Survey").Controls(OptionFrame).Visible = False
Forms("Survey").Controls(Option69).Visible = False
Forms("Survey").Controls(Option70).Visible = False
Forms("Survey").Controls(Option71).Visible = False
Forms("Survey").Controls(Option72).Visible = False
Forms("Survey").Controls(Option73).Visible = False
Forms("Survey").Controls(Option74).Visible = False
Forms("Survey").Controls(Option75).Visible = False
Forms("Survey").Controls(Option76).Visible = False
Forms("Survey").Controls(Option77).Visible = False
Forms("Survey").Controls(Option78).Visible = False
Case OptionBox
Forms("Survey").Controls(AnswerField).Visible = False
Forms("Survey").Controls(OptionTitle).Visible = True
Forms("Survey").Controls(OptionFrame).Visible = True
Forms("Survey").Controls(Option69).Visible = True
Forms("Survey").Controls(Option70).Visible = True
Forms("Survey").Controls(Option71).Visible = True
Forms("Survey").Controls(Option72).Visible = True
Forms("Survey").Controls(Option73).Visible = True
Forms("Survey").Controls(Option74).Visible = True
Forms("Survey").Controls(Option75).Visible = True
Forms("Survey").Controls(Option76).Visible = True
Forms("Survey").Controls(Option77).Visible = True
Forms("Survey").Controls(Option78).Visible = True
End Select
End Sub

You're not thinking "out of the box", here. In this type of environment, thinking "inside the box" can ruin your day.
This is a perfect example of when to use a table-driven approach. The primary question here is; Can/Will the questions ever change? The probable answer is, Yes. In this case, I would do the something like this:
Create a table called Questions. In that table, list the questions (possibly in a Memo field, but a Text field may work), the question type, the control name and the value (True or False). Then, you can query the Questions table based on question type, and loop through the resulting dataset to set the Visible property of your controls. This way, you can always add more questions later if necessary. In fact, you might also add a Primary Key called QuestionID, and a True/False field called Active so you can go back and remove some of the questions without creating orphaned records, and query only questions marked as Active.
If I'm misunderstanding your purpose, let me know and I'll try to edit my answer accordingly.

Related

If combo box contains text like multiple criteria then disable text boxes below

I'd like to disable text boxes if the SponName combo box contains certain company names. I thought I could try a for loop for this, but I'm not sure if I created the right variables or used the for loop properly. Please help!
I've tried cobbling together the following code from the threads below but can't quite adapt it to my problem. I'm still learning VBA and am not great with declaring variables. There's no error message, but the text fields just won't disable after updating SponName.
VBA code for if like multiple criteria
Private Sub SponName_AfterUpdate()
Dim sponcontains As Variant
sponcontains = SponName.Text
Criteria = Array("Company1*", "Company2*", "Company3*", "Company24*")
For i = LBound(Criteria) To UBound(Criteria)
If InStr(sponcontains, Criteria(i)) > 0 Then
cps_manufsite_name.Enabled = False
cps_manufsite_city.Enabled = False
cps_manufsite_st.Enabled = False
cps_manufsite_ctry.Enabled = False
Else
cps_manufsite_name.Enabled = True
cps_manufsite_city.Enabled = True
cps_manufsite_st.Enabled = True
cps_manufsite_ctry.Enabled = True
End If
Next i
End Sub
Use Text property only when control still has focus. You need Value property which is default for data controls so don't have to reference. Explicitly declare all variables. Should have Option Explicit at top of all modules. Set the VBA editor > Tools > Options > Require Variable Declaration to automatically add to new modules - will have to type into existing. Use of * wildcard not appropriate with InStr() function - it's just another literal character.
Like this - default value for Boolean variable is False:
Option Compare Database
Option Explicit
___________________________________________________________________________________
Private Sub SponName_AfterUpdate()
Dim sponcontains As Variant, criteria As Variant, booE As Boolean, i As Integer
sponcontains = Me.SponName
criteria = Array("Company1", "Company2", "Company3", "Company24")
For i = LBound(criteria) To UBound(criteria)
If InStr(sponcontains, criteria(i)) > 0 Then
booE = True
Exit For
End If
Next
cps_manufsite_name.Enabled = Not booE
cps_manufsite_city.Enabled = Not booE
cps_manufsite_st.Enabled = Not booE
cps_manufsite_ctry.Enabled = Not booE
End Sub
But your solution without loop is just as valid and most likely shorter. Again, use Boolean variable to set Enabled state instead of duplicating.
booE = InStr("Company1,Company2,Company3,Company24", Me.SponName) > 0
Consider what would happen if you had to modify this list. Would have to modify code and distribute new db version to users. Alternatively, use a table with an attribute (can be a yes/no field) for company status. Code can do a lookup to table. Better to use company ID value to search. Your combobox should have that as a column in its RowSource and usually that would be the combobox's value.
booE = DLookup("Status", "Companies", "CompanyID = " & Me.SponName)
Use of Conditional Formatting can often avoid VBA altogether.

How can I skip selecting a slicer item if is doesn't exist in my reference data (Pivot Table)

I am trying to update/filter a pivot table and select the following values. (See example code)
With ActiveWorkbook.SlicerCaches("Slicer_State")
.SlicerItems("Analysis").Selected = True
.SlicerItems("Development").Selected = True
.SlicerItems("Analysis_Complete").Selected = True
.SlicerItems("Submitted").Selected = True
.SlicerItems("(blank)").Selected = True
.SlicerItems("Closed").Selected = False
.SlicerItems("Rejected").Selected = False
.SlicerItems("Resolved").Selected = False
.SlicerItems("Test").Selected = False
.SlicerItems("Verified").Selected = False
End With
However, sometimes the item "submitted" won't exist in the source data and returns invalid argument errors.
If the data doesn't exist, how can I skip over the line?
Thank you

How can I improve this iterative function?

I am trying to simplify this function which is similar from
Function Snake_makestep()
maincar.Location = locate(xpos, ypos)
car0.Location = locate(posx(0), posy(0))
car1.Location = locate(posx(1), posy(1))
If car2.Visible = True Then
car2.Location = locate(posx(2), posy(2))
End If
If car3.Visible = True Then
car3.Location = locate(posx(3), posy(3))
End If
If car4.Visible = True Then
car4.Location = locate(posx(4), posy(4))
End If
To
If car30.Visible = True Then
car30.Location = locate(posx(30), posy(30))
End If
End Function
I'm not sure If I can/how to use Controls.Find solution within this function. Any help?
To answer the question as asked:
For i = 2 To 30
Dim car = Controls("car" & i)
If car.Visible Then
car.Location = locate(posx(i), posy(i))
End If
Next
Visible and Location are both members of the Control class so it doesn't matter what type of control those car variables are.
Note that this assumes that all controls are on the form itself. If they are in a different parent container, you'd need to use the Controls collection of that container.
Also, I have started i at 2 there, so you'd still need the explicit code for car0 and car1. If they are always visible then you could start the loop at 0 and it would still work, saving you those two lines of code as well.

How to hide columns based on name in Excel 2010?

I am trying to hide columns based on name using VBA inside Excel 2010. Each of my columns have a product version and some results below it. The product version does repeat throughout the spreadsheet since I have it categorized by OS. Thus, I'm hiding multiple columns based on selection, like a filter would do. If I could hide based on the name and not the column letter (A,B,C,...), then adding columns in between in the future would prevent more code changes on the location of those columns.
What I'm currently doing right now is fixed to the column letter. This limits me in the sense that I cannot add columns in between without having to change the code (column letter). Example:
`If productver_2dot5.Value = True Then
Columns("E").Hidden = False
Columns("M").Hidden = False
Columns("AC").Hidden = False
Columns("AT").Hidden = False
Columns("BD").Hidden = False
Columns("BR").Hidden = False
Else
Columns("E").Hidden = True
Columns("M").Hidden = True
Columns("AC").Hidden = True
Columns("AT").Hidden = True
Columns("BD").Hidden = True
Columns("BR").Hidden = True
End If`
What I would like to do is to hide any columns that contains the name 'Product Ver 2" (example) in one of its cells.
Sub HideBlahs()
Dim col As Range
For Each col In ActiveSheet.UsedRange.Columns
If Application.CountIf(col, "blah") > 0 Then
col.EntireColumn.Hidden = True
End If
Next col
End Sub
FYI your posted code reduces to:
Range("E1,M1,AC1,AT1,BD1,BR1").EntireColumn.Hidden = Not productver_2dot5.Value

DataGridView column order does not seem to work

I have a DataGridView bound to a list of business objects:
Dim template As New IncidentTemplate
Dim temps As List(Of IncidentTemplate) = template.LoadAll
Dim bs As New BindingSource
If Not temps Is Nothing Then
bs.DataSource = temps
Me.dgvTemplates.DataSource = bs
End If
I then add an unbound button column and make some of the bound columns invisible:
Dim BtnCol As New DataGridViewButtonColumn
With BtnCol
.Name = "Edit"
.Text = "Edit"
.HeaderText = String.Empty
.ToolTipText = "Edit this Template"
.UseColumnTextForButtonValue = True
End With
.Columns.Add(BtnCol)
BtnCol = Nothing
For Each col As DataGridViewColumn In Me.dgvTemplates.Columns
Select Case col.Name
Case "Name"
col.DisplayIndex = 0
col.FillWeight = 100
col.Visible = True
Case "Description"
col.DisplayIndex = 1
col.FillWeight = 100
col.Visible = True
Case "Created"
col.DisplayIndex = 3
col.HeaderText = "Created On"
col.DefaultCellStyle.Format = "d"
col.FillWeight = 75
col.Visible = True
Case "CreatedBy"
col.DisplayIndex = 2
col.HeaderText = "Created By"
col.FillWeight = 75
col.Visible = True
Case "Edit"
col.DisplayIndex = 4
col.HeaderText = ""
col.FillWeight = 30
col.Visible = True
Case Else
col.Visible = False
End Select
Next
This seems to work reasonably well except no matter what I do the button column (Edit) always displays in the middle of the other columns instead of at the end. I've tried both DGV.Columns.Add and DGV.Columns.Insert as well as setting the DisplayIndex of the column (this works for all other columns) but I am unable to make the button column display in the correct location. I've also tried adding the button column both before and after setting the rest of the columns but this seems to make no difference Can anyone suggest what I am doing wrong? It's driving me crazy....
I stumbled on your post while looking to solve a similar problem. I finally tracked it down by doing as you mention (using the DisplayIndex property) and setting the AutoGenerateColumns property of the DataGridView to false. This property is not visible in the designer, so I just added it to the constructor for my form. Be sure to do this before setting the data source for your grid.
Hope this helps...
The AutoCreateColumn is the problem. The following article gives an example for how to fix it.
From DataDridView DisplayOrder Not Working
When setting the column’s DisplayIndex in a data grid view, some columns were out of order. To fix the issue, I had to set AutoGenerateColumns to true before setting the data source, and to FALSE after.
For Example:
dgvReservedStalls.AutoGenerateColumns = True
dgvReservedStalls.DataSource = clsReservedStalls.LoadDataTable()
dgvReservedStalls.AutoGenerateColumns = False
Same problem here, and after searching for a while, I found out that by setting the DisplayIndexes in Ascending order made it for me.
It's counter-intuitive, because it's a number, but I still had to set them in order.
This works:
With customersDataGridView
.Columns("ContactName").DisplayIndex = 0
.Columns("ContactTitle").DisplayIndex = 1
.Columns("City").DisplayIndex = 2
.Columns("Country").DisplayIndex = 3
.Columns("CompanyName").DisplayIndex = 4
End With
While this did not:
With customersDataGridView
.Columns("ContactName").DisplayIndex = 0
.Columns("CompanyName").DisplayIndex = 4
.Columns("Country").DisplayIndex = 3
.Columns("ContactTitle").DisplayIndex = 1
.Columns("City").DisplayIndex = 2
End With
I tried the above solutions without success. Then I found this article: It made it all better.
http://msdn.microsoft.com/en-us/library/vstudio/wkfe535h(v=vs.100).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1