• Articles
  • Borland C++ 5.02 Code For A Print Previe
Published by
Jan 22, 2014 (last update: Jan 27, 2014)

Borland C++ 5.02 Code For A Print Preview Window

Score: 4.6/5 (15 votes)
*****
INTRODUCTION

I have used Borland C++ version 5.02 to code application development projects for small businesses in my local area for years. It is a very robust software platform and a cornerstone of these custom software engagements is the “Print Preview” feature. Here I will feature an example of a check register reconciliation, which utilized my developer skills to create a “Print Preview” function.

DECLARE THE NEEDED C++ CLASSES

The first thing that needs to be done is to declare the classes required for the print preview window. The “TPrevWindow” class is derived from the base class of "TWindow" as found in OWL (Object Windows Library). It includes member functions for page navigation and printing. The response table in this class associates defined constants for bitmap images with their respective member functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

// this is the class declaration for the “TPrevWindow” class, which
// contains member functions for scrolling forwards and backwards
// through print preview pages as well as the printing function itself.
// also, each of these member functions are associated with bitmaps as
// seen here under the response table. lastly, there is a "TPrinter"
// object, “Printer”, that is used throughout the code.
//
// class TPrevWindow
// ~~~~~ ~~~~~~~~~~~
class TPrevWindow : public TWindow {
  public:
    TPrevWindow(TWindow* parent = 0);
    void PrnNext();
    void PrnPrevious();
    void PrnImage();
    void Paint(TDC& dc, bool erase, TRect& rect);
  private:
    TPrinter* Printer;
  DECLARE_RESPONSE_TABLE(TPrevWindow);
};
DEFINE_RESPONSE_TABLE1(TPrevWindow, TWindow)
  EV_COMMAND(IDB_BITMAP1, PrnNext),
  EV_COMMAND(IDB_BITMAP2, PrnPrevious),
  EV_COMMAND(IDB_BITMAP3, PrnImage),
END_RESPONSE_TABLE;


Next, we need to declare the dialog class “TBalEndDlg” of the base class "TDialog" that will do the work of accepting user input, extracting data, etc. to prepare for the upcoming print preview operation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

// this class contains controls for accepting user input as well
// as “TButtonGadget” and “TButtonGadgetEnabler” objects to be
// utilized for constructing the print preview window near the
// end of processing.
//
// class TBalEndDlg
// ~~~~~ ~~~~~~~~~~~~
class TBalEndDlg : public TDialog {
  public:
    TBalEndDlg(TWindow* parent, TResId resId, TBalEndStruct& transfer);
    TEdit *Edit1,*Edit2;

    LRESULT WMChar(WPARAM, LPARAM);

  protected:
    void    CmOk();

  private:
    TButtonGadget* G1;
    TButtonGadget* G2;
    TButtonGadgetEnabler* Ge1;
    TButtonGadgetEnabler* Ge2;
    void    SetupWindow();
    char    StartingAmt[MAXSELL];
    char    EndDate[MAXDAT];

  DECLARE_RESPONSE_TABLE(TBalEndDlg);
};

DEFINE_RESPONSE_TABLE1(TBalEndDlg, TDialog)
  EV_COMMAND(IDOK, CmOk),
  EV_MESSAGE(WM_CHAR, WMChar),
END_RESPONSE_TABLE;


NEXT, SET UP THE PRINT PREVIEW

Here is the command that runs the dialog “TBalEndDlg” from the “TTestWindow” class, which is used for the main program window. The resource used to create the user input screen is “IDD_STATEMENTBAL”. The directive within the main window class “TTestWindow” used to construct the input control transfer mechanism is “TBalEndStruct BalEndStruct;”. The object “BalEndStruct” is specified below in the call to run the dialog “TBalEndDlg”.

1
2
3
4
5
6
7
8
9
10
11

void
TTestWindow::Reconciliation()
{

 if (TBalEndDlg(this, IDD_STATEMENTBAL, BalEndStruct).Execute() == IDOK) {

 }

}


And here is what the “IDD_STATEMENTBAL” dialog resource coding looks like.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

IDD_STATEMENTBAL DIALOG 15, 20, 205, 65
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Reconciliation Entry Screen"
FONT 8, "MS Sans Serif"
{
 CONTROL "Register Starting Balance: ", 962, "static", SS_LEFT | WS_CHILD, 30 10, 130, 12
 CONTROL "Register Ending Date: ", 963, "static", SS_LEFT | WS_CHILD, 30 25, 130, 12
 EDITTEXT IDC_STARTINGBAL, 113, 10, 55, 12, ES_LEFT | WS_BORDER | WS_TABSTOP | WS_CHILD, 0
 EDITTEXT IDC_ENDDATE, 103, 25, 55, 12, ES_LEFT | WS_BORDER | WS_TABSTOP | WS_CHILD, 0
 DEFPUSHBUTTON "&OK", IDOK, 70, 45, 30, 19, 0, 0
 PUSHBUTTON "&Cancel", IDCANCEL, 100, 45, 30, 19, 0, 0
}


This is what the input screen looks like during runtime.




This next patch of C++ code will engage after the “TBalEndDlg” dialog call has occurred. It will commence setting up for the print preview process by first accepting a starting balance and an ending date. These will be used for the data extraction process that follows after the “OK” button in the above referenced dialog resource has been clicked. After this is complete, it will calculate the number of pages based on 50 lines per page. Then it will construct a “frame_d” object from the “TDecoratedFrame” base class. It will initialize various settings including the control bar that the buttons for the member functions are embedded in. It will also set the dimensions of the print preview window as well as enabling and disabling the navigation buttons based on how many pages have been calculated for the print preview operation. You will also notice the use of defined constants in the file input/output operations I use. These are used to set the offset in the filestreams I use to read from and write to binary fixed length data files that work with the programming.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
	
// instantiate the “TBalEndDlg” dialog class.
//
TBalEndDlg::TBalEndDlg(TWindow* parent, TResId resid,
  TBalEndStruct& transfer)
