リストビューのソートについて


ぱお  2005-03-17 02:22:20  No: 88886

環境:WinXP,VB6

ファイルを一覧表示するリストビューで更新日時ソートが出来るように
なりましたが、リストビュー内にはチェックボックスを設けておりチェック
したファイルを隣のリストビューにコピーできます。

が、しかし!!!

降順ソートするとチェックものとは違うファイルがコピーされてしまいます。
例)一番下のファイルをチェックしてコピーすると一番上のファイルがコピー

チェックボックスが付いてきていないと言うことですよね。
何故でしょうか????


LESIA  2005-03-17 02:32:12  No: 88887

チェックしたファイルの判断はどうやってますか?
その判断方法が間違っていると思うんですが・・・

「何故でしょうか????」といわれても、ソースをみてみないと
これ以上は、なんとも言えません。


ぱお  2005-03-17 03:18:09  No: 88888

レスありがとうございます。
以下のソースで検索リストから選択リストにファイル名をコピーしています。

    Dim i As Integer
    Dim j As Integer
    Dim checkflag As Integer
    Dim itmX As ListItem

    For i = 1 To 検索リスト.ListItems.Count
     
        If 検索リスト.ListItems(i).Checked = True Then
        
            If intAddCount = 100 Then
                MsgBox ("選択可能なファイル数は100件までです。")
                Exit Sub
            End If
        
            '/// 重複してコピーしないように
            checkflag = 0
            For j = 1 To 選択リスト.ListItems.Count
                If 選択リスト.ListItems(j) = 検索リスト.ListItems(i) Then
                    checkflag = 1
                    Exit For
                End If
            Next j

            '/// コピーを実行
            If checkflag = 0 Then
                Set itmX = 選択リスト.ListItems.Add(, , 検索リスト.ListItems(i))
                itmX.SubItems(1) = FileDateTime(strOpenFilePath & 検索リスト.ListItems(i))
                intAddCount = intAddCount + 1
                
                '/// 結合ファイル名をプリセット
                If intAddCount = 1 Then
                    Text1.Text = 検索リスト.ListItems(検索リスト.ListItems.Count)
                End If
                
                '/// 選択ファイル数を表示
                If intAddCount > 0 Then
                    AddCounter.Caption = intAddCount & "件"
                End If
            End If
        End If
    Next i


ぱお  2005-03-17 03:27:21  No: 88889

降順にした時はループを逆に回さなくてはいけないのでしょうか????


ぱお  2005-03-17 05:12:32  No: 88890

すみません。何だか良くわからないことを書いてしまって。
自分でも頭がパニックで現象が良く分からなかったので。

検証した結果、日付でソートするとファイル名が不定になる事が分かりました。
ファイル名とチェックボックスの位置が画面上と内部では違うという事かな。

検索していたら、ファイル名でソートしてから日付でソートと2回
ソートすれば大丈夫とありましたが、実行しても駄目でした。
ファイル名でソートは文字列をテキストとして比較しています。
こんな感じです。

    Dim strText1    As String  'ファイル名1
    Dim strText2    As String  'ファイル名2
    
    strText1 = GetTextFromlParam(hwnd, lParam1, GetProp(hwnd, PROP_SORT_KEY))
    strText2 = GetTextFromlParam(hwnd, lParam2, GetProp(hwnd, PROP_SORT_KEY))
    
    If GetProp(hwnd, PROP_SORT_ORDER) = 0 Then
        
        If strText1 < strText2 Then
            CompareFuncByText = 0
        ElseIf strText1 = strText2 Then
            CompareFuncByText = 1
        Else
            CompareFuncByText = 2
        End If
    Else
        If strText1 < strText2 Then
            CompareFuncByText = 2
        ElseIf strText1 = strText2 Then
            CompareFuncByText = 1
        Else
            CompareFuncByText = 0
        End If
    End If

Windowsのエクスプローラとは違う結果になるので比較の方法が違うのかな。
何故ファイル名がめちゃくちゃになるのでしょうか???


パオ  URL  2005-03-17 08:15:25  No: 88891

>     strText1 = GetTextFromlParam(hwnd, lParam1, GetProp(hwnd, PROP_SORT_KEY))
もしかして、APIでソートしてます?

コントロールの標準機能だけでソートしているのなら、
ListItem経由で取れますけど、APIでソートしているなら、
項目の読み取りもAPIで行わないと。


ぱお  2005-03-17 18:38:10  No: 88892

>>strText1 = GetTextFromlParam(hwnd, lParam1, GetProp(hwnd, PROP_SORT_KEY))
>もしかして、APIでソートしてます?

strText1,strText2にはリストビュー上に表示されている日付が入ってきます。
なのでソート自体はAPIでは行っていないと思うのですが。
すみません自分で作った訳ではないのです。

ソースをいただいたところです。
http://www.mitene.or.jp/~sugisita/api_comct.html
「リストアイテムを数値型、日付型でソートする」をいただきました。

