tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re^3: 塗りつぶし(黒)の円をPC画面中央に配置する
投稿日: 2015/04/13(Mon) 11:21
投稿者魔界の仮面弁士
> decPC_Yoko = 255  '横方向の画面の大きさ*
> decHaba = (Me.Size.Width * 2.54 * 10) / (gr.DpiX * decPC_Yoko)

DpiX を使っていることから、「1.0 インチ= 25.4ミリメートル」を想定して
計算されているのでしょうか。decPC_Yoko の単位系は何を想定していますか?


>  y = (Me.Size.Height / 2)

Me.Size だと、タイトルバーなども含んだ領域になってしまいますよ。
下記の冒頭の図であれば、(2) のウィンドウ領域を示していることになります。

今回指定したいのは、(1)のクライアント領域ですよね。
http://www.atmarkit.co.jp/fdotnet/dotnettips/379getclientrect/getclientrect.html


> gr.PageUnit = GraphicsUnit.Millimeter
PageUnit で変換されるのは、あくまでも「描画座標」の指定です。

Me.Size や Me.ClientSize は Grapchis.PageUnit の影響を受けませんので、
>   Dim r As Integer = 100
>   gr.FillEllipse(Brushes.Black, x - r, y - r, r * 2, r * 2)
というコードだと、
 「xピクセル−rミリ, yピクセル−rミリ, rミリ×2, rミリ×2」
な値を、ミリメートル単位系のキャンバスに描いていることになってしまいます。
最初からミリメートル単位のキャンバスサイズを得たいのであれば、
Form の ClientSize ではなく、Graphics の ClipBounds を使うのが手っ取り早いでしょう。

もちろん、Form 側から得たピクセル単位を mm単位あるいは cm単位に
計算しなおす手法でも、計算さえ間違えなければ同じ結果が得られますけれどね。


> どの部分を改善したら良くなりますでしょうか?
上記を改修すれば、期待する結果になると思いますよ。



==== 以下蛇足 ===
元のコードに気になる点があるので、少し指摘させてください。(本題からは外れますが)


> Private Sub form1_paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
>   Dim gr As Graphics = Me.CreateGraphics

まず、ここの取り扱いを見直しましょう。

(a)CreateGraphics の利用は避けましょう。簡単に記述できることから、サンプルコード等では
 よく利用されていますが、実際には CreateGraphics が必要になるのは、やや特殊なケースです。

(b)通常は、Paint イベントの e.Grapchis が使われます。Paint イベントは、ウィンドウの再描画が
 必要になったタイミングで発生し、再描画に必要なキャンバスを e.Grapchis として提供してくれます。

(c)また、描画内容があまり変化しない場合(背景画像など)には、再描画の手間を減らすため、
 Bitmap オブジェクトを用意し、そこに Graphics.FromImage でキャンパスを生成して、
 その描画された Bitmap を、Form や PictureBox の BackgroundImage に指定する手法がよく利用されます。

(d) (b) の e.Graphics は、自分で作成したオブジェクトでは無いため、Dispose してはいけません。
 一方、CreateGraphics あるいは (c) の Graphics.FromImage の場合、その Grapchis リソースは
 自分で生成したオブジェクトですので、使用後即座に、Dispose メソッド ないしは Using を用いて
 破棄する必要があります。(この点について、提示頂いたコードでは既に守られているようですね)


>  Dim x, y, decPC_Yoko As Integer
>  x = (Me.Size.Width / 2)
>  y = (Me.Size.Height / 2)

変数 x や y を Integer にするなら、上記は / 2 ではなく \ 2 の方が良いですね。

Integer / Integer の演算結果は Double 型です。(例えば 234.5 などといった値になりえます)
代入している x や y は Integer なので、ここで暗黙の型変換が生じてしまいます。

Integer \ Integer であれば、演算結果も Integer になります。


> ご指導のほど何卒宜しくお願い申し上げます。
一応、提示されたコードとは別案のサンプルも貼っておきます。

Option Strict On
Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        Me.DoubleBuffered = True
    End Sub

    Private Sub Form1_Resize(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Resize
        'フォームのサイズが変わったときに、再描画を指示する
        Me.Invalidate()
    End Sub

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Me.Paint
        Dim g As Graphics = e.Graphics
        g.ResetTransform()

        '単位系を論理センチに変更する。(モニタによっては追加調整の必要アリ)
        '下記を実行しない場合は、ピクセル単位で描画される。
        'g.ScaleTransform(e.Graphics.DpiX / 2.54!, e.Graphics.DpiY / 2.54!)

        '画面の中央が原点となるよう、座標系を水平移動する
        Dim sz As RectangleF = g.ClipBounds
        g.TranslateTransform(sz.Width / 2, sz.Height / 2)

        '赤:一辺10の正方形を「右下が画面の中心」になるように描画
        g.DrawRectangle(Pens.Red, -10, -10, 10, 10)

        '青:一辺10の正方形を「左下が画面の中心」になるように描画
        g.DrawRectangle(Pens.Blue, 0, -10, 10, 10)

        '緑:一辺10の正方形を「右上が画面の中心」になるように描画
        g.DrawRectangle(Pens.Green, -10, 0, 10, 10)

        '紫:一辺10の正方形を「左上が画面の中心」になるように描画
        g.DrawRectangle(Pens.Purple, 0, 0, 10, 10)

        '黒:一辺10の正方形に内接する円を「画面の中心」に描画
        g.FillEllipse(Brushes.Black, -5, -5, 10, 10)

        g.ResetTransform()
    End Sub
End Class


なお、描画処理が複雑でもたつくような場合は、Resize イベントではなく
ResizeEnd で Invalidate するようにしてみてください。ただしその場合、
リサイズ中は再描画されず、リサイズ完了後に描画されることになります。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。