Programming」カテゴリーアーカイブ

Binding

あーやっと WPF の Binding っつーのが解ってきたぞと。

class ob
{
public BitmapImage bi{get;set;}
public string fName{get;set;}
public string nSize{get;set;}
}

とかクラスを作ってデータを詰め込んで listView に Add する。

ob ob1 = new ob();
//…略
listView1.Items.Add(ob1);

そのクラスメンバの名前をデータが入る場所に指定しておけばイイわけだ。
死ぬほど解りにくい…もの凄く限定された使い方しか理解していないし。

ファイルアイコンの取得はどうすればいいのだろう?
System.Drawing は使えないし方法が見つからない、あぁ初心者状態。

それよりスクリーンショットを見れば解るだろうけど、
WPF の ListView は選択なんかが Vista の Explorer と同じ描写になる。

前から不思議に思っていた、Vista の Explorer はチラつかない。
急激にリサイズしようがグルグル回そうが何をしようが全然チラツキしない。
ソレが気になるようになったので色々ファイラを探したがモレなくチラついた。

もしかして WPF もしくは DirectX 直使いで描写しているのかなと。
こうやって試したがやはりそういうことみたい、同じになるもの。

WinFX での描写はやはり WPF でやるべきだ。
結局は GDI 描写になる WindowsForm では何の意味もない。
この美しい描写をアピールすればもっと Vista を理解する人が増えるだろうに。

Visual Studio 2008 の本がボチボチ出てきたけど、どれも WindowsForm のまま…
そりゃ今までのスキルが生かせるけど時代に合わないんだってば!

ウインド表示直後に処理

久々に SDK チップスネタでも書こう。

WM_SHOW を捕まえて処理するとウインド表示に時間が掛かる場合がある。
このイベント処理が終わった後でないと実際の描写が行われないからだ。

だから表示された直後に作成や描写を行えば見た目の起動速度が向上する。
しかしそんな都合のよいメッセージは飛んでこない。

が、実はデルヒャァにはある。

procedure CMShowingChanged(var Message:TMessage);message CM_SHOWINGCHANGED;

をフォームの private に定義してハンドラを書くだけ…
但し表示状態が変わる毎に飛んでくるので一番最初に捕まえた時以外は弾くこと。
Y901 はそのツマラン方法で見た目の起動時間を短縮するセコイことをやっていた。

はて、CM_SHOWINGCHANGED なんて無い VC++ ではどうすんだ?
で考えた、PostMessage を使ってまえ!

SendMessage は処理が終わるまで制御を戻してくれない。
PostMessage はキューにメッセージを放り込んで即制御を戻す。
だから WM_SHOW 処理の一番最後で適当なメッセージを投げればよい。

#define WM_SHOWEND (WM_APP + 3)

とか定義しておいて WM_SHOW 処理の一番最後に

PostMessage(hWnd, WM_SHOWEND, 0L, 0L);

とすればキューに自分宛の WM_SHOWEND がセットされる。
キューって何?な人は Windows をもっと勉強してください。
後は WndProc で普通に

case WM_SHOWEND:

を処理、これで見た目の起動時間が早いアプリのできあがり!
詳しくは Cinema のソースコードで、オープンソースは楽だ。

フォーム表示直後に実行されるメソッド OnShowed を作る – Sakura scope

他にも同じコトを考える人がいるのね。
ビルダァ(名古屋弁化できん…)には CM_SHOWINGCHANGED は無いのかな?
でも WM_USER を使うのは止めておいたほうがいいみたいよ

WM_APPの薦め。

それより Windows SuperFetch がある Vista ではあまり意味が無い…

Intellisense の更新

全然完璧じゃなかった…
コレじゃ Add で同一キーが混在する場合があるやないの。

void CPairList::Add(LPCWSTR szKey, LPCWSTR szValue)
{
    vec_t::iterator it = m_vec.begin();
    vec_t::iterator itend = m_vec.end();
    for (; it != itend; it++)
    {
        if ( (*it).first == szKey)
        {
            (*it).second = szValue;
            return;
        }
    }
    m_vec.push_back(Pair(szKey, szValue));
}

でいいかな。
つーか wstring を二回も typedef する必要なんて無いわな。
キリがないので続きは多分今週末に更新する Cinema のソースで。

ところで。

Intellisense の更新は手動でやれないのかなぁ?
一度作ったクラスにメソッドを追加していくと認識されない場合が多い。

知らない人のために一応書くとコード補完機能のことである。
Ctrl+Space や先頭に :: を打つとグローバルな関数や変数を補完してくれたりとか
ドットや -> を打つと全自動でクラスメソッドを一覧表示してくれてありがたい。

