C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: 下付文字を含んだ文字列の表示、印刷について。(再)


(過去ログ 100 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■59541 / inTopicNo.1)  下付文字を含んだ文字列の表示、印刷について。(再)
  
□投稿者/ mine (26回)-(2011/05/31(Tue) 07:52:18)

分類:[.NET 全般] 

以前に同じ内容の質問をさせて頂きましたところ多くの方から有益なご指導を頂き表示については全く問題なくできるようになったのですが、
Previewや印刷をさせると下付文字の位置がずれてしまうのです。
Form1にtempPic, PictureBox1, cmdHyouzi1, cmdPreview, cmdPint, PritPreviewDialog1, PrintDocument1を貼り付けcmdHyouzi,をClickすると
PictureBox1に文字列が表示され、cmdPreview,をClickするとPreviewが、cmdPint,をClickすると印刷が行はれるようにしています。
全Codeを次に記載しましたがなぜPictureBox1への表示とPreview、印刷とで狂いがでるのでしょうか?
何方か是非お教え下さい。 よろしくお願い申し上げます。

Module Module1
    Public Structure SpecTxt
        Public Cont As String               '制御文字
        Public Str As String                '文字列
        Public StartX As Integer            'startX位置
        Public StartY As Integer            'startY位置
        Public Length As Integer            'EndX位置
        Public Offset As Integer            '下付き文字などの位置修正用
        Public Width As Integer             '文字列の印字長さ
        Public Height As Integer            '文字列の印字高さ
        Public Font As Font
    End Structure
    Public S() As SpecTxt
    Public CuX As Integer               '文字列の表示位置X
    Public CuY As Integer               '文字列の表示位置X
End Module

