MFC   VC++   Visual Studio   Visual Studio   プログラミング

数字を数値としてソート

 リストコントロールなどでアイテムをソートする場合、文字列としてソートしたり数字としてソートしたりすると思います。
 その時、文字列としてソートする場合、比較関数内ではCStringのCompareやCompareNoCaseなどを使い、数字としてソートする場合、一旦intなどへ変換してから数値比較すると思います。
 しかし、文字列の中に数字が入っていた場合、数字は文字として認識されソートされるため、数値順に並ばなかったりします。(例:Sample1.txt Sample10.txt Sample2.txt Sample3.txt)
 エクスプローラーなどでは、きちんと数字部分は数値として認識されソートされるため、それと同じようにソートされるように比較関数を考えてみました。

 まず最初に、比較する二つの文字列は、関数によってLPARAMだったりCStringだったりするため、ここでは使い回しが出来るように、普通にCStringとして宣言しておきます。
 その都度、リストから文字列を取得したり、ポインタから文字列を取得したり、CStringにする変換処理を入れてください。

 ソートフラグも状況によって取得の仕方が違うため、最後の一行の「SortFlag」は独自に書き換えてください。
 ソート後の昇順降順の入れ替えなども独自に行ってください。

 コードは以下のようになります。
 やり方としては、文字列を先頭から比較していき、数字が出たら数値比較をし、文字の違いが出たらその時点で比較完了という流れです。
 一応、全角数字も数値として扱います。
 全角文字を対象にしない場合、strNumWを除外してください。
 Unicode仕様です。マルチバイトの場合、少し改良が必要です。

   CString str1, str2;    // 比較するための二つの変数(状況によって変換)
    int iSort = 0;        // ソート結果を入れる変数

    int iLen1 = str1.GetLength();
    int iLen2 = str2.GetLength();
    int iLen = min(iLen1, iLen2);    // 文字列長の短い方に合わせるため

    CString strRes1, strRes2;        // 数字部分を受け取るための変数
    const CString strNumH = _T("0123456789");        // 半角数字を用意
    const CString strNumW = _T("0123456789");        // 全角数字を用意
    int iFlag;        // 同じ位置に数字がある場合はその開始位置を、違う場合or無い場合は-1を入れるための変数
    iFlag = (str1.FindOneOf(strNumH + strNumW) == str2.FindOneOf(strNumH + strNumW))    // 数字が最初に出てくる位置が同じかどうか
         ? str1.FindOneOf(strNumH + strNumW) : -1;

    // 数字の開始位置が同じで、それまでの文字列も同じだった場合
    if (iFlag != -1 && str1.Left(iFlag) == str2.Left(iFlag))    // 数字部分で比較
    {
        do
        {
            // 数字分以降を抽出
            str1 = str1.Mid(iFlag);
            str2 = str2.Mid(iFlag);

            // 数字部分のみを抽出
            strRes1 = str1.SpanIncluding(strNumH + strNumW);
            strRes2 = str2.SpanIncluding(strNumH + strNumW);

            if (strRes1 == strRes2)        // 抽出した数字が同じだった場合、もう一度それより後ろについて繰り返す
            {
                str1 = str1.Mid(strRes1.GetLength()); ← 2015/01/01 修正
                str2 = str2.Mid(strRes1.GetLength()); ← 2015/01/01 修正
                iFlag = (str1.FindOneOf(strNumH + strNumW) == str2.FindOneOf(strNumH + strNumW)) ? str1.FindOneOf(strNumH + strNumW) : -1;
            }
            else        // 数字に違いが出た場合、数値として比較してループ終了
            {
                iSort = (_tstoi(strRes1) < _tstoi(strRes2)) ? -1 : 1;
                break;
            }
        } while (iFlag != -1);
    }
    else    // 数字が出てくる前に文字列が違う場合、普通にCStringの比較関数を使用
    {
        iSort = lParam1.Compare(lParam2);
    }

    // 比較した部分が同じで、文字列長が違う場合の処理
    if (iSort == 0 && iLen1 != iLen2)
        iSort = (iLen1 < iLen2) ? -1 : 1;

    return (SortFlag ? iSort * -1 : iSort);        // 「SortFlag」は昇順降順の状況を示す値が入る


以上、独自の方法で数字を数値としてソートするようにしたのですが、要領が悪く、アイテムが多くなると処理が遅くなりそうなので、あとはそれぞれ改良してみてください。
ランキングへ     posted by 遠雷 | Comment(0) | MFC

