2

Programming in Windows with Visual Studio 2010 C++ and MFC. My question is about how best to store, update, and pass around program settings or options.

I have a simple main GUI window/frame/dialog. On that main window I have an options button. When I click the options button I create an Options Dialog.

Inside the options dialog I get a reference to the "application" (an MFC concept, globally available) and grab a reference to my custom settings class (an instance is stored in the application class. From there, I can populate my options dialog and save my options back.

Perhaps I should be using Dependency injection to inject the settings into my option dialog? Or perhaps I should not even be accessing the settings from within the dialog class? MaybeI should expose the settings via set/get on the dialog class?

Also, now I want to show some options right there on the main window, while still keeping them settable on the original options dialog. So now I'm wondering what a good design is for this. If I set an option on my options dialog I want it to update the options displayed on the main window.

I guess this is a good spot for the Observer pattern but I'm trying to figure out how to piece it altogether in a MFC context (which as best as I can tell is basically pretty much the same as any other GUI toolkit in any other language, so if you're not into MFC I still want your comments)

  1. How should I be passing my settings around?
  2. How do I keep the GUI display of the settings in sync with each other? Such that after clicking OK on the options dialog box, the options directly shown on the main window are updated?

3 Answers 3

5

Multiple places to change, all places need to know the current value...sounds like the Observer Pattern.

a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is mainly used to implement distributed event handling systems. The Observer pattern is also a key part in the familiar Model View Controller (MVC) architectural pattern...

1
  • I would also go for the observer pattern. Commented Jul 27, 2011 at 6:39
1

Ok I have solved this problem using Dependency Injection and the Observer pattern.

To pass settings around

I have a single Settings object that I instantiate in my MFC app object, MyApp (a subclass of CWinApp). Previously I added a getter function call GetSettings() on my MyApp. This allowed me to get the settings from any window class because there is member method ((MyApp*)AfxGetApp())->GetSettings(). This however suffers the problems of global state and making it non-obvious that a class utilizes the settings object. Now instead I dependency inject my settings object into my CDialog class via the constructor. Then I dependency inject it into my OptionsDialog class. This takes care of passing the settings around.

To keep GUI display of settings in sync

I used the Observer pattern. I created two abstract classes Subject and Observer as:

#pragma once
#include <list>

class Observer;

class Subject
{
public:
    virtual ~Subject()  {}
    virtual void AttachObserver(Observer *observer);
    virtual void DetachObserver(Observer *observer);
    virtual void NotifyObservers();

protected:
    Subject() {}

private:
    std::list<Observer *> observers_;
};

and:

#pragma once

class Subject;

class Observer
{
public:
    virtual ~Observer() {}
    virtual void Update(Subject *subject) = 0;

protected:
    Observer() {}

};

Then I made my Settings class derive from Subject and called NotifyObservers() from my settings' class's Save() method.

Finally I made my OptionDialogPanel on my main window derive from Observer. In my OnInitDialog() I call settings_->AttachObserver(this) to register my option panel as a listener of my settings object. Then I implemented the Update method to grab fresh settings from my settings object and put them in into the text boxes:

void OptionsDialogPanel::Update(Subject *subject)
{
    if(subject == settings_)
    {
        UpdateToCurrentSettings();
    }
}
0

Sounds like a job for the Monostate Pattern.

A monostate class contains only private static data members and public non-static member functions to access these members. This way, all objects of this class share the same state.

Read the article and see if it's what you're looking for.

5
  • Seems like a glorified singleton...
    – TheLQ
    Commented Jul 27, 2011 at 5:30
  • I'm unlikely to go for a singleton-style pattern. It's true that my app will probably have only one instance of a settings class but that will be because I only instantiate one instance.
    – User
    Commented Jul 27, 2011 at 5:55
  • Singleton and monostate both enforce singularity, but have very different mechanisms. A singleton enforces a single instance of an object, while all instances of a monostate behave like one object. So when you change a setting in one instance of a monostate, the new value is instantly available in another instance of that monostate. They settings are in sync because they are effectively the same object. Robert Martin compares them in some detail.
    – Gnawme
    Commented Jul 27, 2011 at 6:16
  • Ah I see how it's different although it's a kind of global state. Which means it's non-obvious to the caller of a method that the method depends on a settings object (although that is the situation I have now). I have to ponder that more. It solves the first problem of how to pass settings around but it doesn't solve the problem of how to keep the settings in sync. I'm not so much referring to keeping the settings objects in sync as physically keeping the GUI display in sync.
    – User
    Commented Jul 27, 2011 at 15:18
  • Not sure how you'd do this in MFC, but I once wrote a Qt-based settings monostate. Whenever someone changed a setting, the monostate sent a Qt signal. Any GUI element that had a slot connected to that signal got updated with the new setting.
    – Gnawme
    Commented Jul 27, 2011 at 19:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.