Exploring the TimeCheck Application (Part 14)

Today we’ll wrap up the discussion about frmConfigure. If you remember from the Exploring the TimeCheck Application (Part 13) post, we’ve finished up the major configuration controls, but there are three areas that you still need to know about:

 

  • Constructors
  • Form Loading
  • Form Closing


All three of these elements appear in this post. Let’s begin with the constructors. The application can either create frmConfigure by defining a blank form or by passing information needed to populate the form with data. The following code shows both of the constructors needed to fulfill these tasks:

// Create a variable to hold the user data.
public UserSettings UserData;
 
// Create a variable to hold the group data.
public GroupSettings GroupData;
 
public frmConfigure()
{
   // Perform the default configuration.
   InitializeComponent();
 
   // Check for the user data.
   if (UserData == null)
 
      // Initialize the user data.
      UserData = new UserSettings();
 
   // Check for the group data.
   if (GroupData == null)
 
      // Initialize the group data.
      GroupData = new GroupSettings();
 
   // Fill the administrator provided task and project lists.
   FillLists();
}
 
public frmConfigure(UserSettings UserData, GroupSettings GroupData)
{
   // Perform the default configuration.
   InitializeComponent();
 
   // Check for the user data.
   if (UserData == null)
 
      // Initialize the user data.
      this.UserData = new UserSettings();
 
   // Otherwise, use the supplied settings.
   else
      this.UserData = UserData;
 
   // Check for the group data.
   if (GroupData == null)
 
      // Initialize the group data.
      this.GroupData = new GroupSettings();
 
   // Otherwise, use the supplied settings.
   else
      this.GroupData = GroupData;
 
   // Fill the administrator provided task and project lists.
   FillLists();
}

In both cases, the constructor must create the UserData and GroupData local variables that you’ve seen used for so many purposes in the application. When the caller supplies the required data, frmConfigure uses it. Otherwise, frmConfigure creates new, blank variables that the application can fill with data. No matter how the data are supplied, the constructors call FillLists() to fill the user interface with data so that the user can see the settings (if any).

The form isn’t completely populated with data, nor is it stable at this point. The application raises the FormLoad() event at some point, which calls this event handler:

private void frmConfigure_Load(object sender, EventArgs e)
{
   // When there is user data to use, display it.
   if (UserData != null)
   {
      // Configure the form fields.
      cbProjectName.SelectedText = UserData.DefaultProject;
      cbWorkType.SelectedText = UserData.DefaultTask;
      txtNetLocation.Text = UserData.NetworkPath;
      chkCustomProject.Checked = GroupData.CustomProject;
      chkCustomWork.Checked = GroupData.CustomTask;
   }
}

At this point, the form is ready for the user to interact with. We’ll be looking at some additional code later to handle the requirements for working with administrators, versus standard users. For now, just consider that the form is ready to use. The user does whatever he/she needs to do, and then clicks either Cancel or OK to close the form. Now, some actions automatically save data because you simply don’t want to take a chance that the user will close the form in some other way and lose settings. However, it’s important to save the data one last time when the user clicks OK to ensure absolutely every change appears on disk. That’s the purpose of the two event handlers shown here.

private void btnCancel_Click(object sender, EventArgs e)
{
   // Close this dialog box.
   Close();
}
 
private void btnOK_Click(object sender, EventArgs e)
{
   // Save the changes to the user data.
   if (cbProjectName.SelectedText != "")
      UserData.DefaultProject = cbProjectName.SelectedText;
   if (cbWorkType.SelectedText != "")
      UserData.DefaultTask = cbWorkType.SelectedText;
   UserData.NetworkPath = txtNetLocation.Text;
   UserSettings.SetUserSettings(UserData);
 
   // Save the changes to the group data.
   GroupData.CustomProject = chkCustomProject.Checked;
   GroupData.CustomTask = chkCustomWork.Checked;
   GroupData.ProjectList.Clear();
   foreach (String Item in lstStandardProjects.Items)
      GroupData.ProjectList.Add(new Project(Item));
   GroupData.TaskList.Clear();
   foreach (String Item in lstStandardTasks.Items)
      GroupData.TaskList.Add(new Task(Item));
   GroupSettings.SaveSettings(GroupData);
 
   // Close the dialog box.
   Close();
}

As you can see, clicking Cancel simply closes the form. However, when you click OK, the application saves the data as it appears on screen. This is important because it’s possible that things could have gotten out of sync as the user interacted with the form. The result of the btnOK_Click() event handler is that the data on disk appears precisely the same as the user saw it on screen.

At this point, you have a basic frmConfigure completed. The next post will focus on the code used to make frmMain work. In the meantime, let me know if you have any questions about any of the frmConfigure code at John@JohnMuellerBooks.com.

 

Using CodeBlocks 10.05 – Part 5

This post begins with the code found in Book IV Chapter 3 (found in \Author\BookIV\Chapter03) of my book,  C++ All-In-One Desk Reference For Dummies. I’ve been testing my code for use with CodeBlocks 10.05 continues. I introduced this new version in Using CodeBlocks 10.05 – Part 1, where I discussed the general look of the new version.

The example on page 456 (example Constructor04) is supposed to fail. It’s an example of what happens when you add a specific constructor to a class without also defining a default constructor. CodeBlocks 10.05 fails in the same way that its predecessor does. However, the order of the candidates may differthe Simple::Simple(int) version may appear first. I’ve pointed out a few other error message changes in other posts (you can see the entire list of posts for this book in the Category Archive for C++ All-in-One for Dummies).

Otherwise, all of the other examples in Book IV Chapter 3 should work as described in the book. Since there was little to talk about in Book IV Chapter 3, let’s also discuss Book IV Chapter 4.

The example that begins on page 482 (example OverridingDerived, found in \Author\BookIV\Chapter04) of the book compiles with three warning messages in CodeBlocks 10.05 as shown here:

 

C:\Author\BookIV\Chapter04\OverridingDerived\main.cpp: In constructor ‘Printer::Printer(std::string, Printer::PrinterType, int, int)’:

C:\Author\BookIV\Chapter04\OverridingDerived\main.cpp:19: warning: ‘Printer::Type’ will be initialized after

C:\Author\BookIV\Chapter04\OverridingDerived\main.cpp:22: warning:   base ‘Peripheral’

C:\Author\BookIV\Chapter04\OverridingDerived\main.cpp:20: warning:   when initialized here

Linking console executable: bin\Debug\OverridingDerived.exe
Output size is 1000.61 KB
Process terminated with status 0 (0 minutes, 2 seconds)
0 errors, 3 warnings

CodeBlocks 10.05 performs some additional checks that CodeBlocks 8.02 didn’t, so it will catch problems like the one shown in this listing. The example still works as described in the book. To get rid of the warning messages, you need to change the order of inheritance for the Printer class as shown here:

class Printer : public Peripheral {
public:
    enum PrinterType {laser, inkjet};
    PrinterType Type;
    Printer(string aname, PrinterType atype, int aprice,
        int aserial) :
        Peripheral(aname, aprice, aserial), Type(atype) {}
};

The idea is to ensure initialization takes place in the correct order. Even though the initialization order doesn’t make a difference in this example, it could in code you write. Notice that Type(atype) now appears after Peripheral(aname, aprice, aserial), which provides the correct initialization order.

In the next post I’ll start with Book IV Chapter 5. In the meantime, let me know if you have any questions about the CodeBlocks 10.05 updates for this book at John@JohnMuellerBooks.com.