Printing

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
35 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Printing

Peter Simmonds
How do I send the contents of a view to a printer?

One other problem. I can create 3D toolbar buttons OK but when I
check hasFlatAppearence the toolbar background goes white. The
backColor is set to COLOR_3DFACE so this shouldn't happen.
Any ideas?

Where can I get basic questions answered? Is there a book
(apart from Ted Bracht's)?

Peter Simmonds
Northampton, UK


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Ian Bartholomew-19
Peter,

> How do I send the contents of a view to a printer?

Can you give a bit more detail about what you want to print, text/graphics/a
mixture of the two/code from a workspace/a "print screen" emulation ....

> One other problem. I can create 3D toolbar buttons OK but when I
> check hasFlatAppearence the toolbar background goes white. The
> backColor is set to COLOR_3DFACE so this shouldn't happen.
> Any ideas?

There are a couple of ways that seem to work but it's a bit of a black art
and I don't really know the "correct" way.

1) Set the backcolour for the Shell to COLOR_3DFACE as well.  This is the
method I tend to use as the Shell's background is usually covered by other
subviews.
2) Set the #isTransparent aspect of the Toolbar to true.  I've no idea why
this works, it seems to me to be the wrong way round....

> Where can I get basic questions answered? Is there a book
> (apart from Ted Bracht's)?

No other books, as far as I know.  Asking here (or looking through the
newsgroup archive), trial-and-error using a workspace and browsing the image
are the ways I tend to work things out.

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Peter Simmonds
>
> > How do I send the contents of a view to a printer?
>
> Can you give a bit more detail about what you want to print,
text/graphics/a
> mixture of the two/code from a workspace/a "print screen" emulation ....
>

I want to print from a subclass of View in its onPaintRequired: method. I
will have
a PaintEvent to get a Canvas from so what I want to do is redirect the
output
of my code from the Canvas to a "printing canvas". The output will be a
mixture
of 2D graphics and text.

Peter Simmonds
Northampton, UK


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Chris Uppal-3
Peter Simmonds wrote:

> I want to print from a subclass of View in its onPaintRequired: method. I
> will have
> a PaintEvent to get a Canvas from so what I want to do is redirect the
> output
> of my code from the Canvas to a "printing canvas". The output will be a
> mixture
> of 2D graphics and text.

Code like:

    canvas := PrinterCanvas choose ifNil: [^ self].
    canvas startDocNamed: 'Hi!'; startPage.
         "paint code goes here"
    canvas endPage; endDoc.
    canvas free.

should get you started with a Canvas that you can paint on.

Be aware that the canvas will have a different resolution from the canvas that
you paint on in your normal View code, so you'll have to scale the widths of
your lines appropriately.  I add a method to Canvas:

=====================
pixelsFromDesktopPixels: aPointOrNumber
 "answer the given point or number scaled from the desktop
 resolution (ppi) to that of the reciever.  A kludge for  simple
 adaptation of features defined in terms of screen pixels
 to other resolutions"
#CUadded.

 ^ self resolution / View desktop resolution * aPointOrNumber.
=====================

to help with that, although it is, as the comment states, just a kludge.  You
will need a similar hack (or something better) in order to get the fonts scaled
correctly.

Windows also has lots of bells and whistles for manipulating the mapping
between coordinates and actual Pixels, all of which confuse me utterly.  They
are not activated by default, so the mapping is 1-to-1 unless you change it
yourself.  (I believe that you should be able to get better results if you /do/
use the advanced mappings, but I've never had the courage to try ;-)

If you want to do this properly, then the chances are that you'll want to use
more of the underlying Windows printing system than is exposed in a vanilla
Dolphin installation.  Ian's printing goodies contain wrappers for a lot more
of the API, even if you don't use all of his printing framework (which is, if I
understand it correctly, oriented towards printing using the Rich Text control
and so not quite what you need here.)

Be prepared to waste a lot of ink ;-)   I found it helpful to install a
PostScript printer driver, set to print to file, and then used the Aladdin
PostScript viewer (freeware) to look at the results -- it's not perfect but it
has probably saved me at least one printer cartridge already.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Ian Bartholomew-19
In reply to this post by Peter Simmonds
Peter,
> I want to print from a subclass of View in its onPaintRequired:
> method. I will have
> a PaintEvent to get a Canvas from so what I want to do is redirect the
> output
> of my code from the Canvas to a "printing canvas". The output will be
> a mixture
> of 2D graphics and text.

I would do this by having an Object that knew how to draw itself and then
passing it a canvas to draw on.  Your #onPaintRequired: method would be
_something_ like

MyView>>onPaintRequired: aPaintEvent
    self model drawOn: aPaintEvent canvas

and another method would print to a printer

MyView>>printIt
    | printerCanvas |
    printerCanvas := PrinterCanvas choose.
    printerCanvas
        startDoc;
        startPage.
    self model drawOn: printerCanvas.
    printerCanvas
        endPage;
        endDoc.

