• 文章
  • Borland C++ 5.02 打印预览代码
发布
2014年1月23日 (最后更新:2014年6月16日)

Borland C++ 5.02 打印预览窗口代码

评分:4.2/5 (41票)
*****
引言

多年来,我一直使用 Borland C++ 5.02 版本为本地小型企业编码 应用程序开发 项目。它是一个非常健壮的 软件 平台,而这些 定制软件 项目的基石就是“打印预览”功能。在这里,我将展示一个支票登记对账的示例,该示例利用了我的 开发人员技能 来创建一个“打印预览”功能。

声明所需的 C++ 类

首先需要声明打印预览窗口所需的类。“TPrevWindow”类是从 OWL(对象窗口库)中的“TWindow”基类派生的。它包含了页面导航和打印的成员函数。该类中的响应表将定义的位图图像常量与其对应的成员函数关联起来。

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;


接下来,我们需要声明“TDialog”基类的对话框类“TBalEndDlg”,它将负责接受用户输入、提取数据等,为即将进行的打印预览操作做准备。

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;


接下来,设置打印预览

这是从用于主程序窗口的“TTestWindow”类运行“TBalEndDlg”对话框的命令。用于创建用户输入屏幕的资源是“IDD_STATEMENTBAL”。主窗口类“TTestWindow”中用于构造输入控件传输机制的指令是“TBalEndStruct BalEndStruct;”。对象“BalEndStruct”在下面调用运行“TBalEndDlg”对话框时指定。

1
2
3
4
5
6
7
8
9
10
11

void
TTestWindow::Reconciliation()
{

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

 }

}


下面是“IDD_STATEMENTBAL”对话框资源编码的样子。

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
}


这是运行时输入屏幕的样子。




接下来的这段 C++ 代码将在“TBalEndDlg”对话框调用发生后执行。它将开始为打印预览过程做准备,首先接受一个起始余额和结束日期。这些将用于随后的数据提取过程,该过程在上述对话框资源中的“OK”按钮被点击后进行。完成此操作后,它将根据每页 50 行计算页数。然后,它将从“TDecoratedFrame”基类构造一个“frame_d”对象。它将初始化各种设置,包括嵌入了成员函数按钮的控件栏。它还将设置打印预览窗口的尺寸,并根据为打印预览操作计算的总页数启用和禁用导航按钮。您还会注意到我在文件输入/输出操作中使用了定义的常量。这些常量用于设置文件流中读取和写入与 编程 配合使用的二进制固定长度数据文件的偏移量。

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
510