実行ファイルアイコン(Vista/7編)

 今回は前回のXP編に続きVista/7編を書いていきます。
 Vistaと7はほとんど違いがないため一緒にしました。

 基本的には前回とほとんど同じなので、今回は相違点だけを書いていくので、詳しくは前回の記事を参考にして下さい。

 まず、使用する実行ファイル、アイコンは前回と同様で、起動/実行に関する状況もまったく一緒なので省略します。

 XPとの違いが出るのはエクスプローラー上での表示で、Vistaからは256x256がサポートされるようになり、それに関する挙動に違いがでます。

エクスプローラー
 エクスプローラー上でのそれぞれの表示方法は上図のようになり、やはりここでXPとの違いが多く出ます。
 ちょっと図がわりにくいので、詳細を書くと、特大アイコン/大アイコン→256、中アイコン→48、中と小の間→32、小アイコン/一覧/詳細→16、並べて表示→48となっています。

 具体的にXPとの相違点を挙げると、今まで無かった大アイコン以上の表示で256の画像が表示され、デスクトップ上のアイコンが32から48になり、実行ファイル選択時に、今まではファイルの説明しか表示されなかったステータスバーにも256の画像が表示されます。
 ちょっとわかりにくいのですが、エクスプローラーの表示設定の「中アイコン」と「小アイコン」の間にだけ32が表示されます。

 特に面白いのがドラッグ中の画像とゴミ箱へ移動させるときの確認ダイアログ上の画像で、どんな表示方法のときでも大きさは違いますが256の画像が表示されます。
 しかし例外もあり、デスクトップ上では何故かドラッグ中の画像が48です。
デスクトップ drag ステータスバー

 冒頭でVistaと7はほとんど違いがないと書きましたが、相違点を挙げると、7ではエクスプローラーの表示方法に「コンテンツ」が追加されていて、その場合は32が表示されます。
 さらに、ステータスバーの画像が256から48になっています。

 ここで一応断っておくと、これらの実験はAeroを切った状態でしか行っていないため、状況が違う事があるかもしれません。
ランキングへ     posted by 遠雷 | Comment(0) | その他

実行ファイルアイコン(XP編)

アイコン一覧 今回は、実行ファイルのアイコンの表示のされ方について、アイコンが表示されるとき、どの場面でどのサイズが使われていいるかを調べてみました。

 まず、実験に使ったアイコンは、左図のように32ビットの画像のみを使い、256/48/32/24/16の5種類のサイズを含め、どのサイズが表示されているかすぐにわかるようにサイズを入れたものを使っています。

 実行ファイルは、ダイアログベースプロジェクトで、起動時に通知領域へアイコンを登録し、終了時にそのアイコンを削除するだけの簡単なプログラムで、あとはすべてデフォルトのままです。

 通知領域へ登録するアイコンは、デフォルトで読み込まれる「m_hIcon」を使用しました。

起動時 最初は、普通にソフトを起動したとき左図の上側のようになり、タイトルバー、タスクバー、通知領域のアイコンはすべて"32"になりました。
 次に、OnInitDialog関数内の「SetIcon(m_hIcon, FALSE);」をコメントアウトした場合左図の下側のようになり、通知領域以外"16"となります。
 この挙動はメインウインドウがダイアログでないときと同じになります。

aboutdlg ちなみに、デフォルトのバージョン情報ダイアログ上のアイコンは、左図のように"32"になります。
 ここで、このアイコン設定を「Real Size Image(SS_REALSIZEIMAGE)」にすると表示が"256"になり、XPでは表示されず、Vista/7ではそのまま表示されますが、文字の後ろにアイコンが表示されるなど変になります。

エクスプローラー
 次にエクスプローラー上での表示のされ方で、表示方法の違いによるサイズは上図のようになります。

 その他に、デスクトップ上へショートカットを作った場合、メニューから「送る」で呼び出す場合は下図のようになります。
desktop 送る

 以上のように、ほとんど予想通りの表示のされ方ですが、状況によって変わってくることもあるので、アイコン作成時の参考にでもしてみて下さい。

 ちなみに、結局24が表示される事はありませんでした。
 何か設定を変えるとか、特定の状況では表示されるんですかね?

 今回使用したソフトを使ってみたい方は、icon.zipからダウンロードして下さい。

 次回、Vista/7編へ続く。
ランキングへ     posted by 遠雷 | Comment(0) | その他