How and when you use the #printIt method really depends on your application
and the situations in which you want a hard copy to be produced.

The printer and screen canvas are going to have different capabilities,
extents and resolutions for example, so your #drawOn: method will have to be
able to adjust it's rendering to cope with that.

As a simple example.... add the following method to the Dolphin example
class ScribbleView

ScribbleView>>printIt
    | printerCanvas |
    printerCanvas := PrinterCanvas choose.
    printerCanvas
        startDoc;
        startPage.
    self model do: [:each | each drawOn: printerCanvas].
    printerCanvas
        endPage;
        endDoc

In a workspace evaluate

s := Scribble show

draw a nice picture in the Scribble shell and then evaluate

s view printIt

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Peter Simmonds
In reply to this post by Peter Simmonds
Thanks for your help. One last thing on printing. How can I programmatically
change the orientation of the paper. That is from Portrait to Landscape and
vice versa.

Peter Simmonds
Northampton, UK


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Blair McGlashan
In reply to this post by Chris Uppal-3
"Chris Uppal" <[hidden email]> wrote in message
news:[hidden email]...
> Peter Simmonds wrote:
>
> > I want to print from a subclass of View in its onPaintRequired: method.
I
> > will have
> > a PaintEvent to get a Canvas from so what I want to do is redirect the
> > output
> > of my code from the Canvas to a "printing canvas". The output will be a
> > mixture
> > of 2D graphics and text.
> >...

> .....
> Be prepared to waste a lot of ink ;-)   I found it helpful to install a
> PostScript printer driver, set to print to file, and then used the Aladdin
> PostScript viewer (freeware) to look at the results -- it's not perfect
but it
> has probably saved me at least one printer cartridge already.

If your printer driver doesn't have a preview mode (or your printer is an
Epson and you don't want to use its driver because it crashes frequently
requiring a machine restart to sort out), then I can recommend Fine Print.
Not only does this handy utility give you a preview, but it can also pack a
number of pages onto one physical page, a big saving for draft output. There
is a free "trial" version which prints a small banner on each page, but this
is not a problem for draft output. It doesn't cost much anyway:

http://fineprint.com/products/fineprint/index.html

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Ian Bartholomew-19
In reply to this post by Peter Simmonds
Peter,

> Thanks for your help. One last thing on printing. How can I
> programmatically change the orientation of the paper. That is from
> Portrait to Landscape and vice versa.

With great difficulty, unfortunately.  I've extracted some code from my
printer goodie that will work for the _default_ printer (you don't get a
normal PrinterDialog that allows you to choose) as an example.  FileIn the
code between the =~=~=s, it adds some required structures and an interface
method, then evaluate the following in a workspace.  Changing the argument
in the second section allows you to print in Portrait(1) or Landscape(2)

It could probably be simplified but I wasted a lot of ink, paper and brain
cells getting to this point so I tend to leave it alone.

"Get a PRINTDLGEX struct for the default printer"
printDlgStruct := PRINTDLGEX new.
printDlgStruct
    ownerView: View active;
    flags: ("PD_RETURNDEFAULT" 1024);
    nCopies: 1;
    nStartPage: -1.
ComDlgLibrary default printDlgEx: printDlgStruct asParameter.

"Set the DEVMODE orientation 1=Portrait 2=Landscape"
addr := KernelLibrary default globalLock: printDlgStruct hDevMode.
(DEVMODE new initializeAtAddress: addr) dmOrientation: 1.
KernelLibrary default globalUnlock: printDlgStruct hDevMode.

"Create a PrinterCanvas for the default printer in this orientation"
devModeAddr := KernelLibrary default globalLock: printDlgStruct hDevMode.
devMode := DEVMODE new initializeAtAddress: devModeAddr.
devNamesAddr := KernelLibrary default globalLock: printDlgStruct hDevNames.
devNames := DEVNAMES new initializeAtAddress: devNamesAddr.
printerDC := GDILibrary default
    createDC: (String fromAddress: devNamesAddr yourAddress + devNames
wDriverOffset)
    lpszDevice: (String fromAddress: devNamesAddr yourAddress + devNames
wDeviceOffset)
    lpszOutput: (String fromAddress: devNamesAddr yourAddress + devNames
wOutputOffset)
    lpdvminit: devMode.
KernelLibrary default globalUnlock: printDlgStruct hDevNames.
KernelLibrary default globalUnlock: printDlgStruct hDevMode.
pc := PrinterCanvas withOwnedDC: printerDC asInteger.

"Test it"
pc
    startDoc;
    startPage;
    text: 'This is a test' at: 100@100;
    endPage;
    endDoc.

=~=~=~=~=~=

"Filed out from Dolphin Smalltalk XP"!

Win32Structure subclass: #DEVMODE

instanceVariableNames: ''

classVariableNames: ''

poolDictionaries: ''

classInstanceVariableNames: ''!

