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

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

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

全過去ログを検索

<< 0 >>
■46193  Re[1]: List<T>.FindAll() で順序は維持されるか?
□投稿者/ ななし -(2010/01/27(Wed) 19:36:12)
    No46152 (みきぬ さん) に返信
    >>このメソッドは順次検索を実行します。

    原文は
    This method performs a linear search;
    となってました。
    http://ja.wikipedia.org/wiki/%E7%B7%9A%E5%9E%8B%E6%8E%A2%E7%B4%A2
    にも「先頭から順に」と書いてあるので、大丈夫じゃないでしょうか。

    検索は先頭からするけど、返すリストは逆順(とか不定)、という実装には今後も変更されないと思いますが、
    メソッドの解説への記述の追加依頼を出されてはいかがですか?

    ちなみに今の実装ですが、■No46182 でのみきぬさんのコードより単純に、先頭から処理してありました。
記事No.46152 のレス /過去ログ78より / 関連記事表示
削除チェック/

■88572  Re[6]: コントロールを自然に動かすには??
□投稿者/ 熊さん -(2018/09/08(Sat) 16:01:04)
    2018/09/08(Sat) 16:01:51 編集(投稿者)

    ありがとうございます。
    確かにこのコードだとほとんど残像が気になりませんね。

    以下のコードが残像の出るコードです。

    フォーム上に
    PictureBox1とNumericUpDown1を配置して
    ホイールでNumericUpDown1を回していただけますでしょうか?

    すると位置が変化するはずのない赤色の中央線がぴくぴく動くことがご確認いただけると思います。

    PictureBox1.Invalidate()


    ' PictureBox1.Refresh()
    すると少しましにはなるのですが
    やはりぴくぴく動いてしまいます。


    Public Class Form6


    Public YRate As Single

    Public ProfilePosition As New XY_Profile

    Public Class XY_Profile

    Property X_Int As Integer
    Property Y_Int As Integer

    End Class



    Private Sub Form6_Imaging_Load(sender As Object, e As EventArgs) Handles MyBase.Load


    PBox1 = PictureBox1.Bounds

    With NumericUpDown1
    .Minimum = 10
    .Maximum = 100
    .DecimalPlaces = 0
    .Increment = 3
    .Value = 100
    End With

    PictureBox1.SizeMode = PictureBoxSizeMode.Zoom


    ProfilePosition.X_Int = CInt((PictureBox1.Width - 3) / 2)
    ProfilePosition.Y_Int = CInt((PictureBox1.Height - 3) / 2)



    End Sub



    Private PBox1 As Rectangle


    Private pPen As New Pen(Color.FromArgb(60, Color.Red), 2)

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

    Dim Pbox As PictureBox = CType(sender, PictureBox)

    Dim g As Graphics = e.Graphics
    g.DrawLine(pPen, 0, ProfilePosition.Y_Int, Pbox.Width, ProfilePosition.Y_Int)
    g.DrawLine(pPen, ProfilePosition.X_Int, 0, ProfilePosition.X_Int, Pbox.Height)

    End Sub



    Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged


    YRate = NumericUpDown1.Value / 100

    PictureBox1.SetBounds(PBox1.X, PBox1.Top + CInt(PBox1.Height * (1 - YRate) * 0.5), PBox1.Width, CInt(PBox1.Height * YRate))

    ProfilePosition.Y_Int = CInt(0.5 * (PictureBox1.Height - 4))

    ' PictureBox1.Refresh()

    PictureBox1.Invalidate()


    End Sub

    End Class
記事No.88470 のレス /過去ログ152より / 関連記事表示
削除チェック/