:
  TDialog(parent, resid)
{
  Edit1 = new TEdAmt_(this, IDC_ENDBAL, sizeof(transfer.StartingAmt));
  Edit2 = new TEdate(this, IDC_ENDDATE, sizeof(transfer.EndDate));

  TransferBuffer = (void far*)&transfer;
}

// let’s get the Winform screen set up.
void
TBalEndDlg::SetupWindow()
{
  // declare variables for this function.
  long int  ttt,ttt1,ttt2,ttt3;
  int       a,t,ax;
  char      var[3],Date_[MAXDAT];
  struct    dosdate_t d;
  ldiv_t    n;

  TDialog::SetupWindow();

  // clear out the starting amount field.
  Edit1->Clear();

  // grab today’s date and assign it to the ending date input. 
  _dos_getdate(&d);
  ttt1 = d.month;
  ttt2 = d.day;
  ttt3 = d.year;

  // take the current date components month, day and year and
  // convert to chars to be stored in the char array “Date_”.	
  for(a=0; a<MAXDAT; a++) Date_[a]=32;
	  Date_[2]=47;
	  Date_[5]=47;
	  t=0;
		  do {

			  if(t==0) ttt=ttt1;
				  if(t==1) ttt=ttt2;
					  if(t==2) {
					  ttt=ttt3;
					  if ( ttt < 2000 )
					  ttt = ttt - 1900;
					  else
					  ttt = ttt - 2000;
					  }

  var[0]=48;
  var[1]=48;
  var[2]=32;
  ax=1;
  do {
  n=ldiv(ttt,10L);
  ttt=n.quot;
  if(n.rem==0) var[ax]=48;
	  	if(n.rem==1) var[ax]=49;
		  if(n.rem==2) var[ax]=50;
			  if(n.rem==3) var[ax]=51;
				  if(n.rem==4) var[ax]=52;
					  if(n.rem==5) var[ax]=53;
						  if(n.rem==6) var[ax]=54;
  if(n.rem==7) var[ax]=55;
	  if(n.rem==8) var[ax]=56;
		  if(n.rem==9) var[ax]=57;
  ax--;
  } while(ttt>0);

  if(t==0) for(a=0; a<2; a++) Date_[a]=var[a];
	  if(t==1) for(a=0; a<2; a++) Date_[3+a]=var[a];
		  if(t==2) for(a=0; a<2; a++) Date_[6+a]=var[a];

  t++;
  } while(t<3);
  Date_[MAXDAT-1]=0;
  Edit2->SetText(Date_);

  for(a=0; a<MAXDAT-1; a++) Horddatexz[a]=Date_[a];

  Datedispz = 0;

}