DEVMODE guid: (GUID fromString: '{BC292F08-565C-4AED-AE80-7B52F463FBD1}')!

DEVMODE comment: 'See [DolphinImageFolder]/Ian Bartholomew/Documentation for
details

(C) 2004 Ian Bartholomew

[hidden email]

Public Domain Freeware'!

!DEVMODE categoriesForClass!External-Data-Structured-Win32!IDB Goodies! !

!DEVMODE methodsFor!

dwSize: anObject

"Set the receiver's dwSize field to the value of anObject."

bytes wordAtOffset: 37 put: anObject! !

!DEVMODE categoriesFor: #dwSize:!**compiled accessors**!public! !

!DEVMODE class methodsFor!

defineFields

"Define the fields of the Win32 DEVMODE structure.

DEVMODE compileDefinition

DEVMODE decompileDefinition


typedef struct _devicemode

BCHAR dmDeviceName[CCHDEVICENAME];

WORD dmSpecVersion;

WORD dmDriverVersion;

WORD dmSize;

WORD dmDriverExtra;

DWORD dmFields;

union {

struct {

short dmOrientation;

short dmPaperSize;

short dmPaperLength;

short dmPaperWidth;

};

POINTL dmPosition;

};

short dmScale;

short dmCopies;

short dmDefaultSource;

short dmPrintQuality;

short dmColor;

short dmDuplex;

short dmYResolution;

short dmTTOption;

short dmCollate;

BCHAR dmFormName[CCHFORMNAME];

WORD dmLogPixels;

DWORD dmBitsPerPel;

DWORD dmPelsWidth;

DWORD dmPelsHeight;

union {

DWORD dmDisplayFlags;

DWORD dmNup;

}

DWORD dmDisplayFrequency;

#if(WINVER >= 0x0400)

DWORD dmICMMethod;

DWORD dmICMIntent;

DWORD dmMediaType;

DWORD dmDitherType;

DWORD dmReserved1;

DWORD dmReserved2;

#if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400)

DWORD dmPanningWidth;

DWORD dmPanningHeight;

#endif

#endif /* WINVER >= 0x0400 */

} DEVMODE;"

self

defineField: #dmDeviceName type: (ArrayField type: String length: 32);

defineField: #dmSpecVersion type: WORDField filler;

defineField: #dmDriverVersion type: WORDField filler;

defineField: #dmSize type: WORDField writeOnly beOverride;

defineField: #dmDriverExtra type: WORDField filler;

defineField: #dmFields type: DWORDField filler;

defineField: #dmOrientation

type: WORDField new

offset: 44;

defineField: #dmPaperSize

type: WORDField new

offset: 46;

defineField: #dmPaperLength

type: WORDField filler

offset: 48;

defineField: #dmPaperWidth

type: WORDField filler

offset: 50;

defineField: #dmPosition

type: (StructureField type: POINTL) beFiller

offset: 44;

defineField: #dmScale type: WORDField filler;

defineField: #dmCopies type: WORDField filler;

defineField: #dmDefaultSource type: WORDField filler;

defineField: #dmPrintQuality type: WORDField filler;

defineField: #dmColor type: WORDField filler;

defineField: #dmDuplex type: WORDField filler;

defineField: #dmYResolution type: WORDField filler;

defineField: #dmTTOption type: WORDField filler;

defineField: #dmCollate type: WORDField filler;

defineField: #dmFormName type: (ArrayField type: String length: 32)
beFiller;

defineField: #dmLogPixels type: WORDField filler;

defineField: #dmBitsPerPel type: DWORDField filler;

defineField: #dmPelsWidth type: DWORDField filler;

defineField: #dmPelsHeight type: DWORDField filler;

defineField: #dmDisplayFlags

type: DWORDField filler

offset: 116;

defineField: #dmNup

type: DWORDField filler

offset: 116;

defineField: #dmDisplayFrequency type: DWORDField filler;

defineField: #dmICMMethod type: DWORDField filler;

defineField: #dmICMIntent type: DWORDField filler;

defineField: #dmMediaType type: DWORDField filler;

defineField: #dmDitherType type: DWORDField filler;

defineField: #dmReserved1 type: DWORDField filler;

defineField: #dmReserved2 type: DWORDField filler;

defineField: #dmPanningWidth type: DWORDField filler;

defineField: #dmPanningHeight type: DWORDField filler! !

!DEVMODE class categoriesFor: #defineFields!initializing!public! !



"Filed out from Dolphin Smalltalk XP"!

Win32Structure subclass: #DEVNAMES

instanceVariableNames: ''

classVariableNames: ''

poolDictionaries: ''

classInstanceVariableNames: ''!

DEVNAMES guid: (GUID fromString: '{776A9E91-190A-4EA6-969C-92BC7B280AD9}')!

DEVNAMES comment: 'See [DolphinImageFolder]/Ian Bartholomew/Documentation
for details

(C) 2004 Ian Bartholomew

