チュートリアル - DotNet を使用した印刷

次のチュートリアルでは、DotNet を使用してテキスト ファイルを表示、印刷するときの基本事項を示します。

関連トピック:

MAXScript における DotNet

dotNetObject

MaxCustomControls アセンブリ

全体の流れ:

テキスト ボックスおよび 2 つのボタンを含む MaxCustomControls アセンブリを使用して MaxForm を定義します。

[印刷] (Print)ボタンのイベント ハンドラによって呼び出されるテキスト ファイルを印刷する関数を実装します。

[ファイルを開く](Open File)ボタンのイベント ハンドラの呼び出し時にテキスト ファイルを開く関数を実装します。

イベント ハンドラを登録します。

イベント ハンドラにガベージ コレクションが実行されないようにします。

    --Example code provided by Artur Leão
    (
    dotNet.loadAssembly "MaxCustomControls.dll"
    local filetoprint = ""
    local printFont = dotnetobject "System.Drawing.Font" "Arial" 10
    local streamReader

    hForm = dotNetObject "MaxCustomControls.MaxForm"
    hForm.Size = dotNetObject "System.Drawing.Size" 640 480
    hForm.FormBorderStyle = (dotnetclass "System.Windows.Forms.FormBorderStyle").FixedToolWindow
    hForm.Text = "Printing with dotNet"
    hForm.ShowInTaskbar = False

    txtTextBox = dotNetObject "System.Windows.Forms.TextBox"
    txtTextBox.MultiLine = True
    txtTextBox.WordWrap = False
    txtTextBox.Size = dotNetObject "System.Drawing.Size" 500 430
    txtTextBox.Location = dotNetObject "System.Drawing.Point" 10 10
    txtTextBox.ScrollBars = txtTextBox.ScrollBars.Both

    btnOpenFile = dotNetObject "System.Windows.Forms.Button"
    btnOpenFile.Location = dotNetObject "System.Drawing.Point" 520 10
    btnOpenFile.Text = "Open File"

    btnPrint = dotNetObject "System.Windows.Forms.Button"
    btnPrint.Location = dotNetObject "System.Drawing.Point" 520 40
    btnPrint.Text = "Print"

    frmOpenFileDialog = dotNetObject "System.Windows.Forms.OpenFileDialog"
    frmOpenFileDialog.Filter = "txt files (*.txt)|*.txt|Script Files (*.ms)|*.ms|ini files (*.ini)|*.ini|XML files (*.xml)|*.xml|All files (*.*)|*.*"

    fn btnOpenFile_Click = (
      dlgResult = dotNetClass "System.Windows.Forms.DialogResult"
      if frmOpenFileDialog.ShowDialog() == dlgResult.OK do (
        IOFile = dotNetClass "System.IO.File"
        txtTextBox.Text = IOFile.ReadAllText frmOpenFileDialog.Filename
        filetoprint = frmOpenFileDialog.Filename
      )--end if
    )--end fn

    fn pd_PrintPage sender ev = (
      count = 0
      linesperpage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics)
      yPos = 0
      leftMargin = ev.MarginBounds.Left
      topMargin = ev.MarginBounds.Top
      currentline = ""
      brush = dotnetobject "System.Drawing.Solidbrush" (dotnetclass "System.Drawing.Color").black
      stringformat = dotnetobject "System.Drawing.StringFormat"
      while count < linesperpage do(
        currentline = streamReader.ReadLine()
        if currentline == undefined do exit
        yPos = topMargin + count * printFont.GetHeight(ev.Graphics)
        ev.Graphics.DrawString currentline printFont brush leftMargin yPos stringformat
        count += 1
      )--end while loop
      if currentline != undefined then
        ev.HasMorePages = true
      else
        ev.HasMorePages = false
    )--end fn

    fn btnPrint_Click = (
      if filetoprint != "" then (
        try (
          streamReader = dotnetobject "System.IO.Streamreader" filetoprint
          pd = dotnetobject "System.Drawing.Printing.PrintDocument"
          dotnet.addeventhandler pd "PrintPage" pd_PrintPage
          pd.Print()
          streamReader.Close()
        )catch print (getCurrentException())
      )--end if
    )--end fn

    dotNet.AddEventHandler btnOpenFile "Click" btnOpenFile_Click
    dotNet.AddEventHandler btnPrint "Click" btnPrint_Click

    hForm.Controls.Add(txtTextBox)
    hForm.Controls.Add(btnOpenFile)
    hForm.Controls.Add(btnPrint)

    dotnet.setLifetimeControl btnOpenFile #dotnet
    dotnet.setLifetimeControl btnPrint #dotnet

    hForm.ShowModeless()
    )

ステップごとの解説

