Programming Assignment 3

Date Posted: November 5
Final Project Due: Tuesday, December 3
Final Project DDD: Tuesday, December 10, 3:00 P.M.


Programming Assignment 3

Background Information
  Programming assignment 3 adds some new functionality to the Genetics Simulator written for programming assignment 2, but the primary addition is that it adds a Graphical User Interface (GUI). The exact layout of the GUI is left up to the programmer. The image below shows the layout of the GUI in the demonstration program. All functionality represented by the demonstration GUI must be implemented.



Your Assignment
  You are to modify programming assignment 2 to add a Graphical User Interface to the Genetics Simulation.

All requirements from programming assignments 1 and 2 are to be followed unless modified in the following list of requirements for this simulation.

  1. The GUI shall provide a text field where the user can enter the name of the data file to be used. There will also be two buttons. One button will cause the name of the data file to be read from the text field and passed to the data parser to initialize the simulation data. The other button will exit the application.
  2. There must be appropriate display widgets included in the GUI to display the following information:
    1. The genus, species and common name of the test organism.
    2. The number of chromosomes included in the simulation.
    3. A description of each gene including its name, dominant and recessive trait, letter used to represent each, and the chromosome on which it resides
    4. The genotype of each of the parent organisms.
    5. The result of running the experiment
    6. A text field where the user can enter the number of offspring to generate.
    7. A button to run the experiment.
    8. A text field where the user can enter the name of a text file into which to save the results of a run and a button to initiate saving to the selected text file.
  3. The user may run as many different experiments as desired, i.e. each time the "run experiment" button is pressed a genetic cross shall be calculated using the currently available data.
Deliverables
  These products as specified below shall be delivered electronically via e-mail to the instructor.

Since Programming Assignment 3 is for extra credit no documentation is required and no extra credit will be given for documentation. This assignment is worth 15 extra credit points added to your final total. Note: the application must meet the basic requirements to receive any extra credit. There will be no credit given for a GUI that is non-functional.

Final Project -- The entire software project (compatible with Microsoft Visual Studio 2012 or 2015) shall be compressed into a zip file and submitted for instructor approval NLT Tuesday, December 3.
Just turning in your source files is not acceptable.




To download a sample executable as well as a data file and a parser for the data file click here.



Hints
This information should guide you through creating the project and setting up things like the timer.

Remember that some versions of Visual Studio cannot work on a project stored on your thumb drive. You will have to create the project on the hard drive, work on it there, and then copy it onto your thumb drive for safe keeping.

Creating the Project and Adding the Genetics Sim Classes
  1. Create this as a MFC application program.
  2. In the MFC Application Wizard use the following settings:
    1. Application type:
            Dialog based
            Uncheck "Use Unicode libraries"
            Check "MFC standard"
            Check "Use MFC in a shared DLL"
    2. User Interface Features:
            Accept all default settings
    3. Advanced Features:
            Uncheck "ActiveX controls"
            Accept all other defaults
    4. Generated Classes:
            Accept all defaults unless you want to change the name of the main classes.
  3. Copy all of the class files from programming assignment 2 into the program 3 folder, except for the file containing main().
  4. Add all the classes to the project
    1. Right click the "Header Files" folder in the Prog 3 project (in the Solution Explorer pane of Visual Studio)
    2. Select "Add" and from the sub-menu select "Existing Item".
    3. In the dialog box that appears select all of the .h files you just copied into the project. Make sure you do not select any .h files that are already part of the project.
    4. Repeat for the "Source Files" directory selecting all of the .cpp files you copied from program 2.
  5. Compile the project. Expect to get a multitude of errors. Most, if not all of these will be "unexpected end of file while looking for precompiled headers". To fix this do the following:
    1. Double click a line in the list of errors in the Output pane to display the file where that error is found.
    2. At the top of that source file add the line: #include "stdafx.h". Put this before any other include.
  6. Recompile the project. This should give you a successful compile, but you will see a lot of warnings everywhere you used any of the standard Kernigan and Ritchie string functions (strcpy, strcmp, strlen, etc.). Ignore these warnings.
Editing the Dialog Resource
  1. Open the IDD_programName_DIALOG dialog resource in the resource editor.
  2. Delete the Cancel button.
  3. Delete the static text that appears in the middle of the dialog box.
  4. Resize the dialog to make it large enough to draw the Genetics Sim. This doesn't have to be exact as you can programmatically resize the window before it is displayed. See the "Resizing" hint below.
  5. Move the OK button to its new location and change the caption to "End Simulation".
  6. Add other widgets as needed so that all required data is displayed.