[hidden email]

Public Domain Freeware'!

!DEVNAMES categoriesForClass!External-Data-Structured-Win32!IDB Goodies! !

!DEVNAMES class methodsFor!

defineFields

"Define the fields of the Win32 DEVNAMES structure.

DEVNAMES compileDefinition

DEVNAMES decompileDefinition


typedef struct _deviNAMES

WORD wDriverOffset;

WORD wDeviceOffset;

WORD wOutputOffset;

WORD wDefault;

// strings follow here

} DEVNAMES"

self

defineField: #wDriverOffset type: WORDField new;

defineField: #wDeviceOffset type: WORDField new;

defineField: #wOutputOffset type: WORDField new;

defineField: #wDefault type: WORDField new! !

!DEVNAMES class categoriesFor: #defineFields!initializing!public! !



"Filed out from Dolphin Smalltalk XP"!

Win32Structure subclass: #PRINTPAGERANGE

instanceVariableNames: ''

classVariableNames: ''

poolDictionaries: ''

classInstanceVariableNames: ''!

PRINTPAGERANGE guid: (GUID fromString:
'{2CA95384-EE76-4CE7-A2E8-D8BF613E90F8}')!

PRINTPAGERANGE comment: 'See [DolphinImageFolder]/Ian
Bartholomew/Documentation for details

(C) 2004 Ian Bartholomew

[hidden email]

Public Domain Freeware'!

!PRINTPAGERANGE categoriesForClass!External-Data-Structured-Win32!IDB
Goodies! !

!PRINTPAGERANGE class methodsFor!

defineFields

"Define the fields of the Win32 PRINTPAGERANGE structure.

PRINTPAGERANGE compileDefinition

typedef struct tagPRINTPAGERANGE {

DWORD nFromPage;

DWORD nToPage;

} PRINTPAGERANGE;"

self

defineField: #nFromPage type: DWORDField new;

defineField: #nToPage type: DWORDField new! !

!PRINTPAGERANGE class categoriesFor: #defineFields!initializing!public! !

"Filed out from Dolphin Smalltalk XP"!

Win32Structure subclass: #PRINTDLGEX

instanceVariableNames: 'pageRanges'

classVariableNames: ''

poolDictionaries: ''

classInstanceVariableNames: ''!

PRINTDLGEX guid: (GUID fromString:
'{B691F392-B721-4F29-BB6D-3F2477CC294A}')!

PRINTDLGEX comment: 'See [DolphinImageFolder]/Ian Bartholomew/Documentation
for details

(C) 2004 Ian Bartholomew

[hidden email]

Public Domain Freeware'!

!PRINTDLGEX categoriesForClass!External-Data-Structured-Win32!IDB Goodies! !

!PRINTDLGEX methodsFor!

dwSize: anObject

bytes dwordAtOffset: 0 put: anObject!

initialize

super initialize.

self

lpPageRanges: (pageRanges := StructureArray length: 10 elementClass:
PRINTPAGERANGE);

nMaxPageRanges: 10!

ownerView: aView

"Set the parent window for the dialog to aView."

| hWnd |

hWnd := aView asParameter.

hWnd isNull ifFalse: [self hwndOwner: hWnd]!

pageRangeAt: anInteger

^pageRanges at: anInteger! !

!PRINTDLGEX categoriesFor: #dwSize:!accessing!public! !

!PRINTDLGEX categoriesFor: #initialize!initializing!public! !

!PRINTDLGEX categoriesFor: #ownerView:!accessing!public! !

!PRINTDLGEX categoriesFor: #pageRangeAt:!accessing!public! !

!PRINTDLGEX class methodsFor!

defineFields

"Define the fields of the Win32 PRINTDLG structure.

PRINTDLGEX compileDefinition

PRINTDLGEX decompileDefinition

typedef struct tagPDEX {

DWORD lStructSize;

HWND hwndOwner;

HGLOBAL hDevMode;

HGLOBAL hDevNames;

HDC hDC;

DWORD Flags;

DWORD Flags2;

DWORD ExclusionFlags;

DWORD nPageRanges;

DWORD nMaxPageRanges;

LPPRINTPAGERANGE lpPageRanges;

DWORD nMinPage;

DWORD nMaxPage;

DWORD nCopies;

HINSTANCE hInstance;

LPCTSTR lpPrintTemplateName;

LPUNKNOWN lpCallback;

DWORD nPropertyPages;

HPROPSHEETPAGE *lphPropertyPages;

DWORD nStartPage;

DWORD dwResultAction;

} PRINTDLGEX, LPPRINTDLGEX;"

self

defineField: #dwSize type: DWORDField writeOnly beOverride;

defineField: #hwndOwner type: DWORDField new;

defineField: #hDevMode type: HANDLEField new;

defineField: #hDevNames type: HANDLEField new;

defineField: #hDC type: DWORDField new;

defineField: #flags type: DWORDField new;

defineField: #flags2 type: DWORDField filler;