ほとんどカスタマイズは行っていません。
昇順降順にする機能が動作しなかったので呼び出しの時に指定して
昇順降順を可能にしました。

以下は呼び出し時-------

Private Sub 検索リスト_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)

    Static TextSortOrder As String
    Static DateSortOrder As String

    Select Case ColumnHeader.Index
    Case 1  ' テキストでソート
        Select Case TextSortOrder
        Case "ASC"
            TextSortOrder = "DESC"
            Call ListView_SortItems(検索リスト, ColumnHeader.Index, lvwSortText, lvwSortDescending)
        Case Else
            TextSortOrder = "ASC"
            Call ListView_SortItems(検索リスト, ColumnHeader.Index, lvwSortText, lvwSortAscending)
        End Select
        DateSortOrder = ""
    Case 2  ' 日付でソート
        Select Case DateSortOrder
        Case "ASC"
            DateSortOrder = "DESC"
            Call ListView_SortItems(検索リスト, ColumnHeader.Index, lvwSortDate, lvwSortDescending)
        Case Else
            DateSortOrder = "ASC"
            Call ListView_SortItems(検索リスト, ColumnHeader.Index, lvwSortDate, lvwSortAscending)
        End Select
        TextSortOrder = ""
    End Select
        
    検索リスト.Refresh

End Sub

どうか宜しくお願いします。


パオ  URL  2005-03-17 19:49:57  No: 88893

> なのでソート自体はAPIでは行っていないと思うのですが。
うそつきー。
サンプル見たら、思いっきり LVM_SORTITEMS が使われてるじゃないですか。

http://www.mitene.or.jp/~sugisita/api_comct.html
> 「リストアイテムを数値型、日付型でソートする」をいただきました。
ここを見ると、
  「大小比較を自前のコールバック関数に置き換えることで実現」
としっかり書いてありますねぇ。APIへコールバックしてますよって。

ベースはこれですかね。
http://support.microsoft.com/kb/170884/

チェックボックスの確認を、ListItem経由で行っているようですけど、
ここを、ListView_GetCheckStateマクロ……というか、
LVM_GETITEMSTATEメッセージ操作に置き換えて試してみてはどうかな。

でも、うまくいくかどうかは、試して無いので保証不可能なり。


ぱお  2005-03-17 21:20:17  No: 88894

すみません。
VB初めて・・・というかプログラムを本格的に始めて2週間。。
良く分からないのですが何とかしなくては。

下記のようなものを見つけました。
こういうことですよね。

Option Explicit
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long

Private Const LVM_FIRST = &H1000
Private Const LVM_GETITEMSTATE = (LVM_FIRST + 44)
Private Const LVIS_STATEIMAGEMASK = &HF000

'リストビューチェックボックスのチェック状態を取得する関数
Private Function LvwGetCheckState(lvwCTRL As ListView, _
lngIndex As Long) As Boolean
    'lvwCTRL : リストビュー , lngIndex : アイテムのIndex
    '戻り値 : BOOL値(True:チェックON, False:チェックOFF)
    Dim lngState As Long 
    lngState = SendMessage(lvwCTRL.hwnd, LVM_GETITEMSTATE, _
    lngIndex, ByVal LVIS_STATEIMAGEMASK)
    LvwGetCheckState = (lngState And &H2000)
End Function

んで以下を修正。
If 検索リスト.ListItems(i).Checked = True Then

→If LvwGetCheckState(検索リスト, 検索リスト.ListItems(i).Index) = True Then

でも、上手くいかない。。


パオ  URL  2005-03-17 21:55:40  No: 88895

→If LvwGetCheckState(検索リスト, 検索リスト.ListItems(i).Index) = True Then

項目の読み取りもAPIで試してねって言ってるのにのにのに。
ListItemは使わずに試してくださいませ。

APIでソートしちゃったので、ListItemが保持しているIndexと、
実際の位置がずれているんじゃ無いかなーと想像してます。
外してたらごめんなさい。


ぱお  2005-03-17 22:59:53  No: 88896

>APIでソートしちゃったので、ListItemが保持しているIndexと、
>実際の位置がずれているんじゃ無いかなーと想像してます。
>外してたらごめんなさい

なるほどです。
Listitemを使用しないでIndexを取得しなくてはならないと言う事ですよね。

と言う事は以下で良いのでしょうか?
→If LvwGetCheckState(検索リスト, CLng(i)) = True Then

んー。上手くいかない。
難しいです。。


pao  2005-03-18 01:42:35  No: 88897

> Listitemを使用しないでIndexを取得しなくてはならないと言う事ですよね。

ListItemsコレクションのプロパティは、Indexだけじゃないでしょう。
検索リスト.ListItems(i).Text も使ってますよね。
それと、APIの場合、項目のIndexは、0から(VBは1から)始まるので注意。

http://support.microsoft.com/kb/170884/
をよく読んでいれば、APIでソートした場合、ListItemsコレクションが
ソートされないことや、その対処法として、ListView_GetListItem()関数
で項目のテキスト取得ができることが解かったはずだが。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加