Recent

Author Topic: PrintViewer  (Read 15239 times)

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #15 on: September 03, 2016, 04:43:56 pm »
This activates by a button, and deactivates by the same button... as a toggle.

PageMemo is a TRichMemo.
PaperArea is a panel... the code will size it.
TextArea is a TImage. It should be placed on the PaperArea panel.
It will also be sized by the code.
The PaperArea.visible should be set to false.
The code will turn it on and off.

It will walk through the pages... with NEXT popup for advancing.
When all pages have been shown, a DONE popup will show.
To exit toggle your View button again.

As is, this is just a "look at" routine to see if you want to edit your document.

Code: Pascal  [Select]
  1. procedure TCmdForm.ViewPageClick(Sender: TObject);
  2. var
  3.   fr: TFormatRange;
  4.   dc: THandle;
  5.   ox, oy, w, h: LongInt;
  6.   cpMin: LRESULT;
  7.   c: Integer;
  8.   PgWide, PgHigh, PgSide, PgHead, InchW, InchH: double;
  9.   PixHigh, PixWide: integer;
  10.   PageAvialable: boolean;
  11. begin
  12.   if PaperArea.visible=false then
  13.      begin
  14.         PgWide:= 8.5; PgHigh:= 11.0; PgSide:= 1.0; PgHead:= 1.0;
  15.  
  16.         // setup the TextArea dimensions
  17.         PaperArea.top:= 40;
  18.         PaperArea.height:= round(PgHigh * Screen.PixelsPerInch) div 2;
  19.         PaperArea.width:= round(PgWide * Screen.PixelsPerInch) div 2;
  20.         PaperArea.left:= (PageMemo.width - PaperArea.width) div 2;
  21.  
  22.         InchH:= PgHigh/2 - PgHead; // Phead is half of head and tail
  23.         InchW:= PgWide/2 - PgSide;  // Pside is half of left and right
  24.         PixHigh:= round(InchH * Screen.PixelsPerInch); // standard = 96 per inch
  25.         PixWide:= round(InchW * Screen.PixelsPerInch); // twips are 1440 per inch
  26.  
  27.         // setup the printable region
  28.         TextArea.Top:= Screen.PixelsPerInch div 2;   // half of screen pixels per inch
  29.         TextArea.height:= PixHigh;
  30.         TextArea.width:= PixWide;
  31.         TextArea.left:= Screen.PixelsPerInch div 2;  // half of screen pixels per inch
  32.         TextArea.Picture.Bitmap.SetSize(round(PixWide * 2), round(PixHigh * 2));  // *2 for half size
  33.         PaperArea.visible:= true;
  34.  
  35.         // restart and clear the canvas
  36.         TextArea.Canvas.Brush.Color:= clWindow;
  37.         TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  38.         TextArea.Canvas.MoveTo(0, 0);
  39.  
  40.         dc:= TextArea.Canvas.Handle;
  41.  
  42.         ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  43.         oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  44.         w:= XPixToTwips(PixWide * 2);  //GetDeviceCaps(dc, PHYSICALWIDTH);   // *2 for half size
  45.         h:= YPixToTwips(PixHigh * 2);  //GetDeviceCaps(dc, PHYSICALHEIGHT);  // *2 for half size
  46.  
  47.         fr.hdc:= dc;       // fr._hdc := dc; **on another system**
  48.         fr.hdcTarget:= dc;
  49.  
  50.         fr.rc.Left:= ox;
  51.         fr.rc.Right:= ox+w;
  52.  
  53.         fr.rc.Top:= oy;
  54.         fr.rc.Bottom:= oy+h;
  55.  
  56.         SendMessage(PageMemo.Handle, EM_SETSEL, 0, -1);
  57.         SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));
  58.         SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);
  59.  
  60.         PageAvialable:= true;
  61.         while (fr.chrg.cpMin<fr.chrg.cpMax) and (PageAvialable) do
  62.               begin
  63.               cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  64.               if (cpMin<=fr.chrg.cpMin) then
  65.                  begin
  66.                    PageAvialable:= false; //  document has no content
  67.                    break;
  68.                  end;
  69.               fr.chrg.cpMin:= cpMin;
  70.               PageAvialable:= EndPage(fr.hdc) > 0;
  71.               if (fr.chrg.cpMin<fr.chrg.cpMax) then
  72.                  begin
  73.                  showmessage('Next');
  74.                  TextArea.Canvas.Brush.Color:= clWindow;
  75.                  TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  76.                  TextArea.Canvas.MoveTo(0, 0);
  77.                  PageAvialable:= true;
  78.                  end;
  79.               end;
  80.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0);
  81.         showmessage('Done');
  82.  
  83.         if PageAvialable
  84.            then EndDoc(fr.hdc)
  85.            else AbortDoc(fr.hdc);
  86.  
  87.         TextArea.Picture.Bitmap.Canvas.Changed;
  88.      end else PaperArea.visible:= false;
  89. end;  
  90.  

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #16 on: September 05, 2016, 02:34:26 pm »
This is an upgrade to ViewPage. It has 7 variables that could be made global to control page dimensions and its preview scale. They are noted.

This version can count the sum of pages, display the current page number, and navigate back and forward among the pages.

I have compared the page formatting to WordPad, and it has identical paging.

It uses a modal interrupter to manage the page navigation. I don't like it but I couldn't see any other way for arresting the page view. It does, however, permit you drag it around to get it out of the way.

If any of you have been downloading the code, please note that I have changed some of the variables in this version. I have also made extensive revisions on the entire code.

Perhaps some of you can improve on the project. If so, please post it.

Code: Pascal  [Select]
  1. procedure TCmdForm.ViewPageClick(Sender: TObject);
  2. var
  3.   fr: TFormatRange;
  4.   dc: THandle;
  5.   ox, oy, w, h: LongInt;
  6.   cpMin: LRESULT;
  7.   x: Integer;
  8.   PgWide, PgHigh, PgLft, PgRht, PgTop, PgBtm, InchW, InchH, ViewScale: double;
  9.   PixHigh, PixWide, ViewChg, BegChar, PgCnt, PgSum: integer;
  10.   MorePages: boolean;
  11.   BackPages, xstr, PgStr: string;
  12.  
  13. begin
  14.   if PaperArea.visible=false then
  15.      begin
  16.         // define paper size
  17.         // these 7 can be global for changeable paper size and display
  18.         PgWide:= 8.5; PgHigh:= 11.0;
  19.         PgLft:= 1.0; PgRht:= 1.0;
  20.         PgTop:= 1.0; PgBtm:= 1.0;
  21.         ViewScale:= 2; // display size: 0.5=double, 1.0=full, 2.0=half
  22.  
  23.         // setup the PaperArea metrics
  24.         PaperArea.top:= 40;  // 40 fits my layout
  25.         PaperArea.height:= Round(PgHigh * Screen.PixelsPerInch / ViewScale);
  26.         PaperArea.width:= Round(PgWide * Screen.PixelsPerInch / ViewScale);
  27.         PaperArea.left:= Round((PageMemo.width - PaperArea.width) / 2);  // centering view page
  28.  
  29.         // setup the TextArea metrics
  30.         InchH:= PgHigh - PgTop - PgBtm;
  31.         InchW:= PgWide - PgLft - PgRht;
  32.         PixHigh:= Round(InchH * Screen.PixelsPerInch / ViewScale);
  33.         PixWide:= Round(InchW * Screen.PixelsPerInch / ViewScale);
  34.  
  35.         // setup the TextArea position
  36.         TextArea.Top:= Round((Screen.PixelsPerInch * PgTop) / ViewScale);
  37.         TextArea.height:= PixHigh;
  38.         TextArea.width:= PixWide;
  39.         TextArea.left:= Round((Screen.PixelsPerInch * PgLft) / ViewScale);
  40.         TextArea.Picture.Bitmap.SetSize(Round(PixWide * ViewScale), Round(PixHigh * ViewScale));
  41.  
  42.         // get the page count
  43.         cpMin:= 0; PgSum:= 0; MorePages:= true;
  44.         while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
  45.               begin
  46.               // clear the image canvas
  47.               TextArea.Canvas.Brush.Color:= clWindow;
  48.               TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  49.               TextArea.Canvas.MoveTo(0, 0);
  50.  
  51.               // set the printing metrics
  52.               dc:= TextArea.Canvas.Handle;
  53.               ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  54.               oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  55.               w:= XPixToTwips(Round(PixWide * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  56.               h:= YPixToTwips(Round(PixHigh * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  57.               FillChar(fr, SizeOf(TFormatRange), 0);
  58.               fr.hdc:= dc;       // fr._hdc := dc; **on another system**
  59.               fr.hdcTarget:= dc;
  60.               fr.rc.Left:= ox;
  61.               fr.rc.Right:= ox+w;
  62.               fr.rc.Top:= oy;
  63.               fr.rc.Bottom:= oy+h; //
  64.               fr.chrg.cpMin:= cpMin;
  65.               SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0);  // hide selection
  66.               SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  67.               SendMessage(PageMemo.Handle, EM_SETSEL, cpMin, -1);  // select to end of document
  68.               SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  69.               SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  70.               SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  71.  
  72.               cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  73.               SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  74.  
  75.               if (fr.chrg.cpMin=fr.chrg.cpMax)
  76.                  then MorePages:= false
  77.                  else PgSum:= PgSum + 1;
  78.               end;
  79.  
  80.         // print each page
  81.         MorePages:= true; ViewChg:= 0;
  82.         cpMin:= 0; BackPages:=''; BegChar:= 0;
  83.         PaperArea.visible:= true; PgCnt:= 0;
  84.         while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
  85.               begin
  86.               if (ViewChg<0) then
  87.                  begin
  88.                  x:= pos(',',BackPages);
  89.                  if x>0 then delete(BackPages,1,x);
  90.                  x:= pos(',',BackPages);
  91.                  if x>0 then
  92.                     begin
  93.                     xstr:= copy(BackPages,1,x-1);
  94.                     delete(BackPages,1,x);
  95.                     cpMin:= StrToInt(xstr);
  96.                     PgCnt:= PgCnt - 2;
  97.                     if cpMin<0 then
  98.                        begin
  99.                        cpMin:= 0; BackPages:='';
  100.                        PgCnt:= 0;
  101.                        end;
  102.                     end else begin
  103.                              cpMin:= 0; BackPages:='';
  104.                              PgCnt:= 0;
  105.                              end;
  106.                  end;
  107.               BackPages:= IntToStr(cpMin)+','+BackPages; //showmessage(BackPages);
  108.               ViewChg:= 0;
  109.               BegChar:= cpMin; //showmessage(IntToStr(BegChar));
  110.  
  111.               // clear the image canvas
  112.               TextArea.Canvas.Brush.Color:= clWindow;
  113.               TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  114.               TextArea.Canvas.MoveTo(0, 0);
  115.  
  116.               // set the printing metrics
  117.               dc:= TextArea.Canvas.Handle;
  118.               ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  119.               oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  120.               w:= XPixToTwips(Round(PixWide * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  121.               h:= YPixToTwips(Round(PixHigh * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  122.               FillChar(fr, SizeOf(TFormatRange), 0);
  123.               fr.hdc:= dc;       // fr._hdc := dc; **on another system**
  124.               fr.hdcTarget:= dc;
  125.               fr.rc.Left:= ox;
  126.               fr.rc.Right:= ox+w;
  127.               fr.rc.Top:= oy;
  128.               fr.rc.Bottom:= oy+h; //
  129.               fr.chrg.cpMin:= cpMin;
  130.               SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0); // hide selection
  131.               SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  132.               SendMessage(PageMemo.Handle, EM_SETSEL, cpMin, -1);  // select to end of document
  133.               SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  134.               SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  135.               SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  136.  
  137.               cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  138.               SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  139.  
  140.               if (cpMin<=fr.chrg.cpMin) then
  141.                   begin
  142.                    MorePages:= false; //  document has no content
  143.                    break;
  144.                   end;
  145.  
  146.               fr.chrg.cpMin:= cpMin;  // set to start of next page
  147.               PgCnt:= PgCnt + 1;
  148.               PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
  149.               PgStr:= PgStr+IntToStr(PgSum)+' Pages';
  150.  
  151.               if (BegChar=0) then // pause at first-page
  152.                  begin
  153.                  case QuestionDlg (PgStr,'Navigation at Home',mtCustom,
  154.                                    [mrCancel, 'Quit', mrYes, 'Next'],'') of
  155.                       mrYes: ViewChg:= 1;
  156.                       mrCancel: MorePages:= false;
  157.                       end;
  158.                  end  else if (fr.chrg.cpMin<fr.chrg.cpMax) then // pause at each-page
  159.                            begin
  160.                            case QuestionDlg (PgStr,'Page Navigation',mtCustom,
  161.                                              [mrNo,'Back', mrCancel, 'Quit', mrYes, 'Next'],'') of
  162.                                 mrNo: ViewChg:= -1;
  163.                                 mrYes: ViewChg:= 1;
  164.                                 mrCancel: MorePages:= false;
  165.                                 end;
  166.                            end;
  167.               if (fr.chrg.cpMin=fr.chrg.cpMax) then // pause at last-page
  168.                  begin
  169.                  case QuestionDlg (PgStr,'Navigation at End',mtCustom,
  170.                                    [mrNo,'Back', mrCancel, 'Quit'],'') of
  171.                       mrNo: ViewChg:= -1;
  172.                       mrCancel: MorePages:= false;
  173.                       end;
  174.                  end;
  175.               TextArea.Canvas.Brush.Color:= clWindow;
  176.               TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  177.               TextArea.Canvas.MoveTo(0, 0);
  178.               end;
  179.  
  180.         // clean up
  181.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  182.         if MorePages
  183.            then EndDoc(fr.hdc) // close EM_FORMATRANGE
  184.            else AbortDoc(fr.hdc);
  185.         TextArea.Picture.Bitmap.Canvas.Changed;  // reset image event
  186.         PaperArea.visible:= false;
  187.      end else begin
  188.               SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  189.               if MorePages
  190.                  then EndDoc(fr.hdc) // close EM_FORMATRANGE
  191.                  else AbortDoc(fr.hdc);
  192.               TextArea.Picture.Bitmap.Canvas.Changed;  // reset image event
  193.               PaperArea.visible:= false;
  194.               end;
  195. end;
  196.  

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #17 on: September 06, 2016, 01:41:33 pm »
I have found an odd behavior... only a TButton can allow the ViewPage procedure to display the PaperArea panel.

TToolbar button, TMainMenu item, and TBitBtn will not allow it to show. It blinks on, and then it is gone. What would cause that to happen?

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: PrintViewer
« Reply #18 on: September 06, 2016, 02:28:20 pm »
Most likely because fr is not initialized before hitting this while loop:
Code: Pascal  [Select]
  1.   if PaperArea.visible=false then
  2.      begin
  3. ...
  4.         // get the page count
  5.         cpMin:= 0; PgSum:= 0; MorePages:= true;
  6.         while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
  7. ...

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #19 on: September 06, 2016, 04:06:19 pm »
engkin,

Yes, that was the problem. I thought it could be an issue when I reconstructed the code, but it didn't show any defect while using the Tbutton, so I thought it was OK.

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #20 on: September 06, 2016, 07:20:41 pm »
engkin,

The following is a change to initialization code. But it still has an odd behavior. The SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0) command doesn't work with the TtoolButton, but it does with the Tbutton. Yet if I page through a few pages by the Tbutton, then the TtoolButton can do the EM_HIDESELECTION just fine.

As a temporary fix I am masking over the RichMemo screen with a panel that is set to "align client." I can't stand the flicker and flash.

Since Tbutton makes TtoolButton work, it must be an uninitialized variable, but I can't figure it out. How can any variable effect EM_HIDESELECTION ?

Code: Pascal  [Select]
  1. procedure TCmdForm.DisplayPages(Sender: TObject);
  2. var
  3.   fr: TFormatRange;
  4.   dc: THandle;
  5.   ox, oy, w, h: LongInt;
  6.   cpMin: LRESULT;
  7.   x: Integer;
  8.   PgWide, PgHigh, PgLft, PgRht, PgTop, PgBtm, InchW, InchH, ViewScale: double;
  9.   PixHigh, PixWide, ViewChg, BegChar, PgCnt, PgSum: integer;
  10.   MorePages: boolean;
  11.   BackPages, xstr, PgStr: string;
  12.  
  13. begin
  14.   // define paper size... these 7 can be global for paper size and display
  15.   PgWide:= 8.5; PgHigh:= 11.0;
  16.   PgLft:= 1.0; PgRht:= 1.0;
  17.   PgTop:= 1.0; PgBtm:= 1.0;
  18.   ViewScale:= 2; // display size: 0.5=double, 1.0=full, 2.0=half
  19.  
  20.   // setup the PaperArea metrics
  21.   PaperArea.top:= 0;  // 40 fits my layout
  22.   PaperArea.height:= Round(PgHigh * Screen.PixelsPerInch / ViewScale);
  23.   PaperArea.width:= Round(PgWide * Screen.PixelsPerInch / ViewScale);
  24.   PaperArea.left:= Round((PageMemo.width - PaperArea.width) / 2);  // centering view page
  25.  
  26.   // setup the TextArea metrics
  27.   InchH:= PgHigh - PgTop - PgBtm;
  28.   InchW:= PgWide - PgLft - PgRht;
  29.   PixHigh:= Round(InchH * Screen.PixelsPerInch / ViewScale);
  30.   PixWide:= Round(InchW * Screen.PixelsPerInch / ViewScale);
  31.  
  32.   // setup the TextArea position
  33.   TextArea.Top:= Round((Screen.PixelsPerInch * PgTop) / ViewScale);
  34.   TextArea.height:= PixHigh;
  35.   TextArea.width:= PixWide;
  36.   TextArea.left:= Round((Screen.PixelsPerInch * PgLft) / ViewScale);
  37.   TextArea.Picture.Bitmap.SetSize(Round(PixWide * ViewScale), Round(PixHigh * ViewScale));
  38.  
  39.   // clear the image canvas
  40.   TextArea.Canvas.Brush.Color:= clWindow;
  41.   TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  42.   TextArea.Canvas.MoveTo(0, 0);
  43.   cpMin:= 0;
  44.  
  45.   PaperArea.visible:= true;
  46.   ScrollView.visible:= true;
  47.  
  48.   // set the printing metrics
  49.   dc:= TextArea.Canvas.Handle;
  50.   ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  51.   oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  52.   w:= XPixToTwips(Round(PixWide * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  53.   h:= YPixToTwips(Round(PixHigh * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  54.   FillChar(fr, SizeOf(TFormatRange), 0);
  55.   fr.hdc:= dc;       // fr._hdc := dc; **on another system**
  56.   fr.hdcTarget:= dc;
  57.   fr.rc.Left:= ox;
  58.   fr.rc.Right:= ox+w;
  59.   fr.rc.Top:= oy;
  60.   fr.rc.Bottom:= oy+h; //
  61.   fr.chrg.cpMin:= cpMin;
  62.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  63.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0);  // hide selection
  64.   SendMessage(PageMemo.Handle, EM_SETSEL, cpMin, -1);  // select to end of document
  65.   SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  66.   SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  67.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  68.  
  69.   // get the page count
  70.   cpMin:= 0; PgSum:= 0; MorePages:= true;
  71.   while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
  72.         begin
  73.         // clear the image canvas
  74.         TextArea.Canvas.Brush.Color:= clWindow;
  75.         TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  76.         TextArea.Canvas.MoveTo(0, 0);
  77.  
  78.         // set the printing metrics
  79.         dc:= TextArea.Canvas.Handle;
  80.         ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  81.         oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  82.         w:= XPixToTwips(Round(PixWide * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  83.         h:= YPixToTwips(Round(PixHigh * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  84.         FillChar(fr, SizeOf(TFormatRange), 0);
  85.         fr.hdc:= dc;       // fr._hdc := dc; **on another system**
  86.         fr.hdcTarget:= dc;
  87.         fr.rc.Left:= ox;
  88.         fr.rc.Right:= ox+w;
  89.         fr.rc.Top:= oy;
  90.         fr.rc.Bottom:= oy+h; //
  91.         fr.chrg.cpMin:= cpMin;
  92.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  93.         SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0);  // hide selection
  94.         SendMessage(PageMemo.Handle, EM_SETSEL, cpMin, -1);  // select to end of document
  95.         SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  96.         SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  97.         SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  98.  
  99.         cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  100.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  101.  
  102.         if (fr.chrg.cpMin=fr.chrg.cpMax)
  103.            then MorePages:= false
  104.            else PgSum:= PgSum + 1;
  105.         end;
  106.  
  107.   // print each page
  108.   MorePages:= true; ViewChg:= 0; PgCnt:= 0;
  109.   cpMin:= 0; BackPages:=''; BegChar:= 0;
  110.  
  111.   // clear the image canvas
  112.   TextArea.Canvas.Brush.Color:= clWindow;
  113.   TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  114.   TextArea.Canvas.MoveTo(0, 0);
  115.  
  116.   // set the printing metrics
  117.   dc:= TextArea.Canvas.Handle;
  118.   ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  119.   oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  120.   w:= XPixToTwips(Round(PixWide * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  121.   h:= YPixToTwips(Round(PixHigh * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  122.   FillChar(fr, SizeOf(TFormatRange), 0);
  123.   fr.hdc:= dc;       // fr._hdc := dc; **on another system**
  124.   fr.hdcTarget:= dc;
  125.   fr.rc.Left:= ox;
  126.   fr.rc.Right:= ox+w;
  127.   fr.rc.Top:= oy;
  128.   fr.rc.Bottom:= oy+h; //
  129.   fr.chrg.cpMin:= cpMin;
  130.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  131.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0);  // hide selection
  132.   SendMessage(PageMemo.Handle, EM_SETSEL, cpMin, -1);  // select to end of document
  133.   SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  134.   SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  135.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  136.  
  137.   while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
  138.         begin
  139.         if (ViewChg<0) then
  140.            begin
  141.            x:= pos(',',BackPages);
  142.            if x>0 then delete(BackPages,1,x);
  143.            x:= pos(',',BackPages);
  144.            if x>0 then
  145.               begin
  146.               xstr:= copy(BackPages,1,x-1);
  147.               delete(BackPages,1,x);
  148.               cpMin:= StrToInt(xstr);
  149.               PgCnt:= PgCnt - 2;
  150.               if cpMin<0 then
  151.                  begin
  152.                  cpMin:= 0; BackPages:='';
  153.                  PgCnt:= 0;
  154.                  end;
  155.               end else begin
  156.                        cpMin:= 0; BackPages:='';
  157.                        PgCnt:= 0;
  158.                        end;
  159.            end;
  160.         BackPages:= IntToStr(cpMin)+','+BackPages; //showmessage(BackPages);
  161.         ViewChg:= 0;
  162.         BegChar:= cpMin; //showmessage(IntToStr(BegChar));
  163.  
  164.         // clear the image canvas
  165.         TextArea.Canvas.Brush.Color:= clWindow;
  166.         TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  167.         TextArea.Canvas.MoveTo(0, 0);
  168.  
  169.         // set the printing metrics
  170.         dc:= TextArea.Canvas.Handle;
  171.         ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  172.         oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  173.         w:= XPixToTwips(Round(PixWide * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  174.         h:= YPixToTwips(Round(PixHigh * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  175.         FillChar(fr, SizeOf(TFormatRange), 0);
  176.         fr.hdc:= dc;       // fr._hdc := dc; **on another system**
  177.         fr.hdcTarget:= dc;
  178.         fr.rc.Left:= ox;
  179.         fr.rc.Right:= ox+w;
  180.         fr.rc.Top:= oy;
  181.         fr.rc.Bottom:= oy+h; //
  182.         fr.chrg.cpMin:= cpMin;
  183.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  184.         SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0); // hide selection
  185.         SendMessage(PageMemo.Handle, EM_SETSEL, cpMin, -1);  // select to end of document
  186.         SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  187.         SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  188.         SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  189.  
  190.         cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  191.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  192.  
  193.         if (cpMin<=fr.chrg.cpMin) then
  194.             begin
  195.              MorePages:= false; //  document has no content
  196.              break;
  197.             end;
  198.  
  199.         fr.chrg.cpMin:= cpMin;  // set to start of next page
  200.         PgCnt:= PgCnt + 1;
  201.  
  202.         // begin modal dialogs
  203.         if (PgSum>1) then
  204.            begin
  205.            PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
  206.            PgStr:= PgStr+IntToStr(PgSum)+' Pages';
  207.            end else PgStr:= 'Single Page';
  208.         if (PgSum=1) then // pause at only-page
  209.            begin
  210.            case QuestionDlg (PgStr,'No Navigation',mtCustom,
  211.                             [mrCancel, 'Quit'],'') of
  212.                 mrCancel: MorePages:= false;
  213.                 end;
  214.            end;
  215.         if (BegChar=0) and (PgSum>1) then // pause at first-page
  216.            begin
  217.            case QuestionDlg (PgStr,'Navigation at Home',mtCustom,
  218.                             [mrCancel, 'Quit', mrYes, 'Next'],'') of
  219.                 mrCancel: MorePages:= false;
  220.                 mrYes: ViewChg:= 1;
  221.                 end;
  222.            end  else if (fr.chrg.cpMin<fr.chrg.cpMax) then // pause at each-page
  223.                      begin
  224.                      case QuestionDlg (PgStr,'Page Navigation',mtCustom,
  225.                                       [mrNo,'Back', mrCancel, 'Quit', mrYes, 'Next'],'') of
  226.                           mrNo: ViewChg:= -1;
  227.                           mrCancel: MorePages:= false;
  228.                           mrYes: ViewChg:= 1;
  229.                           end;
  230.                      end;
  231.         if (fr.chrg.cpMin=fr.chrg.cpMax) and (PgSum>1) then // pause at last-page
  232.            begin
  233.            case QuestionDlg (PgStr,'Navigation at End',mtCustom,
  234.                              [mrNo,'Back', mrCancel, 'Quit'],'') of
  235.                 mrNo: ViewChg:= -1;
  236.                 mrCancel: MorePages:= false;
  237.                 end;
  238.            end;
  239.         // end of modal dialogs
  240.         end;
  241.  
  242.   // clean up
  243.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  244.   if MorePages
  245.      then EndDoc(fr.hdc) // close EM_FORMATRANGE
  246.      else AbortDoc(fr.hdc);
  247.   TextArea.Picture.Bitmap.Canvas.Changed;  // reset image event
  248.   PaperArea.visible:= false;
  249.   ScrollView.visible:= false;
  250. end;  
  251.  

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: PrintViewer
« Reply #21 on: September 06, 2016, 08:58:08 pm »
If you want to get rid of flickering, give LockWindowUpdate a try.

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: PrintViewer
« Reply #22 on: September 07, 2016, 01:33:39 am »
Rick, I don't see any flickering on my side. I replaced the dialogs with a simple:
Code: Pascal  [Select]
  1.         Application.ProcessMessages;
  2.         Sleep(200);

It could be your version of Lazarus that gives flickering.

As for TToolBtn, most likely the procedure is blocking the GUI thread. As you know, the arrangement you have now is just for testing. The GUI thread should not be trapped in DisplayPages procedure. Even for testing, it would be easier to have First, Previous, Next and Last buttons instead of dialogs.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2284
    • havefunsoft.com
Re: PrintViewer
« Reply #23 on: September 07, 2016, 03:24:53 am »
Rick, I don't see any flickering on my side.
This is probably because you're not using Windows XP machine.
The WinAPI drawing process has been modified to use double-buffering, starting with Vista.
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: PrintViewer
« Reply #24 on: September 07, 2016, 06:16:01 am »
Rick, I don't see any flickering on my side.
This is probably because you're not using Windows XP machine.
The WinAPI drawing process has been modified to use double-buffering, starting with Vista.

You are right, it flickers because of WM_ERASEBKGND message handling in the panel (PaperArea). Erasing around the image and leaving the image rectangle area intact solved it on my side.

To test it quickly I hacked the TPanel class:
Code: Pascal  [Select]
  1.   TPanel=class(ExtCtrls.TPanel)
  2.   public
  3.     DoNotEraseRect: TRect;
  4.     procedure EraseBackground(DC: HDC); override;
  5.   end;
  6.  
  7. ...
  8.  
  9. procedure TPanel.EraseBackground(DC: HDC);
  10. var
  11.   ARect: TRect;
  12.   ABrush: HBrush;
  13. begin
  14.   if DC = 0 then Exit;
  15.   if DoNotEraseRect.Right = 0 then
  16.     Inherited
  17.   else
  18.   begin
  19.     ABrush := HBRUSH(Brush.Reference.Handle);
  20.  
  21.     ARect := Types.Rect(0, 0, Width, DoNotEraseRect.Top);
  22.     FillRect(DC, ARect, ABrush);
  23.  
  24.     ARect := Types.Rect(0, 0, DoNotEraseRect.Left,Height);
  25.     FillRect(DC, ARect, ABrush);
  26.  
  27.     ARect := Types.Rect(DoNotEraseRect.Right, 0, Width, Height);
  28.     FillRect(DC, ARect, ABrush);
  29.  
  30.     ARect := Types.Rect(0, DoNotEraseRect.Bottom, Width, Height);
  31.     FillRect(DC, ARect, ABrush);
  32.   end;
  33. end;

Specifing the area in the DisplayPages procedure after setting TextArea position and dimensions:
Code: Pascal  [Select]
  1.     PaperArea.DoNotEraseRect := TextArea.BoundsRect;

@Rick, test it and if it solves your problem then use the proper way.

I don't think calling TextArea.Canvas.FillRect is needed.

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #25 on: September 07, 2016, 01:41:59 pm »
I have noticed the edges flicker, but what I meant by flicker and flash was the EM_FORMATRANGE loop, as it selected each RichMemo text. It is highlighting the selection, and also scrolling RichMemo to the end of the document. Which (PageMemo.Handle, EM_HIDESELECTION, 1, 0) is supposed to suppress.

But as you noted... getting out of the modal loop may solve everything.

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #26 on: September 07, 2016, 07:37:16 pm »
OK. No more modal loop. This version works with all buttons and menus, but the EM_HIDESELECTION is still disfunctional. It doesn't hide the highlighting of selections.

So I have kept the Memo shield. It is called ScrollView (a TScrollBox). It is set to alClient, masking the entire memo. Eventually it will be used for zooming, so maybe I don't care about EM_HIDESELECTION... except that it might be slowing the process down.

The PaperArea panel has three Tbuttons (Back, Quit, and Next) for navigation. Then it also has a TStaticText called PageMonitor for posting page number and total pages.

Code: Pascal  [Select]
  1. // globals
  2. var cpMin, PixH, PixW: longint;
  3.     ViewScale: double;
  4.     dc: THandle;
  5.     fr: TFormatRange;
  6.     ox, oy, w, h: LongInt;
  7.     MorePages: boolean;
  8.     BackPages: string;
  9.     PgCnt, PgSum: integer;
  10.  
  11. function XPixToTwips(px: integer): integer;
  12. var
  13.   dc: THandle;
  14. begin
  15.   dc:= GetDC(HWND_DESKTOP);
  16.   Result:= Round(1440*px/GetDeviceCaps(dc, LOGPIXELSX));
  17.   ReleaseDC(HWND_DESKTOP, dc);
  18. end;
  19.  
  20. function YPixToTwips(px: integer): integer;
  21. var
  22.   dc: THandle;
  23. begin
  24.   dc:= GetDC(HWND_DESKTOP);
  25.   Result:= Round(1440*px/GetDeviceCaps(dc, LOGPIXELSY));
  26.   ReleaseDC(HWND_DESKTOP, dc);
  27. end;
  28.  
  29. procedure TCmdForm.SetupViewPage(BegPos, EndPos: longint);
  30. begin
  31.   // clear the image canvas
  32.   TextArea.Canvas.Brush.Color:= clWindow;
  33.   TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  34.   TextArea.Canvas.MoveTo(0, 0);
  35.  
  36.   // set the printing metrics
  37.   dc:= TextArea.Canvas.Handle;
  38.   ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  39.   oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  40.   w:= XPixToTwips(Round(PixW * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  41.   h:= YPixToTwips(Round(PixH * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  42.   FillChar(fr, SizeOf(TFormatRange), 0);
  43.   fr.hdc:= dc;       // fr._hdc:= dc; **on some systems**
  44.   fr.hdcTarget:= dc;
  45.   fr.rc.Left:= ox;
  46.   fr.rc.Right:= ox+w;
  47.   fr.rc.Top:= oy;
  48.   fr.rc.Bottom:= oy+h;
  49.   fr.chrg.cpMin:= BegPos; // set to 0 for start of document
  50.   fr.chrg.cpMax:= EndPos; // set to -1 for end of document
  51.  
  52.   // get document content
  53.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  54.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0); // hide selection
  55.   SendMessage(PageMemo.Handle, EM_SETSEL, BegPos, EndPos);  // select to end of document
  56.   SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  57.   SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  58.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  59. end;
  60.  
  61. procedure TCmdForm.btnViewClick(Sender: TObject);
  62. begin
  63.   PaperArea.visible:= true;
  64.   ScrollView.visible:= true;
  65.   SetupViewPage(0, -1);
  66.   PostFirstPage(self);
  67. end;
  68.  
  69. procedure TCmdForm.btnViewBackClick(Sender: TObject);
  70. var xstr: string;
  71.     x: integer;
  72. begin
  73.    x:= pos(',',BackPages);
  74.    if x>0 then delete(BackPages,1,x);  // delete next page reference
  75.  
  76.    x:= pos(',',BackPages);
  77.    if x>0 then
  78.       begin
  79.       xstr:= copy(BackPages,1,x-1);
  80.       delete(BackPages,1,x);          // delete current page reference
  81.       cpMin:= StrToInt(xstr);
  82.       PgCnt:= PgCnt - 2;
  83.       if cpMin<0 then
  84.          begin
  85.          cpMin:= 0; BackPages:='0,';
  86.          PgCnt:= 0;
  87.          end;
  88.       end else begin
  89.                cpMin:= 0; BackPages:='0,';
  90.                PgCnt:= 0;
  91.                end;
  92.  
  93.   if PgCnt<0 then PgCnt:= 0;
  94.   PostNewPage;
  95. end;
  96.  
  97. procedure TCmdForm.btnViewNextClick(Sender: TObject);
  98. begin
  99.   PostNewPage;
  100. end;
  101.  
  102. procedure TCmdForm.btnViewQuitClick(Sender: TObject);
  103. begin
  104.   // clean up
  105.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  106.   if MorePages
  107.      then EndDoc(fr.hdc) // close EM_FORMATRANGE
  108.      else AbortDoc(fr.hdc);
  109.   TextArea.Picture.Bitmap.Canvas.Changed;  // reset image event
  110.   PaperArea.visible:= false;
  111.   ScrollView.visible:= false;
  112. end;
  113.  
  114. procedure TCmdForm.PostNewPage;
  115. var PgStr: string;
  116. begin
  117.   if PgCnt<PgSum then
  118.      begin
  119.       SetupViewPage(cpMin, -1);
  120.       BackPages:= IntToStr(cpMin)+','+BackPages;
  121.       cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  122.       SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  123.       fr.chrg.cpMin:= cpMin;
  124.       PgCnt:= PgCnt + 1;
  125.  
  126.      end;
  127.   PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
  128.   PgStr:= PgStr+IntToStr(PgSum);
  129.   PageMonitor.caption:= PgStr;
  130. end;
  131.  
  132. procedure TCmdForm.PostFirstPage(Sender: TObject);
  133. var
  134.   PgWide, PgHigh, PgLft, PgRht, PgTop, PgBtm, InchW, InchH: double;
  135.   PgStr: string;
  136.  
  137. begin
  138.   // define paper size... these 7 can be global for paper size and display
  139.   PgWide:= 8.5; PgHigh:= 11.0;
  140.   PgLft:= 1.0; PgRht:= 1.0;
  141.   PgTop:= 1.0; PgBtm:= 1.0;
  142.   ViewScale:= 2; // display size: 0.5=double, 1.0=full, 2.0=half
  143.  
  144.   // setup the PaperArea metrics
  145.   PaperArea.top:= 0;  // 0 or 40 fits my layout
  146.   PaperArea.height:= Round(PgHigh * Screen.PixelsPerInch / ViewScale);
  147.   PaperArea.width:= Round(PgWide * Screen.PixelsPerInch / ViewScale);
  148.   PaperArea.left:= Round((PageMemo.width - PaperArea.width) / 2);  // centering view page
  149.  
  150.   // setup the TextArea metrics
  151.   InchH:= PgHigh - PgTop - PgBtm;
  152.   InchW:= PgWide - PgLft - PgRht;
  153.   PixH:= Round(InchH * Screen.PixelsPerInch / ViewScale);
  154.   PixW:= Round(InchW * Screen.PixelsPerInch / ViewScale);
  155.  
  156.   // setup the TextArea position
  157.   TextArea.Top:= Round((Screen.PixelsPerInch * PgTop) / ViewScale);
  158.   TextArea.height:= PixH;
  159.   TextArea.width:= PixW;
  160.   TextArea.left:= Round((Screen.PixelsPerInch * PgLft) / ViewScale);
  161.   TextArea.Picture.Bitmap.SetSize(Round(PixW * ViewScale), Round(PixH * ViewScale));
  162.  
  163.   // get total page count
  164.   SetupViewPage(0, -1);
  165.   cpMin:= 0; PgSum:= 0; MorePages:= true;
  166.   while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
  167.         begin
  168.         SetupViewPage(cpMin, -1);
  169.         cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  170.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  171.         fr.chrg.cpMin:= cpMin;
  172.         PgSum:= PgSum + 1;
  173.         if (fr.chrg.cpMin=fr.chrg.cpMax)
  174.            then MorePages:= false;
  175.         end;
  176.  
  177.   // print first page
  178.   MorePages:= true; PgCnt:= 0;
  179.   cpMin:= 0; BackPages:='';
  180.  
  181.   BackPages:= IntToStr(cpMin)+','+BackPages; //showmessage(BackPages);
  182.   SetupViewPage(cpMin, -1);
  183.  
  184.   cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  185.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  186.  
  187.   fr.chrg.cpMin:= cpMin;  // set to start of next page
  188.   PgCnt:= PgCnt + 1;
  189.  
  190.   PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
  191.   PgStr:= PgStr+IntToStr(PgSum);
  192.   PageMonitor.caption:= PgStr;
  193. end;  
  194.  

It is much healthier now. Thanks for prodding me to revise the procedure.

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #27 on: September 07, 2016, 08:26:48 pm »
Just a note. I tested this with an inline image. It showed the image, but there still isn't a way to save the image with the file.

Rick.
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: PrintViewer
« Reply #28 on: September 08, 2016, 04:52:18 am »
It looks much better. You really did a great job here.

It is natural to move the global vars and all these procedures to a class in a separate unit. This way you can reuse this code in another place or in a totally different project.

what I meant by flicker and flash was the EM_FORMATRANGE loop, as it selected each RichMemo text. It is highlighting the selection, and also scrolling RichMemo to the end of the document. Which (PageMemo.Handle, EM_HIDESELECTION, 1, 0) is supposed to suppress.

On my side EM_FORMATRANGE does not scroll the RichMemo nor does it highlight the selection. I just tested EM_HIDESELECTION with two buttons:
Code: Pascal  [Select]
  1. procedure TCmdForm.HideSelectBtnClick(Sender: TObject);
  2. begin
  3.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0);
  4. end;
  5.  
  6. procedure TCmdForm.ShowSelectionBtnClick(Sender: TObject);
  7. begin
  8.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0);
  9. end;

It seems to work on my side. Test it and let us know. Notice that I did not install the package, as I don't use it. For testing I create the RichMemo in code:
Code: Pascal  [Select]
  1.   PageMemo := TRichMemo.Create(Self);
  2.   PageMemo.Left := 300;
  3.   PageMemo.Height := 600;
  4.   PageMemo.Width := 600;
  5.   PageMemo.ScrollBars := ssAutoBoth;
  6.   PageMemo.Parent := Self;

I doubt this difference has any effect, but just in case thought to mention it.

You can use WM_SETREDRAW to pause/resume drawing of the RichMemo.

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #29 on: September 08, 2016, 01:38:31 pm »
What is happening on my end must be a Windows XP thing. WM_SETREDRAW sounds like it might help.

I have made a name change to the initial function that starts the Page Review. It is btnViewPagesClick. I thought it made it more recognizable against the other buttons that are available.

This update also employs a Zoom button that toggles between half and full size viewing. In full mode it allows for scrolling, and the application can always be moved from its launch size to full screen to not have to scroll.

I have attached a

Code: Pascal  [Select]
  1. // globals
  2. var cpMin, PixH, PixW: longint;
  3.     ViewScale: double;
  4.     dc: THandle;
  5.     fr: TFormatRange;
  6.     ox, oy, w, h: LongInt;
  7.     MorePages: boolean;
  8.     BackPages,TotalPages: widestring;
  9.     PgCnt, PgSum: integer;
  10.  
  11. function XPixToTwips(px: integer): integer;
  12. var
  13.   dc: THandle;
  14. begin
  15.   dc:= GetDC(HWND_DESKTOP);
  16.   Result:= Round(1440*px/GetDeviceCaps(dc, LOGPIXELSX));
  17.   ReleaseDC(HWND_DESKTOP, dc);
  18. end;
  19.  
  20. function YPixToTwips(px: integer): integer;
  21. var
  22.   dc: THandle;
  23. begin
  24.   dc:= GetDC(HWND_DESKTOP);
  25.   Result:= Round(1440*px/GetDeviceCaps(dc, LOGPIXELSY));
  26.   ReleaseDC(HWND_DESKTOP, dc);
  27. end;
  28.  
  29. procedure TCmdForm.SetupViewPage(BegPos, EndPos: longint);
  30. begin
  31.   // clear the image canvas
  32.   TextArea.Canvas.Brush.Color:= clWindow;
  33.   TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  34.   TextArea.Canvas.MoveTo(0, 0);
  35.  
  36.   // set the printing metrics
  37.   dc:= TextArea.Canvas.Handle;
  38.   ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  39.   oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  40.   w:= XPixToTwips(Round(PixW * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  41.   h:= YPixToTwips(Round(PixH * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  42.   FillChar(fr, SizeOf(TFormatRange), 0);
  43.   fr.hdc:= dc;       // fr._hdc:= dc; **on some systems**
  44.   fr.hdcTarget:= dc;
  45.   fr.rc.Left:= ox;
  46.   fr.rc.Right:= ox+w;
  47.   fr.rc.Top:= oy;
  48.   fr.rc.Bottom:= oy+h;
  49.   fr.chrg.cpMin:= BegPos; // set to 0 for start of document
  50.   fr.chrg.cpMax:= EndPos; // set to -1 for end of document
  51.  
  52.   // get document content
  53.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  54.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0); // hide selection
  55.   SendMessage(PageMemo.Handle, EM_SETSEL, BegPos, EndPos);  // select to end of document
  56.   SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  57.   SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  58.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  59. end;
  60.  
  61. procedure TCmdForm.CountPages;
  62. begin
  63. // get total page count
  64.   SetupViewPage(0, -1);
  65.   cpMin:= 0; PgSum:= 0; PgCnt:= 0; MorePages:= true; TotalPages:= '';
  66.   while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
  67.         begin
  68.         SetupViewPage(cpMin, -1);
  69.         PgCnt:= PgCnt + 1;
  70.         if PgCnt=1  // start=@ medial=# close=*
  71.            then TotalPages:= '@'+IntToStr(PgCnt)+':'+IntToStr(cpMin)+','+TotalPages // beg - 1
  72.            else TotalPages:= '#'+IntToStr(PgCnt)+':'+IntToStr(cpMin)+','+TotalPages;
  73.         cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  74.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  75.         fr.chrg.cpMin:= cpMin;
  76.         PgSum:= PgSum + 1;
  77.         if (fr.chrg.cpMin=fr.chrg.cpMax)
  78.            then MorePages:= false;
  79.         end;
  80.   TotalPages:= '*'+IntToStr(PgCnt)+':'+IntToStr(cpMin)+','+TotalPages; // end + 1
  81.   //showmessage(TotalPages);
  82. end;
  83.  
  84. procedure TCmdForm.ConfigureView;
  85. var
  86.   PgWide, PgHigh, PgLft, PgRht, PgTop, PgBtm, InchW, InchH: double;
  87.   PgCnt: longint;
  88. begin
  89.   // define paper size... these 7 can be global for paper size and display
  90.   PgWide:= 8.5; PgHigh:= 11.0;  // US Letter Size
  91.   PgLft:= 1.0; PgRht:= 1.0;
  92.   PgTop:= 1.0; PgBtm:= 1.0;
  93.  
  94.   // setup the PaperArea metrics
  95.   PaperArea.top:= 0;  // 0 or 40 fits my layout
  96.   PaperArea.height:= Round(PgHigh * Screen.PixelsPerInch / ViewScale);
  97.   PaperArea.width:= Round(PgWide * Screen.PixelsPerInch / ViewScale);
  98.   PaperArea.left:= Round((PageMemo.width - PaperArea.width) / 2);  // centering view page
  99.   if PaperArea.left<0 then PaperArea.left:= 0;
  100.  
  101.   // setup the TextArea metrics
  102.   InchH:= PgHigh - PgTop - PgBtm;
  103.   InchW:= PgWide - PgLft - PgRht;
  104.   PixH:= Round(InchH * Screen.PixelsPerInch / ViewScale);
  105.   PixW:= Round(InchW * Screen.PixelsPerInch / ViewScale);
  106.  
  107.   // setup the TextArea position
  108.   TextArea.Top:= Round((Screen.PixelsPerInch * PgTop) / ViewScale);
  109.   TextArea.height:= PixH;
  110.   TextArea.width:= PixW;
  111.   TextArea.left:= Round((Screen.PixelsPerInch * PgLft) / ViewScale);
  112.   TextArea.Picture.Bitmap.SetSize(Round(PixW * ViewScale), Round(PixH * ViewScale));
  113. end;
  114.  
  115. procedure TCmdForm.btnViewPagesClick(Sender: TObject);
  116. begin
  117.   PaperArea.visible:= true;
  118.   ScrollView.visible:= true;
  119.   SetupViewPage(0, -1);
  120.   PostFirstPage;
  121. end;
  122.  
  123. procedure TCmdForm.btnViewZoomClick(Sender: TObject);
  124. begin
  125.   if ViewScale>1.5           // zoom toggle between full and half
  126.      then ViewScale:= 1.0
  127.      else ViewScale:= 2.0;
  128.   ConfigureView;
  129. end;
  130.  
  131. procedure TCmdForm.btnViewBackClick(Sender: TObject);
  132. var xstr: string;
  133.     x: integer;
  134. begin
  135.    x:= pos(',',BackPages);
  136.    if x>0 then delete(BackPages,1,x);  // delete next page reference
  137.  
  138.    x:= pos(',',BackPages);
  139.    if x>0 then
  140.       begin
  141.       xstr:= copy(BackPages,1,x-1);
  142.       delete(BackPages,1,x);          // delete current page reference
  143.       cpMin:= StrToInt(xstr);
  144.       PgCnt:= PgCnt - 2;
  145.       if cpMin<0 then
  146.          begin
  147.          cpMin:= 0; BackPages:='0,';
  148.          PgCnt:= 0;
  149.          end;
  150.       end else begin
  151.                cpMin:= 0; BackPages:='0,';
  152.                PgCnt:= 0;
  153.                end;
  154.  
  155.   if PgCnt<0 then PgCnt:= 0;
  156.   PostNewPage;
  157. end;
  158.  
  159. procedure TCmdForm.btnViewNextClick(Sender: TObject);
  160. begin
  161.   PostNewPage;
  162. end;
  163.  
  164. procedure TCmdForm.btnViewQuitClick(Sender: TObject);
  165. begin
  166.   // clean up
  167.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  168.   if MorePages
  169.      then EndDoc(fr.hdc) // close EM_FORMATRANGE
  170.      else AbortDoc(fr.hdc);
  171.   TextArea.Picture.Bitmap.Canvas.Changed;  // reset image event
  172.   PaperArea.visible:= false;
  173.   ScrollView.visible:= false;
  174. end;
  175.  
  176. procedure TCmdForm.PostNewPage;
  177. var PgStr: string;
  178. begin
  179.   if PgCnt<PgSum then
  180.      begin
  181.       SetupViewPage(cpMin, -1);
  182.       BackPages:= IntToStr(cpMin)+','+BackPages;
  183.       cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  184.       SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  185.       fr.chrg.cpMin:= cpMin;
  186.       PgCnt:= PgCnt + 1;
  187.  
  188.      end;
  189.   PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
  190.   PgStr:= PgStr+IntToStr(PgSum);
  191.   PageMonitor.caption:= PgStr;
  192. end;
  193.  
  194. procedure TCmdForm.PostFirstPage;
  195. var
  196.   PgStr: string;
  197. begin
  198.   ViewScale:= 2.0; // display size: 0.5=double, 1.0=full, 2.0=half
  199.   ConfigureView;
  200.   CountPages;
  201.  
  202.   MorePages:= true; PgCnt:= 0;
  203.   cpMin:= 0; BackPages:='';
  204.   BackPages:= IntToStr(cpMin)+','+BackPages; //showmessage(BackPages);
  205.   SetupViewPage(cpMin, -1);
  206.   cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  207.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  208.   fr.chrg.cpMin:= cpMin;  // set to start of next page
  209.   PgCnt:= PgCnt + 1;
  210.  
  211.   PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
  212.   PgStr:= PgStr+IntToStr(PgSum);
  213.   PageMonitor.caption:= PgStr;
  214. end;
  215.  

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit