Friday, January 11, 2013

Dividing and Centering Text Output


Dividing and Centering Text Output


Sometimes we need text output to the console window or a file to be centered and or preceeded by a divider to make it more readable. In such cases, we can create two functions OutputDivider ( ) and OutputCentered ( ) to add to our formatting ability. A complete program example at the end shows how to use both functions together.

The OutputDivider Function:

The divider function should accept a stream to output. The stream could be a file stream, ifstream, or output to the screen, cout. We should set what character is repeated across the screen and how many times, which is the desired length of the divider.

Function Definition:
OutputDivider( )
//-----------------------------------------------------------------------------
// Function:     OutputDivider
// Description:  Output fillSymbol character a count of numberOfSymbols to
//               streamOut, keeping the original fill character when done.
//-----------------------------------------------------------------------------

void OutputDivider( ostream& outStream, char fillSymbol, int numberOfSymbols )
{
     char oldFillSymbol;

     //Set oldFillSymbol to the current fill character.
     oldFillSymbol = outStream.fill( );

     //Set the fill to the fillSymbol passed.
     outStream.fill( fillSymbol );

     //Output to stream, outStream, the fill across width, numberOfSymbols.
     outStream << setw( numberOfSymbols ) << "" << endl;

     //Restore old fill symbol so not to affect outside setw( ) formatting.
     outStream.fill( oldFillSymbol );
}

This function works by accepting, as the first parameter, an ostream which all output will be sent to, named outStream. This might be a type of file stream, such as ofstream, perhaps named myOutputFile, or to cout, the screen. The second parameter passed into the function is char fillSymbol, which is the symbol or character to be output. The third parameter, int numberOfSymbols, is the number of times the character is repeatedly printed.

Once a fill symbol is set for a stream, such as with a call to outStream.fill( ) the symbol for that stream is then changed going forward, whether or not we are in the local scope of a function or not. This is because we are directing changes to the actual stream itself, through the reference to ostream& instead of a local copy. To make sure outside calls to setw( ) aren't changed after each run of our function we store the original fill in char oldFillSymbol to be restored at the end.

Then we set the fill to fillSymbol passed and subsequently output the fill across the screen using setw( ). Here's how the function is called, see the final example at the end for further clarification:

Function Call:
OutputDivider( )
//Output to cout a divider of dashes, '-', across the screen, 50 chars.
OutputDivider ( cout, '-' , 50 );



The OutputCentered Function:

The OutputCentered ( ) function should accept a stream, similar to the OutputDivider() function above. The output will be of some text, a string, in the center of the resulting output.
Function Definition
OutputCentered( )
//-----------------------------------------------------------------------------
// Function:    OutputCentered
// Description: Outputs to output stream passed, outStream, the string of text
//              passed, centerText, across the desired number of characters,
//              screenLength.
//-----------------------------------------------------------------------------

void OutputCentered( ostream& outStream, string centerText, int screenLength )
{
     int centeredLength;

     //Minus the length of the text from the output's total length, screenWidth.
     centeredLength = screenLength - centerText.length( );

     //Test if centering is necessary, the centeredLength is two or more.
     if (centeredLength >= 2)
     {
          //Calculate total width of output to be appropriately centered.
          centeredLength = ( (centeredLength / 2) + centerText.length( ) );
     }

     //Output centerText, string passed, across centeredLength.
     outStream << setw( centeredLength ) << centerText << endl;
}


This function works by accepting, as the first parameter, an ostream which all output will be sent to, named outStream. Again, this might be a type of file stream, such as an ofstream or just an output to screen, cout. The second and third parameter, a string centerText and then int screenLength which specifies the length of characters to center the text across.

To understand how this works consider screenLength value represents the number of boxes lined up in a row. We need to put the characters of string centerText in the center-most boxes. In order to know which box is destined to be an empty box, or how many boxes to keep empty as we move from left to right we start by finding out how many empty boxes we'll actually have. To do that we minus the length of the text from the total screen size. The second line of the function does this exactly, determines the number of empty boxes (characters).

Next, we test if we need to center at all. If we know there are two or more empty boxes than there are characters the we should do some centering, otherwise there will be no even number of empty boxes so there's no centering possible and the function should just output string centerText.

If there is centering to be done we calculate the length to center across, dividing the number of empty characters, centeredWidth and adding in the length of the string.

Finally, the function outputs the centerText, which is centered using setw( ) to set the width/length of the calculated centeredLength.

Function Call:
OutputCentered( )
//Output the text, "Centered!", to cout centered across fifty characters.
OutputCentered ( cout, "Centered!", 50 );


The Complete Example

To wrap up, we can observe both the OutputCentered and Output functions working side by side to  tidy up output.


Complete Example, using OutputCentered and OutputDivider
main.cpp
//===================================INCLUDES==================================
#include <iostream> //Included for text output, cout.
#include <iomanip> //Included for setw(), fill(), output manipulation.
#include <string> //Included for string type.

//Assuming namespace ::std.
using namespace std;

//=============================FUNCTION PROTOTYPES=============================
void OutputDivider( ostream& outStream, char fillSymbol, int numberOfSymbols );
void OutputCentered( ostream& outStream, string centerText, int screenLength );

//==================================MAIN ENTRY=================================
int main( void )
{
    //The length of the output, used to set all lengths the same.
    int outputLength = 60;

    //A string to output, centered, at some point.
    string str1 = "Neato, n Stuff";


    //Output a divider of outputLength number of characters.
    OutputDivider ( cout, '=', outputLength );

    //Output "Centered!" centered across outputLength number of characters.
    OutputCentered ( cout, "Centered!", outputLength );

    //Output a divider of outputLength number of characters.
    OutputDivider ( cout, '*', outputLength );

    //Output the string, str1, centered on the screen.
    OutputCentered ( cout, str1, outputLength );


    //End the program, returning zero.
    return ( 0 );
}


//=============================FUNCTION DEFINITIONS============================
//-----------------------------------------------------------------------------
// Function:     OutputDivider
// Description:  Output fillSymbol character a count of numberOfSymbols to
//               streamOut, keeping the original fill character when done.
//-----------------------------------------------------------------------------

void OutputDivider( ostream& outStream, char fillSymbol, int numberOfSymbols )
{
     char oldFillSymbol;

     //Set oldFillSymbol to the current fill character.
     oldFillSymbol = outStream.fill( );

     //Set the fill to the fillSymbol passed.
     outStream.fill( fillSymbol );

     //Output to stream, outStream, the fill across width, numberOfSymbols.

     outStream << setw( numberOfSymbols ) << "" << endl;
     //Restore old fill symbol so not to affect outside setw( ) formatting.
     outStream.fill( oldFillSymbol );
}


//-----------------------------------------------------------------------------
// Function:    OutputCentered
// Description: Outputs to output stream passed, outStream, the string of text
//              passed, centerText, across the desired number of characters,
//              screenLength.
//-----------------------------------------------------------------------------

void OutputCentered( ostream& outStream, string centerText, int screenLength )
{
     int centeredLength;

     //Minus the length of the text from the output's total length, screenWidth.
     centeredLength = screenLength - centerText.length( );

     //Test if centering is necessary, the centeredLength is two or more.
     if (centeredLength >= 2)
     {
          //Calculate total width of output to be appropriately centered.
          centeredLength = ( (centeredLength / 2) + centerText.length( ) );
     }

     //Output centerText, string passed, across centeredLength.
     outStream << setw( centeredLength ) << centerText << endl;
}


Output:

No comments:

Post a Comment