// 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  datecomponent,monthvar,dayvar,yearvar;
  int          a,t,b;
  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);
  monthvar = d.month;
  dayvar = d.day;
  yearvar = 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) datecomponent = monthvar;
			  if(t == 1) datecomponent = dayvar;
			  if(t == 2) {
			  datecomponent = yearvar;
				  // y2k adjustment.	
				  if (datecomponent < 2000 )
				  datecomponent = datecomponent - 1900;
				  else
				  datecomponent = datecomponent - 2000;
				      }

  var[0] = 48;
  var[1] = 48;
  var[2] = 32;
  b=1;
  do {
  n=ldiv(datecomponent,10L);
  datecomponent =n.quot;
		if(n.rem==0) var[b] = 48;
	  	if(n.rem==1) var[b] = 49;
		if(n.rem==2) var[b] = 50;
		if(n.rem==3) var[b] = 51;
		if(n.rem==4) var[b] = 52;
		if(n.rem==5) var[b] = 53;
		if(n.rem==6) var[b] = 54;
  		if(n.rem==7) var[b] = 55;
	  	if(n.rem==8) var[b] = 56;
		if(n.rem==9) var[b] = 57;
  b--;
  } while(datecomponent > 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,fileinfo,f,r,date_compare,b,ff;
  long int   fileoffset, sizeofdatafile,accum,accum2,startbal,convert_to_number[MAXSELL],endbal, enddate_month;
  long int   enddate_day, enddate_year, transdate_month, transdate_day, transdate_year;
  char       kh,ch,dh,eh,transaction_date[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 retrieved 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 retrieved ending date into month, day and year numerical
  // components for further processing.
  a=0;
  do {

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

  for(ff=0; ff<2; ff++) {
  convert_to_number[ff] = 0;
  if(EndDate[b+ff] == 48) convert_to_number[ff] = 0;
  if(EndDate[b+ff] == 49) convert_to_number[ff] = 1;
  if(EndDate[b+ff] == 50) convert_to_number[ff] = 2;
  if(EndDate[b+ff] == 51) convert_to_number[ff] = 3;
  if(EndDate[b+ff] == 52) convert_to_number[ff] = 4;
  if(EndDate[b+ff] == 53) convert_to_number[ff] = 5;
  if(EndDate[b+ff] == 54) convert_to_number[ff] = 6;
  if(EndDate[b+ff] == 55) convert_to_number[ff] = 7;
  if(EndDate[b+ff] == 56) convert_to_number[ff] = 8;
  if(EndDate[b+ff] == 57) convert_to_number[ff] = 9;
  }
  if(a == 0) enddate_month = (convert_to_number[0] * 10) + (convert_to_number[1] * 1);
  if(a == 1) enddate_day = (convert_to_number[0] * 10) + (convert_to_number[1] * 1);
  if(a == 2) {
  enddate_year = (convert_to_number[0] * 10) + (convert_to_number[1] * 1);
  // include y2k adjustment.
  if(enddate_year >= 80) enddate_year = enddate_year + 1900;
  if(enddate_year < 80) enddate_year = enddate_year + 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) convert_to_number[a]=0;
	  if(StartingAmt[a] == 49) convert_to_number[a]=1;
	  if(StartingAmt[a] == 50) convert_to_number[a]=2;
	  if(StartingAmt[a] == 51) convert_to_number[a]=3;
	  if(StartingAmt[a] == 52) convert_to_number[a]=4;
	  if(StartingAmt[a] == 53) convert_to_number[a]=5;
  	  if(StartingAmt[a] == 54) convert_to_number[a]=6;
	  if(StartingAmt[a] == 55) convert_to_number[a]=7;
	  if(StartingAmt[a] == 56) convert_to_number[a]=8;
	  if(StartingAmt[a] == 57) convert_to_number[a]=9;
	  }
  startbal = ( (convert_to_number[0] * 100000000) + (convert_to_number[1] * 10000000) + (convert_to_number[2] * 1000000) +
  (convert_to_number[3] * 100000) + (convert_to_number[4] * 10000) + (convert_to_number[5] * 1000) + (convert_to_number[6] * 100) + (convert_to_number[8] * 10) + (convert_to_number[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;

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

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

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

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

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

  a = 0;
  do {

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

  for(ff=0; ff<2; ff++) {
  convert_to_number[ff] = 0;
  if(transaction_date [b+ff] == 48) convert_to_number[ff] = 0;
  if(transaction_date [b+ff] == 49) convert_to_number[ff] = 1;
  if(transaction_date [b+ff] == 50) convert_to_number[ff] = 2;
  if(transaction_date [b+ff] == 51) convert_to_number[ff] = 3;
  if(transaction_date [b+ff] == 52) convert_to_number[ff] = 4;
  if(transaction_date [b+ff] == 53) convert_to_number[ff] = 5;
  if(transaction_date [b+ff] == 54) convert_to_number[ff] = 6;
  if(transaction_date [b+ff] == 55) convert_to_number[ff] = 7;
  if(transaction_date [b+ff] == 56) convert_to_number[ff] = 8;
  if(transaction_date [b+ff] == 57) convert_to_number[ff] = 9;
  }
  if(a == 0) transdate_month = convert_to_number[0]*10 + convert_to_number[1]*1;
  if(a == 1) transdate_day = convert_to_number[0]*10 + convert_to_number[1]*1;
  if(a == 2) {
  transdate_year = (convert_to_number[0] * 10) + (convert_to_number[1] * 1);
  // include y2k adjustment.
  if(transdate_year >= 80) transdate_year = transdate_year + 1900;
  if(transdate_year < 80) transdate_year = transdate_year + 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.
  date_compare = 1;
  if(transdate_year < enddate_year) date_compare = 0;

	  if(transdate_year == enddate_year && transdate_month < enddate_month) date_compare = 0;

		  if(transdate_year == enddate_year && transdate_month == enddate_month) {
			  if(transdate_day <= enddate_day) date_compare = 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' && date_compare == 0 ) {
	inn -> seekpos(fileoffset+MAXDAT+MAXINVNO+MAXSELL+MAXNOTE2+MAXSELL+MAXSELL
	+MAXSELL+MAXCCODE+MAXCOMPANY2+MAXSELL+MAXANS+MAXANS-12, ios::in);
			  for(a=0; a<MAXSELL-1; a++) ofile.writeByte(ifile.readByte());
			  ofile.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' && date_compare == 0 ) {
  inn -> seekpos(fileoffset+MAXDAT+MAXINVNO+MAXSELL+MAXNOTE2+MAXSELL-5, ios::in);
			  for(a=0; a<MAXSELL-1; a++) ofile.writeByte(ifile.readByte());
			  ofile.writeByte('W');
			  PickVar++;
  }

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

  } while(fileoffset < sizeofdatafile);
  ifile.close();
  ofile.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.
  fileinfo = open("test_x.txt", ios::binary);
  sizeofdatafile = filelength(fileinfo);
  close(fileinfo);

  ifile.open("test_x.txt", ios::in | ios::binary);
  inn = ifile.rdbuf();
  CountVar_ = 0;
  KountVar = 0;
  fileoffset = 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(fileoffset+MAXSELL-1, ios::in);
  kh = ifile.readByte();
  inn -> seekpos(fileoffset, ios::in);
  for(a=0; a<MAXSELL; a++) ExtractedAmt[a] = ifile.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++) {
  convert_to_number[a]=0;
  if(StartingAmt[a] == 48) convert_to_number[a] = 0;
  if(StartingAmt[a] == 49) convert_to_number[a] = 1;
  if(StartingAmt[a] == 50) convert_to_number[a] = 2;
  if(StartingAmt[a] == 51) convert_to_number[a] = 3;
  if(StartingAmt[a] == 52) convert_to_number[a] = 4;
  if(StartingAmt[a] == 53) convert_to_number[a] = 5;
  if(StartingAmt[a] == 54) convert_to_number[a] = 6;
  if(StartingAmt[a] == 55) convert_to_number[a] = 7;
  if(StartingAmt[a] == 56) convert_to_number[a] = 8;
  if(StartingAmt[a] == 57) convert_to_number[a] = 9;
  }
  // accumulate for deposit transactions into the variable “accum”.
  if ( kh == 'D' ) accum = accum + ( (convert_to_number[0] * 100000000) + (convert_to_number[1] * 10000000) + (convert_to_number[2] * 1000000) +
  (convert_to_number[3] * 100000) + (convert_to_number[4] * 10000) + (convert_to_number[5] * 1000) + (convert_to_number[6] * 100) + (convert_to_number[8] * 10) + (convert_to_number[9] * 1) );
  // accumulate for withdrawal transactions into the variable “accum2”.
  if ( kh == 'W' ) accum2 = accum2 + ( (convert_to_number[0] * 100000000) + (convert_to_number[1] * 10000000) + (convert_to_number[2] * 1000000) +
  (convert_to_number[3] * 100000) + (convert_to_number[4] * 10000) + (convert_to_number[5] * 1000) + (convert_to_number[6] * 100) + (convert_to_number[8] * 10) + (convert_to_number[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(fileoffset, ios::in);
		      for(r=0; r<MAXSELL-1; r++) Xvault2_[r][CountVar_] = ifile.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(fileoffset, ios::in);
				  	for(r=0; r<MAXSELL-1; r++) Xvault4_[r][KountVar] = ifile.readByte();
				  	KountVar++;
		  }

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

  } while(fileoffset < sizeofdatafile);
  ifile.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,
// “fileoffset”. 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;
fileoffset = 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);
 }

}


为屏幕上的打印预览编写代码

下面是“TPrevWindow”类中的“Paint(TDC& dc, bool erase, TRect& rect)”成员组件下的代码,它将在数据提取处理完成后出现的装饰窗口框架中绘制打印预览信息。

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

void
TPrevWindow::Paint(TDC& dc, bool erase, TRect& rect)
{
  // declare variables for this function.
  long int   datecomponent,monthvar,dayvar,yearvar, pagevar;
  int          exta,a,b,f,r,t,ext1,ext2,ext3,ext4,ext44,MarkVar1,MarkVar2,ext5,ext6,ext7;
  float       linecounter;
  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”.	
  Pagevar = PageCount;
  for(a=0; a<5; a++) var2[a] = 32;
  var2[4] = 48;
  b=4;
  do {
  n = ldiv(pagevar,10L);
  pagevar = n.quot;
  if(n.rem==0) var2[b] = 48;
  if(n.rem==1) var2[b] = 49;
  if(n.rem==2) var2[b] = 50;
  if(n.rem==3) var2[b] = 51;
  if(n.rem==4) var2[b] = 52;
  if(n.rem==5) var2[b] = 53;
  if(n.rem==6) var2[b] = 54;
  if(n.rem==7) var2[b] = 55;
  if(n.rem==8) var2[b] = 56;
  if(n.rem==9) var2[b] = 57;
  b--;
  } while(pagevar > 0);
  var2[5]=0;


  // take the current date components month, day and year and
  // convert to chars to be stored in the char array “Date_”.	
  _dos_getdate(&d);
  monthvar = d.month;
  dayvar = d.day;
  yearvar = 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) datecomponent = monthvar;
			  if(t == 1) datecomponent = dayvar;
			  if(t == 2) {
			  datecomponent = yearvar;
				  // y2k adjustment.	
				  if (datecomponent < 2000 )
				  datecomponent = datecomponent - 1900;
				  else
				  datecomponent = datecomponent - 2000;
				      }

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


  // 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);

  linecounter = 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;
		}
  		linecounter = linecounter + 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();
}

这就是打印预览屏幕的样子。




导航和打印按钮的代码来了

下一部分将探讨用于“TPrevWindow”类成员函数的代码。下面我包含了在操作员单击打印预览窗口的“右箭头”按钮后导航到下一页的 C++ 代码。如前所述,它会将提取的支票登记二进制数据文件“test_x.txt”的文件偏移量向前移动 50 行支票登记交易。

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

// 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          fileinfo,a,f,CountVar_,r,KountVar,b;
  long int   sizeofdatafile,fileoffset_local, convert_to_number[13],accum,accum2;
  char       Runbal[MAXSELL],kh;
  streambuf *inn = cin.rdbuf();
  ifpstream ifile;
  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++;
  fileoffset = fileoffset + ( 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.
  fileinfo = open("test_x.txt", ios::binary);
  sizeofdatafile = filelength(fileinfo);
  close(fileinfo);

  ifile.open("test_x.txt", ios::in | ios::binary);
  inn = ifile.rdbuf();
  CountVar_ = 0;
  KountVar = 0;
  fileoffset_local = fileoffset;

  // 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(fileoffset_local+MAXSELL-1, ios::in);
  kh = ifile.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(fileoffset_local, ios::in);
		  for(r=0; r<MAXSELL-1; r++) Xvault2_[r][CountVar_] = ifile.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(fileoffset_local, ios::in);
			  for(r=0; r<MAXSELL-1; r++) Xvault4_[r][KountVar] = ifile.readByte();
			  KountVar++;
		  }
 // advance to the next fixed width record in the extracted check book data file.
 fileoffset_local = fileoffset_local + MAXSELL;

  } while(CountVar_< 50 && KountVar < 50 && fileoffset_local < sizeofdatafile);
  ifile.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);

  }

}