Public Class Form1
    Dim flgShow As Boolean = False
    Dim Txt As String = "!s腐食代(外側)を除いた外径 = D!uo!s − 2 × α!uo"

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        CuX = 50
        CuY = 20
    End Sub

    Private Function FontEm(ByVal FFont As Font) As Single
        FontEm = FFont.Size * 96 / 72
    End Function

    ' Function StrWidth
    ' strのFFontで表示した場合のWidthを返す。
    Private Function StrWidth(ByVal str As String, ByVal FFont As Font) As Integer
        Dim tg As Graphics = tempPic.CreateGraphics()
        Dim sf As New StringFormat
        Dim stringRegions As Region()
        'tempPic.Visible = False
        Dim gt As Graphics = tempPic.CreateGraphics
        '文字列を描画する
        tg.DrawString(str, FFont, Brushes.Black, 0, 0, sf)
        Dim characterRanges(0) As CharacterRange
        characterRanges(0) = New CharacterRange(0, str.Length)
        sf.SetMeasurableCharacterRanges(characterRanges)
        '文字列のレイアウト四角形を指定する
        Dim layoutRect As New RectangleF(0, 0, 3000, 100)

        '文字列に外接するRegion配列を取得する()        
        stringRegions = tg.MeasureCharacterRanges(str, FFont, layoutRect, sf)
        '取得した文字列の大きさを使って四角を描画する()
        Dim rect(0) As RectangleF
        rect(0) = stringRegions(0).GetBounds(tg)
        tg.DrawRectangle(Pens.Blue, Rectangle.Round(rect(0)))
        Debug.Print(Rectangle.Round(rect(0)).Size.Width)
        'Return Rectangle.Round(rect(0)).Size.Width 
        Return CInt(Rectangle.Round(rect(0)).Size.Width * 1.05)
    End Function

    ' Function Str
    ' Txtを"!"で分割しそれぞれの文字列のPropertyをS()として返す。
    ' S()の次元はRegionMaxである。
    Private Function Str(ByVal Txt As String, ByRef RegionMax As Integer) As SpecTxt()
        '計測する文字の範囲を指定する
        Dim ContCountMax As Integer  '"!"の数
        'Dim RegionMax As Integer  'Regionの最大数
        Dim i As Integer
        Dim StrTwCont() As String

        'Txtを制御文字列"!"で分割しStrTwContにいれる。
        'Splitでは最初の"!"より前の文字列がStrTwCont(0)に入るがこれは常に""なので要注意
        StrTwCont = Txt.Split(CChar("!"))
        ContCountMax = UBound(StrTwCont)
        RegionMax = ContCountMax - 1
        ReDim S(RegionMax)

        '分割様文字はCCharでCharcterに変換しておかないとErrorとな  
        For i = 0 To RegionMax
            S(i).Cont = Mid(StrTwCont(i + 1), 1, 1)
            S(i).Str = Mid(StrTwCont(i + 1), 2, StrTwCont(i + 1).Length - 1)
            'S(i).StartX = 1
            S(i).Length = StrTwCont(i + 1).Length
            Select Case S(i).Cont
                Case "s"
                    S(i).Font = fontReg
                    S(i).Offset = 0
                Case "t"
                    S(i).Font = fontSuffix
                    'S(i).Offset = -15
                    'S(i).Offset = -8
                    S(i).Offset = -FontEm(fontReg) * 0.6
                Case "u"
                    S(i).Font = fontSuffix
                    'S(i).Offset = 17
                    'S(i).Offset = 14
                    S(i).Offset = FontEm(fontReg) * 0.6
            End Select
        Next
        Return S
    End Function

    '************************************************************
    ' DrawFormula
    ' PictureBox1,PrintDocument1への描画コード
    '************************************************************
    Private Sub DrawFormula(ByVal Txt As String, ByVal CuX As Integer, ByVal CuY As Integer, ByVal g As Graphics)

        Dim RegionMax As Integer  'Regionの最大数
        Dim i As Integer
        Dim sf As New StringFormat

        'Txtを制御文字列"!"で分割しSにいれる。
        S = Str(Txt, RegionMax)

        Dim gt As Graphics = tempPic.CreateGraphics
        Dim stringRegions As Region()
        Dim rect(0) As RectangleF
        ReDim StartX(RegionMax)

        For i = 0 To RegionMax
            
            '各文字列の表示幅を求める
            gt.DrawString(S(i).Str, S(i).Font, Brushes.Black, 0, i * 20, sf)
            Dim characterRanges(0) As CharacterRange
            characterRanges(0) = New CharacterRange(0, S(i).Str.Length)
            sf.SetMeasurableCharacterRanges(characterRanges)

            '文字列のレイアウト四角形を指定する
            Dim layoutRect As New RectangleF(0, i * 20, 3000, 100)

            '文字列に外接するRegion配列を取得する() 
            stringRegions = gt.MeasureCharacterRanges(S(i).Str, S(i).Font, layoutRect, sf)

            '取得した文字列の大きさを使って四角を描画する()

            rect(0) = stringRegions(0).GetBounds(g)
            gt.DrawRectangle(Pens.Blue, Rectangle.Round(rect(0)))
            'Debug.Print(Rectangle.Round(rect(0)).Size.Width)
            S(i).Width = Rectangle.Round(rect(0)).Size.Width

            '各文字列の表示start位置を求める
            If i = 0 Then
                S(0).StartX = CuX
            Else
                S(i).StartX = S(i - 1).StartX + S(i - 1).Width
                Debug.Print("S(" & i & ").StartX) = " & "S(" & i - 1 & ").StartX" & " + S(" & i - 1 & ").Width = " & _
                    S(i - 1).StartX & " + " & S(i - 1).Width & " = " & S(i - 1).StartX + S(i - 1).Width)
            End If
            '各文字列の表示
            g.DrawString(S(i).Str, S(i).Font, Brushes.Black, S(i).StartX, CuY + S(i).Offset, sf)
        Next

    End Sub

    ' PictureBox1への描画
    Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _
        Handles PictureBox1.Paint

        If flgShow = True Then
            Call DrawFormula(Txt, CuX, CuY, e.Graphics)
        End If
    End Sub

    Private Sub PrintDocument1_printpage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
        If flgShow = True Then
            Call DrawFormula(Txt, CuX, CuY, e.Graphics)      '(e.Graphics)とすることが必要、(e)ではErrorとなる。
        End If
    End Sub

    Private Sub cmdHyouzi_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdHyouzi.Click
        flgShow = True
        PictureBox1.Invalidate()
    End Sub

    Private Sub cmdPreview_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPreview.Click
        Dim RectWorking As Rectangle
        RectWorking = Screen.PrimaryScreen.WorkingArea
        Debug.Print("RectWorking.Width, height = " & RectWorking.Width & ", " & RectWorking.Height)
        PrintPreviewDialog1.Width = 750
        PrintPreviewDialog1.Height = 900
        PrintPreviewDialog1.Top = 0
        PrintPreviewDialog1.Left = CInt((RectWorking.Width - PrintPreviewDialog1.Width) / 2)
        PrintPreviewDialog1.Document = PrintDocument1
        PrintPreviewDialog1.ShowDialog()
    End Sub

    Private Sub cmdPicPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPicPrint.Click
        Call PrintDocument1.Print()
    End Sub

End Class

引用返信 編集キー/
■59542 / inTopicNo.2)  Re[1]: 下付文字を含んだ文字列の表示、印刷について。(再)
□投稿者/ shu (734回)-(2011/05/31(Tue) 08:02:13)
2011/05/31(Tue) 08:05:43 編集(投稿者)

No59541 (mine さん) に返信

FontEm = FFont.Size * 96 / 72

これが1pt = 72in
画面解像度 96dpi=1インチ当りのドット数(ピクセル数)が96
という計算だからです。
プリンタは300dpiとかもっと多かったりするので96ではなく対応したdpiを
掛ける必要があります。

Graphics.DpiX, Graphics.DpiY

引用返信 編集キー/
■59544 / inTopicNo.3)  Re[2]: 下付文字を含んだ文字列の表示、印刷について。(再)
□投稿者/ mine (28回)-(2011/05/31(Tue) 08:25:03)
No59542 (shu さん) に返信
shu さん 早速にご指導有り難う御座います。
> FontEm = FFont.Size * 96 / 72
> これが1pt = 72in
> 画面解像度 96dpi=1インチ当りのドット数(ピクセル数)が96
> という計算だからです。
> プリンタは300dpiとかもっと多かったりするので96ではなく対応したdpiを
> 掛ける必要があります。
> Graphics.DpiX, Graphics.DpiY
FontEmはS(i).offset以外には使用していないのですがなぜ下付文字の位置がずれるのでしょうか?
Graphics.DpiX, Graphics.DpiYはどの様に使うべきかお教え下さい。
よろしくお願い申し上げます。

引用返信 編集キー/
■59545 / inTopicNo.4)  Re[3]: 下付文字を含んだ文字列の表示、印刷について。(再)
□投稿者/ shu (735回)-(2011/05/31(Tue) 08:44:12)
No59544 (mine さん) に返信
> FontEmはS(i).offset以外には使用していないのですがなぜ下付文字の位置がずれるのでしょうか?
> Graphics.DpiX, Graphics.DpiYはどの様に使うべきかお教え下さい。
> よろしくお願い申し上げます。


DrawFormula内でg.DpiXとg.DpiYをそれぞれ参照してみて下さい。
画面のときは96, プリンタのときはそれより大きい値が返ってくると思います。
それがプリンタ出力時の解像度です。 FontEmで掛けている96はこの画面のときのDpiXなりDpiYです。
ついでに72で割っているのはg.PageUnitがGraphicsUnit.Pixelになっているためだと思いますので、
PageUnitを変更して描画する場合は計算が変わってきます。
引用返信 編集キー/
■59546 / inTopicNo.5)  Re[4]: 下付文字を含んだ文字列の表示、印刷について。(再)
□投稿者/ けーりん (1回)-(2011/05/31(Tue) 09:10:15)
このスレとNo59543のスレと、どっちが本スレですか?
どちらかいらないのならば、いらないスレを解決済みにして、本スレに誘導するようにしてください。
引用返信 編集キー/
■59547 / inTopicNo.6)  Re[4]: 下付文字を含んだ文字列の表示、印刷について。(再)
□投稿者/ mine (29回)-(2011/05/31(Tue) 09:21:03)
No59545 (shu さん) に返信
shu さん 早速ご指導有り難う御座います。
> DrawFormula内でg.DpiXとg.DpiYをそれぞれ参照してみて下さい。
> 画面のときは96, プリンタのときはそれより大きい値が返ってくると思います。
画面のときは96, プリンタのときは600でした。
> それがプリンタ出力時の解像度です。 FontEmで掛けている96はこの画面のときのDpiXなりDpiYです。
> ついでに72で割っているのはg.PageUnitがGraphicsUnit.Pixelになっているためだと思いますので、
> PageUnitを変更して描画する場合は計算が変わってきます。
g.PageUnitは特に設定していませんのでGraphicsUnit.Pixelに成っていると思います。
小生のコードで実行すると下付き文字のズレは下付き文字列の前の標準文字列の長さに夜かも判りませんが
せいぜい1文字以内です。画面のときは96, プリンタのときは600のDpiXによる差とは思えないのですが。
またInternetで調べた中に
「VB.NETではプログラマに負担を掛けないよう、解像度と印刷サイズは自動変換される。 
何も設定しないで、普段通り描画すれば、
Pixel単位は1/100インチなる実空間サイズとして処理される。
point指定された文字サイズはpointが維持される。Pointは元々実空間単位(1/72インチ)なのでその
サイズ通り印刷される。」
といった記述がありました。
どの様にしたらよいかご指導下さい。 よろしくお願い申し上げます。
引用返信 編集キー/
■59548 / inTopicNo.7)  Re[5]: 下付文字を含んだ文字列の表示、印刷について。(再)
□投稿者/ shu (736回)-(2011/05/31(Tue) 09:37:22)
No59547 (mine さん) に返信

FontEmはGraphicsに依存しない計算をしているので自動計算の範疇には入らないです。

例えば
1pt = 1/100in、画面解像度 = 100dpiとします。計算を簡易にするため

12 * 600 / 100 = 72
12 * 100 / 100 = 12

となり
プリンタ解像度で計算した場合 72/600 inchのオフセット
画面解像度で計算したプリンタ上では 12/600 inchのオフセット
の差になり60/600 inch= 10/100in = 10ptの差になります。

引用返信 編集キー/
■59552 / inTopicNo.8)  Re[6]: 下付文字を含んだ文字列の表示、印刷について。(再)
□投稿者/ mine (30回)-(2011/05/31(Tue) 11:09:52)
No59548 (shu さん) に返信
shu さんご指導有り難う御座います。
> ■No59547 (mine さん) に返信
>
> FontEmはGraphicsに依存しない計算をしているので自動計算の範疇には入らないです。
>
> 例えば
> 1pt = 1/100in、画面解像度 = 100dpiとします。計算を簡易にするため
>
> 12 * 600 / 100 = 72
> 12 * 100 / 100 = 12
>
> となり
> プリンタ解像度で計算した場合 72/600 inchのオフセット
> 画面解像度で計算したプリンタ上では 12/600 inchのオフセット
> の差になり60/600 inch= 10/100in = 10ptの差になります。
さきにご連絡したと思いますがFontEmはS(i).offsetの計算のみに使用しています。
S(i).offsetは下付き文字の上下の高さの調整で横位置には全く関係がありません。
現在問題にしているのは下付き文字の横位置なのですが一度小生のCodeを動かして見て
頂けませんでしょうか?
なおスレッド59541のコードは一部ミスが在りますのでスレッド59543のコード
でお願い申し上げます。 更にご指導はスレッド59543の方に御願いしたいと思います。
スレッド59541は解決済みとさせて頂きますのでよろしく。
解決済み
引用返信 編集キー/
■59553 / inTopicNo.9)  Re[5]: 下付文字を含んだ文字列の表示、印刷について。(再)
□投稿者/ mine (31回)-(2011/05/31(Tue) 11:12:47)
No59546 (けーりん さん) に返信
> このスレとNo59543のスレと、どっちが本スレですか?
> どちらかいらないのならば、いらないスレを解決済みにして、本スレに誘導するようにしてください。
質問箱になれていないため失礼しました。
ご指導に従い 本スレ(59543)にご指導頂くようにお願い申し上げます。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -