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

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

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

MCLJJeiokgXkmmrel


(過去ログ 100 を表示中)

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

■59543 / inTopicNo.1)  下付文字を含んだ文字列の表示、印刷について。(再)(修正)
  
□投稿者/ mine (27回)-(2011/05/31(Tue) 08:05:30)

分類:[.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 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

        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

引用返信 編集キー/
■59554 / inTopicNo.2)  Re[1]: 下付文字を含んだ文字列の表示、印刷について。(再)(修正)
□投稿者/ けーりん (2回)-(2011/05/31(Tue) 11:49:39)
こちらが本スレということで、ageておきます。
(もしかしたら、先のスレが解決済みになっているので、本件が解決してこのスレが放置されたと誤解されると悪いので。)
引用返信 編集キー/
■59561 / inTopicNo.3)  Re[2]: 下付文字を含んだ文字列の表示、印刷について。(再)(修正)
□投稿者/ shu (738回)-(2011/05/31(Tue) 16:19:49)
No59552 (mine さん) に返信

> さきにご連絡したと思いますがFontEmはS(i).offsetの計算のみに使用しています。
> S(i).offsetは下付き文字の上下の高さの調整で横位置には全く関係がありません。
横のずれなんていう話は全然なかったと思いますが見落としていますか?縦方向のオフセットが
ずれるのは変わりないと思うのですが、試してみましたか?


Rectangle.Roundしないで、描画時にInteger化してみてはどうでしょう?



※終了するならこっちを終了して、前スレの内容を修正した方がよいと思います。ここまでの
流れが分かりにくいですよね?

引用返信 編集キー/
■59562 / inTopicNo.4)  Re[3]: 下付文字を含んだ文字列の表示、印刷について。(再)(修正)
□投稿者/ ABEX (1回)-(2011/05/31(Tue) 16:28:42)
No59561 (shu さん) に返信
> 横のずれなんていう話は全然なかったと思いますが見落としていますか?

前の質問(No59324)の続きということでしょうね。
引用返信 編集キー/
■59573 / inTopicNo.5)  Re[3]: 下付文字を含んだ文字列の表示、印刷について。(再)(修正)
□投稿者/ mine (32回)-(2011/05/31(Tue) 17:37:37)
No59561 (shu さん) に返信
> ■No59552 (mine さん) に返信
>
>>さきにご連絡したと思いますがFontEmはS(i).offsetの計算のみに使用しています。
>>S(i).offsetは下付き文字の上下の高さの調整で横位置には全く関係がありません。
> 横のずれなんていう話は全然なかったと思いますが見落としていますか?縦方向のオフセットが
> ずれるのは変わりないと思うのですが、試してみましたか?

はじめから問題は下付き文字の印字スタートX 位置の問題だったのですが小生の思いこみで
単に位置がずれると記述してしまいました。誤解を招いたことをお詫び致します。
コードを実行していただけばすぐ判ると思ったのが間違いでした。

> Rectangle.Roundしないで、描画時にInteger化してみてはどうでしょう?
未熟者でRectangle.Roundでなくrect(0)のサイズを獲得する方法が判りません。
RectangleFを使うのでしょうか? 宜しくご指導下さい。

> ※終了するならこっちを終了して、前スレの内容を修正した方がよいと思います。ここまでの
> 流れが分かりにくいですよね?
ご指摘のとおりかも判りませんがCodeの修正をする方法が判らなかったので新しい方を使用することにしました。
ご容赦下さい。


引用返信 編集キー/
■59576 / inTopicNo.6)  Re[4]: 下付文字を含んだ文字列の表示、印刷について。(再)(修正)
□投稿者/ shu (741回)-(2011/05/31(Tue) 17:55:40)
No59573 (mine さん) に返信

> 未熟者でRectangle.Roundでなくrect(0)のサイズを獲得する方法が判りません。
> RectangleFを使うのでしょうか? 宜しくご指導下さい。
rect(0).widthがSingle型で返ってくるのでこれを使うとよいでしょう。構造体の
各値もSingleにした方がいいかもしれません。


> Dim gt As Graphics = tempPic.CreateGraphics
印刷用のGraphicsでないものを使っているのでDpiが合わないGraphicsをつかって
計測処理を行っていますね。これだと前スレで言った内容と同じことになります。
Dpi付きのビットマップから作成されるとよいかと思います。
Bitmap.SetResolution にて設定が出来ます。
引用返信 編集キー/
■59578 / inTopicNo.7)  Re[5]: 下付文字を含んだ文字列の表示、印刷について。(再)(修正)
□投稿者/ shu (742回)-(2011/05/31(Tue) 22:51:53)
2011/05/31(Tue) 22:55:00 編集(投稿者)
2011/05/31(Tue) 22:52:11 編集(投稿者)

