tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルListViewのスクロール
記事No10730
投稿日: 2012/03/12(Mon) 15:14
投稿者じょば
言語 : Visual Basic 2010 Express

ListViewのスクロールに関する御質問です。
Viewプロパティは、Details でデータを一覧表示しています。

縦スクロールバーを表示し、上下に隠れた部分はマウスでスクロール
する事により表示できますが、これをキーボードの上下キーで行えない
かとチャレンジしています。

一通り、ListViewのプロパティやメソッドを確認したのですが、私の
知識では不可能でした。

上に隠れた部分を表示するには、TopItemプロパティとEnsureVisible
メソッドで実装できます。
しかし、下に隠れた部分を一行ずつスクロールして表示する方法を
見つける事ができません。

表示する行数を固定にすれば可能ですが、同じEXEでも実行するOSにより
表示される行数が異なりますし、フォームの大きさが可変であり、
ListViewの高さも連動して可変しますから、行数は固定できません。

下矢印キーで、下に隠れた部分を一行ずつスクロールして表示する方法は、
ありますでしょうか?

よろしくお願いいたします。

[ツリー表示へ]
タイトルRe: ListViewのスクロール
記事No10731
投稿日: 2012/03/12(Mon) 15:40
投稿者じょば
じょばです。

書き忘れました。

上下矢印キーでスクロールさせたいのは、フォーカスがListViewに無いときの場合です。

フォーカスはフォームにあり、左右の矢印では表示するデータ自体の移動に使います。

フォームのKeyPreviewプロパティーをTrueにして、矢印キー押下をKeyDownイベントで
受け取り、独自のスクロール処理をしようとしています。

[ツリー表示へ]
タイトルRe^2: ListViewのスクロール
記事No10733
投稿日: 2012/03/12(Mon) 18:18
投稿者VBレスキュー(花ちゃん)
仮にスクロールバーを動かしたらその時点でフォーカスが移りませんか?
(ListView を都度書き換える事になるので)

[ツリー表示へ]
タイトルRe^3: ListViewのスクロール
記事No10734
投稿日: 2012/03/12(Mon) 18:45
投稿者じょば
管理人様、レスありがとうございます。

> 仮にスクロールバーを動かしたらその時点でフォーカスが移りませんか?
> (ListView を都度書き換える事になるので)

試してみましたが、マウスでスクロールバーを動かした時点では、
フォーカスはListViewに移らないようです。

フォーカスがListViewに移れば、上下の矢印キーでスクロールでき
ますからコードで制御する必要はないのですが。

現在の仕様だと、左右の矢印で読込んでいるテキストデータの
レコード移動を行っていますので、左右の矢印を押下すると、
フォーカスはフォームに移るようになっています。