■88584  Re[7]: コントロールを自然に動かすには??
□投稿者/ 魔界の仮面弁士 -(2018/09/09(Sun) 01:09:10)
    2018/09/09(Sun) 04:49:21 編集(投稿者)

    No88572 (熊さん  さん) に返信
    > すると位置が変化するはずのない赤色の中央線がぴくぴく動くことがご確認いただけると思います。

    「位置がまったく変化していない」ことは確認済みでしょうか。

    たとえば、現在の処理方法で詰めていくのなら、
      PictureBox1.SetBounds(…)
      ProfilePosition.Y_Int = …
    の直後に
      Me.Text = CStr(PictureBox1.Top + ProfilePosition.Y_Int)
    などを置いてみて、NumericUpDown を動かしたときに
    タイトルバーに記載される値がブレないことを確認するなど。



    > PBox1.Top + CInt(PBox1.Height * (1 - YRate) * 0.5)
    上記の計算式の場合、YRate が Single なので、
    0.5 や 0.5R ではなく、0.5F と書いた方が良いですよ。


    さて、以下は提示頂いたコードとは別のやり方になるのですが:

    中央線は、PictureBox の位置に合わせて調整するとはいえ、
    Form 上から見れば、常に同じ位置にあるわけですよね。

    であれば Load 時にでも、その中央線の交点座標を、
    PictureBox1 の中での位置として保持するのではなく、
    「Form のクライアント座標」に変換して保持されては如何でしょう。

    そうすれば、NumericUpDown は PictureBox1 の位置調整に
    特化して処理できますので、描画処理も簡潔になりそうな気がします。


    ということで、書き直してみました。


    Public Class Form6
    Private pPen As Pen '十字線の描画用ペン
    Private PBox1 As Rectangle '100% の時の PictureBox1 の位置情報
    Private CenterPos As Point '十字線の中央位置(Formのクライアント領域基準)
    Private Sub Form6_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
    pPen.Dispose() '不要になった Pen の処分
    End Sub
    Private Sub Form6_Imaging_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    pPen = New Pen(Color.FromArgb(60, Color.Red), 2) '十字線描画用
    PBox1 = PictureBox1.Bounds '初期位置の保存

    '十字線の中央位置(PictureBoxのクライアント領域基準)
    Dim centerPic As New Point(PictureBox1.Width \ 2, PictureBox1.Height \ 2)

    '十字線の中央位置(Formのクライアント領域基準)
    CenterPos = centerPic + New Size(PictureBox1.Location)
    End Sub
    Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles PictureBox1.Paint
    Dim Pbox As PictureBox = CType(sender, PictureBox)

    '十字線の中央位置(PictureBoxのクライアント領域基準)
    Dim xy = CenterPos - New Size(PictureBox1.Location)

    Dim g = e.Graphics
    g.DrawLine(pPen, 0, xy.Y, PictureBox1.Width, xy.Y)
    g.DrawLine(pPen, xy.X, 0, xy.X, PictureBox1.Height)
    End Sub

    Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged
    If PBox1.IsEmpty Then
    Return 'ロード前なので何もしない
    End If

    '位置調整の「前」に、描画状態を無効化しておく
    PictureBox1.Invalidate()

    '位置調整
    Dim val As Integer = CInt(NumericUpDown1.Value) '10〜100
    Dim sz As New Size(PBox1.Width, PBox1.Height * val \ 100)
    Dim xy As New Point(PBox1.Left, PBox1.Top + (PBox1.Height - sz.Height) \ 2)
    PictureBox1.Bounds = New Rectangle(xy, sz)
    End Sub
    End Class


    なお元のコードでは、座標の計算時に、
    Decimal, Integer, Single, Double の型が混ざっていたので、
    勝手ながらすべて Integer のみで演算されるよう改修しています。

    ただし「CInt(z * 0.5)」を「z \ 2」で代用した関係上、
    NumericUpDown の値によっては、PictureBox1 の位置と大きさが
    ごく僅かにズレが生じることがあります。

    具体的には、「CInt(z * 0.5)」と「z \ 2」の計算を比較すると、
    z = 105 の場合は、どちらの計算でも 52 と算出されますが、
    z = 103 の場合は、前者が 52、後者は 51 となるというものです。
記事No.88470 のレス /過去ログ152より / 関連記事表示
削除チェック/

■88592  Re[9]: コントロールを自然に動かすには??
□投稿者/ 魔界の仮面弁士 -(2018/09/09(Sun) 16:03:28)
    No88588 (熊さん さん) に返信
    > 問題解決しました。
    なお No88572 で投稿いただいたコードだと、
    >>   Me.Text = CStr(PictureBox1.Top + ProfilePosition.Y_Int)
    の実験で、中央線の座標に ±1 程度のブレが見られましたので、
    そもそもの計算で誤差が生じていた、というのも原因の一つかと思います。
    (それは残像ではなく、計算ミスということになりそうですが)


    > PictureBox1.Invalidate()はPictureBox1に描画するように指令を出すためのコマンドのはずです。
    ちょっと違います。


    【Invalidate】の仕事は、そのウィンドウ内に『更新リージョン』を作成するだけであり、
    正確には描画依頼そのものではありません。

    ざっくり言えば、「現在の描画内容が無効である」とマーキングするためのもの。
    今回は引数無しで呼び出しているので、領域すべてが無効化されます。
    https://msdn.microsoft.com/ja-jp/library/cc410421.aspx


    【Update】は、その更新リージョンが空ではない場合に、そのコントロールに対して
    WM_PAINT ウィンドウメッセージを送信してクライアント領域を更新します。
    これにより Paint イベントが誘発されます。
    (更新すべき領域が何もなければ、呼び出しても何も起きません)

    ウィンドウメッセージは通常、待機行列にキューイングされた上で、
    アイドル時に順次処理されるようになっているのですが、Update メソッドを
    呼び出した場合は、その待機行列を通さずに直接再描画メッセージが飛んできます。
    https://msdn.microsoft.com/ja-jp/library/cc428780.aspx


    【Refresh】は、Invalidate + Update と同義です。
    直ちに再描画を行い時にのみ呼び出します。


    PictureBox の上に他のウインドウが覆いかぶさっていて、それが取り除かれた時に
    再描画されるのも、その重なっていた領域分の更新リージョンが生成されるためです。
    この場合は明示的に Update を呼ばずとも、アイドル時に自動的に Paint イベントが呼ばれます。


    >> '位置調整の「前」に、描画状態を無効化しておく
    >> PictureBox1.Invalidate()
    > が
    > PictureBox1.Bounds = New Rectangle(xy, sz)
    > の前にありますが、
    Update や Refresh ではなく、Invalidate である点がミソです。


    > PictureBox1.Bounds = New Rectangle(xy, sz)
    > の後でないと設定したサイズが描画されないのではないでしょうか?
    Bounds の直後に呼ぶとしたら、Invalidate ではなく Update または Refresh ですよ。

    今回は Update を呼び出していませんが、それはリサイズ直後に End Sub しているからです。
    アイドル時に Invalidate された領域への再描画が発生するので、
    あえて Update を呼ぶ必要も無いという訳ですね。


    それともう一つ。現在の描画状態を無効化せずに Top 位置を変えると、
    以前描いた中央線ごと移動してしまうので、一瞬、正しくない位置に線があるように
    見えてしまうという問題もあります。だからこそ、「直前」の無効化が重要となります。

    直前には Invalidate を呼ばず、直後に呼び出してみるとか、
    直前の Invalidate を Refresh に変えて呼び出してみると、
    これらの違いを体感できるかと思います。
記事No.88470 のレス /過去ログ152より / 関連記事表示
削除チェック/



<< 0 >>

パスワード/

- Child Tree -