印刷処理で列項目とデータを整列させて出力したいです。
投稿者 たかくん  (社会人)
投稿日時
2013/3/30 17:40:08
続きのコードを掲載します。
''' <summary>
''' 文字列リストをバイト配列リストに変換する。
''' </summary>
''' <param name="str"></param>
''' <returns>バイト配列リスト</returns>
''' <remarks></remarks>
Private Function ChangeShift_JisEncoding(ByVal str As String()) As List(Of Byte())
Dim data As New List(Of Byte())
Dim bytedata As Byte()
Try
For Each dat As String In str
bytedata = System.Text.Encoding.GetEncoding("Shift_jis").GetBytes(dat)
data.Add(bytedata)
Next
Catch ex As Exception
Log(ex, "CustomerSearchFormClass->ChangeShift_JisEncoding()")
End Try
Return data
End Function
''' <summary>
''' バイト配列リストをShift_Jis文字列リストに変換する。
''' </summary>
''' <param name="bytedata"></param>
''' <returns>Shift_Jis文字列リスト</returns>
''' <remarks></remarks>
Private Function ChangeShift_JisString(ByVal bytedata As List(Of Byte())) As List(Of String)
Dim data As New List(Of String)
Dim tmp As String
Try
For Each dat As Byte() In bytedata
tmp = System.Text.Encoding.GetEncoding("Shift_jis").GetString(dat)
data.Add(tmp)
Next
Catch ex As Exception
Log(ex, "CustomerSearchFormClass->ChangeShift_JisString()")
End Try
Return data
End Function
Private Function GetByteCount(ByVal str As String()) As List(Of Integer)
Dim data As New List(Of Integer)
Dim count As Integer
Try
For Each dat As String In str
count = System.Text.Encoding.GetEncoding("Shift_jis").GetByteCount(dat)
data.Add(count)
Next
Catch ex As Exception
Log(ex, "CustomerSearchFormClass->ChangeShift_JisEncoding()")
End Try
Return data
End Function
''' <summary>
''' 文字列リストをバイト配列リストに変換する。
''' </summary>
''' <param name="str"></param>
''' <returns>バイト配列リスト</returns>
''' <remarks></remarks>
Private Function ChangeShift_JisEncoding(ByVal str As String()) As List(Of Byte())
Dim data As New List(Of Byte())
Dim bytedata As Byte()
Try
For Each dat As String In str
bytedata = System.Text.Encoding.GetEncoding("Shift_jis").GetBytes(dat)
data.Add(bytedata)
Next
Catch ex As Exception
Log(ex, "CustomerSearchFormClass->ChangeShift_JisEncoding()")
End Try
Return data
End Function
''' <summary>
''' バイト配列リストをShift_Jis文字列リストに変換する。
''' </summary>
''' <param name="bytedata"></param>
''' <returns>Shift_Jis文字列リスト</returns>
''' <remarks></remarks>
Private Function ChangeShift_JisString(ByVal bytedata As List(Of Byte())) As List(Of String)
Dim data As New List(Of String)
Dim tmp As String
Try
For Each dat As Byte() In bytedata
tmp = System.Text.Encoding.GetEncoding("Shift_jis").GetString(dat)
data.Add(tmp)
Next
Catch ex As Exception
Log(ex, "CustomerSearchFormClass->ChangeShift_JisString()")
End Try
Return data
End Function
Private Function GetByteCount(ByVal str As String()) As List(Of Integer)
Dim data As New List(Of Integer)
Dim count As Integer
Try
For Each dat As String In str
count = System.Text.Encoding.GetEncoding("Shift_jis").GetByteCount(dat)
data.Add(count)
Next
Catch ex As Exception
Log(ex, "CustomerSearchFormClass->ChangeShift_JisEncoding()")
End Try
Return data
End Function
投稿者 るきお  (社会人)
投稿日時
2013/3/31 15:20:37
あきらかな間違いが2点あります。
1つはフォントの名前が違います。
"MS 明朝"ではなく、"MS 明朝"が正しい名前です。
紛らわしいのですがMSは全角です。(これはフォントを扱う人の間では昔から紛らわしことで有名)。
次にPadLeft、PadRightの使い方を誤解しています。
これらは指定した幅になるようにスペース(または指定した文字)を埋め込む機能です。
そのために何文字埋め込めばよいかは自動的に計算されるので、引数には幅自体を渡します。
ただこの計算は文字数で行われるので全角・半角が混在する場合はたかくんさんが苦慮されているように独自の計算を行う必要があります。
つまり、PadLeft、PadRightを使わないか、使う場合でも本当のサイズではなく全角・半角を考慮したサイズを渡す必要があります。
後者は保守性がとても悪いので私は前者をお勧めします。
つまり、次のようなプログラムになります。
上記2点の他にもいろいろ整理してしまいました。
1つはフォントの名前が違います。
"MS 明朝"ではなく、"MS 明朝"が正しい名前です。
紛らわしいのですがMSは全角です。(これはフォントを扱う人の間では昔から紛らわしことで有名)。
次にPadLeft、PadRightの使い方を誤解しています。
これらは指定した幅になるようにスペース(または指定した文字)を埋め込む機能です。
そのために何文字埋め込めばよいかは自動的に計算されるので、引数には幅自体を渡します。
ただこの計算は文字数で行われるので全角・半角が混在する場合はたかくんさんが苦慮されているように独自の計算を行う必要があります。
つまり、PadLeft、PadRightを使わないか、使う場合でも本当のサイズではなく全角・半角を考慮したサイズを渡す必要があります。
後者は保守性がとても悪いので私は前者をお勧めします。
つまり、次のようなプログラムになります。
上記2点の他にもいろいろ整理してしまいました。
Public Class Form1
''' <summary>
''' 帳票描画
''' </summary>
''' <param name="size">印刷可能範囲</param>
''' <returns>帳票画像</returns>
''' <remarks></remarks>
Private Function DrawReport(ByVal size As Size, ByVal data As DataTable) As Bitmap
Dim report As New Bitmap(size.Width, size.Height)
Using font As Font = New Font("MS 明朝", 10)
Using pen As New Pen(Brushes.Black, 1)
Using g As Graphics = Graphics.FromImage(report)
'●1.全体設定
Dim locate As Point = New Point(1, 1)
g.Clear(Color.White)
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
g.DrawRectangle(pen, New Rectangle(locate, New Size(size.Width - 2, size.Height - 2)))
'●2.ヘッダー部
Dim nameTitle As String = Fit("氏名", 12, LeftRightAlignment.Left)
Dim postTitle As String = Fit("郵便番号", 12, LeftRightAlignment.Left)
Dim adrsTitle As String = Fit("住所", 25, LeftRightAlignment.Left)
Dim yearTitle As String = Fit("年齢", 4, LeftRightAlignment.Right)
Dim sexTitle As String = Fit("性別", 4, LeftRightAlignment.Right)
Dim title As String = nameTitle & postTitle & adrsTitle & yearTitle & sexTitle
g.DrawString(title, font, Brushes.Black, locate)
'●3.明細部
'▼3-1.行間計算等
Dim pitch As Integer = font.Height + 3
Dim maxrow As Integer = size.Height / pitch
Dim rowcounter As Integer = 0
Do While rowcounter < maxrow
'▼3-2.罫線
locate = New Point(1, rowcounter * pitch + pitch)
g.DrawLine(pen, locate, New Point(size.Width - 2, locate.Y))
'▼3-3.明細内容
If rowcounter < data.Rows.Count Then
Dim row As DataRow = data.Rows(rowcounter)
Dim Name As String = Fit(row(0), 12, LeftRightAlignment.Left)
Dim post As String = Fit(row(1), 12, LeftRightAlignment.Left)
Dim adrs As String = Fit(row(2), 25, LeftRightAlignment.Left)
Dim year As String = Fit(row(3), 4, LeftRightAlignment.Right)
Dim sex As String = Fit(row(4), 4, LeftRightAlignment.Right)
Dim line As String = Name & post & adrs & year & sex
g.DrawString(line, font, Brushes.Black, locate)
End If
rowcounter += 1
Loop
End Using
End Using
End Using
Return report
End Function
投稿者 るきお  (社会人)
投稿日時
2013/3/31 15:29:29
続きです。
問題の個所以外で私が整理したポイント。
・Try ~ Catch で未知の例外をキャッチしないでください。(例外が発生したときは例外を返してください。想定していない例外が発生した場合、処理を続行しても問題が発生しないことが保証できません。ログに出力したい場合は、アプリケーションイベントのUnhandledExceptionイベントを使用すると良いと思います。デバッグなしで実行すると機能します。)
・変数の名前がわかりにくいように感じました。data(rowcounter)("Naming")、strlist(0)、datalist(0)の役割文体が不明瞭だったため整理しました。
なお、今回のような投稿をされる場合は、
プログラムをコピー&貼り付けすればすぐに実行できる状態にすると回答者が多くなると思います。
私の例で行くとButton1_Clickがあった方がよいということです。
たかくんさんのプログラムを試すためには回答者が自分でButton1_Clickを作る必要があり手間です。
熟練のプログラマはプログラムをみただけで回答してくれると期待されているかもしれませんが、明確なビルドエラーでもなければそれはたいてい無理です。
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim table As New DataTable
table.Columns.Add("Naming", GetType(String))
table.Columns.Add("PostalNo", GetType(String))
table.Columns.Add("Address", GetType(String))
table.Columns.Add("Year", GetType(Integer))
table.Columns.Add("Sex", GetType(String))
table.Rows.Add("徳川家康", "111-1111", "千代田区千代田1-1", 40, "男")
table.Rows.Add("楠正成", "222-2222", "奈良県吉野市1-100", 30, "男")
table.Rows.Add("後桜町天皇", "222-2222", "京都府1-1", 20, "女")
Dim report As Bitmap = DrawReport(New Size(640, 800), table)
PictureBox1.Image = report
End Sub
Private sjis As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift_jis")
''' <summary>
''' 文字列が指定された幅になるようにスペースを埋め込みます。
''' 文字列のサイズはShiftJISに換算して計算します。
''' <para>指定された文字列が幅を上回る場合の処理は未実装です。</para>
''' </summary>
''' <param name="value">対象の文字列。</param>
''' <param name="size">幅。通常の印字領域の幅をバイト数で指定します。</param>
''' <param name="align">右寄せか左寄せか。スペースを埋め込む方向を変化させます。</param>
Private Function Fit(value As String, size As Integer, align As LeftRightAlignment) As String
Dim byteCount As Integer = sjis.GetByteCount(value)
If size = byteCount Then
'領域のサイズと実際の値のサイズが一致する場合何もする必要なし。
Return value
ElseIf size < byteCount Then
'領域のサイズより実際の値のサイズが大きい場合。
'実際の値を切り詰めて表示するか、領域サイズを広げるなど仕様変更が必要。
'ここでは仮にこのまま返す。(=がたがたになる。)
Return value
Else
'領域のサイズより実際の値のサイズが小さい場合。
'領域サイズになるように" "をくっつけて返す。
Dim result As String
Dim padding As New String(" "c, size - byteCount)
If align = LeftRightAlignment.Left Then
result = value & padding
Else
result = padding & value
End If
Return result
End If
End Function
End Class
問題の個所以外で私が整理したポイント。
・Try ~ Catch で未知の例外をキャッチしないでください。(例外が発生したときは例外を返してください。想定していない例外が発生した場合、処理を続行しても問題が発生しないことが保証できません。ログに出力したい場合は、アプリケーションイベントのUnhandledExceptionイベントを使用すると良いと思います。デバッグなしで実行すると機能します。)
・変数の名前がわかりにくいように感じました。data(rowcounter)("Naming")、strlist(0)、datalist(0)の役割文体が不明瞭だったため整理しました。
なお、今回のような投稿をされる場合は、
プログラムをコピー&貼り付けすればすぐに実行できる状態にすると回答者が多くなると思います。
私の例で行くとButton1_Clickがあった方がよいということです。
たかくんさんのプログラムを試すためには回答者が自分でButton1_Clickを作る必要があり手間です。
熟練のプログラマはプログラムをみただけで回答してくれると期待されているかもしれませんが、明確なビルドエラーでもなければそれはたいてい無理です。
投稿者 たかくん  (社会人)
投稿日時
2013/3/31 22:16:13
今晩は、るきおさんお久しぶりです。
プロになって8ヶ月が経ちました。
今の自分に一番足りない部分を学んだ気がします。
「相手、お客様、上司」等人を意識した仕事をする事が大切ですね。
るきおさんのコードや説明はどまでも人に親切ですよね。
「ここまでしていただけるのか・・・」そんな印象でした。
ここまでしていただいた自分は嬉しかったです。
目の前の事に精一杯ではまだまだですね。
このコードで理想の動きが実現できる事が確認できました。
「得した感満喫です」
ありがとうございます。
相手が嬉しいと感じてもらえる仕事を目指します。
プロになって8ヶ月が経ちました。
今の自分に一番足りない部分を学んだ気がします。
「相手、お客様、上司」等人を意識した仕事をする事が大切ですね。
るきおさんのコードや説明はどまでも人に親切ですよね。
「ここまでしていただけるのか・・・」そんな印象でした。
ここまでしていただいた自分は嬉しかったです。
目の前の事に精一杯ではまだまだですね。
このコードで理想の動きが実現できる事が確認できました。
「得した感満喫です」
ありがとうございます。
相手が嬉しいと感じてもらえる仕事を目指します。
下記のコードは顧客情報の抽出結果を印刷する時のメソッドなのですが項目とデータが綺麗に表示
できず困ってます。
Shift_JISに変換してみたもののまだガタガタの表示になってます。
各項目事にPadding()しているのですがどうもうまくいかないです。
どうすれば綺麗に表示できるでしょうか?
解る方よろしくお願いします。
''' <summary>
''' 帳票描画
''' </summary>
''' <param name="size">印刷可能範囲</param>
''' <returns>帳票画像</returns>
''' <remarks></remarks>
Private Function DrawReport(ByVal size As Size, ByVal data As DataTable) As Bitmap
Dim report As New Bitmap(size.Width, size.Height)
Try
Using font As Font = New Font("MS 明朝", 10)
Using pen As New Pen(Brushes.Black, 1)
Using g As Graphics = Graphics.FromImage(report)
Dim pitch As Integer = font.Height + 3
Dim maxrow As Integer = size.Height / pitch
Dim rowcounter As Integer = 0
Dim locate As Point = New Point(1, 1)
Dim strlist As String() = New String() {"氏名", "郵便番号", "住所", "年齢", "性別"}
Dim bytedata As List(Of Byte()) = Me.ChangeShift_JisEncoding(strlist)
Dim count As List(Of Integer) = Me.GetByteCount(strlist)
Dim datalist As List(Of String) = Me.ChangeShift_JisString(bytedata)
Dim name As String = datalist(0).PadRight(12 - count(0), " ")
Dim post As String = datalist(1).PadRight(12 - count(1))
Dim adrs As String = datalist(2).PadRight(25 - count(2), " ")
Dim year As String = datalist(3).PadLeft(4 - count(3))
Dim sex As String = datalist(4).PadLeft(4 - count(4))
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
g.DrawRectangle(pen, New Rectangle(locate, New Size(size.Width - 2, size.Height - 2)))
Dim title As String = name + post + adrs + year + sex
g.DrawString(Title, font, Brushes.Black, locate)
Do While rowcounter < maxrow
locate = New Point(1, rowcounter * pitch + pitch)
g.DrawLine(pen, locate, New Point(size.Width - 2, locate.Y))
If rowcounter < data.Rows.Count Then
strlist(0) = data(rowcounter)("Naming").ToString.Trim
strlist(1) = data(rowcounter)("PostalNo").ToString.Trim
strlist(2) = data(rowcounter)("Address").ToString.Trim
strlist(3) = data(rowcounter)("Year").ToString.Trim
strlist(4) = data(rowcounter)("Sex").ToString.Trim
bytedata = Me.ChangeShift_JisEncoding(strlist)
count = Me.GetByteCount(strlist)
datalist = Me.ChangeShift_JisString(bytedata)
name = datalist(0).ToString.PadRight(12 - count(0), " ")
post = datalist(1).ToString.PadRight(12 - count(1))
adrs = datalist(2).ToString.PadRight(25 - count(2), " ")
year = datalist(3).ToString.PadLeft(4 - count(3))
sex = datalist(4).ToString.PadLeft(4 - count(4))
Dim row As String = name + post + adrs + year + sex
g.DrawString(row, font, Brushes.Black, locate)
End If
rowcounter += 1
Loop
End Using
End Using
End Using
Catch ex As Exception
Log(ex, "CustomerSearchFormClass->DrawReport()")
End Try
Return report
End Function