Vol.833 26.Nov.2021

セリカLB2000GT VB2019_印刷

C セリカLB2000GT 〜18R-Gエンジン

by fjk

 abc817で「トヨタセリカLB2000GT」(hachette)の組立が終わったことを報告したが、同シリーズは更に1/4スケールの「18R-Gエンジン」が追加となり150号まで続いた。エンジンモデルはスケルトン構造で、ピストンやクランクシャフト、バルブ、ラジエターファンが動くなど、ガソリンエンジンの構造がよく判る。この頃の車のエンジンはユーザー自身がカスタマイズ化するなど結構手入れをすることが当たり前だったのだが、今の車は電子化され、ユーザには手に負えない物となった。
 車本体よりパーツが少ないのだが、組立には3日を要した。特にネジ止めにはヘッドが6角の専用ネジが多く採用され、これに合う工具がなく、ラジオペンチでこまめに回すしかなかった(ミニ6角BOXで合う物もあったが)。
 このシリーズの問題点は、車本体の所でも述べたが、各号の付属パーツと組立時のタイミングが合わず、パーツの取り置きが多いことである。コロナの影響で生産計画がうまくいかなかったのかもしれないが、今後のシリーズには取り置きが無いようにして欲しいものである。

  
完成した18R-Gエンジン


V VisualBasic(7) 〜印刷

by fjk

 印刷はPrintDocumentクラスのPrintメソッドで開始するが、どのように印刷するかをPrintPageイベントハンドラ内に記述する。PrintPageイベントで受け取るPrintPageEventArgsオブジェクトのGraphicsプロパティにDrawImageやDrawStringメソッドなどを使って描画を行い、Printメソッドで印刷を実行する。

1.とりあえず画像を印刷してみる
 @ 新しいフォームを作成し、Button1(印刷)、PicturbBox1、TextBox1を配置し、下記を入力。
 A TextBoxをクリックし、ファイル選択画面でファイルを選ぶと、picturboxに画像を表示する。
 B「印刷」ボタンを押すと、プリンタ選択ダイアログが表示され、「OK」を押すと印刷を開始する。
 C「印刷中」とダイアログが表示され。選択したプリンタ(orファイル)に画像が印刷される。
※ この例で、画像の印刷位置は左上(x=0、y=0)で、紙面の横幅いっぱいに印刷(余白が正しくないので左に寄っている)。
 余白については、後述の「印刷設定」を参考に。
