Граница области доступной к печати в WinForms и учёт полей

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

Admiralisimys
Постоялец
Постоялец
 
Сообщения: 318
Зарегистрирован: 01.06.2009 (Пн) 10:26

Граница области доступной к печати в WinForms и учёт полей

Сообщение Admiralisimys » 08.11.2011 (Вт) 0:07

Здравствуйте.

В книге Чарльза Петцольда "Программирование для Microsoft Windows на Microsoft Visual Basic .NET" прочитал следующее
учёт заданных пользователем полей - это проблема программирования печати из приложений Windows Forms.
Предлагается формула приблизительного расчёта этих границ
Код: Выделить всё
Dim rectf As New RectangleF(ppea.MarginBounds.Left - (ppea.PageBounds.Width - grfx.VisibleClipBounds.Width) / 2, _
    ppea.MarginBounds.Top - (ppea.PageBounds.Height - grfx.VisibleClipBounds.Height) / 2, _
    ppea.MarginBounds.Width, ppea.MarginBounds.Height)
grfx.DrawRectangle(Pens.Black, rectf.X, rectf.Y, rectf.Width, rectf.Height)

В случаи если данные расчёты не устраивают, то предложено обратится к Win32 - вызвать GetDeviceCaps с параметрами PHYSICALOFFSETX/PHYSICALOFFSETY. Как я понимаю это будет самая верхняя левая точка (расчёт заданных пользователем полей пока не берём к вниманию).
А какая будет самая нижняя правая точка? VisibleClipBounds.Width/VisibleClipBounds.Height ?

Вот программа-пример
Код: Выделить всё
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Drawing.Printing
Imports System.Runtime.InteropServices

Class PrintPreviewSample
    Inherits Form

    Declare Function GetDeviceCaps_OldSchoolDeclaration Lib "gdi32.dll" Alias "GetDeviceCaps" (ByVal hDC As IntPtr, ByVal nIndex As Integer) As Integer

    <DllImport("gdi32.dll")> Public Shared Function GetDeviceCaps(ByVal hDC As IntPtr, ByVal nIndex As Integer) As Integer
    End Function

    Const PHYSICALOFFSETX As Integer = 112
    Const PHYSICALOFFSETY As Integer = 113

    'Dim ppc As New PreviewPrintController()
    Dim ppc As PreviewPrintController
    Dim prndoc As New PrintDocument()
    Dim bAllowDrawPreview As Boolean = False
    Dim prseldlg As New PrinterSelectionDialog()

    Shared Sub Main()
        Application.Run(New PrintPreviewSample())
    End Sub

    Sub New()
        Text = "Print Preview Sample"
        Menu = New MainMenu()
        Menu.MenuItems.Add("&Print and draw preview...", AddressOf MenuPrintAndDrawPreviewOnClick)
        Menu.MenuItems.Add("&Select printer...", AddressOf MenuPrintSelectOnClick)

        prndoc.DocumentName = Text
        'prndoc.PrintController = ppc
        AddHandler prndoc.PrintPage, AddressOf OnPrintPage

        prseldlg.PrinterName = prndoc.PrinterSettings.PrinterName
    End Sub

    Private Sub MenuPrintAndDrawPreviewOnClick(ByVal obj As Object, ByVal ea As EventArgs)
        ppc = New PreviewPrintController()
        prndoc.PrintController = ppc
        prndoc.Print()

        bAllowDrawPreview = True
        Invalidate()
    End Sub

    Private Sub MenuPrintSelectOnClick(ByVal obj As Object, ByVal ea As EventArgs)
        prseldlg.ShowDialog()
        prndoc.PrinterSettings.PrinterName = prseldlg.PrinterName
    End Sub

    Private Sub OnPrintPage(ByVal obj As Object, ByVal ppea As PrintPageEventArgs)
        Dim grfx As Graphics = ppea.Graphics()
        Dim fnt As New Font("Times New Roman", 120)
        Dim sPrinter As String = prndoc.PrinterSettings.PrinterName
        Dim szf As SizeF = grfx.MeasureString(sPrinter, fnt)

        Dim hDc As IntPtr = grfx.GetHdc()
        Dim x1 As Integer = GetDeviceCaps_OldSchoolDeclaration(hDc, PHYSICALOFFSETX)
        Dim y1 As Integer = GetDeviceCaps_OldSchoolDeclaration(hDc, PHYSICALOFFSETY)

        Dim x2 As Integer = GetDeviceCaps(hDc, PHYSICALOFFSETX)
        Dim y2 As Integer = GetDeviceCaps(hDc, PHYSICALOFFSETY)
        grfx.ReleaseHdc(hDc)

        grfx.Clear(Color.White)

        Dim rectf As New RectangleF(ppea.MarginBounds.Left - (ppea.PageBounds.Width - grfx.VisibleClipBounds.Width) / 2, _
                                    ppea.MarginBounds.Top - (ppea.PageBounds.Height - grfx.VisibleClipBounds.Height) / 2, _
                                    ppea.MarginBounds.Width, ppea.MarginBounds.Height)
        grfx.DrawRectangle(Pens.Black, rectf.X, rectf.Y, rectf.Width, rectf.Height)

        grfx.DrawRectangle(Pens.Blue, x1, y1, grfx.VisibleClipBounds.Width, grfx.VisibleClipBounds.Height)
        grfx.DrawRectangle(Pens.Brown, x2, y2, grfx.VisibleClipBounds.Width, grfx.VisibleClipBounds.Height)

        grfx.DrawString(sPrinter, fnt, Brushes.Black, (grfx.VisibleClipBounds.Width - szf.Width) / 2, (grfx.VisibleClipBounds.Height - szf.Height) / 2)

        ppea.HasMorePages = False
    End Sub
    'Private Sub ScaleImageIsotropically - From ImagePrint by Charles Petzold
    Private Sub ScaleImageIsotropically(ByVal grfx As Graphics, ByVal img As Image, ByVal rectf As RectangleF)
        Dim szf As New SizeF(img.Width / img.HorizontalResolution, img.Height / img.VerticalResolution)
        Dim fScale As Single = Math.Min(rectf.Width / szf.Width, rectf.Height / szf.Height)
        szf.Width *= fScale
        szf.Height *= fScale
        grfx.DrawImage(img, rectf.X + (rectf.Width - szf.Width) / 2, rectf.Y + (rectf.Height - szf.Height) / 2, szf.Width, szf.Height)
    End Sub

    Protected Overrides Sub OnPaint(ByVal pea As PaintEventArgs)
        If bAllowDrawPreview Then ScaleImageIsotropically(pea.Graphics, ppc.GetPreviewPageInfo()(0).Image, ClientRectangle)
        bAllowDrawPreview = False
    End Sub