いじってみました。コンボボックスを追加しPageUnitの選択を出来るようにしました。変化を確認してみて下さい。
worldは選ぶとエラーになります。inchはCX,CYを小さくしないと表示されないでしょう。Dispayの時の画面、プリンタの判断は
簡単な方法が分からなかったのでDpi値が150より小さければ画面としました。
tempPicへの描画は変になっているかもしれません。


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

    Private flgShow As Boolean = False
    Private Txt As String = "!s腐食代(外側)を除いた外径 = D!uo!s − 2 × α!uo"
    Private fntReg As Font
    Private fntSuffix As Font

    Public Sub New()
        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。
        fntReg = Label1.Font
        fntSuffix = Label2.Font
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        CuX = 50.0!
        CuY = 20.0!
        ComboBox1.DataSource = [Enum].GetValues(GetType(GraphicsUnit))
    End Sub

    Private Function FontEm(ByVal FFont As Font, ByVal g As Graphics) As Single
        Select Case g.PageUnit
            Case GraphicsUnit.Display
                If g.DpiX < 150 Then
                    FontEm = FFont.Size * g.DpiY / 72
                Else
                    FontEm = FFont.Size * 100 / 72
                End If
            Case GraphicsUnit.Pixel
                FontEm = FFont.Size * g.DpiY / 72
            Case GraphicsUnit.Point
                FontEm = FFont.Size
            Case GraphicsUnit.Inch
                FontEm = FFont.Size / 72
            Case GraphicsUnit.Document
                FontEm = FFont.Size * 300 / 72
            Case GraphicsUnit.Millimeter
                FontEm = FFont.Size / 72 * 25.4!
            Case Else
                FontEm = FFont.Size * g.DpiY / 72
        End Select
    End Function

    ' Function Str
    ' Txtを"!"で分割しそれぞれの文字列のPropertyをS()として返す。
    ' S()の次元はRegionMaxである。
    Private Function Str(ByVal Txt As String, ByRef RegionMax As Integer, ByVal g As Graphics) 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 = fntReg
                    S(i).Offset = 0
                Case "t"
                    S(i).Font = fntSuffix
                    'S(i).Offset = -15
                    'S(i).Offset = -8
                    S(i).Offset = -FontEm(fntReg, g) * 0.6
                Case "u"
                    S(i).Font = fntSuffix
                    'S(i).Offset = 17
                    'S(i).Offset = 14
                    S(i).Offset = FontEm(fntReg, g) * 0.6
            End Select
        Next
        Return S
    End Function

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

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

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

        Dim gt As Graphics = tempPic.CreateGraphics
        Dim stringRegions As Region()
        Dim rect(0) As RectangleF
        gt.PageUnit = g.PageUnit

        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)
            stringRegions = g.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 = rect(0).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 Then
            e.Graphics.PageUnit = ComboBox1.SelectedValue
            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 Then
            e.Graphics.PageUnit = ComboBox1.SelectedValue
            DrawFormula(Txt, CuX, CuY, e.Graphics)      '(e.Graphics)とすることが必要、(e)ではErrorとなる。
        End If
        e.HasMorePages = False
    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
        flgShow = True
        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

End Class

引用返信 編集キー/
■59579 / inTopicNo.8)  Re[6]: 下付文字を含んだ文字列の表示、印刷について。(再)(修正)
□投稿者/ mine (33回)-(2011/06/01(Wed) 08:40:06)
No59578 (shu さん) に返信
shuさん 度々のご指導有り難う御座います。
> 2011/05/31(Tue) 22:55:00 編集(投稿者)
> 2011/05/31(Tue) 22:52:11 編集(投稿者)
>
> いじってみました。コンボボックスを追加しPageUnitの選択を出来るようにしました。変化を確認してみて下さい。
> worldは選ぶとエラーになります。inchはCX,CYを小さくしないと表示されないでしょう。Dispayの時の画面、プリンタの判断は
> 簡単な方法が分からなかったのでDpi値が150より小さければ画面としました。
> tempPicへの描画は変になっているかもしれません。

修正して頂いたCodeを早速試してみました。
小生の作成したCodeに比べ下付き文字の横位置が劇的に改善されていることに驚いています。
これをもとに細かい調整をしましたところほぼ目的を達成出来ました。
本当にご指導有り難う御座いました。 重ねて御礼申し上げますとともに今後ともよろしくお願い申し上げます。。
解決済み
引用返信 編集キー/
■60136 / inTopicNo.9)  MCLJJeiokgXkmmrel
□投稿者/ Lina (1回)-(2011/06/21(Tue) 17:12:43)
Lina さんの Web サイト

分類:[VBScript] 

Youツ池e a real deep tihnekr. Thanks for sharing.
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -