ScrollBoxのMouseWheelイベントをFormMouseWheelで捕まえる[VCL]

ScrollBoxのMouseWheelが捕まえられないときは、FormのMouseWheelイベントで捕まえる方法がある。

以上は、ScrollBoxがダイレクトにForm1にのっかっている時の例。
Form上のPanelの上にScrollBoxを配置しているときなどはもう一ひねり必要になる。

Unicodeのコード番号からStringを取得する

VclとFireMonkey共通。

“80CC”等、コードポイント(番号)の文字列をStringに変換するには、基本的には以下でOK。

ただし実際にはサロゲートペア用に割り当てられた番号(D800~DFFF)に配慮する必要がある。Androidで、サロゲートペア用の番号を指定するとアプリが落ちる場合もある(Android4.4.2で確認)
そこに配慮した関数。

サロゲートペア文字も取得するには、もう一手間が必要。
サロゲートペア用の番号は”20B9F”など5桁になる。
少し汎用にstd::wstringを使った関数。(注:C++Builderはwchar_tが2byte)

(注:C++Builder Berlin Update2では、Androidではwstring版の”wcstol”がバグっているようなので、さらに一手間かけてstring版の”strtol”を使う必要がある)

念のため、Stringに変換するには以下のように呼び出す。

(なおC++Builder BerlinではStringはUnicodeStringのtypedef)

C++Builder Berlin Update2 / Windows7(Sp1)で確認。

文字列に任意の角度で斜体をかける[VCL]

C++Builderで、文字に任意の角度で斜体をかけて描画する方法。
基本的に文字も点の集まりなので、その点の位置をずらして変形する。
具体的には、
 ①文字をパスでImage等のCanvasに描く
 ②パスから点の集合を取得する
 ③点の位置をずらした新たな点集合を作成
 ④変形用の点集合でCanvasに描く
という手順になる。

Vclにはパスを扱うクラスはないので、WindowsAPIを直接使うことになる。
以下、サンプル。FormにTrackBarとImageを置いた例。
(boost::shared_arrayを使っているが、生ポインタをnewしてももちろん動く)

こんな感じで変形する。

点の情報をずらすだけなので、さまざまな形に変形可能。
たとえば文字列に楕円が食い込んだように変形させる関数のサンプル。

こんな感じで変形する。

C++Builder Berlin Update2 / Windows7(Sp1)で確認。

TListViewのItemをソートする3方法[Vcl]

TListViewのソート方法については、ヘルプのコード例を見てもいまいち分からなかったので整理してみる。(Style:vsReportの場合)。
まだ正確に把握しきってない可能性はあるが…。

まず、ListViewでは以下の3方法のSortが可能。
 stText…いわゆる文字列ソート。ListItemのCaption順にソートする
 stData…ListItemに格納されたDataを比較する
 stBoth…上記両方でソート(たぶん)

1.stSort

これは単純。TListViewのSotrTypeプロパティにstTextを指定するだけ。コードを書く必要はない。

2.stData

こっちは、事前にListItemのDataプロパティに何かの値をセットしておく必要がある。
たとえばクラスのポインタとか。

実例として、各ItemのDataが、intメンバを持つクラスのポインタを保有している場合。(エラー処理は省略)

Compoare値が0より大きいか小さいか、でソート順が決まる。

3.stBoth

ここがちょっと分かりにくいパターン。
基本的に、まずデータを比較し、同じ場合はTextを比較するという手順を踏む(たぶん)
コード例。

4.実行時にTSortTypeを変えたい場合

アプリケーションのオプション設定等でSortTypeを変更したい場合は、ちょっと面倒。
ここで気になるのがListViewのOnCompareイベントの引数
 int Data
とは何だろうってこと。
ヘルプをざっと見た限りだと、こういう事らしい。
 Data == 0 なら、stTextかstNone
 Data != 0 なら、stDataかstBoth

ということで、仮に実行時にSortTypeを変更し、反映したい場合は、以下のようなコードになるはず。

うーん、このコードだと、そもそも引数のDataを利用する必要がないような…。
もっとスマートな方法がある気がする。

TListViewをGroup名順に並び替える[Vcl]

C++BuilderでTListViewをStyle:vsReportで使用している場合、Group名順に並び替えるには、GoupItemのIndexプロパティを変更するだけでいい。(GroupViewプロパティはTrue)

以下のコードでは、std::mapにGroup名とTListGroup(のポインタ)を格納して、自動的に名前順に並び替えている。

なお、このサンプルでは、名前のないGroupが先頭に来てしまう。名前のないGroupを最後にするには、Indexを明示的に付けなけれぱOK。自動的に最後になる。(正確に言うと自動的にカウントアップされたIndexが割り振られる)

以下、蛇足。

Indexプロパティって何?

ListViewにGroupを動的に追加する場合、GroupIDは自分で設定するけど、Indexは特に指定しない。
Indexプロパティは、GroupがAddされるたびに自動的に連番で振られる(らしい)。
ちなみに以下のようにループを回すと、GroupID順でなくIndex順にアクセスされる。(GroupID順だと思い込んでバグったことがある)

なおIndexを指定する場合、ダブりを気にする必要はない。

つまり

グループ0Index = 0
グループ1Index = 1
グループ2Index = 2

この「グループ2」のIndexを0に変更すると、以下のように全グルーブのIndexが割り振り直される。
グループ0Index = 1
グループ1Index = 2
グループ2Index = 0

なので、Groupの最後を先頭に持ってくるのは以下のコードですむ。

(なお”Group->Count-1″を超えるIndexを指定すると例外が投げられる。)

ここらへん、TListGroupsの継承元のTCollectionクラスあたりの仕様を把握していると直感的に分かるのかもしれないけど、ちょっと苦労した。

Windows7(64bit)/C++Builder Berlin(Update1)で確認