VB.netでListViewを仮想モードで開いてサムネイル(小さい画像の一覧)を表示しています。
vb
1Public Class Form1 2 Public imageDir As String = "C:\Users\user\Pictures" ' 画像ディレクトリ 3 Public jpgFiles As String() = System.IO.Directory.GetFiles(imageDir, "*.jpg", IO.SearchOption.TopDirectoryOnly) 4 Public thumbnail(jpgFiles.Length) As Image 5 Public width1 As Integer = 100 6 Public height1 As Integer = 80 7 Public Imagelist1 As New ImageList 8 Public index As Integer = 0 9 10 ' 幅w、高さhのImageオブジェクトを作成 11 Function createThumbnail(ByVal image As Image, ByVal w As Integer, ByVal h As Integer) As Image 12 Dim canvas As New Bitmap(w, h) 13 14 Dim g As Graphics = Graphics.FromImage(canvas) 15 g.FillRectangle(New SolidBrush(Color.White), 0, 0, w, h) 16 17 Dim fw As Double = CDbl(w) / CDbl(image.Width) 18 Dim fh As Double = CDbl(h) / CDbl(image.Height) 19 Dim scale As Double = Math.Min(fw, fh) 20 Dim w2 As Integer = CInt(image.Width * scale) 21 Dim h2 As Integer = CInt(image.Height * scale) 22 23 g.DrawImage(image, (w - w2) \ 2, (h - h2) \ 2, w2, h2) 24 g.Dispose() 25 26 Return canvas 27 End Function 28 29 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 30 ListView1.Enabled = True 31 ListView1.Visible = True 32 ListView1.VirtualMode = True 33 ListView1.OwnerDraw = True 34 35 Imagelist1.ImageSize = New Size(width1, height1) 36 ListView1.LargeImageList = Imagelist1 37 ListView1.VirtualListSize = jpgFiles.Length 38 39 For i As Integer = 0 To jpgFiles.Count - 1 40 thumbnail(i) = Nothing 41 Next 42 End Sub 43 44 Private Sub ListView1_RetrieveVirtualItem(sender As Object, e As RetrieveVirtualItemEventArgs) Handles ListView1.RetrieveVirtualItem 45 e.Item = New ListViewItem(jpgFiles(e.ItemIndex), e.ItemIndex) 46 End Sub 47 48 Private Sub ListView1_DrawItem(sender As Object, e As DrawListViewItemEventArgs) Handles ListView1.DrawItem 49 e.DrawDefault = False 50 e.DrawBackground() 51 52 If thumbnail(e.ItemIndex) Is Nothing Then 53 Dim original As Image 54 Try 55 original = Bitmap.FromFile(jpgFiles(e.ItemIndex)) 56 Catch 57 original = My.Resources.Resource1._error 58 End Try 59 thumbnail(e.ItemIndex) = createThumbnail(original, Width, Height) 60 End If 61 62 Dim imagerect As New Rectangle(New Point(e.Bounds.X + ((e.Bounds.Width - width1) / 2), e.Bounds.Y), New Size(width1, height1)) 63 e.Graphics.DrawImage(thumbnail(e.ItemIndex), imagerect) 64 'e.Item.ForeColor = Color.AliceBlue ' ←コメント状態を解除するとListView1が高速で点滅状態になる 65 'ListView1.Items(index).BackColor = Color.Aqua ' ←コメント状態を解除するとListView1が高速で点滅状態になる 66 67 e.DrawFocusRectangle() 68 ListView1.Items(index).Focused = True 69 ListView1.Items(index).Selected = True ' ←選択状態の時の青い色にならない 70 End Sub 71 72 Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 73 index = index - 1 74 If index < 0 Then index = 0 75 76 ListView1.Items(index).Focused = True 77 ListView1.Items(index).Selected = True ' ←選択状態の時の青い色にならない 78 ListView1.Items(index).BackColor = Color.Aqua ' ←色が変わらない 79 End Sub 80 81 Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click 82 index = index + 1 83 If index > ListView1.Items.Count - 1 Then index = ListView1.Items.Count - 1 84 85 ListView1.Items(index).Focused = True 86 ListView1.Items(index).Selected = True ' ←選択状態の時の青い色にならない 87 ListView1.Items(index).BackColor = Color.Aqua ' ←色が変わらない 88 End Sub 89 90 Private Sub ListView1_ItemActivate(sender As Object, e As EventArgs) Handles ListView1.ItemActivate 91 ListView1.Items(index).BackColor = Color.Aqua ' ←色が変わらない 92 End Sub 93 94 Private Sub ListView1_VirtualItemsSelectionRangeChanged(sender As Object, e As ListViewVirtualItemsSelectionRangeChangedEventArgs) Handles ListView1.VirtualItemsSelectionRangeChanged 95 ListView1.Items(e.EndIndex).BackColor = Color.Aqua ' ←色が変わらない 96 End Sub 97End Class 98
フォームにはListViewの他にButton2とButton3が配置してあります。Button2で前の項目を、Button3で次の項目を選択状態にして項目の背景色を変えるコードを書いたつもりです。しかしButton2やButton3を押しても選択状態にならず背景色も変わりません。僕の勝手な推測ですが、
ListView1.OwnerDraw = True
を設定している事により、描画の必要性があるときに
** Private Sub ListView1_DrawItem(sender As Object, e As DrawListViewItemEventArgs) Handles ListView1.DrawItem**
が呼び出されて描画処理を行っているようなのですが、どうもいろんなタイミングでListView1_DrawItemが呼び出されているのではないかと思います。ListViewをスクロールした時や最初にサムネイル一覧を作成する時は呼び出される必要があると思いますが、その他のたいして呼び出す必要がなさそうな時、例えば
**ListView1.Items(index).Selected = True **
を実行した時や
ListView1.Items(index).BackColor = Color.Aqua
を実行した時なども呼び出されているっぽいです。
そしてListView1_DrawItemでの描画処理で上書きしてしまって何も変化がないように見えているのではないかと思います。
ListView1_DrawItemが呼び出されたときに、それがスクロール処理や一番最初のサムネイル作成以外で呼び出された事が分かれば処理を抜けるようにすれば上書きを防ぐことが出来るのではないかと思いますが、どういうイベントによって呼び出されたのかを知る方法が分かりません。
ListViewの選択された項目を選択状態の時の薄い青色の状態か、項目の背景色を目立つ色に変えたいのですが、どのようにすればいいでしょうか。
追記 1月10日20時19分
YAmaGNZ様が教えてくれたコードを
Dim imagerect As New Rectangle(New Point(e.Bounds.X + ((e.Bounds.Width - width1) / 2), e.Bounds.Y), New Size(width1, height1))
の直前に挿入したのですが、全部の項目が赤色になってしまいました。
また、Button2やButton3を押しても色が変わりません。(なんとなく該当の項目がちらついているようには見えます)
項目をマウスでクリックしても色が変わりません。予想では選択した項目だけ赤色でほかは無色になると思ってたのですが、そうはなっていないのでどこかがおかしいと思うのですがどこがおかしいのか分かりません。
プロパティの変更は
ListView1.MultiSelect = False
ぐらいしか変更してないと思います。コードの変更箇所だけ下に載せてみます
VB
1 Private Sub ListView1_DrawItem(sender As Object, e As DrawListViewItemEventArgs) Handles ListView1.DrawItem 2 e.DrawDefault = False 3 e.DrawBackground() 4 5 If thumbnail(e.ItemIndex) Is Nothing Then 6 Dim original As Image 7 Try 8 original = Bitmap.FromFile(jpgFiles(e.ItemIndex)) 9 Catch 10 original = My.Resources.Resource1._error 11 End Try 12 thumbnail(e.ItemIndex) = createThumbnail(original, Width, Height) 13 End If 14 15 'ここから追加------------------------------------------------------- 16 If (e.State And ListViewItemStates.Selected) <> 0 Then 17 '選択されているので選択色(例で赤とする)で塗りつぶす 18 e.Graphics.FillRectangle(Brushes.Red, e.Bounds) 19 Else 20 '選択されていないので通常色で塗りつぶす 21 Using b = New SolidBrush(e.Item.BackColor) 22 e.Graphics.FillRectangle(b, e.Bounds) 23 End Using 24 End If 25 'ここまで------------------------------------------------------------ 26 27 Dim imagerect As New Rectangle(New Point(e.Bounds.X + ((e.Bounds.Width - width1) / 2), e.Bounds.Y), New Size(width1, height1)) 28 e.Graphics.DrawImage(thumbnail(e.ItemIndex), imagerect) 29 'e.Item.ForeColor = Color.AliceBlue ' ←コメント状態を解除するとListView1が高速で点滅状態になる 30 'ListView1.Items(index).BackColor = Color.Aqua ' ←コメント状態を解除するとListView1が高速で点滅状態になる 31 32 e.DrawFocusRectangle() 33 'ListView1.Items(index).Focused = True '←コメントにしました 34 'ListView1.Items(index).Selected = True '←コメントにしました ' ←選択状態の時の青い色にならない 35 End Sub
再質問で申し訳ないのですがよろしくお願いいたします。
追記2 1月10日21時43分
Debug.WriteLine(e.State)
でe.State
の状態を調べた所、全部の項目が選択状態になっていました。なので全部赤色になってたわけです。なぜselected
になっているのかは分かりません。selected
の代わりにfocus
で試してみた所focus
は一つの項目だけ設定されてたので一つの項目だけが赤色になるようにできました。
If (e.State And ListViewItemStates.Selected) <> 0 Then
を
If (e.State And ListViewItemStates.Focused) <> 0 Then
あるいは
If e.ItemIndex = index Then
にすることでうまい具合に動作するようになりました。
追記3 1月10日22時06分
YAmaGNZ様がe.Item.Selectedの事を教えてくださり試してみた所うまく動作しました。
If (e.Item.Selected And ListViewItemStates.Selected) <> 0 Then
ありがとうございました。
追記4 1月10日22時29分
YAmaGNZ様のご指摘があり正しいのは
If e.Item.Selected Then
だとの事です。それと「選択されている」と判断するのであればFocusedやItemIndexではなく、Selectedを使用すべきとの事です。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/01/10 11:29
2022/01/10 11:42
2022/01/10 11:47
2022/01/10 12:57
2022/01/10 13:05
2022/01/10 13:11
2022/01/10 13:15
2022/01/10 13:20
2022/01/10 13:28