// after the operator clicks the “OK” button, grab the Winform
// screen inputs and commence the data extraction process.
void
TBalEndDlg::CmOk()
{
  // declare variables for this function.
  int        a,PickVar,CountVar_,KountVar,fd,f,r,tty,ax,ff;
  long int   max98,ttt,accum,accum2,startbal,hold[MAXSELL],endbal;
  long int   cc,cc1,cc2,ee,ee1,ee2;
  char       kh,ch,dh,eh,Datvarx[MAXDAT],ExtractedAmt[MAXSELL];
  ldiv_t     n;
  streambuf  *inn = cin.rdbuf();

  // set the cursor to a hourglass.
  SetCursor(0, IDC_WAIT);


  for(a=0; a<MAXSELL; a++) StartingAmt[a]=32;
     for(a=0; a<MAXDAT; a++) EndDate[a]=32;

  // grab data from the Winform screen controls.
  GetDlgItemText(IDC_STARTINGBAL, StartingAmt, MAXSELL);
  GetDlgItemText(IDC_ENDDATE, EndDate, MAXDAT);


                  // format the retreived starting amount so it is right justified.
		  for(a=0; a<MAXSELL; a++) {
		     if(StartingAmt[a]<46 || StartingAmt[a]>57) StartingAmt[a]=32;
		  }
			  r=0;
			  do {
			     if(StartingAmt[9]<48 || StartingAmt[9]>57) {
				for(f=9; f>0; f--) StartingAmt[f]=StartingAmt[f-1];
				StartingAmt[0]=32;
			     }
			  r++;
			  } while(r<10);


  // parse the retreived ending date into month, day and year numerical
  // components for further processing.
  a=0;
  do {

	  if(a==0) ax=0;
		  if(a==1) ax=3;
			  if(a==2) ax=6;

  for(ff=0; ff<2; ff++) {
  hold[ff]=0;
	  if(EndDate[ax+ff]==48) hold[ff]=0;
		  if(EndDate[ax+ff]==49) hold[ff]=1;
			  if(EndDate[ax+ff]==50) hold[ff]=2;
				  if(EndDate[ax+ff]==51) hold[ff]=3;
					  if(EndDate[ax+ff]==52) hold[ff]=4;
						  if(EndDate[ax+ff]==53) hold[ff]=5;
							  if(EndDate[ax+ff]==54) hold[ff]=6;
  if(EndDate[ax+ff]==55) hold[ff]=7;
	  if(EndDate[ax+ff]==56) hold[ff]=8;
		  if(EndDate[ax+ff]==57) hold[ff]=9;
  }
  if(a==0) cc = hold[0]*10 + hold[1]*1;
	  if(a==1) cc1 = hold[0]*10 + hold[1]*1;
		  if(a==2) {
		  cc2 = hold[0]*10 + hold[1]*1;
			  if(cc2>=80) cc2 = cc2 + 1900;
				  if(cc2<80) cc2 = cc2 + 2000;
		  }

  a++;
  } while(a<3);

  // convert the starting amount to a numerical value.
  for(a=0; a<MAXSELL; a++) Sellvarq_[a]=StartingAmt[a];
	  for(a=0; a<MAXSELL-1; a++) {
	  hold[a]=0;
		  if(StartingAmt[a]==48) hold[a]=0;
			  if(StartingAmt[a]==49) hold[a]=1;
				  if(StartingAmt[a]==50) hold[a]=2;
					  if(StartingAmt[a]==51) hold[a]=3;
						  if(StartingAmt[a]==52) hold[a]=4;
							  if(StartingAmt[a]==53) hold[a]=5;
  if(StartingAmt[a]==54) hold[a]=6;
	  if(StartingAmt[a]==55) hold[a]=7;
		  if(StartingAmt[a]==56) hold[a]=8;
			  if(StartingAmt[a]==57) hold[a]=9;
	  }
  startbal = hold[0]*100000000 + hold[1]*10000000 + hold[2]*1000000 + hold[3]*100000 + hold[4]*10000
  + hold[5]*1000 + hold[6]*100 + hold[8]*10 + hold[9]*1;

  // now, let’s prepare for data extraction from the check register
  // by purging the last used extracted data file and opening a new 
  // stream to a file of the same name that is set for append record
  // mode. we will also open a stream to the check register fixed width
  // binary data file to read needed data from.
  remove("test_x.txt");

  PickVar = 0;

  fd = open("cbook.txt", ios::in | ios::binary);
  ttt = filelength(fd);
  close(fd);

  ifpstream ixfile;
  ixfile.open("cbook.txt", ios::in | ios::binary);
  inn = ixfile.rdbuf();

  ofpstream oafile;
  oafile.open("test_x.txt", ios::ate | ios::app | ios::binary);
  max98=0;
  do {

  // get the first 2 characters of the transaction type designator.
  inn -> seekpos(max98+MAXDAT+MAXINVNO+MAXSELL+MAXNOTE2+MAXSELL+MAXSELL+MAXSELL+MAXCCODE+MAXCOMPANY2-9, ios::in);
  kh=ixfile.readByte();
  eh=ixfile.readByte();
     // get the first character of the transaction cleared designator.
     inn -> seekpos(max98+CHECKBLEN-5-(MAXANS-1), ios::in);
     ch=ixfile.readByte();
	 // get the first character of the transaction paid designator.
         inn -> seekpos(max98+MAXDAT+MAXINVNO+MAXSELL+MAXNOTE2+MAXSELL+MAXSELL+MAXSELL+MAXCCODE+MAXCOMPANY2+MAXSELL+MAXANS-11, ios::in);
	 dh=ixfile.readByte();

  // parse the check register transaction date into month, day and
  // year numerical components for further processing.
  inn -> seekpos(max98+CHECKBLEN-5-(MAXDAT+MAXANS-2), ios::in);
  for(a=0; a<MAXDAT-1; a++) Datvarx[a]=ixfile.readByte();

  a=0;
  do {

  if(a==0) ax=0;
	  if(a==1) ax=3;
		  if(a==2) ax=6;

  for(ff=0; ff<2; ff++) {
  hold[ff]=0;
	  if(Datvarx[ax+ff]==48) hold[ff]=0;
		  if(Datvarx[ax+ff]==49) hold[ff]=1;
			  if(Datvarx[ax+ff]==50) hold[ff]=2;
				  if(Datvarx[ax+ff]==51) hold[ff]=3;
					  if(Datvarx[ax+ff]==52) hold[ff]=4;
						  if(Datvarx[ax+ff]==53) hold[ff]=5;
  if(Datvarx[ax+ff]==54) hold[ff]=6;
	  if(Datvarx[ax+ff]==55) hold[ff]=7;
		  if(Datvarx[ax+ff]==56) hold[ff]=8;
			  if(Datvarx[ax+ff]==57) hold[ff]=9;
  }
  if(a==0) ee = hold[0]*10 + hold[1]*1;
	  if(a==1) ee1 = hold[0]*10 + hold[1]*1;
		  if(a==2) {
		  ee2 = hold[0]*10 + hold[1]*1;
			  if(ee2>=80) ee2 = ee2 + 1900;
				  if(ee2<80) ee2 = ee2 + 2000;
		  }

  a++;
  } while(a<3);

  // now, check to see if the check register transaction date is
  // less than or equal to the ending date from the Winform.
  tty=1;
  if(ee2<cc2) tty=0;

	  if(ee2==cc2 && ee<cc) tty=0;

		  if(ee2==cc2 && ee==cc) {
			  if(ee1<=cc1) tty=0;
		  }

  // if this transaction is a deposit that has not cleared the bank
  // and has not been paid and the check register transaction date is
  // less than or equal to the inputted ending date, then append a ‘D’ and
  // the check register credit amount to the extracted data file and
  // increment the line counter “PickVar” by 1.
  if ( kh == 'D' && eh == 'E' && ch == 'N' && dh == 'N' && tty == 0 ) {
	inn -> seekpos(max98+MAXDAT+MAXINVNO+MAXSELL+MAXNOTE2+MAXSELL+MAXSELL
	+MAXSELL+MAXCCODE+MAXCOMPANY2+MAXSELL+MAXANS+MAXANS-12, ios::in);
			  for(a=0; a<MAXSELL-1; a++) oafile.writeByte(ixfile.readByte());
			  oafile.writeByte('D');
			  PickVar++;
  }

  // if this transaction is not a deposit that has not cleared the bank
  // and has not been paid and the check register transaction date is
  // less than or equal to the inputted ending date, then append a ‘W’ and
  // the check register debit amount to the extracted data file and
  // increment the line counter “PickVar” by 1.
  if ( kh != 'D' && eh != 'E' && ch == 'N' && dh == 'N' && tty == 0 ) {
	  inn -> seekpos(max98+MAXDAT+MAXINVNO+MAXSELL+MAXNOTE2+MAXSELL-5, ios::in);
			  for(a=0; a<MAXSELL-1; a++) oafile.writeByte(ixfile.readByte());
			  oafile.writeByte('W');
			  PickVar++;
  }

  // advance to the next fixed width record in the check register.
  max98 = max98 + CHECKBLEN;

  } while(max98<ttt);
  ixfile.close();
  oafile.close();

  // initialize the 2 2-dimensional char arrays to prepare for
  // loading the first 50 rows of the extracted check register data.
  for(a=0; a<50; a++) {
	  for(f=0; f<MAXSELL-1; f++) Xvault2_[f][a]=32;
		  for(f=0; f<MAXSELL-1; f++) Xvault4_[f][a]=32;
  }

  // loop around the extracted data file "test_x.txt" to load
  // the first 50 rows of data into 2 2-dimensional char arrays
  // that will later populate the print preview window. also,
  // sum deposits and withdrawals with looping.
  fd = open("test_x.txt", ios::binary);
  ttt = filelength(fd);
  close(fd);

  ixfile.open("test_x.txt", ios::in | ios::binary);
  inn = ixfile.rdbuf();
  CountVar_ = 0;
  KountVar = 0;
  maxapart = 0;
  accum = 0;
  accum2 = 0;
  do {

  // read the amount from the current file offset and convert
  // this to a numerical amount for further processing.
  inn -> seekpos(maxapart+MAXSELL-1, ios::in);
  kh=ixfile.readByte();
  		inn -> seekpos(maxapart, ios::in);
			for(a=0; a<MAXSELL; a++) ExtractedAmt[a]=ixfile.readByte();

  for(a=0; a<MAXSELL; a++) {
	  if(StartingAmt[a]<46 || StartingAmt[a]>57) StartingAmt[a]=32;
  }

  r=0;
  do {
  		if(StartingAmt[9]<48 || StartingAmt[9]>57) {
				for(f=9; f>0; f--) StartingAmt[f]=StartingAmt[f-1];
			   StartingAmt[0]=32;
	  	}
  r++;
  } while(r<10);

  for(a=0; a<MAXSELL-1; a++) {
  hold[a]=0;
  if(StartingAmt[a]==48) hold[a]=0;
	  if(StartingAmt[a]==49) hold[a]=1;
		  if(StartingAmt[a]==50) hold[a]=2;
			  if(StartingAmt[a]==51) hold[a]=3;
				  if(StartingAmt[a]==52) hold[a]=4;
					  if(StartingAmt[a]==53) hold[a]=5;
  if(StartingAmt[a]==54) hold[a]=6;
	  if(StartingAmt[a]==55) hold[a]=7;
		  if(StartingAmt[a]==56) hold[a]=8;
			  if(StartingAmt[a]==57) hold[a]=9;
  }
   // accumulate for deposit transactions into the variable “accum”.
   if ( kh == 'D' ) accum = accum + ( hold[0]*100000000 + hold[1]*10000000 + hold[2]*1000000 + hold[3]*100000 + 
   hold[4]*10000+hold[5]*1000 + hold[6]*100 + hold[8]*10 + hold[9]*1 );
      // accumulate for withdrawal transactions into the variable “accum2”.
      if ( kh == 'W' ) accum2 = accum2 + ( hold[0]*100000000 + hold[1]*10000000 + hold[2]*1000000 + hold[3]*100000 + hold[4]*10000 +  
      hold[5]*1000 + hold[6]*100 + hold[8]*10 + hold[9]*1 );
	 // if the transaction is a deposit and all 50 rows of the
         // 2-dimensional char array “Xvault2_” have not been filled,
         // then add the amount to the current slot in the char array
         // “Xvault2_” and then increment the row counter “CountVar_”
         // by 1.		        
	 if ( kh == 'D' && CountVar_ < 50 ) {
	 inn -> seekpos(maxapart, ios::in);
	     for(r=0; r<MAXSELL-1; r++) Xvault2_[r][CountVar_]=ixfile.readByte();
	     CountVar_++;
	 }
	     // if the transaction is a withdrawal and all 50 rows of the
             // 2-dimensional char array “Xvault4_” have not been filled,
             // then add the amount to the current slot in the char array
             // “Xvault4_” and then increment the row counter “KountVar”
             // by 1.		        
	     if ( kh == 'W' && KountVar < 50 ) {
	     inn -> seekpos(maxapart, ios::in);
                 for(r=0; r<MAXSELL-1; r++) Xvault4_[r][KountVar]=ixfile.readByte();
                 KountVar++;
             }

  // advance to the next fixed width record in the extracted check book data file.
  maxapart = maxapart + MAXSELL;

  } while(maxapart<ttt);
  ixfile.close();

  // calculate the ending balance that will appear on the check
  // register reconciliation. this is the starting balance less
  // deposits plus withdrawals.
  endbal = startbal - accum + accum2;

  // take the numerical ending balance amount and convert it to
  // chars to be stored in the char array “totpay”.	
  for(a=0; a<MAXSELL; a++) totpay[a]=32;
	  if(endbal<0) {
	  totpay[0]='-';
	  endbal=-endbal;
	  }
  totpay[9]=48;
  totpay[8]=48;
  totpay[7]=46;
  totpay[6]=48;
  r=9;
  do {
  n=ldiv(endbal,10L);
  endbal=n.quot;
  if(n.rem==0) totpay[r]=48;
	  if(n.rem==1) totpay[r]=49;
		  if(n.rem==2) totpay[r]=50;
			  if(n.rem==3) totpay[r]=51;
				  if(n.rem==4) totpay[r]=52;
					  if(n.rem==5) totpay[r]=53;
  if(n.rem==6) totpay[r]=54;
	  if(n.rem==7) totpay[r]=55;
		  if(n.rem==8) totpay[r]=56;
			  if(n.rem==9) totpay[r]=57;
  r--;
  if(r==7) r--;
  } while(endbal>0);

  r=0;
  do {
  r++;
  } while(totpay[r]==32 && r<MAXSELL-1);
  totpay[r-1]='$';
  
  // set the cursor to an arrow.
  SetCursor(0, IDC_ARROW);

		// this code will calculate the number of pages in the
                // print preview assuming there are 50 lines per page.
		mPage2= 0;
		do {
		mPage2++;
		PickVar = PickVar - 50;
		} while( PickVar >= 50 );
			if ( PickVar > 0 ) mPage2++;

// this code snippet will initialize the trappings of a "TDecoratedFrame"
// object, “frame_d”. it will incorporate the “TPrevWindow” class as well
// as the bitmaps associated with each member function of the class into
// the "TDecoratedFrame" object. a control bar object, “ControlBar”, is
// constructed from "TMyControlBar". the buttons for the member functions
// are embedded into this control bar. the dimensions of the "TDecoratedFrame"
// window are set as well as the page count and the file stream offset,
// “maxapart”. finally, the decorated print preview window is brought to life
// with the directive, “frame_d->Create()”.
TDecoratedFrame* frame_d = new TDecoratedFrame(0, "Reconciliation Preview", new TPrevWindow, false);
hndl = this->GetHandle();
TMyControlBar* ControlBar;
ControlBar = new TMyControlBar(frame_d);
frame_d->Insert(*ControlBar, TDecoratedFrame::Top);
G1 = new TButtonGadget(IDB_BITMAP1, IDB_BITMAP1);
ControlBar->Insert(*G1);
Ge1 = new TButtonGadgetEnabler(frame_d->GetHandle(), G1);
ControlBar->Insert(*new TSeparatorGadget);
G2 = new TButtonGadget(IDB_BITMAP2, IDB_BITMAP2);
ControlBar->Insert(*G2);
Ge2 = new TButtonGadgetEnabler(frame_d->GetHandle(), G2);
ControlBar->Insert(*new TSeparatorGadget);
ControlBar->Insert(*new TButtonGadget(IDB_BITMAP3, IDB_BITMAP3, 0, true));
ControlBar->Insert(*new TSeparatorGadget);
PageCount = 1;
maxapart = 0;
frame_d->Attr.X = 10;
frame_d->Attr.Y = 10;
frame_d->Attr.W = 630;
frame_d->Attr.H = 440;
	// the page navigation buttons are initially enabled and/or
        // disabled based on the number of pages in the print preview
        // operation for cases where the total number of pages is 1 or
        // there are at least 2 or more pages.
	if ( mPage2 == 1 ) {
	Ge1->Enable(false);
	Ge2->Enable(false);
	}
		if ( mPage2 >= 2 ) {
		Ge1->Enable(true);
		Ge2->Enable(false);
		}
			frame_d->Create();

}

