Manipulating Text

The program of this section displays a body of text defined. Each entry contains:

Thus, each line to be displayed contains three columns. The first and second columns are left justified; whereas, the third column is right justified. The output of the program is shown below.

As can be seen, not all of the text is visible. The first program of this chapter displays the text without any scrolling facilities. The second program of this chapter scrolls vertically and the third example builds upon the first and second and scrolls both vertically and horizontally.

The window data structure contains several variables relating to rendering the text, which are shown below.

struct window_data
    int width_of_character,

There are a number of ways of creating a device context. Perhaps the most commonly used method is the function begin_paint. When a device context is required in a circumstance other than when processing the message message::paint, other functions may be used to create a device context; in particular, the function get_device_context. Such a device context may be used to acquire information about the size of font characters. This is the approach used in the program at hand to obtain metrics of the font - as shown below.

case message::create:
  handle device_context = get_device_context(window_handle);

  text_metrics<character> text_metrics_get;


  width_of_character = text_metrics_get.AverageCharacterWidth;

  width_of_capitals = (text_metrics_get.pitch_and_family & 1 ? 3 : 2) * width_of_character/2;

  height_of_character = text_metrics_get.height + text_metrics_get.external_leading;


The code fragment above obtains the average character width and the height of characters - including the external leading of characters. When a variable pitch font is used, the width of capitals is estimated as 150% of the average character width; otherwise, it is set to be the average character width.

To render the three columns of text contained in the header file, the function text_out is used. This is the most commonly used function to perform textual output. The code used to paint the window (and hence draw the text) is shown below. A for loop is used to display multiple text lines using the function text_out - as shown below.

case message::paint:
  paint paint_struct;
  handle device_context = begin_paint(window,&paint_struct);

  enum {column1=30, column2=40};

  for (int i=0; i<lines; i++)
             height_of_character * (i+1),

             width_of_character + column1 * width_of_capitals,
             height_of_character * (i+1),

    set_text_alignment(device_context,text_alignment_flag::right | text_alignment_flag::top);

    character Buffer[32];

             width_of_character + column1 * width_of_capitals + column2 * width_of_character,
             height_of_character * (i+1),
             print_string(Buffer, "%5d",get_system_metrics(Metrics[i].index)));

    set_text_alignment(device_context,text_alignment_flag::left | text_alignment_flag::top);


The number of lines is a fixed value calculated in the header file with identifier lines. The first column is positioned at x-offset:


whereas, the second column is positioned at x-offset:

width_of_character + column1 * width_of_capitals

and the third column is positioned at x-offset:

width_of_character + column1 * width_of_capitals + column2 * width_of_character

The vertical positioning is the same for each string. It is the line number plus one multiplied by the line height (the line height being calculated when processing the message message::create). The function print_string is used to convert a numeric value to a string and the alignment is adjusted to ensure the text is right justified.