Resizing the Window Programmatically
You can resize the window dynamically while the program is running with the following function call which must be in programNameDlg.cpp. A good place to do this is in the OnInitDialog() function. Which, by the way is also a good place to instantiate the Genetics Sim object, read and parse the data file, etc.

      this->SetWindowPos(NULL, xPos, yPos, width, height, 0);

Where:
      xPos = On screen X coordinate of the upper left corner of the dialog.
      yPos = On screen Y coordinate of the upper left corner of the dialog.
      width = Width in pixels of the dialog.
      height = Height in pixels of the dialog.

Buttons, comboboxes, text fields, etc. can also be moved using the variables defined for them.

Getting/Setting text in an Edit Control (text box)
The following code will copy the text in a GUI Edit Control into the defined character array. Assume that m_DataFileName is a variable defined for the edit control.

		char datafile[64];
		m_DataFileName.GetWindowText(datafile, 63);

The following code will set the text in a GUI Edit Control using the defined character array. Assume that m_DataFileName is a variable defined for the edit control.

		m_DataFileName.SetWindowText(datafile);
Run Simulation Event Handlers
The Event Handler function (called OnBnClickedRunSim in the demo) is where you get name of the data file from the dialog widgets. Below is the code for the demo function. Note: m_NumOffspringTF was the variable assigned to the text field object holding the number of offspring.

	void CProg3Dlg::OnBnClickedRunSim()
	{
		char line[32];
		m_NumOffspringTF.GetWindowText(line, 31);
		int numOffspring = atoi(line);
		if(numOffspring <= 0)
		{
			MessageBoxA("You must enter the number of offspring (1-1000).", 
				"Invalid Offspring Count", MB_OK | MB_ICONWARNING);
			return;
		}
		m_TheSim = MendelianSim::getInstance();
		m_TheSim->generateOffspring(numOffspring);
		// Display the results in the list box
		m_TheSim->printResults(&m_ExpResultsListBox);
	}
Below is the code for the demo function handling button clicks on the initialize simuation button.