// the page navigation buttons are enabled and disabled based on the number
// of pages in the print preview and also at what page number in the preview
// operation is currently being viewed. the variable “PageCount” holds the
// number of the currently displayed page in the preview screen. this member
// function, "TBalEndDlg::WMChar(WPARAM cmd, LPARAM cmd2)", will be sent to
// the handle of the decorated print preview window to use the current page
// number as well as the total number of pages in the print preview operation
// to update which navigation buttons on the decorated window are enabled
// and/or disabled.
LRESULT
TBalEndDlg::WMChar(WPARAM cmd, LPARAM cmd2)
{

 if ( mPage2 >= 2 && PageCount < mPage2 && PageCount > 1 ) {
 Ge1->Enable(true);
 Ge2->Enable(true);
 }

 	if ( mPage2 >= 2 && PageCount == mPage2 ) {
        Ge1->Enable(false);
        Ge2->Enable(true);
        }

               if ( mPage2 >= 2 && PageCount == 1 ) {
               Ge1->Enable(true);
               Ge2->Enable(false);
               }

}


CODE THE PRINT PREVIEW OUTPUT TO THE SCREEN

Below is the code under the “Paint(TDC& dc, bool erase, TRect& rect)” member component of the “TPrevWindow” class that will paint the print preview information in the decorated window frame that appears after the data extraction processing is complete.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