※ 画像の印刷サイズを変えるには、以下のメソッドなどを利用。
DrawImage(img.d-x,d-y[,d-w,d-h])
img:元画像、d-x,d-y:描画位置、d-w:描画の幅、d-h:描画の高さ (d-w、d-hを省略すると原寸)
DrawImage(img,d-rect)
img:元画像、d-rect:描画エリアのrect構造体
Public Class Form1
    Private Sub TextBox1_Click(sender As Object, e As EventArgs) Handles TextBox1.Click
        Dim ofd As New OpenFileDialog() With {
            .Title = "ファイル選択",
            “画像ファイル|*.bmp;*.jpg;*.gif;*.png"}
        If ofd.ShowDialog() <> DialogResult.OK Then
            Return
        End If
        TextBox1.Text = System.IO.Path.GetFileName(ofd.FileName)
        Dim img = Image.FromFile(ofd.FileName)
        If img Is Nothing Then
            MessageBox.Show("ファイルが開けません")
            Return
        Else
            PictureBox1.Image = img
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If PictureBox1.Image Is Nothing Then
            MessageBox.Show("印刷する画像がありません")
            Return
        End If
        Dim prd As New System.Drawing.Printing.PrintDocument
        Dim pdg As New PrintDialog
        AddHandler prd.PrintPage, AddressOf prd_PgPrint
        pdg.Document = prd
        If pdg.ShowDialog() = DialogResult.OK Then
            prd.Print()
        End If
    End Sub

    Private Sub prd_PgPrint(sender As Object, e As System.Drawing.Printing.PrintPageEventArgs)
        Dim img As Image = PictureBox1.Image
        Dim mgw As Single = e.MarginBounds.Width
        Dim igw As Single = img.Width
        Dim igh As Single = img.Height
        e.Graphics.DrawImage(img, 0, 0, mgw, mgw * igh / igw)
        e.HasMorePages = False
    End Sub
End Class

 
※ 印刷範囲はMargineBoundsのHeight、Widthプロパティで、画像の縦横サイズはイメージのHeight、Widthプロパティで取得できる。
 (画像の縦横比が変わらないように計算している)。
※ 印刷するデータとしてPrintDocumentを(宣言して)利用する。
※「プリンタを選択して印刷する」にはPrintDialogを(宣言して)利用する。
    obj.ShowDialog でダイアログを表示
    PrintDialogのDocumentプロパティに印刷するPrintDocumentを関連づけておく。
    プリンタとして「Microsoft Print to PDF」などを選ぶとPDFファイルとして出力できる。
※ PrintPageイベントハンドラに関連付けるには、AddHandlerステートメントを用いる。
  AddHandler event, AddressOf eventhandler
    event: obj.PrintPage
    eventhandler:実行する印刷メソッド
印刷デザイン画面 印刷実行(印刷設定)画面
2.Windowsフォームを利用して印刷
 VBには印刷に使える便利な印刷用ツールがある。これらを使うと簡単に印刷できる。新しいフォームに、以下のコントロールと印刷ツールを貼り付け、プロパティを以下のように設定する。
コントロール/ツール プロパティ 
Button1: .text=”プリンタの設定”   
 印刷ツール
Button2: .text=”ページ設定”
Button3: .text=”プレビュー表示”
PrintDocument1  
PrintDialog1: .Document=PrintDocument1
PageSetupDialog1: .Document=PrintDocument1
PrintPreviewDialog: .Document=PrintDocument1

 
 Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If PrintDialog1.ShowDialog() = DialogResult.OK Then
            PrintDocument1.Print()
        End If
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        PageSetupDialog1.ShowDialog()     '
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        PrintPreviewDialog1.ShowDialog()
    End Sub

    Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) _
    Handles PrintDocument1.PrintPage
        Dim mgx As Integer = e.MarginBounds.X
        Dim mgy As Integer = e.MarginBounds.Y
        e.Graphics.FillRectangle(Brushes.YellowGreen, 0, 0, 200, 100)
        Dim f As New Font("MS明朝", 64, FontStyle.Bold)
        e.Graphics.DrawString("VisualBasicで印刷をテスト", f, Brushes.Red, mgx, mgy + 300)
    End Sub
 End Class
デザイン画面でコントロールを配置
(印刷ツールはコンポーネントトレイに)
プリンタの設定画面 ページの設定画面
@ プリンタ選択後、「適用」ボタンを押すとプリンタが選択され、「印刷」ボタンを押すと印刷開始。
A プレビュー表示後、左上のプリンタアイコンをクリックすると、印刷を開始する
プレビュー画面 印刷出力例(周囲に空白がある)
 ここでは、前述のPictureBoxを使わず、画像はFillRectangleメソッド、文字列はDrawStringメソッドで直接PrintDocument1に描画した。なお、印刷範囲をはみ出した文字列は表示(印刷)されない(解決法は次章参照)。
 プレビューと実際の印刷位置は異なり、実際の印刷位置は用紙の印刷範囲の左上が起点で、これはプリンタの物理的余白があるためのようです。
 
3.文字列を折り返して印刷
 Windowsフォームを使った前例に更にTextBox1を追加し、以下のようにプロパティも設定。
   TestBox1: .MultiLine=True
         .Text=“印刷時のはみ出しをチェックしています”
 Form1のコードを以下のように変更すると、TextBox1に記述された文字列を右端で折り返して印刷する。
 文字がはみ出すかどうかは、文字列から1文字づつ取り出し文字列変数(lin)に追加。文字列変数の幅が印刷マージンをはみ出す場合、または改行文字があった場合は、それまでの1行分の文字列をPrint。
 なお、改行記号はVbCr、VbLf、VbCrLfと種類があり、重複処理を避けるためVbLfに統一。