defineField: #exclusionFlags type: DWORDField filler;

defineField: #nPageRanges type: DWORDField new;

defineField: #nMaxPageRanges type: DWORDField new;

defineField: #lpPageRanges

type: (StructureArrayPointerField type: PRINTPAGERANGE length: 10);

defineField: #nMinPage type: DWORDField new;

defineField: #nMaxPage type: DWORDField new;

defineField: #nCopies type: DWORDField new;

defineField: #hInstance type: DWORDField filler;

defineField: #lpPrintTemplateName type: DWORDField filler;

defineField: #lpCallback type: DWORDField filler;

defineField: #nPropertyPages type: DWORDField filler;

defineField: #lphPropertyPages type: DWORDField filler;

defineField: #nStartPage type: DWORDField new;

defineField: #dwResultAction type: DWORDField new! !

!PRINTDLGEX class categoriesFor: #defineFields!initializing!public! !

"Filed out from Dolphin Smalltalk XP"!

!ComDlgLibrary methodsFor!

printDlgEx: aWinPRINTDLGEX

"Displays a Print dialog box or a Print Setup dialog box. The Print dialog
box enables the user to

specify the properties of a particular print job.

HRESULT PrintDlgEx(

LPPRINTDLGEX lppd // address of structure with initialization data

);"

<stdcall: hresult PrintDlgExA PRINTDLGEX*>

#idbAdded.

^self invalidCall! !

!ComDlgLibrary categoriesFor: #printDlgEx:!idb
goodies!primitives!public!win32 functions-common dialog box! !

=~=~=~=~=~=

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Chris Uppal-3
In reply to this post by Peter Simmonds
Peter Simmonds wrote:

> How can I
> programmatically change the orientation of the paper. That is from
> Portrait to Landscape and vice versa.

That's one of the bits of the Windows printing API that isn't exposed in the
standard Dolphin image.  As a starting point, I suggest that you get hold of
Ian's 'IDB Printer' package, and then see the methods Printer>>beLandscape and
#bePortrait.

    <http://www.idb.me.uk/goodies5/goodies5.html>

Ian, are you open to a suggestion ?   I'd like to use the low-level stuff from
that package, but the higher level 'Printer' abstraction doesn't really fit
with /my/ printer framework ;-)  Would you be willing to split the Window API
bit out into a separate package ?  Please don't bother if it's a fuss, of
course.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Schwab,Wilhelm K
In reply to this post by Chris Uppal-3
Chris,

[snip]
> to help with that, although it is, as the comment states, just a kludge.  You
> will need a similar hack (or something better) in order to get the fonts scaled
> correctly.

FWIW, a kludge might be just what is required.


> Windows also has lots of bells and whistles for manipulating the mapping
> between coordinates and actual Pixels, all of which confuse me utterly.  

Good, that means I'm not alone :)


 > They
> are not activated by default, so the mapping is 1-to-1 unless you change it
> yourself.  (I believe that you should be able to get better results if you /do/
> use the advanced mappings, but I've never had the courage to try ;-)

I tried the mapping modes/viewport/origin stuff, and wasn't very happy
with it.  IIRC, there are some newer transformations, but I've ended up
with a home-grown solution that works.


> Be prepared to waste a lot of ink ;-)   I found it helpful to install a
> PostScript printer driver, set to print to file, and then used the Aladdin
> PostScript viewer (freeware) to look at the results -- it's not perfect but it
> has probably saved me at least one printer cartridge already.

For the things that I print, much of the work is done by common
rendering objects that generate on-screen as well as printer graphics.
All coordinates are specified in inches (thanks to Smalltalk, they can
be a mix of floats or integers as appropriate), and the rendering
scales/truncates to the target pixels. Much of the "wasted ink" can be
avoided by sending graphics to bitmaps and viewing them in an
ImagePresenter.  Of course, there are printer-specific problems
(pagination, margins, etc.) that lend themselves to Blair's suggestion.

Have a good one,

Bill


--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Schwab,Wilhelm K
In reply to this post by Ian Bartholomew-19
Peter,

> With great difficulty, unfortunately.  I've extracted some code from my
> printer goodie that will work for the _default_ printer (you don't get a
> normal PrinterDialog that allows you to choose) as an example.  FileIn the
> code between the =~=~=s, it adds some required structures and an interface
> method, then evaluate the following in a workspace.  Changing the argument
> in the second section allows you to print in Portrait(1) or Landscape(2)

Intending no disrespect to Ian's hard work, I find myself wondering
whether it is necessary.  If you control the content of the printed
page, then you should be able to simply rotate everything by 90 degrees,
either using a matrix transformation, or by a more brute force approach.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Ian Bartholomew-19
In reply to this post by Chris Uppal-3
Chris,

> Ian, are you open to a suggestion ?

Always!

>                I'd like to use the low-level
> stuff from that package, but the higher level 'Printer' abstraction
> doesn't really fit with /my/ printer framework ;-)  Would you be
> willing to split the Window API bit out into a separate package ?