void
TPrevWindow::Paint(TDC& dc, bool erase, TRect& rect)
{
  // declare variables for this function.
  long int  ttt,ttt1,ttt2,ttt3;
  int       exta,a,ax,f,r,t,ext1,ext2,ext3,ext4,ext44,MarkVar1,MarkVar2,ext5,ext6,ext7;
  float     rr;
  char      var[3],Date_[MAXDAT],var2[5];
  char      Idate[MAXDAT],Ino[MAXINVNO],Inamt[MAXSELL],Idescr[MAXNOTE2],Icomp[MAXCOMPANY2];
  char      Indescr[MAXNOTE2],Indisc[MAXSELL],Inpay[MAXSELL],Idr[MAXSELL],Ie_desc[MAXNOTE];
  char      Ivalue[MAXSELL2],Icr[MAXSELL],Ibal[MAXSELL],Ivend[MAXCOMPANY2],Icode[MAXCCODE];
  char      Ipd[MAXDAT],Iinv[MAXDAT],Icrx[13],Ibalx[13],Idrx[13];
  struct    dosdate_t d;
  ldiv_t    n;
  TSize     extent;

  // take the current page number of the print preview and
  // convert to chars to be stored in the char array “var2”.	
  ttt=PageCount;
  for(a=0; a<5; a++) var2[a]=32;
  var2[4]=48;
  ax=4;
  do {
  n=ldiv(ttt,10L);
  ttt=n.quot;
	  if(n.rem==0) var2[ax]=48;
		  if(n.rem==1) var2[ax]=49;
			  if(n.rem==2) var2[ax]=50;
				  if(n.rem==3) var2[ax]=51;
					  if(n.rem==4) var2[ax]=52;
						  if(n.rem==5) var2[ax]=53;
	  if(n.rem==6) var2[ax]=54;
		  if(n.rem==7) var2[ax]=55;
			  if(n.rem==8) var2[ax]=56;
				  if(n.rem==9) var2[ax]=57;
  ax--;
  } while(ttt>0);
  var2[5]=0;

  _dos_getdate(&d);
  ttt1 = d.month;
  ttt2 = d.day;
  ttt3 = d.year;

  // take the current date components month, day and year and
  // convert to chars to be stored in the char array “Date_”.	
  for(a=0; a<MAXDAT; a++) Date_[a]=32;
	  Date_[2]=47;
	  Date_[5]=47;
  t=0;
  do {

  if(t==0) ttt=ttt1;
	  if(t==1) ttt=ttt2;
		  if(t==2) {
		  ttt=ttt3;
			  if ( ttt < 2000 )
			  ttt = ttt - 1900;
			  else
			  ttt = ttt - 2000;
			  }

  var[0]=48;
  var[1]=48;
  var[2]=32;
  ax=1;
  do {
  n=ldiv(ttt,10L);
  ttt=n.quot;
	  if(n.rem==0) var[ax]=48;
		  if(n.rem==1) var[ax]=49;
			  if(n.rem==2) var[ax]=50;
				  if(n.rem==3) var[ax]=51;
					  if(n.rem==4) var[ax]=52;
						  if(n.rem==5) var[ax]=53;
	  if(n.rem==6) var[ax]=54;
		  if(n.rem==7) var[ax]=55;
			  if(n.rem==8) var[ax]=56;
				  if(n.rem==9) var[ax]=57;
  ax--;
  } while(ttt>0);

  if(t==0) for(a=0; a<2; a++) Date_[a]=var[a];
	  if(t==1) for(a=0; a<2; a++) Date_[3+a]=var[a];
		  if(t==2) for(a=0; a<2; a++) Date_[6+a]=var[a];

  t++;
  } while(t<3);

  // set the print preview to scale 100 logical units per
  // inch of screen width. set the mapping mode to “MM_LOENGLISH”
  // and save the current device context.
  const UnitsPerInch = 100;
  dc.SaveDC();
  dc.SetMapMode(MM_LOENGLISH);
  int x1 = 0;
  int y1 = 0;

  // using a bold "Times New Roman" font, paint the heading
  // and column labels of the print preview.
  TFont fontBold2("Times New Roman", 20, 8, 0, 0, FW_BOLD);

  dc.SelectObject(fontBold2);

  dc.TextOut(x1 + ( 0.40 * UnitsPerInch ), y1 - ( 0.20 * UnitsPerInch ), "Page:", 5);

  extent = dc.GetTextExtent("Page:", 5);
  ext1 = extent.cx;

  dc.TextOut(x1 + ( 0.40 * UnitsPerInch ), y1 - ( 0.40 * UnitsPerInch ), "Date:", 5);

  extent = dc.GetTextExtent("Date:", 5);
  ext2 = extent.cx;

  dc.TextOut(x1 + ( 5.65 * UnitsPerInch ), y1 - ( 0.20 * UnitsPerInch ), "Acme Company", 12);
  dc.TextOut(x1 + ( 5.65 * UnitsPerInch ), y1 - ( 0.40 * UnitsPerInch ), "123 Acme Blvd.", 14);
  dc.TextOut(x1 + ( 5.65 * UnitsPerInch ), y1 - ( 0.60 * UnitsPerInch ), "Anywhere, Anystate 44444", 24);

  dc.TextOut(x1 + ( 2.55 * UnitsPerInch ), y1 - ( 0.85 * UnitsPerInch ), "Reconciliation", 14);

  dc.TextOut(x1 + ( 0.15 * UnitsPerInch ), y1 - ( 1.15 * UnitsPerInch ), "Starting Balance", 16);
  dc.TextOut(x1 + ( 1.75 * UnitsPerInch ), y1 - ( 1.15 * UnitsPerInch ), "Deposits", 8);
  dc.TextOut(x1 + ( 3.00 * UnitsPerInch ), y1 - ( 1.15 * UnitsPerInch ), "Checks/Withdrawals", 18);
  dc.TextOut(x1 + ( 6.00 * UnitsPerInch ), y1 - ( 1.15 * UnitsPerInch ), "Ending Balance", 14);

  // using a normal "Times New Roman" font, paint the extracted
  // check register data previously stored in the 2 2-dimensional
  // char arrays “Xvault2_” and “Xvault4_”.
  TFont fontNorm2("Courier", 20, 8, 0, 0, FW_NORMAL);

  dc.SelectObject(fontNorm2);

  rr = 1.35;
  f = 0;
  MarkVar1 = 0;
  MarkVar2 = 0;
  do {

	  for(r=0; r<MAXSELL-1; r++) Idr[r]=Xvault2_[r][f];
		  for(r=0; r<MAXSELL-1; r++) Icr[r]=Xvault4_[r][f];

			  for(r=0; r<MAXSELL; r++) {
				  if(Sellvarq_[r]<33 || Sellvarq_[r]>126) Sellvarq_[r]=32;
					  if(Idr[r]<33 || Idr[r]>126) Idr[r]=32;
						  if(Icr[r]<33 || Icr[r]>126) Icr[r]=32;
							  if(totpay[r]<33 || totpay[r]>126) totpay[r]=32;
			  }

  Sellvarq_[MAXSELL-1]=0;
  Idr[MAXSELL-1]=0;
  Icr[MAXSELL-1]=0;
  totpay[MAXSELL-1]=0;

  	if ( PageCount == 1 && MarkVar1 == 0 ) {
        dc.TextOut(x1 + ( 0.15 * UnitsPerInch ), y1 - ( rr * UnitsPerInch ), Sellvarq_, MAXSELL-1);
	MarkVar1 = 1;
	}
  	dc.TextOut(x1 + ( 1.75 * UnitsPerInch ), y1 - ( rr * UnitsPerInch ), Idr, MAXSELL-1);
	dc.TextOut(x1 + ( 3.00 * UnitsPerInch ), y1 - ( rr * UnitsPerInch ), Icr, MAXSELL-1);
  		if ( PageCount == mPage2 && MarkVar2 == 0 && Xvault4_[MAXSELL-2][f+1] == 32 ) {
                dc.TextOut(x1 + ( 6.00 * UnitsPerInch ), y1 - ( rr * UnitsPerInch ), totpay, MAXSELL-1);
		MarkVar2 = 1;
		}
  		rr = rr + 0.20;
  		f++;

  } while(f<50);

  var2[5]=0;
     dc.TextOut(x1 + ( 0.46 * UnitsPerInch ) + ext1, y1 - ( 0.20 * UnitsPerInch ), var2, 5);
	 Date_[MAXDAT-1]=0;
             dc.TextOut(x1 + ( 0.46 * UnitsPerInch ) + ext2, y1 - ( 0.40 * UnitsPerInch ), Date_,    MAXDAT-1);

dc.RestoreObjects();

}


This is what the print preview screen looks like.




HERE’S THE CODE FOR THE NAVIGATION AND PRINT BUTTONS

This next section will explore the coding used for the member functions of the “TPrevWindow” class. Immediately below I have included C++ code for navigating to the next page in the print preview window after the operator has clicked its “right arrow” button. As previously mentioned, it will move the file offset of the extracted check register binary data file “test_x.txt”, forward by 50 rows of check register transactions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

// this “PrnNext” member function of the “TPrevWindow”
// class will advance to the next page in the print
// preview window.
void
TPrevWindow::PrnNext()
{
  // declare variables for this function.
  int       fd,a,f,CountVar_,r,KountVar,ax;
  long int  ttt,maxout_,hold[13],accum,accum2;
  char      Runbal[MAXSELL],kh;
  streambuf *inn = cin.rdbuf();
  ifpstream ivfile;
  ldiv_t    n;

  // if the current page is less than the total
  // number of pages in the print preview 
  // operation, then increment the file stream
  // offset by an amount equivalent to 50 rows
  // of extracted check register data. also,
  // blank out the 2 2-dimensional char arrays
  // used to populate the print preview
  // window.
  if ( PageCount < mPage2 ) {
  PageCount++;
  maxapart = maxapart + ( 50 * MAXSELL );
	  for(a=0; a<50; a++) {
		  for(f=0; f<MAXSELL-1; f++) Xvault2_[f][a]=32;
			  for(f=0; f<MAXSELL-1; f++) Xvault4_[f][a]=32;
	  }

  // get the length of the extracted check register
  // data file and open a file stream to it. also,
  // initialize the variables used before commencing
  // the "do-while" loop.
  fd = open("test_x.txt", ios::binary);
  ttt = filelength(fd);
  close(fd);

  ivfile.open("test_x.txt", ios::in | ios::binary);
  inn = ivfile.rdbuf();
  CountVar_ = 0;
  KountVar = 0;
  maxout_ = maxapart;

  // loop around and fill the 2 2-dimensional
  // char arrays with the next 50 rows of
  // extracted check register data or to the end
  // of the data file, whichever comes first.
  do {

  inn -> seekpos(maxout_+MAXSELL-1, ios::in);
  kh=ivfile.readByte();

          // if it is a deposit transaction, then
          // add the amount to the char array, “Xvault2_”
          // and increment the row counter "CountVar_" by 1.
	  if ( kh == 'D' ) {
	  inn -> seekpos(maxout_, ios::in);
		  for(r=0; r<MAXSELL-1; r++) Xvault2_[r][CountVar_]=ivfile.readByte();
		  CountVar_++;
	  }

	          // if it is a withdrawal transaction, then
   	          // add the amount to the char array, “Xvault4_”
                  // and increment the row counter "KountVar" by 1.
		  if ( kh == 'W' ) {
		  inn -> seekpos(maxout_, ios::in);
			  for(r=0; r<MAXSELL-1; r++) Xvault4_[r][KountVar]=ivfile.readByte();
			  KountVar++;
		  }

  // advance to the next fixed width record in the extracted check book data file.
  maxout_ = maxout_ + MAXSELL;

  } while(CountVar_<50 && KountVar<50 && maxout_<ttt);
  ivfile.close();

  // update the scroller on the print preview window. then fire a message,
  // "WM_CHAR", which is a member function of the "TBalEndDlg" dialog class
  // to the handle of the decorated print preview window to update the left
  // and right navigation keys so they enable and/or disable based on the
  // current page number and the total pages in the print preview operation.
  Scroller->ScrollBy(100, 100);
  Scroller->ScrollBy(-100, -100);
  GetWindowPtr(hndl)->SendMessage(WM_CHAR, 0, 0);

  }

}


