הערה
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות להיכנס או לשנות מדריכי כתובות.
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות לשנות מדריכי כתובות.
Question
Friday, December 4, 2009 4:44 AM | 1 vote
I'm using the PrintPreviewDialog. Works great, but I really need to allow the user to select a printer instead of just having the print go directly to the default printer. Any ideas on this? Can't believe it isn't default functionality in the control.
All replies (21)
Friday, December 11, 2009 12:54 PM ✅Answered | 2 votes
Here is what I did to fix the problem.
I created a class called PrintPreviewDialogSelectPrinter. In it I have two subs. Basically, the class inherits the PrintPreviewDialog, adds a button that functions as I want, and removes the button that doesn't. I finally found a sample online that I could understand. I'm sure there are better ways of doing this, but it works very well. Call it just like PrintPreviewDialog.
Imports System.Drawing.Printing
Public Class PrintPreviewDialogSelectPrinter
Inherits PrintPreviewDialog
Private Sub myPrintPreview_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
'Get the toolstrip from the base control
Dim ts As ToolStrip = CType(Me.Controls(1), ToolStrip)
'Get the print button from the toolstrip
Dim printItem As ToolStripItem = ts.Items("printToolStripButton")
'Add a new button
With printItem
Dim myPrintItem As ToolStripItem
myPrintItem = ts.Items.Add(.Text, .Image, New EventHandler(AddressOf MyPrintItemClicked))
myPrintItem.DisplayStyle = ToolStripItemDisplayStyle.Image
'Relocate the item to the beginning of the toolstrip
ts.Items.Insert(0, myPrintItem)
End With
'Remove the orginal button
ts.Items.Remove(printItem)
End Sub
Private Sub MyPrintItemClicked(ByVal sender As Object, ByVal e As EventArgs)
Dim dlgPrint As New PrintDialog
Try
With dlgPrint
.AllowSelection = True
.ShowNetwork = True
.Document = Me.Document
End With
If dlgPrint.ShowDialog = Windows.Forms.DialogResult.OK Then
Me.Document.Print()
End If
Catch ex As Exception
MsgBox("Print Error: " & ex.Message)
End Try
End Sub
End Class
Friday, December 4, 2009 5:48 AM
you can use a PrintDialog to select the printer
http://msdn.microsoft.com/en-us/library/aa983680(VS.71).aspx
Friday, December 4, 2009 9:03 AM
Override the PrintPreviewDialog and add a button to the toolstrip. Show a control of your choosing on the click of the button. See the PrintRegister program at www.johnweinhold.com for an example.
Friday, December 4, 2009 4:36 PM
I'm using the PrintPreviewDialog control. The sample is using the Print Preview Control.
Is there a way to make the default print button show the printer dialog for selecting a printer instead of going straight to print?
Friday, December 4, 2009 4:47 PM
My sample uses the PrintPreviewDialog. Try it. It shows you how to use the control's events also.
Friday, December 4, 2009 4:49 PM
My sample uses the PrintPreviewDialog. Try it. It shows you how to use the control's events also.
I missed it. Can you be more specific as to where I should look?
Here is what I am doing:
ppdForm.Document = .PreparePrintDocument()
ppdControl.UseAntiAlias = True
ppdControl.WindowState = FormWindowState.Maximized
ppdControl.ShowDialog()
Friday, December 4, 2009 4:55 PM
BTW, I'm looking at the PrintCheckRegister example.
Friday, December 4, 2009 5:08 PM
BTW, I'm looking at the PrintCheckRegister example.
Yes that's the right example. Study it. It shows how to do what you asked. Override the print button OnClick and show the printdialog.
Friday, December 4, 2009 5:14 PM
Well, I don't see it.
Anyone else have any thoughts?
Wednesday, December 9, 2009 7:49 AM
Hello, Allen
Please follow jwavila's advice, PrintDialog is the right Component.
Thanks
Chao
Wednesday, December 9, 2009 3:11 PM
Hello, Allen
Please follow jwavila's advice, PrintDialog is the right Component.
Thanks
Chao
Not really. I know the PrintDialog will do it, but the question is how to override the PrintPreviewDialog.
Wednesday, December 9, 2009 6:07 PM
Add a PrintDocument, PrintPreviewDialog, PrintDialog and a Button to a Windows Form. Replace the Form1 code with the code below. Press F5 and then the ToolStripButton labeled "Printer".
Public Class Form1
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
PrintPreviewDialog1.ShowDialog()
End Sub
Dim WithEvents PDB As New ToolStripButton("Printer")
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
PrintPreviewDialog1.Document = PrintDocument1
PrintDialog1.Document = PrintDocument1
CType(PrintPreviewDialog1.Controls(1), ToolStrip).Items.Add(PDB)
End Sub
Private Sub PDB_Click1(ByVal sender As Object, ByVal e As EventArgs) Handles PDB.Click
PrintDialog1.ShowDialog()
End Sub
End Class
Wednesday, December 9, 2009 6:32 PM
Because the layout in the print preview is depended on the printer and the settings for that printer you should set the printer
using the print dialog prior to viewing it in the print preview control.
Another tactic (the one I use since I don’t like the print preview control) is to build one.
Basically the same code that prints to the printer can draw on any control. I use a panel myself.
Create a class that inherits the PrintDocument and Move the drawing code out of the print doc’s
Print_Page event into a public function that you can pass the graphics objects from a print
document or a control For example if you start a new windows forms project and add a class called
AdressLabels.
Paste the below code into the AdressLabels code window
Namespace AddressLabels
Public Enum TypeOfPrintJob
Display
Paper
End Enum
Public Class Document
Inherits Printing.PrintDocument
#Region " String Formats"
Private strfmtCenter As New StringFormat(StringFormatFlags.NoWrap) With {.Alignment = StringAlignment.Center, .Trimming = StringTrimming.EllipsisCharacter, .LineAlignment = StringAlignment.Center}
Private strfmtLeft As New StringFormat(StringFormatFlags.NoWrap) With {.Alignment = StringAlignment.Near, .Trimming = StringTrimming.EllipsisCharacter, .LineAlignment = StringAlignment.Center}
Private strfmtRight As New StringFormat(StringFormatFlags.NoWrap) With {.Alignment = StringAlignment.Far, .Trimming = StringTrimming.EllipsisCharacter, .LineAlignment = StringAlignment.Center}
Private strfmtWrap As New StringFormat() With {.Alignment = StringAlignment.Near, .Trimming = StringTrimming.None, .LineAlignment = StringAlignment.Near}
#End Region
'What it is being printed on
Private mPrintFor As TypeOfPrintJob
Public Property PrintFor() As TypeOfPrintJob
Get
Return mPrintFor
End Get
Set(ByVal value As TypeOfPrintJob)
mPrintFor = value
End Set
End Property
'Does it have more labels to print
Private mHasMoreLabels As Boolean
Public ReadOnly Property HasMoreLabels() As Boolean
Get
Return mHasMoreLabels
End Get
End Property
'collection of addresses
Private mAddresses As List(Of Address)
Public Property Addresses() As List(Of Address)
Get
If mAddresses Is Nothing Then
mAddresses = New List(Of Address)
End If
Return mAddresses
End Get
Set(ByVal value As List(Of Address))
mAddresses = CType(value, List(Of Address))
End Set
End Property
'font used
Private mLabelFont As Font
Public Property LabelFont() As Font
Get
If mLabelFont Is Nothing Then
mLabelFont = New Font("Arial", 10, FontStyle.Regular, GraphicsUnit.Pixel)
End If
Return mLabelFont
End Get
Set(ByVal value As Font)
mLabelFont = CType(value, Font)
End Set
End Property
'
Private mLayout As LabelLayout
Public Property Layout() As LabelLayout
Get
If mLayout Is Nothing Then
mLayout = New LabelLayout
End If
Return mLayout
End Get
Set(ByVal value As LabelLayout)
mLayout = CType(value, LabelLayout)
End Set
End Property
Private Sub AdressLabels_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint
Dim PrintAddress As Address
'make sure printed flag is cleared
'before starting print job
For Each PrintAddress In Addresses
PrintAddress.Printed = False
Next
End Sub
Private Sub Print_Page(ByVal sender As Object, ByVal e As Printing.PrintPageEventArgs) Handles MyBase.PrintPage
'draw the labels on the printers graphics
DrawLabels(e.Graphics, e.MarginBounds, e.MarginBounds)
'let the print doc know if there is
'more printing to do
e.HasMorePages = HasMoreLabels
End Sub
'All the printing is done here
Public Function DrawLabels(ByVal OnGraphics As Graphics, ByVal PrintArea As Rectangle, ByVal ClipTo As Rectangle) As Point
Dim PrintAddress As Address
Dim CityStateZip As String
Dim BottomRight As New Point(PrintArea.Width, 0)
With Layout
'starting location is upperleft corner of the pages margin
.LabelLocation = PrintArea.Location
.FontHeight = LabelFont.Height
End With
For Each PrintAddress In Addresses
'if past bottom of page bail-out to start new page
If PrintFor = TypeOfPrintJob.Paper AndAlso Layout.LabelBounds.Bottom > PrintArea.Bottom Then
'let document know there are more pages
mHasMoreLabels = True
Return BottomRight
End If
'only print addresses that were not
'printed on any previous pages
If Not PrintAddress.Printed Then
CityStateZip = String.Format("{0}, {1} {2}", PrintAddress.City, PrintAddress.State, PrintAddress.Zip)
'Print label bounds to make it easier to adjust label size
'after you have the size you want comment out
OnGraphics.DrawRectangle(Pens.Blue, Layout.LabelBounds)
' (alignment what-not)
' Text Font Brush Rectangle StringFormat
OnGraphics.DrawString(PrintAddress.Name, LabelFont, Brushes.Black, Layout.Name, strfmtCenter)
OnGraphics.DrawString(PrintAddress.Address, LabelFont, Brushes.Black, Layout.Address, strfmtCenter)
OnGraphics.DrawString(CityStateZip, LabelFont, Brushes.Black, Layout.CityStaeZip, strfmtCenter)
'check to see if another label will fit on the line
If Layout.LabelBounds.Right + Layout.LabelBounds.Width < PrintArea.Right Then
Layout.LabelLocation = New Point(Layout.LabelBounds.Right, Layout.LabelBounds.Top)
Else
'start new line of labels
Layout.LabelLocation = New Point(PrintArea.Left, Layout.LabelBounds.Bottom)
BottomRight.Y += Layout.LabelBounds.Height
End If
'mark is address as printed
PrintAddress.Printed = True
End If
Next
'clear printed flags because all have printed
For Each PrintAddress In Addresses
PrintAddress.Printed = False
Next
mHasMoreLabels = False
Return BottomRight
End Function
End Class
'a single address
Public Class Address
Private mName As String
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal value As String)
mName = value
End Set
End Property
Private mAddress As String
Public Property Address() As String
Get
Return mAddress
End Get
Set(ByVal value As String)
mAddress = value
End Set
End Property
Private mCity As String
Public Property City() As String
Get
Return mCity
End Get
Set(ByVal value As String)
mCity = value
End Set
End Property
Private mState As String
Public Property State() As String
Get
Return mState
End Get
Set(ByVal value As String)
mState = value
End Set
End Property
Private mZip As String
Public Property Zip() As String
Get
Return mZip
End Get
Set(ByVal value As String)
mZip = value
End Set
End Property
Private mPrinted As Boolean
Public Property Printed() As Boolean
Get
Return mPrinted
End Get
Set(ByVal value As Boolean)
mPrinted = value
End Set
End Property
End Class
'Generates layout rectangles for labels
Public Class LabelLayout
Private Const Left_Padding As Integer = 3
Private TopPadding As Integer
Private mLabelLocation As Point
Public Property LabelLocation() As Point
Get
Return mLabelLocation
End Get
Set(ByVal value As Point)
mLabelLocation = value
End Set
End Property
Private mLabelSize As Size
Public Property LabelSize() As Size
Get
Return mLabelSize
End Get
Set(ByVal value As Size)
mLabelSize = value
'vert center address in label
TopPadding = Math.Round((mLabelSize.Height - FontHeight * 3) * 0.5)
End Set
End Property
Private mFontHeight As Double
Public Property FontHeight() As Double
Get
Return mFontHeight
End Get
Set(ByVal value As Double)
mFontHeight = value
'vert center address in label
TopPadding = Math.Round((mLabelSize.Height - mFontHeight * 3) * 0.5)
End Set
End Property
'rectangles for formating the labels layout based on the size and location
Public ReadOnly Property LabelBounds() As Rectangle
Get
Return New Rectangle(mLabelLocation, mLabelSize)
End Get
End Property
Public ReadOnly Property Name() As Rectangle
Get
Return New Rectangle(LabelBounds.Left + Left_Padding, LabelBounds.Top + TopPadding, LabelBounds.Width - Left_Padding * 2, FontHeight)
End Get
End Property
Public ReadOnly Property Address() As Rectangle
Get
Return New Rectangle(Name.Left, Name.Bottom, Name.Width, FontHeight)
End Get
End Property
Public ReadOnly Property CityStaeZip() As Rectangle
Get
Return New Rectangle(Name.Left, Address.Bottom, Name.Width, FontHeight)
End Get
End Property
End Class
End Namespace
Then paste this code over the form1’s code
Public Class Form1
'Label Print document
Private mLabelDoc As AddressLabels.Document
Public Property LabelDoc() As AddressLabels.Document
Get
If mLabelDoc Is Nothing Then
mLabelDoc = New AddressLabels.Document
End If
Return mLabelDoc
End Get
Set(ByVal value As AddressLabels.Document)
mLabelDoc = CType(value, AddressLabels.Document)
End Set
End Property
Private Sub PrintBut_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim dlgPrint As New PrintDialog
'display print dialog to print labels
If dlgPrint.ShowDialog() = Windows.Forms.DialogResult.OK Then
'tell label print document that we are printing on paper
'i.e to printer not to a form
LabelDoc.PrintFor = AddressLabels.TypeOfPrintJob.Paper
'pass the dialogs printer settings to the print doc
LabelDoc.PrinterSettings = dlgPrint.PrinterSettings
'start printing
LabelDoc.Print()
End If
End Sub
Private Sub panPreview_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
'panel to paint the labels on
Dim PreviewOn As Panel = CType(sender, Panel)
Dim BottomRight As Point
'get the scroll offsets
Dim TopLeft As New Point(PreviewOn.HorizontalScroll.Value * -1, PreviewOn.VerticalScroll.Value * -1)
'tell the label print doc that you are printing
'for display i.e. on the panel
LabelDoc.PrintFor = AddressLabels.TypeOfPrintJob.Display
'call the drawlabels sub and pass the graphics from the panel
BottomRight = LabelDoc.DrawLabels(e.Graphics, New Rectangle(TopLeft, New Size(800, 600)), e.ClipRectangle)
'set the min scroll
PreviewOn.AutoScrollMinSize = New Size(BottomRight)
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim RandAddress As New Random
'Sets size for each label
LabelDoc.Layout.LabelSize = New Size(200, 75)
LabelDoc.LabelFont = New Font("Garamond", 14, FontStyle.Regular, GraphicsUnit.Pixel)
'Add some addresses
Dim newAddress As AddressLabels.Address
For I As Integer = 0 To 45
newAddress = New AddressLabels.Address
With newAddress
.Name = String.Format("Else, Someone {0}", I.ToString)
.Address = String.Format("{0} Some Other Ave", RandAddress.Next(1001, 10000).ToString)
.City = "Some Place"
.State = "CA"
.Zip = "93257"
End With
LabelDoc.Addresses.Add(newAddress)
Next
'add print button
Dim butPrint As New Button
With butPrint
.Location = New Point(5, 5)
.Text = "Print"
End With
AddHandler butPrint.Click, AddressOf PrintBut_Click
'add panel to hold print button
Dim TopPanel As New Panel
With TopPanel
.Dock = DockStyle.Top
.Height = butPrint.Bottom + 5
.Controls.Add(butPrint)
End With
'add panel to use for print
'preview
Dim panPreview As New Panel
With panPreview
.Dock = DockStyle.Fill
.BackColor = SystemColors.Window
.BorderStyle = BorderStyle.Fixed3D
.Height = Me.Height - butPrint.Bottom + 20
.AutoScroll = True
End With
AddHandler panPreview.Paint, AddressOf panPreview_Paint
Me.Controls.Add(panPreview)
Me.Controls.Add(TopPanel)
End Sub
End Class
Friday, December 11, 2009 2:04 PM
"I finally found a sample online that I could understand"
Please post a link to your source.
Friday, December 11, 2009 2:20 PM
"I finally found a sample online that I could understand"
Please post a link to your source.
Good idea:
http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_22108522.html
Monday, October 4, 2010 1:55 PM
Hello Allen,
thank you for your code. I use it in my C# application:
public class PrintPreviewDialogSelectPrinter : PrintPreviewDialog
{
public PrintPreviewDialogSelectPrinter()
{
Shown += myPrintPreview_Shown;
}
private void myPrintPreview_Shown(object sender, System.EventArgs e)
{
//Get the toolstrip from the base control
ToolStrip ts = (ToolStrip)this.Controls[1];
//Get the print button from the toolstrip
ToolStripItem printItem = ts.Items[0]; //"printToolStripButton"
ToolStripItem myPrintItem;
myPrintItem = ts.Items.Add(printItem.Text, printItem.Image, new EventHandler(MyPrintItemClicked));
myPrintItem.DisplayStyle = ToolStripItemDisplayStyle.Image;
//Relocate the item to the beginning of the toolstrip
ts.Items.Insert(0, myPrintItem);
//Remove the orginal button
ts.Items.Remove(printItem);
}
private void MyPrintItemClicked(object sender, EventArgs e)
{
PrintDialog dlgPrint = new PrintDialog();
try
{
dlgPrint.AllowSelection = true;
dlgPrint.ShowNetwork = true;
dlgPrint.Document = this.Document;
if (dlgPrint.ShowDialog() == DialogResult.OK)
{
this.Document.Print();
}
}
catch (Exception ex)
{
MessageBox.Show("Print Error: " + ex.Message);
}
}
}
Friday, September 23, 2011 12:55 AM
thanks, it works like a charm. :)
you solved to code this solution, and solved my problem.
Friday, March 1, 2013 8:56 AM | 1 vote
I had the same problem after changing my print method to PrintPreviewDialog. To coorect this I added the line:
pdiag.ShowDialog(); // pdiag previously defined as a PrintDialog
Before my PrintPreviewDialog ... line.
This sets the printer. The print button in the Print Preview tool bar uses it as requested. So the trick is to set it before the PrintPreviewDialogue is executed.
Web Developer
Wednesday, September 17, 2014 2:37 AM
Nice and quick solution (even after 5 years). I needed this for C# and it works still very well.
Monday, December 12, 2016 11:02 AM
Here is what I did to fix the problem.
I created a class called PrintPreviewDialogSelectPrinter. In it I have two subs. Basically, the class inherits the PrintPreviewDialog, adds a button that functions as I want, and removes the button that doesn't. I finally found a sample online that I could understand. I'm sure there are better ways of doing this, but it works very well. Call it just like PrintPreviewDialog.
Imports System.Drawing.Printing Public Class PrintPreviewDialogSelectPrinter Inherits PrintPreviewDialog Private Sub myPrintPreview_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown 'Get the toolstrip from the base control Dim ts As ToolStrip = CType(Me.Controls(1), ToolStrip) 'Get the print button from the toolstrip Dim printItem As ToolStripItem = ts.Items("printToolStripButton") 'Add a new button With printItem Dim myPrintItem As ToolStripItem myPrintItem = ts.Items.Add(.Text, .Image, New EventHandler(AddressOf MyPrintItemClicked)) myPrintItem.DisplayStyle = ToolStripItemDisplayStyle.Image 'Relocate the item to the beginning of the toolstrip ts.Items.Insert(0, myPrintItem) End With 'Remove the orginal button ts.Items.Remove(printItem) End Sub Private Sub MyPrintItemClicked(ByVal sender As Object, ByVal e As EventArgs) Dim dlgPrint As New PrintDialog Try With dlgPrint .AllowSelection = True .ShowNetwork = True .Document = Me.Document End With If dlgPrint.ShowDialog = Windows.Forms.DialogResult.OK Then Me.Document.Print() End If Catch ex As Exception MsgBox("Print Error: " & ex.Message) End Try End Sub End Class
Very good solution. Thanks a lot.
Sunday, January 22, 2017 3:10 PM
I allow myself some remarks to the code:
- Moving the initialising code to sub New() prevents errors at second call
- It is enough, to add a handler to the existing button. One may not exchange it.
- It is usefull, to close the dialog, wenn job is done.
So that is what I use:
Friend Class PrintPreviewDialogWithPrinter
Inherits PrintPreviewDialog
Public Sub New()
'Get the toolstrip from the base control
Dim ts As ToolStrip = CType(Me.Controls("toolStrip1"), ToolStrip)
'Get the print button from the toolstrip
Dim PrintButton As ToolStripItem = ts.Items("printToolStripButton")
AddHandler PrintButton.Click, AddressOf MyPrintItemClicked
End Sub
Private Sub myPrintPreview_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
'if you like:
Me.Height = FrmMain.Height
Me.Width = FrmMain.Width
End Sub
Private Sub MyPrintItemClicked(ByVal sender As Object, ByVal e As EventArgs)
Dim dlgPrint As New PrintDialog
Try
With dlgPrint
.AllowSelection = True
.ShowNetwork = True
.Document = Me.Document 'me verweist offenbar schon auf das Doc im Dialog.
End With
If dlgPrint.ShowDialog = Windows.Forms.DialogResult.OK Then
Me.Document.Print()
End If
Catch ex As Exception
MsgBox("Print Error: " & ex.Message)
End Try
Me.Close() 'to make it more convenient
End Sub