I'm not sure you would gain much.  Each Printer instance maintains
PRINTDLGEX and PAGESETUPDLG structures that hold the required state of the
printer - mainly in it's DEVMODE attribute.  All the rest of the functions,
including the low level stuff, use these structures, as do the
PrintSetupDialog and PageSetupDialog dialogs.  The low level stuff mainly
works by tweaking bits in the DEVMODE structure, as you saw in my earlier
orientation example, so there wouldn't really be a lot of code to add to any
api package and you would still need a lot of non-api support code in the
main package.

Roughly how does your printer framework work?

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Ian Bartholomew-19
In reply to this post by Schwab,Wilhelm K
Bill,

> Intending no disrespect to Ian's hard work, I find myself wondering
> whether it is necessary.  If you control the content of the printed
> page, then you should be able to simply rotate everything by 90
> degrees, either using a matrix transformation, or by a more brute
> force approach.

That would work but using the normal procedure, even though it is more
difficult, is going to be more flexible and also presents a standard way of
working to the user.  By that I mean that things like varying the margins,
changing printers and all the other settings that the PrintSetup and
PageSetup dialogs allow will be accessible in the "normal" Windows way.

It may well be that Peter's application doesn't need any of this and just
rotating the bitmaps may well be the easiest solution.

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Chris Uppal-3
In reply to this post by Ian Bartholomew-19
Ian,

> Roughly how does your printer framework work?

Hmm, you don't believe in asking /easy/ questions do you ;-)

I haven't really had a "vision" for how it works -- it's sedimenting out from a
collection of ad hoc printing code and is still two iterations short of an
abstraction.

The best I can put it is that it treats printing as a process.  There is no
real concept of printing something "on" a printer -- it's too page-oriented for
that.  The key abstraction is (or will be) a PrintController, which may be a
PrintPreview function (window) or a PrintDialog+PrintProgress function
(sequence of windows).  The application creates a PrintController, gives it
some initial settings, and then largely forgets about printing.  The
PrintController calls back into the application when it wants a page of
graphics by sending #printPage:on:in: with a page number, a Canvas (possibly a
PrintCanvas possibly a normal screen Canvas), and a target Rectangle.  The
PrintController looks after things like selecting the page to view in PP, or
collation and page-range selection in real printing (which is important to me).

I'm thinking about adding something whose role in printing is similar to a View
in MVP -- something with the job of rendering a page of a Model on a Canvas.
Or maybe just rendering a page on a Canvas without requiring an explicit Model.

Anyway, at the moment it has reached the point where I'd like to be able to
pass some sort of PrintSettings object around -- particularly so that the PP
function and real printing could agree on whether to use Landscape mode without
the user having to tell /both/ of them.  Also it'd be nice to use the improved
print dialog in XP (one of XP's few genuine improvements, IMO).  It's a
personal thing, but I'd be more comfortable managing the dialogs in the same
way as a PrintDialog in vanilla Dolphin (I already have my own PrintDialog
subclass that exposes the important -- to me -- "advanced" options in a
PRINTDLG).

I /could/ create my own wrappers for all the relevant Windows structures, but
you've already done it -- what's more, I use your IDE printing extensions so
they are already present in my image !  So I'd rather re-use your work, but I'd
without your abstraction (which would overlap confusingly with mine).  I'm
greedy, I know ;-)

    -- chris

P.S.  Now I've written all this, I have a /much/ clearer picture of what the
next iteration will look like.  Ain't upfront design wonderful...


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Christopher J. Demers
In reply to this post by Ian Bartholomew-19
"Ian Bartholomew" <[hidden email]> wrote in message
news:9Nqsc.6847$[hidden email]...
> Chris,
>
> > Ian, are you open to a suggestion ?
>
> Always!

Ian,

Since you are taking requests... ;)  I seem to recall that you have
different versions of a package related to printing for Window XP and non-XP
(or maybe it is a different SP of XP).  I think it is the RTF printing
support.  I wonder how much effort it might be to support both versions in
one package conditionally at runtime?  The problem I have is that I am using
it in a deployed application to print RTF files.  I am using a slightly
tweaked older version and have been afraid to upgrade.  Perhaps I should
just use the lowest common denominator version.  Do you think that would
still work, or did the SP break something?  Will I need to trick your
installer into letting me have the older XP package if my XP version is
newer?

BTW:  Thank you for developing your Dolphin goodies.  We all appreciate them
very much, and you have set a great community precedent for sharing that
many of us try to aspire to.  Your goodies inspired me to release some of my
own.

Chris


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Ian Bartholomew-19
In reply to this post by Chris Uppal-3
Chris,

>> Roughly how does your printer framework work?
>
> Hmm, you don't believe in asking /easy/ questions do you ;-)

And there was me thinking I was being kind when I prepended the question
with "roughly"

