IanSp Ответов: 1

Как разработать подпрограмму, которая записывает данные в форму и может быть использована с помощью файла .printdocument


I'm hoping here is a simple answer that my lack of programming skills are hiding from me... I generate reports that I'd like to immediately display on a FORM for the Users review and acceptance. Once accepted this can be PRINTED. The "on-form" report is a subset of the full report that is included in the printed document (includes logo's, border graphics and more detail text, etc), so most of the generation of the document is the same, but not all. Rather than duplicate all the report code twice, once for the form and again for printing I hope there is a way to generate a common subroutine that both the form report and printing routines can call and that contains the conditional formatting lines.

Для записи в форму:

Module DisplayCode

  Sub WriteOnFrom()
    ' writes to form 

    With frmOutput
      .Visible = True
      .WindowState = FormWindowState.Normal
      .PrintPreviewControl.Visible = False
      Dim drawPen As Pen
      Dim drawBrush As SolidBrush
      Dim drawFont As Font
      Dim drawObject As Graphics = .CreateGraphics()  'Create object for the page
      
      Dim drawString As String = "Sample Text"

      drawObject.Clear(Color.White)   'clears the current screen

      drawFont = New Font("Arial", 16, FontStyle.Bold)
      drawBrush = New SolidBrush(Color.BlueViolet)
      drawObject.DrawString("text in a box", drawFont, drawBrush, 150, 50)
      drawFont = New Font("Calibri", 20, FontStyle.Italic)
      drawBrush = New SolidBrush(Color.Red)
      drawObject.DrawString("text above a line", drawFont, drawBrush, 150, 290)
      drawPen = New Pen(Color.Black, 3)
      drawObject.DrawRectangle(drawPen, 120, 50, 200, 25)
      drawPen = New Pen(Color.Purple, 5)
      drawObject.DrawLine(drawPen, 150, 320, 350, 320)

      drawFont.Dispose()
      drawBrush.Dispose()
      drawObject.Dispose()
    End With

  End Sub

End Module


На объект printdocument:

Public Class PrintOutput
  Inherits System.Drawing.Printing.PrintDocument

Private Sub PrintOutput_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles Me.PrintPage
    'Prepares printed document

    Dim drawPen As Pen
    Dim drawBrush As SolidBrush
    Dim drawFont As Font
    Dim drawString As String = "Sample Text"

    'Can I move this to a subroutine outside the Class?
    drawFont = New Font("Arial", 16, FontStyle.Bold)
    drawBrush = New SolidBrush(Color.BlueViolet)
    e.Graphics.DrawString("text in a box", drawFont, drawBrush, 150, 50)
    drawFont = New Font("Calibri", 20, FontStyle.Italic)
    drawBrush = New SolidBrush(Color.Red)
    e.Graphics.DrawString("text above a line", drawFont, drawBrush, 150, 290)
    drawPen = New Pen(Color.Black, 3)
    e.Graphics.DrawRectangle(drawPen, 120, 50, 200, 25)
    drawPen = New Pen(Color.Purple, 5)
    e.Graphics.DrawLine(drawPen, 150, 320, 350, 320)

    e.HasMorePages = False

    drawFont.Dispose()
    drawBrush.Dispose()
    drawPen.Dispose()

  End Sub
End Class

Конечно, это один и тот же отчет для обоих на данный момент, так что просто пример для демонстрации принципов.

Что я уже пробовал:

Конечно, можно использовать элемент управления PrintPreview на моем frmOutput и разработать все это как объект PrintDocument, но я бы предпочел этого не делать. Во-первых, это занимает некоторое время, чтобы сгенерировать это (on-form мгновенно), во-вторых, я не заинтересован в формате формата бумаги и т. д. и просто помещаю его на frmOutput фиксированного размера и, наконец, я все еще не знаю, как сгенерировать подмножество этого отчета для элемента управления PrintPreview относительно полного отчета для печати.

Кстати, для отчета о форме, похоже, мне все еще нужно использовать .CreateGraphics() писать самой формы, что представляет собой конфликт, чтобы просто с помощью электронной.Графика. для PrintDocument. Я не особенно стремлюсь писать непосредственно в форму, поэтому подойдет любой элемент управления, помещенный в форму, которая принимает текст и графику.

Есть какие-нибудь замечательные предложения?

Richard MacCutchan

Мое единственное предложение состояло бы в том, чтобы перестать делать вещи настолько трудными для себя и использовать встроенные функции Print и PrinPreview .Сеть, с конкретной целью сделать жизнь проще.

IanSp

Спасибо за ваш ответ. В интересах простоты этого вопроса я не перечислил все причины, по которым я предпочел бы не использовать элемент управления PrintPreview в своей форме, но пока я его не исключаю. Однако, если бы я должен был использовать его, как передать условное условие процедуре PrintPage, чтобы я мог распечатать полный вывод на принтер и только его части (подмножество) в элемент управления PrintPreview на форме, я, кажется, не могу найти способ передать флаг подпрограмме PrintPage. Ваша проницательность была бы очень полезна.

1 Ответов

Рейтинг:
11

OriginalGriff

Это довольно просто - в одном фрагменте кода Вы получаете свой графический объект из Form.CreateGraphics:

Dim drawObject As Graphics = .CreateGraphics()  'Create object for the page
В другом случае вы используете предоставленный контекст из PrintDocument:
e.Graphics.DrawString("text in a box", drawFont, drawBrush, 150, 50)

Если вы пишете свой "комбинированный" метод, чтобы принять графический объект в качестве параметра и нарисовать его, вы можете передать контекст из своего метода WriteOnFrom или обработчика событий, и он будет делать то же самое с разными выходами.

Но... ваш метод WriteOnFrom не должен создавать контекст в любом случае - вы должны обрабатывать событие Paint и использовать предоставленный графический контекст там. Если вы этого не сделаете, то вам придется вручную выяснить, что форма была повторно отображена, и заново нарисовать ее самостоятельно. Или когда он заходит за другое приложение, или сворачивается и восстанавливается, вы больше не сможете видеть свои данные.


IanSp

Прекрасно, спасибо! Мне просто нужно было знать, что это выполнимо, и ваш ответ дал мне достаточно, чтобы самому разобраться в деталях. Я создал общую подпрограмму GenerateReport (), передающую графический объект и флаг в качестве параметров:

 
Sub GenerateReport(graphicsTarget As Object, OnForm As Boolean)

    Dim drawPen As Pen
    Dim drawBrush As SolidBrush
    Dim drawFont As Font
    'Dim drawObject As Graphics = graphicsTarget.CreateGraphics()      ' Create the graphics object for the page
    Dim drawString As String = "Sample Text"

    graphicsTarget.Clear(Color.White)   'clears the current screen

    If OnForm Then
      drawFont = New Font("Arial", 16, FontStyle.Bold)
      drawBrush = New SolidBrush(Color.BlueViolet)
      graphicsTarget.DrawString("text in a box", drawFont, drawBrush, 150, 50)
      drawPen = New Pen(Color.Black, 3)
      graphicsTarget.DrawRectangle(drawPen, 120, 50, 200, 25)
    End If
    drawPen = New Pen(Color.Purple, 5)
    drawFont = New Font("Calibri", 20, FontStyle.Italic)
    drawBrush = New SolidBrush(Color.Red)
    graphicsTarget.DrawString("text above a line", drawFont, drawBrush, 150, 290)
    graphicsTarget.DrawLine(drawPen, 150, 320, 350, 320)

    drawFont.Dispose()
    drawBrush.Dispose()
    'drawObject.Dispose()

  End Sub
 

А потом звонили от каждого следующим образом:
 Sub WriteOnFrom()
    ' writes to form 

    Dim OnForm As Boolean = True
    With frmOutput
      .Visible = True
      .WindowState = FormWindowState.Normal
      .PrintPreviewControl.Visible = False
      GenerateReport(frmOutput.CreateGraphics, OnForm)
    End With
  End Sub

  Private Sub PrintOutput_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles Me.PrintPage
    'Prepares printed document

    Dim OnForm As Boolean = False
    GenerateReport(e.Graphics, OnForm)
    'e.HasMorePages = False

  End Sub


Я действительно заметил в своем проекте разработки проблему с потерей графики, как вы упомянули, но в этом примере она не возникает (не знаю почему). Я решил эту проблему в своем проекте, просто вызывая GenerateReport() каждый раз, когда запускается событие Paint. Ваши комментарии заставляют меня думать, что я могу улучшить это. Я постараюсь разобраться в этом сам, но если вы укажете мне лучшее направление, я буду вам очень признателен.

OriginalGriff

Не забудьте также утилизировать свой чертежный карандаш, иначе вы будете "пропускать" ручки для каждого события рисования.
Я бы предположил, что, поскольку перо, шрифт и кисть фактически статичны, вы объявляете их как общие элементы уровня класса (по одному набору для формы и не-формы), поэтому вам вообще не нужно создавать и утилизировать их в своем обработчике событий. Это не только ускоряет ваше событие рисования - всегда хорошая идея, - но и не рискует тем, что ресурсы не будут освобождены.

IanSp

Ваша последняя точка зрения теперь захвачена, спасибо. Я уже давно программирую VB6 и VBA. Я программирую только для того, чтобы сделать свои инженерные расчеты более доступными для других, но VB6 теперь становится трудно поддерживать на Win 10, поэтому я теперь заставляю себя учиться VB.Net. Сначала это было очень тяжело, но теперь мне это нравится... Ваши перспективы бесценны. Еще раз спасибо!

OriginalGriff

Всегда пожалуйста!

Возможно, Вам было бы легче, если бы вы переключились с VB на C# - это почти то же самое (но с { и}), но это не позволяет вам ничего делать, используя устаревший код VB6, так что вы в конечном итоге полностью .NET быстрее.

IanSp

Хммм, я видел это предложение много раз раньше. Однако VBA по-прежнему необходим для моей работы с Excel, и у меня есть большая библиотека кода VB6 для преобразования. Поскольку программирование-это всего лишь неполный рабочий день, изучение нового языка казалось мне 2 гигантскими шагами вместо 1 (хотя мне все еще кажется, что мне приходится касаться практически каждой строки моего унаследованного кода VB6). Я просто надеюсь, что MS продолжит поддерживать его... так же, как я потратил время, чтобы изучить его. Однако, как только я смогу получить полную функциональность в VB.Net я мог бы рассмотреть ваше предложение, конвертируя VB.Net to C# может быть куском пирога по сравнению с преобразованием VB6 (во что угодно).