トップ回答者
Graphicsでの線の描き順

質問
-
初めて、Graphicsオブジェクトを使用します.
次のコードでFormに配置したPictureBoxにx軸とy軸を描きたいのですが、一度描かれた軸が消えてしまいます。
消えない方法をお願いいたします。
Dim gr as Graphics
Dim myMatrix As New Matrix(1, 0, 0, -1, 0, 0)Dim Wd, hg, Khg as Single
Dim jkn as String="平均+合計"
Private Sub PictureBx_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBx.Paint
Dim br As Brush = Brushes.DeepPink
gr = PictureBx.CreateGraphics()
Wd = PictureBx.Width : hg = PictureBx.Height
Khg = hg / 5 * 3
GrafUsInit()
' GrafUsStart()End Sub
Private Sub GrafUsInit()
Dim br As Brush
If InStr(jkn, "平均") Then br = Brushes.LightBlue Else br = Brushes.LightGreen
gr.FillRegion(br, gr.Clip)
gr.Transform = myMatrix
gr.TranslateTransform(Wd * 0.95, Khg, MatrixOrder.Append)
gr.DrawLine(Pens.White, 0, -hg, 0, hg)
gr.DrawLine(Pens.Blue, -Wd, 0, Wd, 0)
End Subよろしくお願いします。
回答
-
Hongliangさん、ご回答有難うございます。
Paintメソッドにe.graphicsを使用した場合、マウスのクリックイベントPictureBx_MouseUpでgrがハンドルされないので
PictureBx_MouseUpイベントで再度e.graphicsを宣言してグラフ領域を再定義しなければなりません。
その為、PictureBoxのCreateGraphicsを使用しました。
この場合、どのようにすると良いでしょうか?
Dim inx As Short
Private Sub PictureBx_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBx.MouseUp
・・・・・・・・・・・・・・・・・・・・・・
' 折れ線グラフ
dispgraf(i)
End SubPrivate Sub dispgraf(ByRef i As Short)
・・・・・・・・・・・・・・・・・・・・・・・・・・
For jx = 1 To P(i).ds : jh = J(i, jx).nn
Dy = CDate(Mid(jh, 1, 4) & "/" & Mid(jh, 6, 2) & "/" & J(i, jx).hi)
x = Int(DateDiff(Microsoft.VisualBasic.DateInterval.Day, now1, Dy) * Xritu) ' X は日付間隔です
Y = (J(i, jx).h - F.thk) * Yritu ' Y 軸の値です
If J(i, jx).LV >= 0 Then
br = Brushes.Black
pn = Pens.Black
Else
br = Brushes.Red
pn = Pens.Red
End If' 折れ線グラフを描く
' ここで変数gr がモジュールレベルで宣言しているのにハンドルされないエラーが出現します
If jx = 1 Then
gr.FillEllipse(br, x - 5, y - 5, 10, 10) ' ここでエラーが出現します
Else
gr.DrawLine(Pn, x1, y1, x, Y)
gr.FillEllipse(br, x - 5, y - 5, 10, 10)
End If
x1 = x : y1 = Y
Next
indx = i
End Subよろしくお願いします。
-
外池と申します。
画面の表示に対してマウス操作をしながらグラフィカルな表示を行う場合には、ガラリと発想を変えないと難しいかもしれません。
基本的に、Graphicsを使って描画する操作は、「全て」、FormのPaintイベントなり、PictureBoxのPaintイベントなりを使って行うように徹底してください。それ以外の場所でGraphicsを創って(Createして)描画することはしないほうが良いです。
本当にそんなことが可能なのか? ということになりますが、次のような考え方でいかがでしょうか?
1) 画面に表示するものばかりを集めた変数なり、コレクションなりを用意します。今回の場合は、線なのであれば、線の開始点と終了点の座標ばかりを集めた配列でも構いません。
2) マウス操作で新たに表示する線が発生した時には、マウスイベントで、座標点の設定だけしてやります。その上で、FormやPictureBoxのInvalidateなり、Refreshなりをしてやります。(これで自動的に次のPaintイベントが発生します。)
3) Paintイベントで、設定された座標点を使って全ての線を描きます。ミソは、Paintイベントが発生する度に、全てを描き直すようなプログラムにしておくことです。
最後の3)の「ミソ」の部分は、無駄なことではないか? と思われるかもしれませんが、グラフが出ている画面は、別のアプリのウィンドウで覆われてしまうこともあるわけで、その別のアプリが終了してグラフが再び前面に現れたときは、全てを描き直さないといけません。
で、2)のマウス操作では、「全て」に含まれるもの(線など)を新たに加えたり、取り除いたりするだけのプログラムにしておき、あとはPaintイベントに任せるようにするわけです。
参考になれば、幸いです。
-
外池様、大変ご丁寧な説明有難うございます。
Net初心者の私には大変参考になりました。
今後ともよろしくお願いいたします。
今回、ご指摘のようにMouseのクリックにて折れ線グラフを次から次へとサンプルデータを変えて表示したかったので
1・Graphicsオブジェクトに座標の設定及びX軸Y軸の描画(Form_Loadイベントから立ち上げ)
2・PictureBoxのクリックにてデータの順次表示(Mouse_Upイベントにて)
と言う構想だったんですが、これは駄目と言うことですね。判りました。
各イベントから作成したGraphicsオブジェクトのモジュール内で有効性が保障されないと言うこと(ガベージ?)。
また、Graphicsオブジェクトを発生するイベントの種類が多く、それぞれ独立している事が判りました。
ご教授の2)マウスクリックイベントから全てをPaintイベントに渡してそこで全てを処理するように変更してやって見ます。
作成に少し時間が掛かるので、しばらくのご猶予をお願いします。
すべての返信
-
Hongliangさん、ご回答有難うございます。
Paintメソッドにe.graphicsを使用した場合、マウスのクリックイベントPictureBx_MouseUpでgrがハンドルされないので
PictureBx_MouseUpイベントで再度e.graphicsを宣言してグラフ領域を再定義しなければなりません。
その為、PictureBoxのCreateGraphicsを使用しました。
この場合、どのようにすると良いでしょうか?
Dim inx As Short
Private Sub PictureBx_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBx.MouseUp
・・・・・・・・・・・・・・・・・・・・・・
' 折れ線グラフ
dispgraf(i)
End SubPrivate Sub dispgraf(ByRef i As Short)
・・・・・・・・・・・・・・・・・・・・・・・・・・
For jx = 1 To P(i).ds : jh = J(i, jx).nn
Dy = CDate(Mid(jh, 1, 4) & "/" & Mid(jh, 6, 2) & "/" & J(i, jx).hi)
x = Int(DateDiff(Microsoft.VisualBasic.DateInterval.Day, now1, Dy) * Xritu) ' X は日付間隔です
Y = (J(i, jx).h - F.thk) * Yritu ' Y 軸の値です
If J(i, jx).LV >= 0 Then
br = Brushes.Black
pn = Pens.Black
Else
br = Brushes.Red
pn = Pens.Red
End If' 折れ線グラフを描く
' ここで変数gr がモジュールレベルで宣言しているのにハンドルされないエラーが出現します
If jx = 1 Then
gr.FillEllipse(br, x - 5, y - 5, 10, 10) ' ここでエラーが出現します
Else
gr.DrawLine(Pn, x1, y1, x, Y)
gr.FillEllipse(br, x - 5, y - 5, 10, 10)
End If
x1 = x : y1 = Y
Next
indx = i
End Subよろしくお願いします。
-
外池と申します。
画面の表示に対してマウス操作をしながらグラフィカルな表示を行う場合には、ガラリと発想を変えないと難しいかもしれません。
基本的に、Graphicsを使って描画する操作は、「全て」、FormのPaintイベントなり、PictureBoxのPaintイベントなりを使って行うように徹底してください。それ以外の場所でGraphicsを創って(Createして)描画することはしないほうが良いです。
本当にそんなことが可能なのか? ということになりますが、次のような考え方でいかがでしょうか?
1) 画面に表示するものばかりを集めた変数なり、コレクションなりを用意します。今回の場合は、線なのであれば、線の開始点と終了点の座標ばかりを集めた配列でも構いません。
2) マウス操作で新たに表示する線が発生した時には、マウスイベントで、座標点の設定だけしてやります。その上で、FormやPictureBoxのInvalidateなり、Refreshなりをしてやります。(これで自動的に次のPaintイベントが発生します。)
3) Paintイベントで、設定された座標点を使って全ての線を描きます。ミソは、Paintイベントが発生する度に、全てを描き直すようなプログラムにしておくことです。
最後の3)の「ミソ」の部分は、無駄なことではないか? と思われるかもしれませんが、グラフが出ている画面は、別のアプリのウィンドウで覆われてしまうこともあるわけで、その別のアプリが終了してグラフが再び前面に現れたときは、全てを描き直さないといけません。
で、2)のマウス操作では、「全て」に含まれるもの(線など)を新たに加えたり、取り除いたりするだけのプログラムにしておき、あとはPaintイベントに任せるようにするわけです。
参考になれば、幸いです。
-
外池様、大変ご丁寧な説明有難うございます。
Net初心者の私には大変参考になりました。
今後ともよろしくお願いいたします。
今回、ご指摘のようにMouseのクリックにて折れ線グラフを次から次へとサンプルデータを変えて表示したかったので
1・Graphicsオブジェクトに座標の設定及びX軸Y軸の描画(Form_Loadイベントから立ち上げ)
2・PictureBoxのクリックにてデータの順次表示(Mouse_Upイベントにて)
と言う構想だったんですが、これは駄目と言うことですね。判りました。
各イベントから作成したGraphicsオブジェクトのモジュール内で有効性が保障されないと言うこと(ガベージ?)。
また、Graphicsオブジェクトを発生するイベントの種類が多く、それぞれ独立している事が判りました。
ご教授の2)マウスクリックイベントから全てをPaintイベントに渡してそこで全てを処理するように変更してやって見ます。
作成に少し時間が掛かるので、しばらくのご猶予をお願いします。
-
外池様、Hongliang様、今回は大変お世話になりました。
ご教授の通りアルゴリズムを変更し、当方の意図するものにすることが出来ました。
有難うございました。
ちなみに作成したPaintイベントのコードです。
Dim init as Boolean = True
Private Sub PictureBx_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBx.Paint
Dim Gr As Graphics = e.Graphics
Dim i As IntegerIf init = True Then
i = AJ(inx)
GrafUmaInit(Gr) ' 初期化 図形領域設定、座標作成
GrafumaStart(i, gr) ' inxの最初のグラフを描画
init = False ' 2度目に入ってこなくする
Else
GrafUmaInit(Gr) ' 初期化 図形領域設定、座標作成
dispShadow(indx, Gr) ' 前に描いたinxのグラフを薄い色に描き換え
i = AJ(inx)
GrafumaStart(i, Gr) ' 次のinxのグラフを描画
End If
End SubinxはMouse_Upイベントで変更、その他の変数はLoadイベントで変更しました。
当方、問題山積の為、今後ともお世話に成ると思いますがよろしくご指導お願いいたします。
---ネット移行者---