> I haven't really had a "vision" for how it works -- it's sedimenting
> out from a collection of ad hoc printing code and is still two
> iterations short of an abstraction.

:-)  I've got a lot of code in that state, as you may have noticed.

> The best I can put it is that it treats printing as a process.
[snip]

I _think_ I see what you are aiming for but I admit I can't really see why
it would be preferable to the more usual way of printing - creating a
"Printer" and then, either directly or indirectly, sending it pages to
print.  It sounds a bit like you are just trying to duplicate the services
provided by the Windows PrintSpooler?.

> Anyway, at the moment it has reached the point where I'd like to be
> able to pass some sort of PrintSettings object around -- particularly
> so that the PP function and real printing could agree on whether to
> use Landscape mode without the user having to tell /both/ of them.

That's basically what I'm using the PRINTDLGEX structure for.  The
PrintDialog and PageSetupDialog can both use it and share the required
state.  I can also access it from, for example, the PrintPreview to generate
a valid preview.

As you mentioned earlier though, my Printing is mainly used in conjunction
with a RichEdit so there may be a better way to do it in a more general
Printer class?.

> I /could/ create my own wrappers for all the relevant Windows
> structures, but you've already done it -- what's more, I use your IDE
> printing extensions so they are already present in my image !  So I'd
> rather re-use your work, but I'd without your abstraction (which
> would overlap confusingly with mine).  I'm greedy, I know ;-)

OK.  I've more or less decided to have another look at the Printer classes
(see the other Chris' post) so I'll see if I can redo the packaging to make
it easier to use.

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Ian Bartholomew-19
In reply to this post by Christopher J. Demers
Chris,

> Since you are taking requests... ;)  I seem to recall that you have
> different versions of a package related to printing for Window XP and
> non-XP (or maybe it is a different SP of XP).  I think it is the RTF
> printing support.  I wonder how much effort it might be to support
> both versions in one package conditionally at runtime?

There are two reasons why the Printing goodies have a number of versions

1) The PrintDialog interface and PRINTDLG/PRINTDLGEX structures are
different for early (ME/98) versions of Windows.  The newer api support in
2000/XP has a number of enhancements that I wanted to use.
2) The RichEdit support in XP(SP1) differs from XP/2000 which differs from
earlier version.  Again, I wanted to use the new api if possible.

>     I wonder how much effort it might be to support
> both versions in one package conditionally at runtime?

It might well be, I can't really remember exploring that avenue.  It may
result in some duplication but could be easier than trying to maintain
separate source packages .

My other problem is that I haven't got anything other than 2000/XP(SP1) to
test on so code for the other Windows will contain a bit of guesswork as I
will be relying on the printed documentation.

>                        The problem I
> have is that I am using it in a deployed application to print RTF
> files.  I am using a slightly tweaked older version and have been
> afraid to upgrade.  Perhaps I should just use the lowest common
> denominator version.  Do you think that would still work, or did the
> SP break something?  Will I need to trick your installer into letting
> me have the older XP package if my XP version is newer?

