アナログ時計を作成中 への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 (削除されました)  ()
投稿日時
2014/12/1 15:14:22
(削除されました)
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2009/11/6 05:59:52
一応、VB.NET 2002 による実装サンプルを紹介しておきます。
http://msdn.microsoft.com/ja-jp/library/aa289159.aspx
できれば自力で解決してほしいところですが、どうしても解決できなかった場合には、
このサンプルコードを参考にしてみてください。結構細かく作りこまれていますよ。
http://msdn.microsoft.com/ja-jp/library/aa289159.aspx
できれば自力で解決してほしいところですが、どうしても解決できなかった場合には、
このサンプルコードを参考にしてみてください。結構細かく作りこまれていますよ。
投稿者 聖帝  (小学生)
投稿日時
2009/11/6 05:20:26
VBで時計とゆうことですね。
はい。
ペイントイベントの中で処理するとDispose()とか必要ないです。
いろんな方法がありますねぇ
タイマーコンポーネントを3つ使う方法もあるし。
はい。
ペイントイベントの中で処理するとDispose()とか必要ないです。
いろんな方法がありますねぇ
タイマーコンポーネントを3つ使う方法もあるし。
投稿者 cupid  (社会人)
投稿日時
2009/11/6 03:34:16
> PictureBox1.Invalidate を呼び出して、PictureBox1 の Paint イベントが
> 定期的に呼び出されるようにすると良いでしょう。
ああ、これは済みません。上の方で書かれてあったのですね。
Invalidateメソッドと言うものを知らなかったので、.....今後は使いましょう。
> 定期的に呼び出されるようにすると良いでしょう。
ああ、これは済みません。上の方で書かれてあったのですね。
Invalidateメソッドと言うものを知らなかったので、.....今後は使いましょう。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2009/11/6 00:28:22
> Paintイベントが発生しない状況で、書き換え必要が生じた場合はどうするんですか?
書き換える必要が生じた場合には、先述したように
再描画を要請するための Invalidate メソッドも呼び出します。
>> プログラムから再描画を要請するための Invalidate / Update / Refresh メソッドも用意されています
これによって、適切なタイミングで Paint イベントが呼び出されます。
これはたとえば、
・グラフ描画アプリで、グラフデータが変更された場合
・アニメーション描画で、次のフレームを描画したい場合
などに使う事ができます。
もし、Invalidate による「再描画依頼」で発生するタイミングでは足りないという場合には、
Update メソッドを併用することで、任意のタイミングで「強制的に再描画」させる事もできます。
書き換える必要が生じた場合には、先述したように
再描画を要請するための Invalidate メソッドも呼び出します。
>> プログラムから再描画を要請するための Invalidate / Update / Refresh メソッドも用意されています
これによって、適切なタイミングで Paint イベントが呼び出されます。
これはたとえば、
・グラフ描画アプリで、グラフデータが変更された場合
・アニメーション描画で、次のフレームを描画したい場合
などに使う事ができます。
もし、Invalidate による「再描画依頼」で発生するタイミングでは足りないという場合には、
Update メソッドを併用することで、任意のタイミングで「強制的に再描画」させる事もできます。
投稿者 neptune  (社会人)
投稿日時
2009/11/6 00:05:35
お邪魔します。
秒針付きの時計なら1秒以内での再描画になるから
>ただ見ているだけではPaintイベントは発生しないでしょ。
ってのは発生しないのでは?
もしかして分針だけ再描画って事ですか?
秒針付きの時計なら1秒以内での再描画になるから
>ただ見ているだけではPaintイベントは発生しないでしょ。
ってのは発生しないのでは?
もしかして分針だけ再描画って事ですか?
投稿者 は?  (その他)
投稿日時
2009/11/6 00:03:14
> 投稿者 cupid (社会人) 投稿日時 2009/11/05 14:37:37
> > この「再描画通知を受け取り、そのタイミングで描画する」という手法は、(以下略)
>
> Paintイベントが発生しない状況で、書き換え必要が生じた場合はどうするんですか?
> 今回のように1分に一度自動的に書き換える場合、ただ見ているだけではPaintイベントは
> 発生しないでしょ。
Timerイベントで1分に一度書き換えればいいのではないかという考えはダメなのかなぁ・・・
> > この「再描画通知を受け取り、そのタイミングで描画する」という手法は、(以下略)
>
> Paintイベントが発生しない状況で、書き換え必要が生じた場合はどうするんですか?
> 今回のように1分に一度自動的に書き換える場合、ただ見ているだけではPaintイベントは
> 発生しないでしょ。
Timerイベントで1分に一度書き換えればいいのではないかという考えはダメなのかなぁ・・・
投稿者 cupid  (社会人)
投稿日時
2009/11/5 23:37:37
> この「再描画通知を受け取り、そのタイミングで描画する」という手法は、(以下略)
Paintイベントが発生しない状況で、書き換え必要が生じた場合はどうするんですか?
今回のように1分に一度自動的に書き換える場合、ただ見ているだけではPaintイベントは
発生しないでしょ。
Paintイベントが発生しない状況で、書き換え必要が生じた場合はどうするんですか?
今回のように1分に一度自動的に書き換える場合、ただ見ているだけではPaintイベントは
発生しないでしょ。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2009/11/5 20:13:02
「CreateGraphics で無ければならない状況」の方が特殊だと思いますよ。
理解して使う分には構いませんが、通常は Paint の方が良好な;充分な結果を得られます。
たとえば、DoubleBuffered プロパティや SetStyle を用いて
ダブルバッファリングを用いた場合、その影響を受けられるのは
Paint イベント(あるいは、OnPaint メソッド)で得られる
PaintEventArgs 型の引数を用いた場合だけです。
一応、CreateGraphics で得た Graphics に対して、ダブルバッファリングを
行うためのクラスも用意されてはいますが、この場合、バッファ内の描画内容を
サーフェイスにレンダリングするタイミングは自前で管理する事になります。
また、CreateGraphics で得たサーフェイスはあくまで一時的な描画となります。
最小化したり他のウィンドウの下に隠れてしまうと、その部分は消えてしまいますので、
そのたびに消えた部分を再描画しなければなりません。
そして本来、その再描画の仕組みを担っているのが Paint イベントです。この引数
e.Graphics を使えば、自分で Graphics を生成する必要も Dispose する必要も
ありませんし、描画すべきタイミングを自分で推し量る必要もありません(プログラムから
再描画を要請するための Invalidate / Update / Refresh メソッドも用意されています)。
この「再描画通知を受け取り、そのタイミングで描画する」という手法は、
Windows フォームの描画原則となっています。この原則は .NET が登場する前から
変わっていません。VB6 しかり、MFC しかり。
なお、書き換え頻度の少ない描画(背景画像など)を表示するのが目的であれば、
CreateGraphics メソッドも Paint イベントも使う必要はありません。あらかじめ
固定画像を用意しておくか、または Graphics.FromImage(Bitmap) に対して描画して、
その画像(Bitmap)を Image/BackgroundImage に割り当てる方が効率的です。
理解して使う分には構いませんが、通常は Paint の方が良好な;充分な結果を得られます。
たとえば、DoubleBuffered プロパティや SetStyle を用いて
ダブルバッファリングを用いた場合、その影響を受けられるのは
Paint イベント(あるいは、OnPaint メソッド)で得られる
PaintEventArgs 型の引数を用いた場合だけです。
一応、CreateGraphics で得た Graphics に対して、ダブルバッファリングを
行うためのクラスも用意されてはいますが、この場合、バッファ内の描画内容を
サーフェイスにレンダリングするタイミングは自前で管理する事になります。
また、CreateGraphics で得たサーフェイスはあくまで一時的な描画となります。
最小化したり他のウィンドウの下に隠れてしまうと、その部分は消えてしまいますので、
そのたびに消えた部分を再描画しなければなりません。
そして本来、その再描画の仕組みを担っているのが Paint イベントです。この引数
e.Graphics を使えば、自分で Graphics を生成する必要も Dispose する必要も
ありませんし、描画すべきタイミングを自分で推し量る必要もありません(プログラムから
再描画を要請するための Invalidate / Update / Refresh メソッドも用意されています)。
この「再描画通知を受け取り、そのタイミングで描画する」という手法は、
Windows フォームの描画原則となっています。この原則は .NET が登場する前から
変わっていません。VB6 しかり、MFC しかり。
なお、書き換え頻度の少ない描画(背景画像など)を表示するのが目的であれば、
CreateGraphics メソッドも Paint イベントも使う必要はありません。あらかじめ
固定画像を用意しておくか、または Graphics.FromImage(Bitmap) に対して描画して、
その画像(Bitmap)を Image/BackgroundImage に割り当てる方が効率的です。
投稿者 失礼よこはいり  (社会人)
投稿日時
2009/11/5 18:31:28
魔界の仮面弁士さまにお尋ねします。
>CreateGraphics は、基本的に使わないでください。描画処理は、Button1 の Click で
> 行うのではなく、PictureBox1 の Paint イベントで e.Graphics に対して行うようにします。
入門書には、pictureBox1.CreateGraphics()を使用されているサンプルが多く使われているようですが使わないほうがよいとおっしゃる理由をおしえてください。
>CreateGraphics は、基本的に使わないでください。描画処理は、Button1 の Click で
> 行うのではなく、PictureBox1 の Paint イベントで e.Graphics に対して行うようにします。
入門書には、pictureBox1.CreateGraphics()を使用されているサンプルが多く使われているようですが使わないほうがよいとおっしゃる理由をおしえてください。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2009/11/5 07:07:49
> 時計の針が一本廻って動くだけです。どうしたら三本ちゃんと動かせるのでしょうか?
まず、長針/短針/秒針の座標が、いずれも CX, CY, EX, EY ですよね。
つまり、すべて同じ座標であるため、重なって 1 本のように表示されてしまっています。
(本来は、それぞれ違う座標になるはずです)
また、たとえ座標が正しかったとしても、ループ内の処理が良くありません。
提示されたコードでは、最内部のループ(J)内で画面をクリアしてから秒針を描いていますが、
その他の針は最内部では描かれていません。J を脱出して I のループになれば長針が描かれますが、
せっかく描いた長針も、次の g.Clear でまた消されてしまい、秒針のみの状態に戻ってしまいます。
まずは、その他の針の座標を正しく計算する事から始めてみてください。
あとは画面を Clear するたびに、毎回、3本の針を DrawLine すれば良いかと。
ただ、それとは別の問題も数多く見受けられます。
・使用したペンが破棄されていません。自分で作成した Pen は、使用後に必ず
Houp.Dispose() / Minp.Dispose() / Secp.Dispose() するようにしてください。
・CreateGraphics は、基本的に使わないでください。描画処理は、Button1 の Click で
行うのではなく、PictureBox1 の Paint イベントで e.Graphics に対して行うようにします。
・空のループ処理は避けてください。待機時間が CPU 性能に依存してしまいますし、
CPU 負荷が跳ね上がってしまい、フォームの移動等すら行えない状態になってしまいます。
このような場合には、ループではなく Timer コントロールを使うようにします。Tick イベントで、
PictureBox1.Invalidate を呼び出して、PictureBox1 の Paint イベントが
定期的に呼び出されるようにすると良いでしょう。
まず、長針/短針/秒針の座標が、いずれも CX, CY, EX, EY ですよね。
つまり、すべて同じ座標であるため、重なって 1 本のように表示されてしまっています。
(本来は、それぞれ違う座標になるはずです)
また、たとえ座標が正しかったとしても、ループ内の処理が良くありません。
提示されたコードでは、最内部のループ(J)内で画面をクリアしてから秒針を描いていますが、
その他の針は最内部では描かれていません。J を脱出して I のループになれば長針が描かれますが、
せっかく描いた長針も、次の g.Clear でまた消されてしまい、秒針のみの状態に戻ってしまいます。
まずは、その他の針の座標を正しく計算する事から始めてみてください。
あとは画面を Clear するたびに、毎回、3本の針を DrawLine すれば良いかと。
ただ、それとは別の問題も数多く見受けられます。
・使用したペンが破棄されていません。自分で作成した Pen は、使用後に必ず
Houp.Dispose() / Minp.Dispose() / Secp.Dispose() するようにしてください。
・CreateGraphics は、基本的に使わないでください。描画処理は、Button1 の Click で
行うのではなく、PictureBox1 の Paint イベントで e.Graphics に対して行うようにします。
・空のループ処理は避けてください。待機時間が CPU 性能に依存してしまいますし、
CPU 負荷が跳ね上がってしまい、フォームの移動等すら行えない状態になってしまいます。
このような場合には、ループではなく Timer コントロールを使うようにします。Tick イベントで、
PictureBox1.Invalidate を呼び出して、PictureBox1 の Paint イベントが
定期的に呼び出されるようにすると良いでしょう。
投稿者 (削除されました)  ()
投稿日時
2009/11/5 06:47:44
(削除されました)
投稿者 胡麻  (高校生)
投稿日時
2009/11/5 06:23:29
ビジュアルベーシックを使って今のところこのようにプログラムしているのですが時計の針が一本廻って動くだけです。どうしたら三本ちゃんと動かせるのでしょうか?
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim g As Graphics = PictureBox1.CreateGraphics
Dim Houp As New Pen(Color.Black)
Dim Minp As New Pen(Color.Black)
Dim Secp As New Pen(Color.Black)
Dim CX As Integer
Dim CY As Integer
Dim EX As Integer
Dim EY As Integer
Dim R As Integer
Dim Deg As Double
Dim Sec As Integer
Dim Min As Integer
Dim Hour As Integer
R = 100 '針の長さ
Deg = Deg + (1 / 30)
CX = 250
CY = 248
EX = CX - (Math.Cos(Math.PI * Deg) * R) + R
EY = CY - (Math.Sin(Math.PI * Deg) * R) - R
g.DrawEllipse(Pens.Blue, 100, 100, 300, 300) '外側の円
g.DrawEllipse(Pens.Blue, 243, 243, 10, 10) '内側の円
Houp.Width = 3
g.DrawLine(Houp, CX, CY, EX, EY) '短針
Minp.Width = 3
g.DrawLine(Minp, CX, CY, EX, EY) '長針
g.DrawLine(Secp, CX, CY, EX, EY) '秒針
Deg = 1 / 2
For I = 0 To 12
For J = 0 To 60
For K = 0 To 60
For L = 0 To 100000
Next L
Next K
Deg = Deg + (1 / 30)
EX = CX - (Math.Cos(Math.PI * Deg) * R)
EY = CY - (Math.Sin(Math.PI * Deg) * R)
g.Clear(Color.White)
g.DrawEllipse(Pens.Blue, 100, 100, 300, 300) '外側の円
g.DrawEllipse(Pens.Blue, 243, 243, 10, 10) '内側の円
g.DrawLine(Secp, CX, CY, EX, EY) '秒針
g.
Next J
g.DrawLine(Minp, CX, CY, EX, EY) '長針
Next I
g.DrawLine(Houp, CX, CY, EX, EY) '短針
End Sub
Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
End Sub
End Class
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim g As Graphics = PictureBox1.CreateGraphics
Dim Houp As New Pen(Color.Black)
Dim Minp As New Pen(Color.Black)
Dim Secp As New Pen(Color.Black)
Dim CX As Integer
Dim CY As Integer
Dim EX As Integer
Dim EY As Integer
Dim R As Integer
Dim Deg As Double
Dim Sec As Integer
Dim Min As Integer
Dim Hour As Integer
R = 100 '針の長さ
Deg = Deg + (1 / 30)
CX = 250
CY = 248
EX = CX - (Math.Cos(Math.PI * Deg) * R) + R
EY = CY - (Math.Sin(Math.PI * Deg) * R) - R
g.DrawEllipse(Pens.Blue, 100, 100, 300, 300) '外側の円
g.DrawEllipse(Pens.Blue, 243, 243, 10, 10) '内側の円
Houp.Width = 3
g.DrawLine(Houp, CX, CY, EX, EY) '短針
Minp.Width = 3
g.DrawLine(Minp, CX, CY, EX, EY) '長針
g.DrawLine(Secp, CX, CY, EX, EY) '秒針
Deg = 1 / 2
For I = 0 To 12
For J = 0 To 60
For K = 0 To 60
For L = 0 To 100000
Next L
Next K
Deg = Deg + (1 / 30)
EX = CX - (Math.Cos(Math.PI * Deg) * R)
EY = CY - (Math.Sin(Math.PI * Deg) * R)
g.Clear(Color.White)
g.DrawEllipse(Pens.Blue, 100, 100, 300, 300) '外側の円
g.DrawEllipse(Pens.Blue, 243, 243, 10, 10) '内側の円
g.DrawLine(Secp, CX, CY, EX, EY) '秒針
g.
Next J
g.DrawLine(Minp, CX, CY, EX, EY) '長針
Next I
g.DrawLine(Houp, CX, CY, EX, EY) '短針
End Sub
Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
End Sub
End Class
Pen,Brushの破棄処理はガベージコレクションに任せてます。
自作物の古いバージョンのコードの一部を抜粋
http://tabbrowser.web.fc2.com
これだけでは動きませんが(w)