这是操作员单击打印预览窗口的“左箭头”按钮后导航到上一页的编程。

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

// 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          fileinfo,a,f,CountVar_,r,KountVar,b;
  long int   sizeofdatafile,fileoffset_local, convert_to_number[13],accum,accum2;
  char       Runbal[MAXSELL],kh;
  streambuf *inn = cin.rdbuf();
  ifpstream ifile;
  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--;
  fileoffset = fileoffset - ( 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.
 fileinfo = open("test_x.txt", ios::binary);
 sizeofdatafile = filelength(fileinfo);
 close(fileinfo);

  ifile.open("test_x.txt", ios::in | ios::binary);
  inn = ifile.rdbuf();
  CountVar_ = 0;
  KountVar = 0;
  fileoffset_local = fileoffset;

  // 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(fileoffset_local+MAXSELL-1, ios::in);
  kh = ifile.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(fileoffset_local, ios::in);
		  for(r=0; r<MAXSELL-1; r++) Xvault2_[r][CountVar_] = ifile.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(fileoffset_local, ios::in);
			  for(r=0; r<MAXSELL-1; r++) Xvault4_[r][KountVar] = ifile.readByte();
			  KountVar++;
		  }

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

  } while(CountVar_< 50 && KountVar < 50 && fileoffset_local < sizeofdatafile);
  ifile.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);

  }

}


下面的代码块在操作员单击打印预览窗口的“打印机”按钮后触发。它将显示一个标准的 Windows 打印机对话框,用于选择所需的打印机。操作员还可以指定所需的份数。

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

// 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.
  int          totcopies,numberofcopies,pcounter;

  // 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 with 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.				
			  fileoffset = 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);

  }

}


这是单击“打印”按钮后出现的内容。




将打印预览渲染到所选打印机的代码

单击打印对话框上的“打印”按钮后,下面的代码将输出渲染到所选打印机。

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);
  }

}


结论

这段打印预览代码已被证明可以在 Windows ME、XP、Vista 和 7 中可靠运行。如果您使用 Borland C++ 5.02 平台进行编码,它将为实现打印预览操作提供一个不错的框架。我的一些 最好的 客户多年来一直使用它。除了我的 编程 服务外,请访问我的网站以了解更多关于我的 电脑维修 服务和我的 “修理我的电脑” 技术技巧。