End Class

'PrinterSelectionDialog.vb by Charles Petzold
'Imports System
'Imports System.Drawing
'Imports System.Drawing.Printing
'Imports System.Windows.Forms

Class PrinterSelectionDialog
    Inherits Form

    Private combo As ComboBox

    Sub New()
        Text = "Select Printer"
        FormBorderStyle = Windows.Forms.FormBorderStyle.FixedDialog
        ControlBox = False
        MaximizeBox = False
        MinimizeBox = False
        ShowInTaskbar = False
        StartPosition = FormStartPosition.Manual

        Dim lbl As New Label()
        lbl.Parent = Me
        lbl.Text = "Printer"
        lbl.Location = New Point(8, 8)
        lbl.Size = New Size(40, Font.Height)

        combo = New ComboBox()
        combo.Parent = Me
        combo.DropDownStyle = ComboBoxStyle.DropDownList
        combo.Location = New Point(48, 8)
        combo.Size = New Size(140, Font.Height)

        For Each str As String In PrinterSettings.InstalledPrinters
            combo.Items.Add(str)
        Next str

        Dim btn As New Button()
        btn.Parent = Me
        btn.Text = "OK"
        btn.Location = New Point(40, 32)
        btn.Size = New Size(40, 16)
        btn.DialogResult = Windows.Forms.DialogResult.OK
        AcceptButton = btn

        ClientSize = New Size(200, 56)
        AutoScaleBaseSize = New Size(4, 8)
    End Sub

    Protected Overrides Sub OnLoad(ByVal ea As EventArgs)
        Location = Point.op_Addition(ActiveForm.Location, Size.op_Addition(SystemInformation.CaptionButtonSize, SystemInformation.FrameBorderSize))
    End Sub

    Property PrinterName() As String
        Get
            Return combo.SelectedItem.ToString()
        End Get
        Set(ByVal value As String)
            combo.SelectedItem = value
        End Set
    End Property
End Class

p.s.
Предварительный просмотр создаётся не самым лучшим образом, но к сожалению при раскомментированном варианте картинка ppc.GetPreviewPageInfo()(0).Image как будто "цементируется", а последующие просто "складируются" что ли.
p.s.s.
В продолжении темы Declare Or DllImport? поставлен эксперимент, и на драйверах принтеров (а не PDF\XPS, для этих всегда 0) были получены разные числовые значения (в одном из запусков и только при одном оставленном объявлении функции). Всего лишь +/- единица, но всё же.

Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 17

    TopList