(
dotNet.loadAssembly "MaxCustomControls.dll"

3ds Max 固有のコントロールを含むカスタム アセンブリをロードします。

local filetoprint = ""

この変数には印刷するファイル名が格納されます。

local printFont = dotnetobject "System.Drawing.Font" "Arial" 10

フォント名 Arial、フォント サイズ 10 で System.Drawing.Font クラスのオブジェクト インスタンスを作成して、このオブジェクトを後で使用するためにユーザ変数に格納します。

local streamReader

このユーザ変数にはストリーム リーダが保持されます。

hForm = dotNetObject "MaxCustomControls.MaxForm"

メイン フォームを作成します。

hForm.Size = dotNetObject "System.Drawing.Size" 640 480

System.Drawing.Size オブジェクトを使用して、フォームのサイズを 640 x 480 に設定します。

hForm.FormBorderStyle = (dotnetclass "System.Windows.Forms.FormBorderStyle").FixedToolWindow

また、フォームの境界スタイルを、System.Windows.Forms.FormBorderStyle クラスによって公開される定義済みの FixedToolWindow に設定します。

あるいは、左側の hForm.FormBorderStyle 値は右側で割り当て元とするクラスと同一となることを利用して、次のようにできます。

hForm.FormBorderStyle = hForm.FormBorderStyle.FixedToolWindow
hForm.Text = "Printing with dotNet"

フォームのタイトルを次の文字列に設定します。

hForm.ShowInTaskbar = False

...新しいフォームが Windows のタスクバーに表示されないことを確認します。

txtTextBox = dotNetObject "System.Windows.Forms.TextBox"

ここで、印刷するファイルの内容を表示するテキストボックスが必要になります。

txtTextBox.MultiLine = True
txtTextBox.WordWrap = False

このテキストボックスは複数行テキストには対応しますが、ワード ラップには対応しません。

txtTextBox.Size = dotNetObject "System.Drawing.Size" 500 430
txtTextBox.Location = dotNetObject "System.Drawing.Point" 10 10

このテキストボックスには 500x430 ピクセルが格納され、その左上隅はフォームの左上隅に対して相対的に、座標 10,10 に配置されます。

txtTextBox.ScrollBars = txtTextBox.ScrollBars.Both

水平および垂直スクロールバーの両方が許可されます。

btnOpenFile = dotNetObject "System.Windows.Forms.Button"
btnOpenFile.Location = dotNetObject "System.Drawing.Point" 520 10
btnOpenFile.Text = "Open File"

印刷するファイルを開くためのボタンが必要になります。

新しいボタン オブジェクトを作成して、その位置をフォーム内の座標 520,10 に設定します。キャプションは[ファイルを開く](Open File)となります。

btnPrint = dotNetObject "System.Windows.Forms.Button"
btnPrint.Location = dotNetObject "System.Drawing.Point" 520 40
btnPrint.Text = "Print"

もう 1 つ、印刷を開始するためのボタンが必要となります。

新しいボタン オブジェクトを作成して、その位置をフォーム内の座標 520,40 に設定します。キャプションは[印刷] (Print)となります。

frmOpenFileDialog = dotNetObject "System.Windows.Forms.OpenFileDialog"
frmOpenFileDialog.Filter = "txt files (*.txt)|*.txt|Script Files (*.ms)|*.ms|ini files (*.ini)|*.ini|XML files (*.xml)|*.xml|All files (*.*)|*.*"

印刷するファイルを選択するために、通常のファイル タイプをフィルタする OpenFileDialog オブジェクト セットが必要になります。

fn btnOpenFile_Click = (

[ファイルを開く](Open File)ボタンが押されたときに呼び出されるイベント ハンドラ関数が必要になります。

dlgResult = dotNetClass "System.Windows.Forms.DialogResult"

以前に定義済みの OpenFileDialog を使用します。このため、ダイアログの結果と定義済みの結果とを比較するための DialogResult クラスを含むユーザ変数が必要になります。

if frmOpenFileDialog.ShowDialog() == dlgResult.OK do (

ダイアログを表示してユーザにファイルを取得させる OpenFileDialog オブジェクトの ShowDialog() メソッドを呼び出します。値が戻されたら、ダイアログの戻り値と DialogResult クラスの OK 値とを比較して、(ユーザによるキャンセルではなく)処理が正常に終了したことを確認します。

IOFile = dotNetClass "System.IO.File"
txtTextBox.Text = IOFile.ReadAllText frmOpenFileDialog.Filename

有効なファイルが選択されたら、System.IO.File クラスを使用して、ファイルを読み込み、その内容をフォームのテキストボックスに割り当てます。System.IO.File クラスの ReadAllText メソッドを呼び出し、引数として OpenFileDialog により返されるファイル名を渡します。このメソッドの結果はテキストボックスのテキストに割り当てられます。

filetoprint = frmOpenFileDialog.Filename

ここで、ローカル変数の filetoprint に選択したファイル名を格納します。このファイル名はファイルの印刷時に使用できます。

)--end if
)--end fn

fn pd_PrintPage sender ev = (

[印刷] (Print)ボタンのイベント ハンドラ関数を定義する前に、印刷処理全体を実行する関数が必要です。これは 2 つの引数、つまり sender と event をとります。

local count = 0

テキストの処理時に行数を増加させるカウント変数が必要となります。

linesperpage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics)

1 ページごとの行数を計算するには、マージン内にあるドキュメントの印刷ページの高さを、印刷フォントの高さで除算する必要があります。

yPos = 0

この変数は、印刷する垂直位置を計算、格納するために使用されます。

leftMargin = ev.MarginBounds.Left
topMargin = ev.MarginBounds.Top

左および上のマージンも、ユーザ変数に取り込みます。

currentline = ""

この変数は現在の行を保持します。

brush = dotnetobject "System.Drawing.Solidbrush" (dotnetclass "System.Drawing.Color").black

黒の塗り潰しブラシ オブジェクトを作成します。

stringformat = dotnetobject "System.Drawing.StringFormat"

この変数には、DrawString メソッドで以降に必要となるオブジェクトが含まれます。

while count < linesperpage do (

カウンタがページごとの行数よりも少ない間は、以下を繰り返します

currentline = streamReader.ReadLine()

ストリームリーダから行を読み込みます - 初めに変数が開始され、[印刷] (Print)ボタンのイベント ハンドラに割り当てられます。

if currentline == undefined do exit

currentline 変数に未定義のものが含まれている場合(つまり、ファイルの最後に達しても読み込みが続く場合)には、ループを終了します。

yPos = topMargin + count * printFont.GetHeight(ev.Graphics)

現在の行カウンタによるフォント強度の高さを上部のマージンに追加することによって、印刷する垂直位置を計算します。

ev.Graphics.DrawString currentline printFont brush leftMargin yPos stringformat

最後に、左マージンと同じ水平位置、および前のステップで計算された yPos 値と文字列形式オブジェクトに基づくフォーマットに従った垂直位置にある現在のフォントおよびブラシを使用して、現在の行の文字列を描画できます。

count += 1

カウンタに 1 が加算され、ページの最後またはファイルの最後に達するまでループが繰り返されます。

)--end while loop
if currentline != undefined then ev.HasMorePages = true else ev.HasMorePages = false

ループが終了した理由を確認します - 現在の行が定義されている場合、印刷するページ数が多いため、PrintDocument オブジェクトの対応するプロパティを設定して印刷を続ける必要があるかどうかを通知します。

同じことを次のように短く記載できます

ev.HasMorePages = currentline != undefined
)--end fn