Public Class Form1
    Private ptx As String							' 印刷するテキスト
    Private pps As Integer = 0							' 印刷文字位置
    Private pfn As Font = New Font("MS明朝", 48, FontStyle.Bold)		' 印刷文字フォント
    Private x As Integer = 0   							' 印刷する初期位置(左上)を指定
    Private y As Integer = 0

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If PrintDialog1.ShowDialog() = DialogResult.OK Then
            PrintDocument1.Print()
        End If
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        PageSetupDialog1.ShowDialog() 
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        PrintPreviewDialog1.ShowDialog()
    End Sub

    Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) _
    Handles PrintDocument1.PrintPage
        ptx = TextBox1.Text					 		' 印刷する文字列
        If pps = 0 Then								' 文字位置が先頭なら、
            ptx = ptx.Replace(vbCrLf, vbLf)					' 改行記号を'\n'に統一する
            ptx = ptx.Replace(vbCr, vbLf)
        End If
        txt_PrintPage(e)							' ptxをe.Graphicに描画する関数
    End Sub

    Private Sub txt_PrintPage(e As System.Drawing.Printing.PrintPageEventArgs)
        While e.MarginBounds.Bottom > y + pfn.Height AndAlso pps < ptx.Length
            Dim lin As String = ""
            While True
                If pps >= ptx.Length OrElse ptx.Chars(pps) = vbLf Then
                    pps += 1							' 改行なら1文字進める
                    Exit While
                End If
                lin += ptx.Chars(pps)						' 1文字追加し、印刷幅を超えるか?
                If e.Graphics.MeasureString(lin, pfn).Width > e.MarginBounds.Width Then
                    lin = lin.Substring(0, lin.Length - 1)			' 追加しすぎたので1文字戻す
                    Exit While
                End If
                pps += 1							' 印刷文字位置を次へ
            End While
            e.Graphics.DrawString(lin, pfn, Brushes.Black, x, y)		' 1行分をe.Graphicsに描画する
            y += pfn.GetHeight(e.Graphics)					' 次の行の印刷位置を計算
        End While
        If pps >= ptx.Length Then						' 次のページがあるか調べる
            e.HasMorePages = False						' 次ページがない
            pps = 0								' 文字列位置を0に初期化する
        Else
            e.HasMorePages = True						' 次ページが残っている
            pps += 1								' 印刷文字位置を次へ
        End If
        y = 0									' 印刷行位置を0に初期化する
    End Sub
End Class
印刷デザイン画面 印刷プレビュー例
 さらに、PrintSettingDialogのEnableMetricプロパティをTrueに(デフォルトでは1/100インチ単位、単位をmmに変更)し、前段のセリカの記事を、フォントサイズ=40、ページの余白を全て0にして印刷すると、用紙一杯に印刷されたが、印刷された用紙では右端で文字が切れている。プリンタに合わせて、右および下で数ミリの余白を設定するのがよさそう。
プレビュー(1頁目) プレビュー(2頁目) 印刷出力例
 とりあえず、文字列を折り返して、複数ページの印刷ができることを確認できたが、プレビュー画面と印刷出力に差があるので、プレビュー画面はあくまでも参考用として、実際に印刷して確かめる必要がある。

HasMorePagesプロパティは、Trueにすると、次ページが残っていることを表し、1頁分のDocumentをPrint後、PrintPageイベントを発生させ、PrintDocument1_PrintPageが再び実行される。

PrintDialog(プリンタ設定)には以下のプロパティなどがあるが、ここでは、まだ対応していない
 AllowSelection:選択した印刷範囲のページ指定を有効にする(初期値False)
 AllowSomePages:印刷範囲のページ指定を有効にする(初期値False)

※文字列のReplaceメソッド:  検索文字列があれば置換文字列に変換した文字列を返す
   Strings.Replace(検索文字列、置換文字列)
※文字列のSubstringメソッド:  文字列から指定された部分文字列を返す(文字列の先頭位置は0)
   String.Substring(開始文字位置[, 文字数])


セリカLB2000GT VB2019_印刷