I'll have a look at the whole Printing goodie with a view to redoing the
packaging (see the other other Chris' post) and integrating all the
different versions into one.

<note to me> There's only 2000 sheets of paper and 3 bottles of printer ink
left in the storage cupboard so I'd better stock up soon if I'm going to
start playing with the Printing api again.....

> BTW:  Thank you for developing your Dolphin goodies.

Thanks for the kind comments.

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Schwab,Wilhelm K
In reply to this post by Ian Bartholomew-19
Ian,

> I _think_ I see what you are aiming for but I admit I can't really see why
> it would be preferable to the more usual way of printing - creating a
> "Printer" and then, either directly or indirectly, sending it pages to
> print.  It sounds a bit like you are just trying to duplicate the services
> provided by the Windows PrintSpooler?.

I suspect that Chris is trying to "turn objects into printed graphics",
which does have a lot of overhead that can be abstracted.  Windows
(usually) does a fine job of spooling graphics to a printer, but it does
not provide much (and probably should not try) for breaking things up
across pages, etc.  Windows can translate and clip; it also scales,
though I prefer to do that myself.  Regardless of whether one turns to
MS for scaling, there is still the question of which transformation,
which clipping rectangle, etc. to use for each object on each page.


Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Chris Uppal-3
In reply to this post by Ian Bartholomew-19
Ian,

> > The best I can put it is that it treats printing as a process.
> [snip]
>
> I _think_ I see what you are aiming for but I admit I can't really see why
> it would be preferable to the more usual way of printing - creating a
> "Printer" and then, either directly or indirectly, sending it pages to
> print.  It sounds a bit like you are just trying to duplicate the services
> provided by the Windows PrintSpooler?.

Hmm, why /did/ I do it that way... ?

Well, the immediate, practical, reason is that my print previewer has a tabbed
UI with one tab for each page, and generates the graphics for the selected page
on demand (its not a tabbed container, just a "tab" view of a list (1 to: n)
plus a single graphics pane for previewing the "current" page).  Obviously the
user will ask to see pages in whatever order suits, so it's easier to make the
"architecture" be driven by the consumer of pages rather than the supplier.
Also I want page ranges, collation, multiple-printing to work (the later two
are implemented badly or not at all in the print drivers I've encountered), so
I code that myself[*].  The code's simple enough but I don't want to duplicate
the logic in every page provider.  So I've pulled it out into the page consumer
(in this case the "print progress" dialog), where it sits very nicely with the
consumer-driven way the previewer works.

([*] Not that the copies and collation flags actually work in Windows; it
seems to be a long standing bug (even affects IE6) that I don't yet have a
workaround for :-(  Someday...)

But that's the practical reason.  The /real/ reason is that I have never been
thinking in terms of a document as a single entity that is flowed over a number
of pages.  I've always been thinking in terms of a collection of largely
independent pages.  So the "inside-out" architecture seems quite natural, even
though it's a bit more work.  Not all applications are like that, it's just how
my particular set of applications turned out.  Though I do have a vague feeling
that the page-centric picture is more general than flowed-document --
there is always going to be a tendency for page-centric thinking to sneak in by
the back door even in flowed-document (page numbering, widow control, and the
like).


> > Anyway, at the moment it has reached the point where I'd like to be
> > able to pass some sort of PrintSettings object around -- particularly
> > so that the PP function and real printing could agree on whether to
> > use Landscape mode without the user having to tell /both/ of them.
>
> That's basically what I'm using the PRINTDLGEX structure for.  The
> PrintDialog and PageSetupDialog can both use it and share the required
> state.  I can also access it from, for example, the PrintPreview to
> generate a valid preview.
>
> As you mentioned earlier though, my Printing is mainly used in conjunction
> with a RichEdit so there may be a better way to do it in a more general
> Printer class?.

I'm currently trying to create a PrintSettings object that can be passed
around.  The basic idea seems simple enough -- it's about half of your Printer
class, so I can copy large chunks of that (BTW, /especial/ thanks for that --
never in a thousand years would I have worked out how to get at the DEVMODE
thingies, for instance.  Deep magic!).  Unfortunately, it's proving tricky in
the details -- the problem is that I want narrow control over the print dialog,
so I want that to be an externally "visible" object, but the dialog
(CUPrintDialog) has to share the PRINTDLG[EX] with the PrintSettings.  I think
something similar will happen with the page setup too, but I haven't really
thought about that yet.  I suspect that I'll end up with something a bit like
the Holy Trinity -- three objects that are yet one  (though, this being
printing code, and /Windows/ printing code at that, the word "Holy" is totally
inappropriate ;-)  More prosaically, I think the PrintSettings will "own" a
CUPrintDialog and a CUPageSetupDialog, but be willing to let external code
"see" the dialogs and control when they are shown.


> OK.  I've more or less decided to have another look at the Printer classes
> (see the other Chris' post) so I'll see if I can redo the packaging to
> make it easier to use.

Many thanks !

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Printing

Ian Bartholomew-19
In reply to this post by Christopher J. Demers
Chris,

> Since you are taking requests... ;)  I seem to recall that you have
> different versions of a package related to printing for Window XP and
> non-XP (or maybe it is a different SP of XP).

I've had a go at refactoring the printer goodie and have come up with a set
of packages that I _think_ will work on all Windows OSs (all I know is that
it works on XP(SP1) and 2000 which are the only ones I have).  I've gone
back to just using the PrintDlg api (rather than trying to use PrintDlg and
PrintDlgEx), which means I lose a small bit of functionality, but makes it a
lot easier to accommodate all OSs.  I've also factored out all the places
where the RichEdit class (my wrapper for the RichTextEdit control available
in XP(SP1)) is used so that doesn't cause a problem any more.

There is a download (18K) available at the following address if you, or
anyone else, would like to try it but please bear in mind that is just a
test version so all the obvious warnings and disclaimers apply.

http://www.idb.me.uk/files/printing.zip

Unzipping the downloaded file should give you a single folder called Printer
which contains 6 packages.  The folder must be moved to my usual goodies
directory tree - normally creating a "My Documents/Dolphin Smalltalk 5.1/Ian
Bartholomew/Printer" folder.

You can't install these packages into an image that already contains any of
my existing printer support so I would recommend using a clean Dolphin 5.1.4
image.  Installing the package "IDB IDE Printer Extensions" should drag in
all the others as prerequisites.

Once installed all the Dolphin browsers should have "Print/Print
Preview/Page Setup" options added to the File menu. You can also use it
programmatically -

"create a Printer for the default system printer"
p := Printer new.

"Change the target printer or it's properties"
p showPrintDialog.

"Print to it - works with RichTextView instances as well"
p print: 'hello world'

I _really_ would appreciate any feedback on this, good or bad, especially
from anyone using it on 98 or ME.

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


12