I have to design a way to know what controls have been changed on our Settings Dialog. This dialog has every type of control you can think of on it.
The reason for it, is the dialog has like 100 controls and when we hit save, it tries saving all settings to the registry, no matter if they have changed or not. It also will restart all of our threads, even if it doesn't need too.
Does anyone have an idea of what I could possibly look into doing?
Yes, not knowing our system makes it harder to explain.
What I mean, is some setting in our settings dialog, if changed will need to restart some of our threads in our product. Some settings do not affect these threads, so they do not need to be restarted.
Currently, if a user goes into the server settings for our product and make a minor change then hits 'Save'. It saves all of the settings, and restarts all of the server threads for our product.
One way is to use the .Tag property of the controls.
When you first load the data, store the values of each control to its own .Tag property too. When the save button is pressed, you can compare the value to the .Tag, and only save that item it has changed.
That's an excellent suggest! The one thing I did not explain, is that one control can be used for more than one item.
Maybe the best way to explain this, is by drawing an image. On the left side of our settings dialog, we have a tree control with a list of items. When a user selects an items, the controls on the right side populate with the items details. Such as its name.
The user can go in and change all the items names, and then save at the end.
So the tag field wouldn't work in this instance, since the value for the control will change when the user selects different items.
I have a feeling this way to confusing to explain.
That's an excellent suggest! The one thing I did not explain, is that one control can be used for more than one item.
Maybe the best way to explain this, is by drawing an image. On the left side of our settings dialog, we have a tree control with a list of items. When a user selects an items, the controls on the right side populate with the items details. Such as its name.
The user can go in and change all the items names, and then save at the end.
So the tag field wouldn't work in this instance, since the value for the control will change when the user selects different items.
Maybe then you can store the data in a manner like i listed in post #5 with all the default values. Then you can use:
vb Code:
CallByName Me.Controls(curObj), curProp, vbGet
To check to see if the values are equal.
your ratings show me that my time means something to you. please show it.
put [HIGHLIGHT="vb"][/HIGHLIGHT] around code
From your explanation it sounds like you must be storing somewhere (perhaps an array?) what the current values of each item are - so just store a duplicate version which contains the original version (or a boolean to say if it has changed), and check that before saving.
This is how it currently works for a simple field like a 'Name'.
All the information is stored in an array, when it is saving we convert the array, to a string. ie.
arrNames() = {"T1","T2","T3"} to sNames = "T1,T2,T3"
Then we save this string into our 'Names' registry entry.
I am not allowed to change how the string is saved in the registry because it would cause our end users to lose their current settings.
This is the solution I have come up with. Being a bit of a kludge Lets talk about one control type. The TextBox as the Names field.
- On the LostFocus for the TextBox, I will compare the current Reg data with the new text value.
- If it has changed, I will save the control id, and index of the item into a new struct called, 'HasChanged'. Which is a list of changed items/fields.
- When the user hits save, I loop through all 'HasChanged' to write the new values to the Reg, and I check to see what threads, if any need to be restarted. I find this out from the Tag property in the control. I am using the Tag to store a bitwise flag that tells me, if this control affects any threads in our product when changed.
For instance, the 'Name' field can change, and we do not need to restart any threads. But if a different field changes. We might have to restart some of them.
I have a suggestion with some "cool" factor in it: what about listening GotFocus and LostFocus event of each of your controls and only checking there whether a property of a control has changed or not?
Code:
Option Explicit
Private WithEvents Focus As FocusEvents
Private m_Changed As Collection
Private m_OriginalText As String
Private m_OriginalValue As Variant
Private Sub Command1_Click()
Dim lngA As Long, strArray() As String
' display the changes that have been made
If m_Changed.Count Then
ReDim strArray(m_Changed.Count - 1)
For lngA = 1 To m_Changed.Count
strArray(lngA - 1) = m_Changed(lngA)
Next lngA
MsgBox Join(strArray, vbNewLine), vbInformation, "Changed!"
End If
End Sub
Private Sub Focus_GotFocus(Control As Control)
If TypeOf Control Is TextBox Then
m_OriginalText = Control.Text
Else
m_OriginalValue = Control.Value
End If
End Sub
Private Sub Focus_LostFocus(Control As Control)
' if value of a control has changed add it in to the collection of changed elements
If TypeOf Control Is TextBox Then
If m_OriginalText <> Control.Text Then
On Error Resume Next
m_Changed.Add Control.Name, Control.Name
On Error GoTo 0
End If
Else
If m_OriginalValue <> Control.Value Then
On Error Resume Next
m_Changed.Add Control.Name, Control.Name
On Error GoTo 0
End If
End If
End Sub
Private Sub Form_Initialize()
Dim Control As Control
' watch for controls that have properties Text and Value
Set Focus = New FocusEvents
For Each Control In Me.Controls
' see if it has Text property
If Focus.Add(Control, "Text") = 0 Then
' it did not have, try Value
Focus.Add Control, "Value"
End If
Next Control
' initialize collection that knows which elements have changed
Set m_Changed = New Collection
End Sub
Private Sub Form_Terminate()
Set Focus = Nothing
End Sub
The required FocusEvent.cls and FocusEvents.cls are attached (as is the whole demo project). Afaik using this would require minimal code changes to what you currently have.