fn btnPrint_Click = (

[印刷] (Print)ボタンのイベント ハンドラを定義できるようになりました。

if filetoprint != "" do (
try (

印刷用に選択したファイル名が空の文字列でない場合は、次の処理を試行します。

streamReader = dotnetobject "System.IO.Streamreader" filetoprint

スクリプトの先頭で初期化される streamReader 変数を System.IO.Streamreader クラスの dotNetObject インスタンスに設定します。これは、MAXScript の fileStream 値に類似しており、ディスク上のファイルに対する IO アクセスが可能になります。

pd = dotnetobject "System.Drawing.Printing.PrintDocument"

また、実際の印刷を行う PrintDocument オブジェクトを作成します。

dotnet.addeventhandler pd "PrintPage" pd_PrintPage

イベント ハンドラを、以前に定義した MAXScript 関数を呼び出す PrintDocument オブジェクトに追加します。

pd.Print()

PrintDocument オブジェクトの Print() メソッドを呼び出して、印刷を開始することができます。これによって、各ページにつき 1 回、PrintDocument の hasMorePages プロパティが、戻り値が返されるポイントで false に設定されるまで、印刷のイベント ハンドラ関数が呼び出されます。

streamReader.Close()

戻ったら、ストリームを閉じます。

) catch print (getCurrentException())

印刷コードに問題がある場合は、エラーを捕捉し、前回の例外を出力します。

)--end if
)--end fn

dotNet.AddEventHandler btnOpenFile "Click" btnOpenFile_Click
dotNet.AddEventHandler btnPrint "Click" btnPrint_Click

以前に定義した 2 つのイベント ハンドラ関数を 2 つのボタンに追加できるようになりました。

hForm.Controls.Add(txtTextBox)
hForm.Controls.Add(btnOpenFile)
hForm.Controls.Add(btnPrint)

テキストボックスと 2 つのボタンもフォームに追加できます。

dotnet.setLifetimeControl btnOpenFile #dotnet
dotnet.setLifetimeControl btnPrint #dotnet

スクリプト化されたイベント ハンドラを DotNet コントロールに追加し、コントロールをラップする MAXScript 値より長い寿命をもつフォームにこれらのコントロールを配置しているため、これらのボタンの寿命コントロールが DotNet により制御されるように設定します。

確認 :

イベント ハンドラの作成時に既定動作とならない理由は?

上記の方法は、その他の DotNet オブジェクトに配置される DotNet オブジェクトにのみ適用されるものです。

イベント ハンドラがあり、オブジェクトの寿命コントロールで変更が生じないようにする場合の例として、タイマ オブジェクトがあります。オブジェクトをラップしている MAXScript 値が削除されるときにタイマ オブジェクトを削除したい場合があります。タイマ オブジェクトの寿命コントロールを #dotnet に設定すると、DotNet オブジェクトではタイマ オブジェクトへの参照が維持されないため、以降のランダムなポイントで DotNet ガベージ コレクションによってタイマ オブジェクトが削除されます。

hForm.ShowModeless()

最後に、フォームを表示します。

)--end script

結果