C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: プログレスバー


(過去ログ 94 を表示中)

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■55921 / inTopicNo.1)  プログレスバー
  
□投稿者/ vbの質問 (1回)-(2010/12/17(Fri) 22:59:08)

分類:[.NET 全般] 

IEのステータスバーの進捗を示すバーのようなプログレスバーを実装したいと思っております。
現状、プログレスバーの進行中はフォームをつかんで移動することができません。またはフォームをつかんで移動させるとプログレスバーの進捗は止まってしまいます。
移動中も進捗が進むような、プログレスバーの実装をどなたかおしえてくださいませんでしょうか。vb2003ですが、verは2005でもまたCシャープでなんでも結構です。
引用返信 編集キー/
■55922 / inTopicNo.2)  Re[1]: プログレスバー
□投稿者/ vbの質問 (2回)-(2010/12/17(Fri) 23:10:55)
No55921 (vbの質問 さん) に返信
> IEのステータスバーの進捗を示すバーのようなプログレスバーを実装したいと思っております。
> 現状、プログレスバーの進行中はフォームをつかんで移動することができません。またはフォームをつかんで移動させるとプログレスバーの進捗は止まってしまいます。
> 移動中も進捗が進むような、プログレスバーの実装をどなたかおしえてくださいませんでしょうか。vb2003ですが、verは2005でもまたCシャープでもなんでも結構です。
引用返信 編集キー/
■55927 / inTopicNo.3)  Re[1]: プログレスバー
□投稿者/ 魔界の仮面弁士 (1992回)-(2010/12/18(Sat) 10:25:20)
No55921 (vbの質問 さん) に返信
> 現状、プログレスバーの進行中はフォームをつかんで移動することができません。
> またはフォームをつかんで移動させるとプログレスバーの進捗は止まってしまいます。
どのようなコードを記述していますか?

> vb2003ですが、verは2005でもまたCシャープでなんでも結構です。
手元に 2003 が無いので検証できないのですが、たとえば下記のようなコードを書いた場合、
フォームの移動は可能ですか? (または、プログレスバーの動作は止まりますか?)

Private beginDate, endDate As Date
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
    Button1.Enabled = False
    Timer1.Interval = 10

    Dim sec As Double = 15.0
    beginDate = Now
    endDate = beginDate.AddSeconds(sec)
    ProgressBar1.Minimum = 0
    ProgressBar1.Maximum = CInt(sec * 1000)
    ProgressBar1.Value = 0
    Label1.Text = ""
    Timer1.Start()
End Sub
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
  #If VBC_VER >= 8.0 Then
    Dim span As TimeSpan = Now - beginDate
  #Else
    Dim span As TimeSpan = Now.Subtract(beginDate)
  #End If
    ProgressBar1.Value = Math.Min(ProgressBar1.Maximum, CInt(span.TotalSeconds * 1000))
    If ProgressBar1.Value < ProgressBar1.Maximum Then
        Label1.Text = String.Format("{0,3:0}.{1:000}", span.Seconds, span.Milliseconds)
    Else
        Label1.Text = ""
        Timer1.Stop()
        Button1.Enabled = True
    End If
End Sub

引用返信 編集キー/
■55928 / inTopicNo.4)  Re[2]: プログレスバー
□投稿者/ vbの質問 (3回)-(2010/12/18(Sat) 10:58:36)
No55927 (魔界の仮面弁士 さん) に返信

魔界の仮面弁士 さんご回答ありがとうございます。
申し訳ございません。現状のことばっかり考えていまして、間違った記述をしてしまいました。

vbコントロールのプログレスバーはフォーム移動中もしょりは問題なく進みます。
vbコントロールのデザインがいやで、滑らかに表示させたかったので(vb.net2003を使用しています)

たとえば最初に四角を書いて

Dim g As Graphics = PictureBox1.CreateGraphics()
Dim rect As Rectangle