YOU WILL NOT BE ABLE TO JUST COPY AND PASTE THIS CODE INTO YOUR PROGRAM AND HAVE IT WORK CORRECTLY. YOU MUST STUDY THE CODE TO SEE WHAT IT IS DOING AND THEN ADAPT IT TO WORK IN YOUR PROGRAM.

	//-------------------------------------------------------------
	// Handle clicks on the Initialize Simulation button
	//-------------------------------------------------------------
	void CProg3Dlg::OnBnClickedButton1()
	{
		char fileName[64]; // Data file name
		char line[64];
		int count;
		Organism *org;
		MasterGene *mGene;
		count = 1;
		vector *gVec;
		char allele1, allele2;
	
		// Get name of the data file
		m_DataFileTF.GetWindowText(fileName, 63);
		// Instantiate the data parser
		m_DataParser = GeneticsSimDataParser::getInstance();
		// Give the data parser the name of the data file and initialize the data
		if(!m_DataParser->initDataFile(fileName))
		{
			MessageBoxA("Failed to open data file.  Application terminating.", 
				"Data File Failure", MB_OK | MB_ICONERROR);
			exit(0);
		}
		// Create the simulation and create the organisms
		m_TheSim = MendelianSim::getInstance();
		m_TheSim->initSim();
	
		//----------------------------------------
		// Get the data and write it to the GUI
		//----------------------------------------
		// Set genius-species name
		m_GenSpecNameTF.SetWindowText(m_DataParser->getScientificName());
		// Set common name
		m_CommonNameTF.SetWindowTextA(m_DataParser->getCommonName());
		// Set chromosome count
		sprintf(line, "%d", m_DataParser->getChromosomeCount());
		m_NumChromosomesTF.SetWindowTextA(line);
		// List gene/chromosome data 
		m_GeneDataListBox.ResetContent();
		org = m_TheSim->getParent1(); // Get a parent
		vector *chVec = org->getChromosomes(); // Get the vector of chromosomes
		for(vector::iterator cItr = chVec->begin(); cItr != chVec->end(); cItr++)
		{
			// Add a chrosoome number
			sprintf(line, "Chromosome %d", count);
			count++;
			m_GeneDataListBox.AddString(line);
			gVec = (*cItr)->getGeneVector();
			// List all the genes in this chromosome
			for(vector::iterator gItr = gVec->begin(); gItr != gVec->end(); gItr++)
			{
				mGene = (*gItr)->getMasterGene();
				sprintf(line, "    Trait Name: %s", mGene->getTraitName());
				m_GeneDataListBox.AddString(line);
				sprintf(line, "        Dominant Name: %s (%c)", mGene->getDominantName(),
					mGene->getDominantChar());
				m_GeneDataListBox.AddString(line);
				sprintf(line, "        Recessive Name: %s (%c)", mGene->getRecessiveName(),
					mGene->getRecessiveChar());
				m_GeneDataListBox.AddString(line);
				sprintf(line, "        Chance of crossover: %.2f", mGene->getCrossOverChance());
				m_GeneDataListBox.AddString(line);
			}
		} // End for all chromosomes
		// List parent 1 data (already have org pointing to it)
		m_Parent1ListBox.ResetContent();
		org = m_TheSim->getParent1(); 
		chVec = org->getChromosomes(); // Get the vector of chromosomes
		for(vector::iterator cItr = chVec->begin(); cItr != chVec->end(); cItr++)
		{
			gVec = (*cItr)->getGeneVector();
			// List all the genes in this chromosome
			for(vector::iterator gItr = gVec->begin(); gItr != gVec->end(); gItr++)
			{
				allele1 = (*gItr)->getStrand1Allele();
				allele2 = (*gItr)->getStrand2Allele();
				mGene = (*gItr)->getMasterGene();
				if(allele1 == allele2) // Its homozygous
				{
					if(isupper(allele1)) // Its dominant
					{
						sprintf(line, "%c%c - Homozygous Dominant - %s = %s",
							allele1, allele2, mGene->getTraitName(), mGene->getDominantName());
						m_Parent1ListBox.AddString(line);
					}
					else // Its recessive
					{
						sprintf(line, "%c%c - Homozygous Recessive - %s = %s",
							allele1, allele2, mGene->getTraitName(), mGene->getRecessiveName());
						m_Parent1ListBox.AddString(line);
					}
				}
				else // Its heterozygous
				{
					if(isupper(allele1)) // Allele1 is the upper case letter
					{
						sprintf(line, "%c%c - Heterozygous Dominant - %s = %s",
							allele1, allele2, mGene->getTraitName(), mGene->getDominantName());
						m_Parent1ListBox.AddString(line);
					}
					else // Allele2 is the upper case letter
					{
						sprintf(line, "%c%c - Heterozygous Dominant - %s = %s",
							allele2, allele1, mGene->getTraitName(), mGene->getDominantName());
						m_Parent1ListBox.AddString(line);
					}
				}
			}
		}
		// List parent 2 data (already have org pointing to it)
		m_Parent2ListBox.ResetContent();
		org = m_TheSim->getParent2(); 
		chVec = org->getChromosomes(); // Get the vector of chromosomes
		for(vector::iterator cItr = chVec->begin(); cItr != chVec->end(); cItr++)
		{
			gVec = (*cItr)->getGeneVector();
			// List all the genes in this chromosome
			for(vector::iterator gItr = gVec->begin(); gItr != gVec->end(); gItr++)
			{
				allele1 = (*gItr)->getStrand1Allele();
				allele2 = (*gItr)->getStrand2Allele();
				mGene = (*gItr)->getMasterGene();
				if(allele1 == allele2) // Its homozygous
				{
					if(isupper(allele1)) // Its dominant
					{
						sprintf(line, "%c%c - Homozygous Dominant - %s = %s",
							allele1, allele2, mGene->getTraitName(), mGene->getDominantName());
						m_Parent2ListBox.AddString(line);
					}
					else // Its recessive
					{
						sprintf(line, "%c%c - Homozygous Recessive - %s = %s",
							allele1, allele2, mGene->getTraitName(), mGene->getRecessiveName());
						m_Parent2ListBox.AddString(line);
					}
				}
				else // Its heterozygous
				{
					if(isupper(allele1)) // Allele1 is the upper case letter
					{
						sprintf(line, "%c%c - Heterozygous Dominant - %s = %s",
							allele1, allele2, mGene->getTraitName(), mGene->getDominantName());
						m_Parent2ListBox.AddString(line);
					}
					else // Allele2 is the upper case letter
					{
						sprintf(line, "%c%c - Heterozygous Dominant - %s = %s",
							allele2, allele1, mGene->getTraitName(), mGene->getDominantName());
						m_Parent2ListBox.AddString(line);
					}
				}
			}
		}
	}