タイトル | : Re^3: 塗りつぶし(黒)の円をPC画面中央に配置する |
記事No | : 11387 |
投稿日 | : 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 するようにしてみてください。ただしその場合、 リサイズ中は再描画されず、リサイズ完了後に描画されることになります。
|