投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/10/13 13:11:01
> 『 g 』を継承することはできませんか?
> 私のテストでは、実現できませんでした。

ごめんなさい。質問の意味が分かりませんでした。
Visual Basic における継承とは、Inherits キーワードのことを指しますが、
それとは違う話でしょうか。プログラミングでいうところの「委譲」の話ですか?


継承ということであれば、PictureBox を Inherits して、
OnPaint メソッドを Overrides すれば、Form 側で Paint イベントを実装せずとも
Graphics 処理を継承先クラスに一任できますが…ややこしくなるので説明は省略して、
OnPaint を使った描画サンプルだけ置いておきます。
https://www.atmarkit.co.jp/fdotnet/practprog/wisearch02/wisearch02_03.html


継承せずに Graphics を処理させる方法としては、
先のように、Graphics を引数にとるプロシージャーを用意して、
それを呼び出すことができます。それでは要件を満たせないでしょうか?


> ⑤  Graphics で記述する方法で、
> 文字盤のところは一度書いたら、そのままにしておき、中の3本の針(+中心点)だけを
> 書き換えることはできますか?

いわゆるレイヤーの概念ですね。

標準では、下記の 3 機能をレイヤーとして使えます。
 (1) PictureBox1.BackgroundImage の背景画像
 (2) PictureBox1.Image の前景画像
 (3) PictureBox1.Paint イベントでの e.Graphics
※このほか、PictureBox1.CreateGraphics() による描画層があります。

時計の針と違って、文字盤は変化しませんので、背景画像として保持しておくのがお奨めです。
Image 系プロパティに渡す画像は、開発時に事前に用意しておいても良いですし、
下記のように実行時に動的に生成しても良いでしょう。

'  Imports System.Drawing 
'  Imports System.Drawing.Drawing2D 

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim size = PictureBox1.Size
    PictureBox1.BackgroundImageLayout = ImageLayout.None
    PictureBox1.BackgroundImage = CreateClockFace(Math.Min(size.Width, size.Height) \ 2)
End Sub

Private Function CreateClockFace(radius As IntegerAs Image
    Dim rect As New Rectangle(0, 0, radius * 2, radius * 2)
    Dim faceRect = Rectangle.Inflate(rect, -5, -5)
    Dim bmp As New Bitmap(rect.Width, rect.Height)
    Using g = Graphics.FromImage(bmp)
        g.Clear(Color.Transparent)
        g.PixelOffsetMode = PixelOffsetMode.HighQuality
        g.CompositingQuality = CompositingQuality.HighQuality

        Using gb As New LinearGradientBrush(rect, Color.LightGreen, Color.Yellow, LinearGradientMode.ForwardDiagonal)
            g.FillEllipse(gb, faceRect)
        End Using
        Using p As New Pen(Brushes.Blue, 5.0F)
            g.DrawEllipse(p, faceRect)
        End Using
        Dim r = faceRect.Width / 2.0F
        For h = 1 To 12
            Dim x = r * CSng(Math.Cos(Math.PI * (h - 1) / 6.0F)) + r + 2.5F
            Dim y = r * CSng(Math.Sin(Math.PI * (h - 1) / 6.0F)) + r + 2.5F
            g.FillEllipse(Brushes.Yellow, x, y, 4.0F, 4.0F)
        Next
    End Using
    Return bmp
End Function



この方法は、レイヤー数をもっと増やしたい場合にも応用できます。

上記のように、背景透過な Bitmap インスタンスを動的に生成しておくと、
あとからそれを、Graphics クラスの DrawImage何某 系メソッドで描画できるので、
BackgroundImage 等を使わずとも、任意の枚数の画像を重ね合わせて表現できます。


> 私の Form の ClientSize と PictureBox は正方形なので、

もしも PictureBox を矩形(正方形/長方形)以外の形状にしたい場合には、
Region プロパティを使うことができます。
https://dobon.net/vb/dotnet/form/formregion.html