In the Outline sample, we placed the code to read the data in the Form_Load event. In this sample we will use the OK button instead.
Open the dialog in the Visual C++ resource editor, then type CTRL-W (for Wizard). You will see a dialog that lets you add event handlers to each element on the form.
On the Object Ids list, select IDOK. On the Messages list, select BN_CLICKED. Now click the Add Function button, and then the Edit Code button.
This will open the code editor. You will see that the Wizard already added the function declaration for you. Now type the following code:
void COutlineCDlg::OnOK()
{
// TODO: Add extra validation here
// comment the following line to avoid closing the
// dialog when the user clicks OK:
//CDialog::OnOK();
// initialize variant to use as optional parameter
COleVariant varDefault;
V_VT(&varDefault) = VT_ERROR;
// suspend repainting to increase speed
m_fg.SetRedraw(FALSE);
// populate the control
AddNode("Win.ini");
AddNode("System.ini");
AddNode("vb.ini");
// expand outline, resize to fit, collapse outline
m_fg.Outline(-1);
COleVariant vCol((short)2, VT_I2);
m_fg.AutoSize(1, vCol, varDefault, varDefault);
m_fg.Outline(1);
// repainting is back on
m_fg.SetRedraw(TRUE);
}
The first thing to notice is that you should comment out the line that calls the default handler for this event (CDialog::OnOK()). The default handler closes the dialog when the user clicks OK, which is not what we want here.
Next, we declare a varDefault variable of type variant and initialize it with type VT_ERROR.
This is necessary because many of the methods in the VSFlexGrid control take optional parameters. In Visual Basic, optional means you don't have to supply them at all. In Visual C++, optional means you don't have to supply the value, but the parameter must still appear in the function calls. This is what the varDefault variable does: it is a parameter without a value. (You may prefer to modify the CvsFlexGrid wrapper classes and overload the methods to user friendlier parameter lists. We chose not to do it here to keep the example simple.)
The code then calls the AddNode function to populate the grid, just like the Visual Basic version of the program did. The AddNode function will be discussed later.
Finally, the code calls the AutoSize method, which takes three variant parameters. One of them holds the value 2 (the last column to be autosized) and the others use varDefault, which means the control will use default values.
Like before, the AddNode routine does most of the work. It reads an INI file and populates the control, creating nodes and branches according to the contents of the file. Here is the C++ version of the AddNode routine (remember to add its declaration to the OutlineCDlg.h file):
void COutlineCDlg::AddNode(LPSTR inifile)
{
long row;
// initialize variant to use as optional parameter
COleVariant varDefault;
V_VT(&varDefault) = VT_ERROR;
// create file node
m_fg.AddItem(inifile, varDefault);
row = m_fg.GetRows() - 1;
m_fg.SetIsSubtotal(row, TRUE);
m_fg.Select(row, 0, varDefault, varDefault);
m_fg.SetCellFontBold(TRUE);
// read ini file
CString fn = (CString)"c:\\windows\\" + (CString)inifile;
FILE* f = fopen(fn, "rt");
while (f && !feof(f)) {
char ln[201];
fgets(ln, 200, f);
// if this is a section, add section node
if (*ln == '[') {
char* p = strchr(ln, ']');
if (p) *p = 0;
m_fg.AddItem(ln + 1, varDefault);
row = m_fa.GetRows() - 1;
m_fg.SetIsSubtotal(row, TRUE);
m_fg.SetRowOutlineLevel(row, 1);
m_fg.Select(row, 0, varDefault, varDefault);
m_fg.SetCellFontBold(TRUE);
// if this is regular data, add branch
} else if (strchr(ln, '=')) {
char* p = strchr(ln, '=');
*p = 0;
CString str = (CString)"\t" + (CString)ln +
(CString)"\t" + (CString)(p + 1);
m_fg.AddItem(str.GetBuffer(0), varDefault);
}
}
if (f) fclose(f);
}
This routine is a line-by-line translation of the Visual Basic AddNode routine presented in the Outline Demo. It uses the MFC CString class to create some of the strings, and a few additional variants for parameters.
The routine starts by adding a row containing the name of the INI file being read. It marks the row as a subtotal using the SetIsSubtotal method so the control will recognize it as an outline node.
Next, the routine reads the INI file line by line. Section names are enclosed in square brackets. The code adds them to the control and marks them as subtotals the same way it marked the file name. The difference is that here the SetRowOutlineLevel method is used to indicate that this node is a child of the previous level-0 node (the one that contains the file name).
Finally, lines containing data are parsed into token and setting and then added to the control. They are not marked as outline nodes.