Here is the programming for navigating to the previous page in the print preview window after the operator has clicked the “left arrow” button.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

// this “PrnPrevious” member function of the “TPrevWindow”
// class will advance to the previous page in the print
// preview window.
void
TPrevWindow::PrnPrevious()
{
  // declare variables for this function.
  int       fd,a,f,CountVar_,r,KountVar,ax;
  long int  ttt,maxout_,hold[13],accum,accum2;
  char      Runbal[MAXSELL],kh;
  streambuf *inn = cin.rdbuf();
  ifpstream ivfile;
  ldiv_t    n;

  // if the current page is greater than one,
  // then decrement the file stream offset by
  // an amount equivalent to 50 rows of
  // extracted check register data. also,
  // blank out the 2 2-dimensional char arrays
  // used to populate the print preview
  // window.
  if ( PageCount > 1 ) {
  PageCount--;
  maxapart = maxapart - ( 50 * MAXSELL );
	  for(a=0; a<50; a++) {
		  for(f=0; f<MAXSELL-1; f++) Xvault2_[f][a]=32;
			  for(f=0; f<MAXSELL-1; f++) Xvault4_[f][a]=32;
	  }

  // get the length of the extracted check register
  // data file and open a file stream to it. also,
  // initialize the variables used before commencing
  // the "do-while" loop.
  fd = open("test_x.txt", ios::binary);
  ttt = filelength(fd);
  close(fd);

  ivfile.open("test_x.txt", ios::in | ios::binary);
  inn = ivfile.rdbuf();
  CountVar_ = 0;
  KountVar = 0;
  maxout_ = maxapart;

  // loop around and fill the 2 2-dimensional
  // char arrays with the next 50 rows of
  // extracted check register data or to the end
  // of the data file, whichever comes first.
  do {

  inn -> seekpos(maxout_+MAXSELL-1, ios::in);
  kh=ivfile.readByte();

          // if it is a deposit transaction, then
          // add the amount to the char array, “Xvault2_”
          // and increment the row counter "CountVar_" by 1.
	  if ( kh == 'D' ) {
	  inn -> seekpos(maxout_, ios::in);
		  for(r=0; r<MAXSELL-1; r++) Xvault2_[r][CountVar_]=ivfile.readByte();
		  CountVar_++;
	  }

	          // if it is a withdrawal transaction, then
   	          // add the amount to the char array, “Xvault4_”
                  // and increment the row counter "KountVar" by 1.
		  if ( kh == 'W' ) {
		  inn -> seekpos(maxout_, ios::in);
			  for(r=0; r<MAXSELL-1; r++) Xvault4_[r][KountVar]=ivfile.readByte();
			  KountVar++;
		  }

  // advance to the next fixed width record in the extracted check book data file.
  maxout_ = maxout_ + MAXSELL;

  } while(CountVar_<50 && KountVar<50 && maxout_<ttt);
  ivfile.close();

  // update the scroller on the print preview window. then fire a message,
  // "WM_CHAR", which is a member function of the "TBalEndDlg" dialog class
  // to the handle of the decorated print preview window to update the left
  // and right navigation keys so they enable and/or disable based on the
  // current page number and the total pages in the print preview operation.
  Scroller->ScrollBy(100, 100);
  Scroller->ScrollBy(-100, -100);
  GetWindowPtr(hndl)->SendMessage(WM_CHAR, 0, 0);

  }

}