コレがメソッド追加で自動反映されるまでの時間がチト長いのよ。
酷いときにはいつまでたっても反映されないということもあるんです。
古い VC++ はよく知らないけどデルヒャァ5は即時反映だったので気になるわ。

普通に手書きすればコンパイルは通るから Intellisense だけの問題だね。
コレでは Visual Studio のエディタを使っている意味はまったく無いんだが…
便利だからと頼りまくってコーディングというのもどうかと思うけど。

なんとかならんかと検索しまくったがみんなやっぱりそんな感じなのね。

どうやらソリューションのディレクトリにある .nbc がその実体らしい。
一端終了後にこのファイルを削除して再起動で作り直しリセットする。
やっぱりこの方法しかないのかな?メンドクセ。

CPairListClass

完璧だ。
Classes.h,Classes.cpp として

#pragma once   

class CPairList 
{ 
private: 
??? typedef std::wstring m_a; 
??? typedef std::wstring m_b; 
??? typedef std::pair<m_a, m_b> Pair; 
??? typedef std::vector<Pair> vec_t; 
??? vec_t m_vec; 
public: 
??? void Add(LPCWSTR szKey, LPCWSTR szValue); 
??? void Remove(LPCWSTR szKey); 
??? std::wstring operator[](std::wstring szKey); 
??? std::wstring GetValue(int i); 
??? std::wstring GetKey(int i); 
??? int Count(); 
};
//??? TODO: "StdAfx.h" #include <vector>    

#include "StdAfx.h"
#include "Classes.h"   

/* 
 *??? CPairListClass 
 */   

void CPairList::Add(LPCWSTR szKey, LPCWSTR szValue) 
{ 
??? m_vec.push_back(Pair(szKey, szValue)); 
}   

void CPairList::Remove(LPCWSTR szKey) 
{ 
??? vec_t::iterator it = m_vec.begin(); 
??? vec_t::iterator itend = m_vec.end(); 
??? for (; it != itend; it++)? 
??  {? 
?????? if ( (*it).first == szKey)? 
?????? {? 
?????????? m_vec.erase(it); 
?????????? break;? 
?????? } 
??? } 
}   

std::wstring CPairList::operator[](std::wstring szKey) 
{ 
??? std::wstring result; 
??? vec_t::iterator it = m_vec.begin(); 
??? vec_t::iterator itend = m_vec.end(); 
??? for (; it != itend; it++)? 
 ?? {? 
?????? if ( (*it).first == szKey)? 
?????? {? 
?????????? result = (*it).second; 
?????????? break; 
??????? } 
??  } 
??? return result; 
}   

int CPairList::Count() 
{ 
??? return m_vec.size(); 
}   

std::wstring CPairList::GetValue(int i) 
{ 
??? return m_vec[i].second; 
}   

std::wstring CPairList::GetKey(int i)  

{ 
??? return m_vec[i].first; 
}

と定義しておいて

CPairList aList; 
aList.Add(L"おまえ", L"あほ");  

wstring ws = aList[L"おまえ"];

な感じで順番は保持されたままの連想配列もどきの完成、STL 恐るべし。
でも現在 ini 保存に std::map を使っているのでココでソートされてしまう…
こっちも変更しなきゃ、あぁ先は長い。

しかしワシもいつのまにかこんなコードが普通に書けるようになった。

思えば二年前に唐突にデルヒャァから C++ に乗り換えして
「やっぱりポインタがワカンネェ!意味は解るけど使い方が全然ワカンネェ!」
だったのにね。

std::pair<_Ty1, _Ty2>

何故気がつかなかったのだ…

std::pair<_Ty1, _Ty2>

のテンプレートに wstring を両方突っ込んで vector コンテナって方法があった。
使うときには first メンバをキーにして取り出せばイイだけだ。
この方法なら設定の並び順は保持可能かつ拡張時の並び順も問題無い!

でもやってみないとどうなるか解らないわな。

class CGesMap
{
private:
    typedef std::wstring m_a;
    typedef std::wstring m_b;
    typedef std::pair<m_a, m_b> Pair;
    typedef std::vector<Pair> vec;
    vec m_vec;
public:
    void SetGesture(LPCWSTR szGesture, LPCWSTR szValue);
    std::wstring GetValue(std::wstring szGesture);
    std::wstring GetValue(int i);
    std::wstring GetKey(int i);
    int Count();
};

こんな感じで明日色々やってみます。
今日も休日出勤で疲れているのでまた明日。