従いまして、希望としてはフォーカスがListViewになくてもコードで
スクロールさせたいのですが (^^;

1.現在ListViewに表示されている行数
2.現在表示されているListViewの最下行のIndex

この、どちらかが取得できれば何とかなりますが、やはり無理なの
でしょうかねぇ・・・

[ツリー表示へ]
タイトルRe^4: ListViewのスクロール
記事No10735
投稿日: 2012/03/12(Mon) 20:48
投稿者VBレスキュー(花ちゃん)
> 1.現在ListViewに表示されている行数
> 2.現在表示されているListViewの最下行のIndex

上記で操作したら、ListViewにフォーカスが移ってしまいますが。?

下記でも同様にListViewにフォーカスが移ってしまいます。
Private Sub Form1_KeyDown(sender As Object, e As  _
                  System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
   If e.KeyCode = Keys.Down Then
      SendMessage(ListView1.Handle, EM_SCROLL, SB_LINEDOWN, 0)
   End If
End Sub

下記を使ってスクロールバーをクリックするのなら移らないかも知れないが、マウスを
使用する事になるので。?
 http://www.hanatyan.sakura.ne.jp/patio/read.cgi?no=315

[ツリー表示へ]
タイトルRe^5: ListViewのスクロール
記事No10736
投稿日: 2012/03/12(Mon) 21:11
投稿者VBレスキュー(花ちゃん)
> 下記を使ってスクロールバーをクリックするのなら移らないかも知れないが、マウスを
> 使用する事になるので。?
>  http://www.hanatyan.sakura.ne.jp/patio/read.cgi?no=315

上記でスクロールバーをクリックしてもやはりListViewにフォーカスが移ってしまいますね。

[ツリー表示へ]
タイトルRe^5: ListViewのスクロール
記事No10737
投稿日: 2012/03/12(Mon) 21:50
投稿者じょば
管理人様

色々と、ありがとうございます。

フォーカスが移るかどうかという件は、私が作成しているAPの仕様で
ありまして、ListViewの仕様という意味ではありませんでした。

書き方が曖昧で、申し訳ありません。

今行いたい事は、フォームでKeyPreviewにTrueを設定して、フォームの
KeyDownイベントによる制御を行いたいという事に尽きます。

メソッドやプロパティを全て眺め尽くしても、

1.現在ListViewに表示されている行数
2.現在表示されているListViewの最下行のIndex

この2つのどちらも取得出来そうにありませんので、やはり考え方と
いうか、やり方を変えた方が良いのではないかと思い始めました。

ListViewではムリなのかもしれないですね。

[ツリー表示へ]
タイトルRe^5: ListViewのスクロール
記事No10738
投稿日: 2012/03/12(Mon) 21:54
投稿者じょば
失礼しました。

コードの例を示して頂いていましたのに、そちらに対するレスを
していませんでした。

SendMessageによる制御の例、ありがとうございます。

なるほど、そういう手もありますね。

明日、職場で試してみようと思います。

また、結果を書き込ませていただきます。1

[ツリー表示へ]
タイトルRe^6: ListViewのスクロール【修正】
記事No10739
投稿日: 2012/03/12(Mon) 23:25
投稿者VBレスキュー(花ちゃん)
>SendMessageによる制御の例、ありがとうございます。
>なるほど、そういう手もありますね。

すみません、上記の件は、私の勘違いでした。
ListView 上では動作しません。


>1.現在ListViewに表示されている行数
>2.現在表示されているListViewの最下行のIndex

なら下記のようにすれば求めることが可能です。

   Dim oldTop As Integer = ListView1.TopItem.Index
   Dim itemBottom As Integer = 0
   For i As Integer = oldTop To ListView1.Items.Count - 1
      ListView1.EnsureVisible(i)
      If oldTop < ListView1.TopItem.Index Then
         itemBottom = i
         Exit For
      End If
   Next
   Dim viewRow As Integer = itemBottom - ListView1.TopItem.Index + 1
   Debug.Print(viewRow.ToString)

簡易的には
ListView のクライアント領域の高さ - ヘッダーの高さ(24) \ GetItemRect で
クライアント領域 に表示されている行数を求める事ができます。
(ヘッダーの高さ = フォントサイズ 9 〜16 なら 24 ですが...。)

別途、オーナードローの機能を利用すれば、ヘッダー等の高さが取得できるので
計算だけで的確な表示行数等必要事項が取得できます。
(これなら、フォントサイズを色々変更されても対応できる)

  ついでに、マウスのテストをしたコードを掲載しておきます。

   3/14 12:43 修正  

  SendMouse.Helper の使用例と DLL は、下記参照
 SendInput関数のDLL化によるマウス操作の簡単自動化(VB.NET)

  http://www.hanatyan.sakura.ne.jp/patio/read.cgi?no=315


Private Sub Form1_KeyDown(sender As Object, e As  _
                  System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
   '計算値の誤差? (取得位置と設定位置でずれるので修正)
   Dim mpo As Point = New Point(Cursor.Position.X + 1, Cursor.Position.Y + 1)
   ListView1.HideSelection = False
   Dim Si As New SendMouse.Helper
   Dim Cpos As Point = ListView1.ClientRectangle.Location
   Dim Spos As Point = ListView1.PointToScreen(Cpos)
   If e.KeyCode = Keys.Down Then
      Spos.X = Spos.X + ListView1.Width - 12
      Spos.Y = Spos.Y + ListView1.ClientSize.Height - 10
      Si.SendMouse(Spos, mpo, 0, 1)
   End If
   If e.KeyCode = Keys.Up Then
      Spos.X = Spos.X + ListView1.Width - 12
      Spos.Y = Spos.Y + ListView1.Top - 6
      Si.SendMouse(Spos, mpo, 0, 1)
   End If
End Sub

場合によっては、ダミーのテキストボックス等を使ってそちらへフォーカスを移す事で。

[ツリー表示へ]
タイトルRe^7: ListViewのスクロール
記事No10742
投稿日: 2012/03/13(Tue) 11:46
投稿者じょば
管理人様、引き続きレスありがとうございます。
具体的なコード例をお示し頂き、非常に感謝しております。

最下行を取得する例の2種類を、それぞれ試させて頂きました。

今回のAPでは、フォームのサイズに連動してListViewの大きさが
変わりますので、フォームのResizeイベントで最下行を取得する
必要があります。

1例目よりも2例目の方が、ListViewのちらつきが押さえられる
ようですので、2例目のコードを参考にさせて頂いて、実装して
みようと思います。

マウスのテストコードも、ありがとうございます。
今現在の私の知識では理解できない部分があるのですが、少し
勉強して、今回のAPに実装できるか確認してみます。

とりあえず、現時点では2例目の最下行を取得する手法で、
下矢印キーでのスクロールを実装してみようと思います。

出来ないと思っていたのですが、コロンブスの卵です。
このような方法があるとは驚きました。
ノウハウを惜しみなく教えて頂き、非常に感謝しています。

本当にありがとうございました m(_ _)m

[ツリー表示へ]
タイトルRe^7: ListViewのスクロール【修正】
記事No10744
投稿日: 2012/03/14(Wed) 10:32
投稿者じょば
【最終報告】

管理人様に掲載して頂いたコードを参考にさせて頂き、昨日、
無事に、APに矢印キーによるスクロールが実装できました。

ありがとうございました。

ListViewのTopItemから順に表示していき、TopItemが変わった
時点で、表示されている行数が分かるという手法を思いつかれる
ところは、さすがです。

私も精進いたしたいと思います。

[ツリー表示へ]
タイトルRe: ListViewのスクロール
記事No10740
投稿日: 2012/03/13(Tue) 00:42
投稿者shu
Itemのフォーカス移動がOKなら

以下のような感じでどうでしょう?

   Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
        Select Case e.KeyCode
            Case Keys.Up
                Dim itm = ListView1.FocusedItem
                If itm.Index > 0 Then
                    Dim newItem = ListView1.Items(itm.Index - 1)
                    newItem.Focused = True
                    ListView1.EnsureVisible(newItem.Index)
                End If
                e.Handled = True
            Case Keys.Down
                Dim itm = ListView1.FocusedItem
                If itm.Index < ListView1.Items.Count - 1 Then
                    Dim newItem = ListView1.Items(itm.Index + 1)
                    newItem.Focused = True
                    ListView1.EnsureVisible(newItem.Index)
                End If
                e.Handled = True
        End Select
    End Sub

[ツリー表示へ]
タイトルRe^2: ListViewのスクロール
記事No10741
投稿日: 2012/03/13(Tue) 11:32
投稿者じょば
shu様、レスして頂きありがとうございます m(_ _)m

今コードを試させて頂きました。
コード中の、Dim itm と Dim newItem は、As ListViewItemと、
型宣言を追加してコンパイルしました。

実行結果ですが、矢印キーでフォーカスを移動する事により、
スクロールしてくれる事が確認できました。

ただ、この方法だとListViewに10行表示されているとして、下に
スクロールするには、下矢印キーを10回押下して、フォーカスが
10行目に達した後で、11回目の押下からスクロールが開始されます。

実用するには、管理人様から頂いたコードで、表示している最下行を
取得しなければならないようです。

ただ、フォーカスの移動によるスクロールができる事が分かったのは
非常に有用な情報です。

ありがとうございます m(_ _)m

[ツリー表示へ]