The patch of code below fires after the operator has clicked the “printer” button on the print preview window. It will show a standard windows printer dialog box for selecting the needed printer. The operator can also specify the number of copies desired.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

// this “PrnImage” member function of the “TPrevWindow”
// class will display a print dialog on top of the print
// preview screen. it allows the operator to select the 
// desired printer to render print preview output to.
// the operator can also set the number of copies for
// the print operation via the
// “mData.GetDevMode()->dmCopies” directive. The other
// parameters of the print dialog could be processed,
// but the customer had no need for this added
// functionality.
void
TPrevWindow::PrnImage()
{
  // declare variables for this function.
  long int  ww,hold[13];
  int       r,a,totcopies,numberofcopies,pcounter;
  char      CheckNo[MAXSELL];
  ifpstream ifile;
  ofpstream ofile;
  ldiv_t    n;

  // set the “Printer” object to null and construct
  // the “mData” object from “TPrintDialog::TData”.
  // then set the “mPageDoc” variable to the number
  // of pages in the print preview operation.
  Printer = 0;
  TPrintDialog::TData mData;
  mPageDoc = mPage2;

	  // upon clicking the “OK” button in the printer
	  // dialog screen, proceed as follows.
	  if ( TPrintDialog(this, mData).Execute() == IDOK ) {

		  // get the number of copies desired from the
                  // printer dialog and multiply that by the 
                  // number of pages in the print preview operation.	
		  totcopies = mData.GetDevMode()->dmCopies;
		  mPage2 = mPage2 * totcopies;
		  // if the current print preview page is
		  // greater than 1, then scroll back the 
		  // print preview by 1 page until you are
		  // viewing the first page of the print preview.		
		  if ( PageCount > 1 ) {
		     do {
		     TPrevWindow::PrnPrevious();
		     } while(PageCount > 1);
		  }

			  // next, intialize a couple of variables and
			  // then render the print preview to the selected
			  // printer for the total number of printed
			  // copies desired.				
			  maxapart = 0;
			  pcounter = 0;
			  do {
			  numberofcopies = 0;
				  do {
				  Printer = new TPrinter;
				  T2Printout   printout("Reconciliation", this);
				  Printer->SetData(&mData);
				  Printer->Print(this, printout, false);
				  Printer = 0;
				  numberofcopies++;
				  } while(numberofcopies < totcopies);
				      if ( PageCount < mPageDoc) TPrevWindow::PrnNext();
			  pcounter++;
			  } while(PageCount <= mPageDoc && pcounter < mPageDoc);

  }

}


This is what appears after the “print” button has been clicked.




CODE FOR THE PRINT PREVIEW RENDERING TO A SELECTED PRINTER

After clicking the “Print” button on the printer dialog box, the output is rendered to the selected printer using the code below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

// this is the class declaration for the “T2Printout” class, which
// handles the rendering of what appears in the print preview window
// to a selected printer from the printer dialog.
//
// class T2Printout
// ~~~~~ ~~~~~~~~~~~~~
class T2Printout : public TPrintout {
  public:
	 T2Printout(const char* title, TWindow* window);
    
    void GetDialogInfo(int& minPage, int& maxPage, int& selFromPage, int& selToPage);
    void PrintPage(int page, TRect& rect, unsigned flags);
    void SetBanding(bool b) {Banding = b;}
    bool HasPage(int pageNumber) {return pageNumber == 1;}

  protected:
	 TWindow* Window;
	 BOOL     Scale;
};

// instantiate the “T2Printout” class.
T2Printout::T2Printout(const char* title, TWindow* window)
  : TPrintout(title)
{
  Window = window;
  Scale = TRUE;
}

// initialize the default parameters for the minimum and
// the maximum number of pages as well as the selected
// number of pages to print. these range from 1 to the
// number of pages in the print preview. there is no
// additional programming to change these parameters
// in this case.
void
T2Printout::GetDialogInfo(int& minPage, int& maxPage, int& selFromPage, int& selToPage)
{
  minPage = 1;
  maxPage = mPage2;
  selFromPage = 1;
  selToPage = mPage2;
}

// this will render the print preview output onto the selected printer.
void
T2Printout::PrintPage(int page, TRect& rect, unsigned flags)
{
  // scale the DC (device context) to the window so the
  // printout will mirror the print preview window. notice
  // that the mapping mode is calibrated in “LOENGLISH”
  // units. this unit of measure equates 100 logical device
  // units to one inch of screen width.
  //
  // declare variables for this function.
  int    prevMode;
  TSize  oldVExt, oldWExt;

  if (Scale) {
    prevMode = DC->SetMapMode(MM_LOENGLISH);
    TRect windowSize = Window->GetClientRect();
    DC->SetWindowExt(windowSize.Size(), &oldWExt);
    DC->SetViewportExt(PageSize, &oldVExt);
    DC->DPtoLP(rect, 2);
  }

  // call the window to paint itself.
  Window->Paint(*DC, FALSE, rect);

  // restore changes made to the DC (device context).
  if (Scale) {
    DC->SetWindowExt(oldWExt);
    DC->SetViewportExt(oldVExt);
    DC->SetMapMode(prevMode);
  }

}


CONCLUSION

This print preview code has proven itself to work reliably in Windows ME, XP, Vista and 7. If you are coding in the Borland C++ 5.02 platform, it will serve as a decent framework for facilitating a print preview operation. Some of my best customers have used this for years. Aside from my programming services, please visit my website to learn more about my computer repair services and my "fix my computer" technical tips.