For i As Integer = 0 To 100000
rect2 = New Rectangle(20, 20, i * 0.001, 10)
g.FillRectangle(Brushes.Green, rect)
Next

などのような記述をしています。また、滑らかに表示する為にオーナードローという手段を使ってもfor文を使った進捗のさせ方で結局つまずいてしまいまして、他の手段、あるいはなにかアイデアがあればと思っております。よろしくお願いします。わざわざコードを記述いただいてほんとうにありがとうございます。動作は確認しました。(VBコントロール自体は正常にうごきます。すいません。)


引用返信 編集キー/
■55929 / inTopicNo.5)  Re[3]: プログレスバー
□投稿者/ vbの質問 (4回)-(2010/12/18(Sat) 11:08:33)
No55928 (vbの質問 さん) に返信

魔界の仮面弁士 さんご回答ありがとうございます。
申し訳ございません。現状のことばっかり考えていまして、間違った記述をしてしまいました。

> vbコントロールのプログレスバーはフォーム移動中もしょりは問題なく進みます。
> vbコントロールのデザインがいやで、滑らかに表示させたかったので(vb.net2003を使用しています)
>
> たとえば最初に四角を書いて
>
> Dim g As Graphics = PictureBox1.CreateGraphics()
> Dim rect As Rectangle
>
> For i As Integer = 0 To 100000
> rect2 = New Rectangle(20, 20, i * 0.001, 10)    ’rectが正でした。
> g.FillRectangle(Brushes.Green, rect)          
> Next
>
> などのような記述をしています。また、滑らかに表示する為にオーナードローという手段を使ってもfor文を使った進捗のさせ方で結局つまずいてしまいまして(フォームが移動できないか、進捗が進まないかのいずれかの現象を回避できず)、他の手段、あるいはなにかアイデアがあればと思っております。よろしくお願いします。わざわざコードを記述いただいてほんとうにありがとうございます。動作は確認しました。(VBコントロール自体は正常にうごきます。すいません。)
>
>
引用返信 編集キー/
■55932 / inTopicNo.6)  Re[3]: プログレスバー
□投稿者/ 魔界の仮面弁士 (1993回)-(2010/12/18(Sat) 12:56:06)
No55928 (vbの質問 さん) に返信
> vbコントロールのデザインがいやで
デザインは ProgressBar.Style で変更できますが、Visual Style が有効な場合には、
Continuous に設定しても Blocks スタイルになってしまうんですよね…。


> Dim g As Graphics = PictureBox1.CreateGraphics()
基本的に、CreateGraphics は使用すべきではありません。
通常は Paint イベントを利用し、e.Graphics に対して描画処理を記述すべきです。

この場合、「時間のかかる処理」の最中に、任意のタイミングで PictureBox の
Invalidate メソッドもしくは Refresh メソッドを呼ぶようにします。


Invalidate とは、「描画すべきデータが更新されたので、次回の描画タイミングで再描画して欲しい」と
OS に依頼するためのメソッドです。これにより、Paint イベントが誘発されます。

Refresh メソッドは、Invalidate メソッド + Update メソッドの組み合わせと同じ意味です。
これは、強制的に再描画を行う必要がある場合に利用されます。

Update メソッドは、「描画の必要があれば、描画処理を実行する」という物です。
特に再描画が不要な状況では、Update を呼び出しても何も起きませんが、
再描画が必要とされる状況では、Paint イベント(OnPaint メソッド)が呼び出されます。


Private currentValue As Integer

Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles PictureBox1.Paint
    Dim rect As New Rectangle(20, 20, Me.currentValue * 0.001, 10)
    e.Graphics.FillRectangle(Brushes.Green, rect)
End Sub

Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
    'Invalidate を使った場合は、ループ処理の速度は低下しない。
    'ただし、描画は強制ではないため、ループ中には実際の描画処理が行われず、
    'End Sub した後に実行される可能性が高い。
    For Me.currentValue = 0 To 100000
        PictureBox1.Invalidate()
    Next
End Sub

Private Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button2.Click
    'Refresh を使うと、本来は再描画不要なタイミングであっても強制的に描画させる事ができる。
    'ただしその分、ループ処理性能は著しく低下する事になる。
    For Me.currentValue = 0 To 100000
        PictureBox1.Refresh()
    Next
End Sub

Private Sub Button3_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button3.Click
    '両者を組み合わせた例。基本的には Invalidate を使うようにしておき、
    '時折、強制描画を挟むようにする(回数で制御する他、Timer で Update する手もある)。
    'Update の頻度を変更することでパフォーマンスを調整できるのが利点。
    For Me.currentValue = 0 To 100000
        PictureBox1.Invalidate()

        If Me.currentValue Mod 100 = 0 Then
            PictureBox1.Update()   '100回ごとに強制描画
        End If
    Next
End Sub


> for文を使った進捗のさせ方で結局つまずいてしまいまして
メインスレッドが重い処理を行っている最中は、描画処理が行われなかったり、
画面操作を受け付けなくなる可能性が高くなります。画面位置の変更などといった
UI操作を受け付けるようにしたい場合には、重い処理を非同期的に実装する事を検討してみてください。

たとえば、各処理を細かく分割しておき、Timer の Tick イベントで、少しずつ処理を
進めていくという手法があります。この手法は、時計やアニメーション処理などで利用できます。

一方、長いループ処理を必要とするケースでは、作業用の別スレッドを用意した方が
望ましいかも知れません。2005 以降では、BackgroundWorker を使うと便利でしょう。
あるいは、Webサービス化して Asnyc 系メソッドで実行するという選択肢もあります。


この他、ループ中で適宜 DoEvents を呼び出すという選択肢もあるのですが、
DoEvents の利用は、イベント再入を引き起こす可能性があるため、
意図しない動作となる事がありますので、極力避けた方が無難です。

引用返信 編集キー/
■55936 / inTopicNo.7)  Re[4]: プログレスバー
□投稿者/ vbの質問 (5回)-(2010/12/20(Mon) 00:35:59)
魔界の仮面弁士さま、ご回答ありがとうございました。
いろいろ勉強になりました。一応解決と判断しました。

> 基本的に、CreateGraphics は使用すべきではありません。
> 通常は Paint イベントを利用し、e.Graphics に対して描画処理を記述すべきです。

確かにそうでした。そうしないと描画がはがれおちてしまうのを忘れてました。


> たとえば、各処理を細かく分割しておき、Timer の Tick イベントで、少しずつ処理を
> 進めていくという手法があります。この手法は、時計やアニメーション処理などで利用できます。

今回、緩やかに増加していく変数というものが表現できなかったのですが、やはりfor文をつかったのがまずかったようです。
for文のしょりのなかで、描画タイミングを拾うのではなく、ゆるやかに増加していく変数を使って描画をしていく方向ですすめてましたが
timerをつかってわりと単純に解決できました。お手数おかけしました。


Dim p As Single

Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint

Dim rect As Rectangle
rect = New Rectangle(21, 21, p, 6)

e.Graphics.DrawRectangle(Pens.Black, 20, 20, 70, 7)
e.Graphics.FillRectangle(Brushes.LimeGreen, rect)

End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

If p < 40 Then
p = p + 0.5
ElseIf p >= 40 And p < 50 Then
p = p + 0.1
ElseIf p >= 50 And p < 60 Then
Me.Timer1.Interval = 20
p = p + 0.1
Label1.Text = p
ElseIf p >= 60 And p < 65 Then
Me.Timer1.Interval = 60
p = p + 0.1
Label1.Text = p
End If

PictureBox1.Invalidate()

If p > 65 Then
Timer1.Stop()
End If

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Me.Timer1.Interval = 10
Me.Timer1.Start()

End Sub


変化量に変化をもたせる為余計な条件があり、長方形が小さいのは実装予定の為です。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -