004-番外2  前へ←  ホームへ  →次へ  006-01

No.005 - 01  スプリットウィンドウ(ブロック型)


アプリ形式の分割ウィンドウやります。




・スプリットウィンドウ

よくCADとかである分割ウィンドウの形式ですが、実際のところそんなに難しくないはずです。
アプリケーションごとに実装するならわりと簡単にできますが、毎回そんなの作ってんのメンドくさいので、
以下に汎用化プログラム書きました。
よかったら参考にしてください。

例によって当サイトのライブラリ「ポインタ・リスト」使ってます


・子ウィンドウの配置に関して

子ウィンドウの配置に関してHTMLのテーブル方式を使います
まずメインウィンドウを M行 N列 の ブロックに分割します。
そのあとで子ウィンドウを追加するときにいくつ分のセルを占有させるかを決定します。
 → 


・ブロック・スカラ−値
X座標系とY座標系は同一の処理が多いので同じ関数で済むように「スカラー値クラス」を作ってまとめます。


・境界線の有効フラグ
ドラッグできる境界線は各ブロックの上下左右にあります。
子ウィンドウが乗ってる線を描画しないようにします。
ドラッグ処理時に、ひとつひとつ判定して境界線を描画するのは大変なのでそれぞれに有効・無効のフラグメンバをつけてやります。
境界線はXY座標だけでなく水平・垂直それぞれのフラグが必要になります。
・・・→

・レートとピクセル

多くのアプリケーションで、ウィンドウサイズを大きくしたり小さくしたりしても
スプリットされている部分は動かず境界線部分が見えたり隠れたり、右下のスプリット子ウィンドウが大きくなったり見えなくなったりします。

このようなことを防ぐために境界線位置をウィンドウ比率にあわせて動くようにします。
ただし最大レート値を 100% として演算してしまうと 100 ピクセル以上の画面サイズでうまく比率が保てないので
最大レート値を けっこう大きめにして内部演算します。
今時の画面サイズは 1024*768 ピクセル 以上は当たり前なので下記サンプルソースでは最大レート値は10000になってます。

ちなみに最大レート値という考え方を常に意識するながらコーディングするのは大変なので
外部向け関数のset_rate_x(), set_rate_y()の引数にはMAX100%のdouble型小数を使います。
こうするとユーザは最大レート値を気にすることなく12.34%とか87.65%などを指定することができます。

・ドラッグ硬直
スプリットウィンドウではドラッグするときウィンドウDCをロックしています。
ドッキングツールバーのダブルクリックの回で書いたようにダブルクリック並の速度でウィンドウDCをロック・解除を繰り返すとマシンがフリーズします。
そこでダブルクリックの検知に手間をかけていましたが、
スプリットウィンドウではダブルクリックは不必要なのでもっと簡単な別の方法をとります。

単純にマウス左ボタンを押し上げたときにタイマを設定してそのタイマの間はドラッグできないようにします。
つまりドラッグ後に硬直時間を作ります。


以下ソース解説。

・スプリッタ子ウィンドウ・クラス
  class SPLIT_WIN_CHILD

メインウィンドウ内に配置する子ウィンドウ用のクラス
スプリッタ・クラスのadd_child関数で「スプリット子ウィンドウ群」 に追加されます。

HWND m_hwnd;  // ウィンドウハンドル
int m_b_x, m_b_y, m_b_cx, m_b_cy; // ブロック位置サイズ

・スプリッタ・ブロック・スカラー値クラス
  class SPLIT_BLOCK_SCALAR
X座標系Y座標系の処理を統一するスカラー値クラスです。

メンバ変数はすべてint か int* 型で、intポインタ型3つ、int型6つの合わせて9つです。

int *m_blk_rate は 各ブロックサイズ(レート式)です。MAX100%でなく最大レート値に対する比率になってます。
int *m_blk_pix は 各ブロックサイズ(ピクセル値)です。
int *m_border_thick は各境界線の厚さを保持します。 境界線の厚さを配列で保持することで柔軟に境界線の厚さを変更することが可能です。
int m_divide_count はブロック分割数です。(== 境界線の数) ブロック数はm_divide_count+1になります。

int m_drag_co はドラッグ座標です。ドラッグ中のマウス座標です。
int m_drag_row はドラッグ行です。そのときドラッグしている行の配列番号が入ります。
int m_base_border_thick は標準の境界線の厚さです。 各境界線の厚さ(*m_border_thick )に -1 が入ってるときはこの標準値を使います。こうすることで全体にあてる境界線の厚さの変更を容易にします。
int m_win_size は保持しておいたウィンドウサイズです。
int m_max_rate は最大レート値です。



メンバ関数は、コンストラクタ、デストラクタを含めて12コです。

SPLIT_BLOCK_SCALAR() コンストラクタはメンバ変数の初期化だけです。
~SPLIT_BLOCK_SCALAR() デストラクタはnew演算したメンバをdelete演算します。
void create(int block_num, int win_size); はこのクラスを起動させます。
get_border_thick(int n) はn番目の境界線の太さを取得します。(各境界線の厚さが個別に変更可能なため)
void set_border_thick(int n, int thick) はn番目の境界線の太さを設定します。(各境界線の厚さが個別に変更可能なため)

get_row_by_pos(int pos) は座標から該当する行を取得します。(基本的にマウス座標から取得用)
get_blk_co_front(int row_num) はn番目のブロックの前側の座標を取得します。(X座標なら側の座標、Y座標なら側の座標)
get_blk_co_rear(int row_num) はn番目のブロックの後ろ側の座標を取得します。(X座標なら側の座標、Y座標なら側の座標)
void set_pix(int block_num, int pix) はn番目のブロックのブロックサイズを設定します。(ピクセル式)
void set_rate(int block_num, int rate) はn番目のブロックのブロックサイズを設定します。(レート式)
void renew_win_size(int win_size) はウィンドウサイズを変更した時に呼び出します。ウィンドウサイズを更新し、各ブロックサイズを補正します。
void set_max_rate(int r) は最大レート値を設定します。

・スプリッタ・クラス

メンバ変数は20個です。

SPLIT_BLOCK_SCALAR m_blk_x, m_blk_y はスプリッタブロック・スカラー値・クラスです。X座標系、Y座標系それぞれを用意します。
HDC m_frame_hdc はドラッグ用ウィンドウDCです。(ドラッグ時ウィンドウDCをロックして保持するため。)
HRGN m_apply_rgn, m_work_rgn, m_work_rgn2, m_last_rgn はドラッグ描画用リージョンです。

HWND m_main_hwnd はメインウィンドウのハンドルです。
PLIST<SPLIT_WIN_CHILD> m_win_children はスプリット配置される子ウィンドウ群です。
char **m_border_valid_horz, **m_border_valid_vert 前述の各境界線が有効フラグです。水平、垂直の2種です。

HCURSOR m_main_def_hcursor はメインウィンドウのデフォルトのマウスカーソルです。
int m_max_rate は最大レート値です。
int m_drag_stopping はドラッグ硬直フラグです。

enum { ID_NONE=0, ID_HORZ=1, ID_VERT=2, ID_CROSS = ID_HORZ | ID_VERT }; は ドラッグ識別定数です。
int m_drag_type, はドラッグ識別変数です。(== 水平ドラッグ | 垂直ドラッグ)
int m_dragging
はドラッグ中かどうかのフラグです。
RECT m_drag_limit はドラッグ移動の限界値座標です。ドラッグ開始時に計算します。
HBRUSH m_half_tone_brushはハーフトーン・ブラシです。(ドッキングツールバーD&D編参照

WNDPROC m_origin_proc はメインウィンドウのオリジナル・プロシージャを保持する変数です。
static PLIST<SPLITTER> SPLITTER::g_splitter_list; はスプリッタ・クラスのthisポインタのリスト(グローバル変数)です。プロシージャ呼出用です。



メンバ関数は31コです。

SPLITTER() コンストラクタ はメンバ変数を初期化し、ハーフトーンブラシを作成します。
~SPLITTER() デストラクタ はthisポインタをリストかr削除し、ハーフトーンブラシをDeleteObject
void create(HWND main_hwnd, int x, int y, int base_thick=5) はこのクラスを起動させます。各メンバを引数のブロックサイズにより生成、new演算します。
void add_child(HWND hwnd, int block_x, int block_y, int block_cx, int block_cy) は子ウィンドウをスプリット配置するリストに追加します。引数はブロック番号、ブロック数で指定します。

on_lbuttondown() はマウス左ボタン押下を処理する関数です。返り値はドラッグ処理をしたら”非0”、無処理なら”0”になります。
on_lbuttonup()   はマウス左ボタン押上を処理する関数です。返り値はドラッグ処理をしたら”非0”、無処理なら”0”になります。
on_mousemove()  はマウス移動を処理する関数です。返り値はドラッグ処理をしたら”非0”、無処理なら”0”になります。
on_timer(UINT id) はタイマを処理する関数です。タイマはドラッグ硬直用です。この関数は自前のタイマ専用プロシージャから呼ばれるのでメインウィンドウのタイマには基本的に影響ありません。
void on_size() はウィンドウサイズが変更されたときに呼ばれる関数です。
void renew_size() はウィンドウサイズが変更されたときに各サイズを更新する関数です。on_size()以外からも呼ばれる関数です。
void recalc_layout() はレイアウト再計算関数です。子ウィンドウの位置とサイズを再計算し、設定します。
void on_block_paint() はブロック描画(テスト用コード)です。通常は使わない関数です。各ブロックの境界を描画し、有効な境界線を黒く塗りつぶします。
get_border_thick_x(int n) はn番目の境界線(X)の太さを取得します。
get_border_thick_y(int n) はn番目の境界線(Y)の太さを取得します。
void set_border_thick_x(int n, int thick) はn番目の境界線(X)の太さを設定します。
void set_border_thick_y(int n, int thick) はn番目の境界線(Y)の太さを設定します。

set_auto_hook(WNDPROC proc=NULL) は自動フックを設定します。この関数を呼ぶとメインウィンドウ側のプロシージャでの処理が生成処理以外はいらなくなります。
is_valid_border_horz(int num) はnum番目の境界線(水平)が有効か無効か判定します。その列の境界線がすべて無効なとき(境界線に子ウィンドウがのってるとき)"0"を返します。そうでなければ"非0"を返します。
is_valid_border_vert(int num) はnum番目の境界線(垂直)が有効か無効か判定します。その列の境界線がすべて無効なとき(境界線に子ウィンドウがのってるとき)"0"を返します。そうでなければ"非0"を返します。
void set_pix_x(int block_num, int rate) はX座標系のnum番目のブロックサイズを設定します(ピクセル式)
void set_pix_y(int block_num, int rate) はY座標系のnum番目のブロックサイズを設定します(ピクセル式)
void set_rate_x(int block_num, double rate) はX座標系のnum番目のブロックサイズを設定します(レート式)
void set_rate_y(int block_num, double rate) はY座標系のnum番目のブロックサイズを設定します(レート式)
void set_max_rate(int r) は最大レート値を設定します。

on_dragging() は「ドラッグ中」を処理する関数です。ドラッグ境界線を描画しています。
start_drag() はドラッグ開始関数です。マウスをキャプチャーしたりウィンドウDCをロックしたりしています。
end_drag()  はドラッグ終了関数です。キャプチャーしたマウスをリリースしたり、ロックしたウィンドウDCを解除したりしています。
void renew_cursor() マウス位置からマウスカーソル・タイプを決定し更新します。

// 各プロシージャ
SplitProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) 自動フック用プロシージャです。
static LRESULT CALLBACK StaticSplitProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) 自動フック用プロシージャ(static)です。
static void CALLBACK StaticSplitTimerProc(HWND hwnd, UINT msg, UINT id, DWORD passed_time) タイマ用プロシージャ(static)です。


<呼び方>
突然ですがスプリッウィンドウ  と スプリッウィンドウ、どちらが正しいのでしょうか。
英語で考えたら両方間違いで、正しくは「スプリッティング・ウィンドウ」かと思われます。
×[ split window ]
×[ splitter window ]
○[ splitting window ]

  (ドッキング・ツールバー も -ing だし)
しかしもう スプリッウィンドウ  でも スプリッウィンドウでも
立派な?和製英語なので 言葉としては両方正解な気がします。
意味通じるし。




split_win.h


#ifndef _SPLIT_WIN_H_
#define _SPLIT_WIN_H_

#include <windows.h>
#include "plist.h"

// リージョン演算
add_rgn(HRGN aim_rgn, int sx, int sy, int ex, int ey, HRGN work_rgn, HRGN work_rgn2){
    SetRectRgn(work_rgn,    sx, sy, ex, ey);
    CombineRgn(work_rgn2, work_rgn, aim_rgn, RGN_OR);
    CombineRgn(aim_rgn, work_rgn2, NULL, RGN_COPY);
}
// スプリッタ子ウィンドウ・クラス
class SPLIT_WIN_CHILD {
    public :
    HWND m_hwnd;
    int m_b_x, m_b_y, m_b_cx, m_b_cy;   // ブロック位置サイズ
    set(HWND hwnd, int block_x, int block_y, int block_cx, int block_cy);
};
// スプリッタ子ウィンドウ・設定
SPLIT_WIN_CHILD::set(HWND hwnd, int block_x, int block_y, int block_cx, int block_cy){
    m_hwnd = hwnd;
    m_b_x  = block_x;
    m_b_y  = block_y;
    m_b_cx = block_cx;
    m_b_cy = block_cy;
}
// スプリッタブロック・スカラー値・クラス
class SPLIT_BLOCK_SCALAR {
    public :
    int *m_blk_rate;            // 各ブロックサイズ(レート)
    int *m_blk_pix;             // 各ブロックサイズ(ピクセル値)
    int *m_border_thick;        // 境界線の厚さ
    int m_divide_count;         // ブロック分割数
    int m_drag_co;              // ドラッグ座標
    int m_drag_row;             // ドラッグ行
    int m_base_border_thick;    // 標準の境界線の厚さ
    int m_win_size;             // ウィンドウサイズ保持
    int m_max_rate;             // 最大レート

    SPLIT_BLOCK_SCALAR();                   // コンストラクタ
    ~SPLIT_BLOCK_SCALAR();                  // デストラクタ
    void create(int block_num, int win_size);       // 生成
    get_border_thick(int n);                // n番目の境界線の太さを取得
    void set_border_thick(int n, int thick);    // n番目の境界線の太さを設定
    get_row_by_pos(int pos);                // 座標から該当する行を取得
    get_blk_co_front(int row_num);          // n番目のブロックの左上側の座標を取得
    get_blk_co_rear(int row_num);           // n番目のブロックの右下側の座標を取得
    void set_pix(int block_num, int pix);   // ブロックサイズ設定(ピクセル式)
    void set_rate(int block_num, int rate); // ブロックサイズ設定(レート式)
    void renew_win_size(int win_size);      // ウィンドウサイズ変更
    void set_max_rate(int r);               // 最大レート値設定
};
// コンストラクタ
SPLIT_BLOCK_SCALAR::SPLIT_BLOCK_SCALAR(){
    m_blk_pix = NULL;
    m_border_thick = NULL;
    m_divide_count=0;
    m_base_border_thick = 0;
    m_max_rate = 10000;
}
// デストラクタ
SPLIT_BLOCK_SCALAR::~SPLIT_BLOCK_SCALAR(){
    if (m_blk_pix) delete[] m_blk_pix;
    if (m_border_thick) delete[] m_border_thick;
}
// 生成
void SPLIT_BLOCK_SCALAR::create(int block_num, int win_size){
    if (block_num<=0) return;
    m_divide_count=block_num-1;
    m_blk_pix  = new int[block_num];
    m_blk_rate = new int[block_num];
    if (block_num>=2) m_border_thick = new int[block_num-1];

    int i, avg, w;
    for(i=0;i<m_divide_count;i++) m_border_thick[i]=-1;

    // レート設定
    avg = m_max_rate/block_num;
    for(i=0;i<m_divide_count;i++) m_blk_rate[i]=avg;
    m_blk_rate[m_divide_count]=m_max_rate-m_divide_count*avg;

    // ピクセル設定
    m_win_size=win_size;
    w = m_win_size-m_divide_count*m_base_border_thick;
    avg = w /block_num;
    for(i=0;i<(block_num-1);i++) m_blk_pix[i]=avg;
    m_blk_pix[block_num-1] = w -avg*m_divide_count-1;
}
// 最大レート値設定
void SPLIT_BLOCK_SCALAR::set_max_rate(int r){
    int i;
    for(i=0;i<m_divide_count;i++) m_blk_rate[i]=m_blk_rate[i]*r/m_max_rate;
    m_max_rate = r;
}
// ウィンドウサイズ変更時
void SPLIT_BLOCK_SCALAR::renew_win_size(int win_size){
    int i, co=0, tmp_size = win_size;
    for(i=0;i<m_divide_count;i++) tmp_size-=get_border_thick(i);
    for(i=0;i<m_divide_count;i++) { m_blk_pix[i] = m_blk_rate[i]*tmp_size/m_max_rate; co+=m_blk_pix[i]; }
    m_blk_pix[m_divide_count] = tmp_size - co-1;
    m_win_size=win_size;
}
// ブロックサイズ設定(レート式)
void SPLIT_BLOCK_SCALAR::set_rate(int block_num, int rate){
    if (block_num<0 || block_num>m_divide_count) return;

    int i, diff, cx=0;
    for(i=0;i<m_divide_count;i++) cx-=get_border_thick(i);
    if (rate>m_max_rate) rate=m_max_rate;
    if (rate<0) rate = 0;

    diff=rate-m_blk_rate[block_num];
    m_blk_rate[block_num] = rate;
    for(i=block_num+1;i<(m_divide_count+1);i++) {
        if (diff<=m_blk_rate[i]){
            m_blk_rate[i] = m_blk_rate[i]-diff;
            diff=0;
            break;
        }
        else {
            diff -= m_blk_rate[i];
            m_blk_rate[i] = 0;
        }
    }
    for(i=block_num-1;i>=0;i--) {
        if (diff<=m_blk_rate[i]){
            m_blk_rate[i] = m_blk_rate[i]-diff;
            diff=0;
            break;
        }
        else {
            diff -= m_blk_rate[i];
            m_blk_rate[i] = 0;
        }
    }
}
// ブロックサイズ設定(ピクセル式)
void SPLIT_BLOCK_SCALAR::set_pix(int block_num, int pix){
    set_rate(block_num, pix*m_max_rate/m_win_size);
}
// 行の座標取得 左上
SPLIT_BLOCK_SCALAR::get_blk_co_front(int row_num){
    int i, x=0;
    if (row_num<0) return 0;
    for(i=0;i<m_divide_count;i++){
        if (i==row_num) return x;
        x+=m_blk_pix[i] + get_border_thick(i);
    }
    return x;
}
// 行の座標取得 右下
SPLIT_BLOCK_SCALAR::get_blk_co_rear(int row_num){
    int co = (row_num<0 || row_num>m_divide_count)? 0 : m_blk_pix[row_num];
    return get_blk_co_front(row_num)+co;
}
// マウスが乗ってる境界の行番号を取得(X)  
SPLIT_BLOCK_SCALAR::get_row_by_pos(int pos){
    int i, x=0, t;
    for(i=0;i<m_divide_count;i++){
        x+=m_blk_pix[i];
        t=get_border_thick(i);
        if (pos>=x && pos<=(x+t)) return i;
        x+= t;
    }
    return -1;
};
// n番目の境界の厚さ取得
SPLIT_BLOCK_SCALAR::get_border_thick(int n){
    if (n<0 || n>=m_divide_count) return 0;
    return (m_border_thick[n]>=0)? m_border_thick[n] : m_base_border_thick;
}
// n番目の境界の厚さ設定
void SPLIT_BLOCK_SCALAR::set_border_thick(int n, int thick){
    if (n<0 || n>=m_divide_count) return;
    m_border_thick[n]=thick;
    int i, co=0, tmp_size = m_win_size;
    for(i=0;i<m_divide_count;i++) tmp_size-=get_border_thick(i);
    for(i=0;i<m_divide_count;i++) { m_blk_pix[i] = m_blk_rate[i]*tmp_size/m_max_rate; co+=m_blk_pix[i]; }
    m_blk_pix[m_divide_count] = tmp_size - co-1;
}
// スプリッタクラス
class SPLITTER {
    public :
    SPLIT_BLOCK_SCALAR m_blk_x, m_blk_y;    // スプリッタブロック・スカラー値・クラス
    HDC m_frame_hdc;    // ドラッグ用DC
    HRGN m_apply_rgn, m_work_rgn, m_work_rgn2, m_last_rgn;    // リージョン

    HWND m_main_hwnd;
    PLIST<SPLIT_WIN_CHILD> m_win_children;  // 子ウィンドウ群
    char **m_border_valid_horz, **m_border_valid_vert;  // 各境界線が有効かどうか
    HCURSOR m_main_def_hcursor;             // デフォルトのマウスカーソル
    int m_max_rate;         // 最大レート値
    int m_drag_stopping;    // ドラッグ硬直

    int m_drag_type, m_dragging;    // ドラッグ識別変数
    RECT m_drag_limit;              // ドラッグ移動の限界値座標
    HBRUSH m_half_tone_brush;       // ハーフトーン・ブラシ
    enum { ID_NONE=0, ID_HORZ=1, ID_VERT=2, ID_CROSS = ID_HORZ | ID_VERT }; // ドラッグ識別定数

    WNDPROC m_origin_proc;  // メインウィンドウのオリジナル・プロシージャ
    static PLIST<SPLITTER> SPLITTER::g_splitter_list;   // 自身ポインタのリスト(グローバル)

    SPLITTER();     // コンストラクタ
    ~SPLITTER();    // デストラクタ
    void create(HWND main_hwnd, int x, int y, int base_thick=5);    // 生成
    void add_child(HWND hwnd, int block_x, int block_y, int block_cx, int block_cy);    // 子ウィンドウ追加
    on_lbuttondown();   // マウス左ボタン押下
    on_lbuttonup();     // マウス左ボタン押上
    on_mousemove();     // マウス移動
    on_timer(UINT id);  // マウス移動
    void on_size();             // ウィンドウサイズ変更
    void recalc_layout();       // レイアウト再計算
    void on_block_paint();      // ブロック描画(テスト用コード)
    get_border_thick_x(int n);  // n番目の境界線の太さを取得(X)
    get_border_thick_y(int n);  // n番目の境界線の太さを取得(Y)
    void set_border_thick_x(int n, int thick);  // n番目の境界線の太さを設定(X)
    void set_border_thick_y(int n, int thick);  // n番目の境界線の太さを設定(Y)

    set_auto_hook(WNDPROC proc=NULL);   // 自動フック
    is_valid_border_horz(int num);      // num番目の境界線の有効か無効か(水平)
    is_valid_border_vert(int num);      // num番目の境界線の有効か無効か(垂直)
    void set_pix_x(int block_num, int rate);        // num番目のブロックサイズ設定(ピクセル)X
    void set_pix_y(int block_num, int rate);        // num番目のブロックサイズ設定(ピクセル)Y
    void set_rate_x(int block_num, double rate);    // num番目のブロックサイズ設定(レート)X
    void set_rate_y(int block_num, double rate);    // num番目のブロックサイズ設定(レート)Y
    void renew_size();          // ウィンドウサイズ変更
    void set_max_rate(int r);   // 最大レート値設定

    on_dragging();  // ドラッグ中
    start_drag();   // ドラッグ開始
    end_drag();     // ドラッグ終了
    void renew_cursor();    // カーソル・タイプ更新

    // 各プロシージャ
    SplitProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
    static LRESULT CALLBACK StaticSplitProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
    static void CALLBACK StaticSplitTimerProc(HWND hwnd, UINT msg, UINT id, DWORD passed_time);
};
// static メンバ実体宣言
PLIST<SPLITTER> SPLITTER::g_splitter_list;

// 自動フック用・プロシージャ(スタティック版)
LRESULT CALLBACK SPLITTER::StaticSplitProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    int i;
    for(i=0;i<g_splitter_list.size();i++){
        if (g_splitter_list[i]->m_main_hwnd==hwnd) return g_splitter_list[i]->SplitProc(hwnd, msg, wp, lp);
    }
}
// 自動フック用・プロシージャ
SPLITTER::SplitProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    switch (msg) {
    case WM_LBUTTONDOWN:if (on_lbuttondown())  return 0;    break;
    case WM_LBUTTONUP:  if (on_lbuttonup())    return 0;    break;
    case WM_MOUSEMOVE:  if (on_mousemove()) return 0;   break;
    case WM_SIZE:       on_size();      break;
//  case WM_PAINT:      on_block_paint();       break;  // テスト用コード
    }
    return (CallWindowProc(m_origin_proc, hwnd, msg, wp, lp));
}

// タイマ・プロシージャ(スタティック)
void CALLBACK SPLITTER::StaticSplitTimerProc(HWND hwnd, UINT msg, UINT id, DWORD passed_time ){
    int i;
    for(i=0;i<g_splitter_list.size();i++){
        if (g_splitter_list[i]->m_main_hwnd==hwnd) {
            g_splitter_list[i]->on_timer(id);
            return ;
        }
    }
}

// 自動フック
SPLITTER::set_auto_hook(WNDPROC proc){
    m_origin_proc = (proc)? proc : (WNDPROC)GetWindowLong(m_main_hwnd, GWL_WNDPROC);
    SetWindowLong(m_main_hwnd, GWL_WNDPROC, (LONG)StaticSplitProc);
}
// 最大レート値設定
void SPLITTER::set_max_rate(int r){
    m_blk_x.set_max_rate(r);
    m_blk_y.set_max_rate(r);
    m_max_rate = r;
};

// コンストラタ
SPLITTER::SPLITTER(){
    g_splitter_list.p_push(this);
    m_main_hwnd = NULL;
    m_dragging = 0;
    m_drag_stopping = 0;
    m_frame_hdc = NULL;
    m_border_valid_horz = m_border_valid_vert = NULL;
    m_drag_type=ID_NONE;
    m_max_rate = 10000;

    WORD gray_pattern[8];
    HBITMAP gray_bitmap;
    int i;
    // ハーフトーン・パレット生成
    for (i=0;i<8;i++) gray_pattern[i] = (WORD)(0x5555 << (i & 1));  // 0x5555 は2bitで  01010101 01010101
    gray_bitmap = CreateBitmap(8, 8, 1, 1, &gray_pattern);
    if (gray_bitmap != NULL) {
        m_half_tone_brush = ::CreatePatternBrush(gray_bitmap);
        DeleteObject(gray_bitmap);
    }
}
// デストラクタ
SPLITTER::~SPLITTER(){
    g_splitter_list.val_pop(this);
    DeleteObject(m_half_tone_brush); // ハーフトーン・パレット破棄
}
// 生成
void SPLITTER::create(HWND main_hwnd, int x, int y, int base_thick){
    RECT rc;
    if (x<=0 || y<=0) return;
    m_main_def_hcursor = (HCURSOR)GetClassLong(m_main_hwnd, GCL_HCURSOR);
    if (!m_main_def_hcursor) m_main_def_hcursor = LoadCursor(NULL, IDC_ARROW);
    m_main_hwnd = main_hwnd;

    m_blk_x.m_base_border_thick=base_thick;
    m_blk_y.m_base_border_thick=base_thick;

    GetClientRect(m_main_hwnd, &rc);
    m_blk_x.create(x, rc.right-rc.left);
    m_blk_y.create(y, rc.bottom-rc.top);

    int i, iy;
    if (y>=2) {
        m_border_valid_horz = new char* [x];
        for(i=0;i<x;i++) m_border_valid_horz[i] = new char[y-1];
        for(i=0;i<x;i++) for(iy=0;iy<(y-1);iy++) m_border_valid_horz[i][iy] = 1;
    }
    if (x>=2) {
        m_border_valid_vert = new char* [x-1];
        for(i=0;i<(x-1);i++) m_border_valid_vert[i] = new char[y];
        for(i=0;i<(x-1);i++) for(iy=0;iy<y;iy++) m_border_valid_vert[i][iy] = 1;
    }
}
// 子ウィンドウ追加
void SPLITTER::add_child(HWND hwnd, int blk_x, int blk_y, int blk_cx, int blk_cy){
    if (!m_main_hwnd) return ;
    SPLIT_WIN_CHILD *pchild=m_win_children.a_push();
    if (blk_x>=(m_blk_x.m_divide_count+1) || blk_y>=(m_blk_y.m_divide_count+1)) return;
    if ((blk_x+blk_cx)>(m_blk_x.m_divide_count+1)) blk_cx=(m_blk_x.m_divide_count+1)-blk_x;
    if ((blk_y+blk_cy)>(m_blk_y.m_divide_count+1)) blk_cy=(m_blk_y.m_divide_count+1)-blk_y;
    pchild->set(hwnd, blk_x, blk_y, blk_cx, blk_cy);

    int ix, iy;
    for(ix=blk_x;ix<(blk_x+blk_cx);ix++){
        for(iy=blk_y;iy<(blk_y+blk_cy-1);iy++) m_border_valid_horz[ix][iy] = 0;
    }
    for(ix=blk_x;ix<(blk_x+blk_cx-1);ix++){
        for(iy=blk_y;iy<(blk_y+blk_cy);iy++)   m_border_valid_vert[ix][iy] = 0;
    }
}

// ドラッグ開始
SPLITTER::start_drag(){
    if (!m_main_hwnd) return 0;
    if (m_dragging) return 0;
    POINT po;
    SetCapture(m_main_hwnd);    // マウス・キャプチャ

    GetCursorPos(&po);
    ScreenToClient(m_main_hwnd, &po);
    m_blk_x.m_drag_row=m_blk_x.get_row_by_pos(po.x);        // マウスが乗ってる境界の行番号を取得(X)  
    m_blk_y.m_drag_row=m_blk_y.get_row_by_pos(po.y);        // マウスが乗ってる境界の行番号を取得(Y)  
    m_drag_type=0;
    if (m_blk_x.m_drag_row>=0) m_drag_type |= ID_VERT;
    if (m_blk_y.m_drag_row>=0) m_drag_type |= ID_HORZ;

    if (m_blk_x.m_drag_row<0 && m_blk_y.m_drag_row<0) return 0; // ドラッグできない

    int i, min_row, max_row;
    if (m_blk_y.m_drag_row>=0){ // m_blk_y.m_drag_row 番目の境界線にマウスが乗ってるとき
        // 移動限界線を計算
        min_row=-1;
        for(i=m_blk_y.m_drag_row;i>=0;i--) if (is_valid_border_horz(i)) { min_row=i; break; };
        m_drag_limit.top = m_blk_y.get_blk_co_front(min_row);
        max_row=m_blk_y.m_divide_count;
        for(i=m_blk_y.m_drag_row+1;i<m_blk_y.m_divide_count;i++) if (is_valid_border_horz(i)) { max_row=i; break; };
        m_drag_limit.bottom = m_blk_y.get_blk_co_rear(max_row)-get_border_thick_y(m_blk_y.m_drag_row);
    }
    if (m_blk_x.m_drag_row>=0){ // m_blk_x.m_drag_row 番目の境界線にマウスが乗ってるとき
        // 移動限界線を計算
        min_row=-1;
        for(i=m_blk_x.m_drag_row;i>=0;i--) if (is_valid_border_vert(i)) { min_row=i; break; };
        m_drag_limit.left = m_blk_x.get_blk_co_front(min_row);
        max_row=m_blk_x.m_divide_count;
        for(i=m_blk_x.m_drag_row+1;i<m_blk_x.m_divide_count;i++) if (is_valid_border_vert(i)) { max_row=i; break; };
        m_drag_limit.right = m_blk_x.get_blk_co_rear(max_row)-get_border_thick_x(m_blk_x.m_drag_row);
    }

    m_dragging = 1;
    LockWindowUpdate(m_main_hwnd);      // DCロック
    m_frame_hdc = GetDCEx(m_main_hwnd, NULL, DCX_CACHE|DCX_LOCKWINDOWUPDATE);   // DC取得
    SelectObject(m_frame_hdc, m_half_tone_brush);

    // リージョン生成
    m_apply_rgn = CreateRectRgn(0, 0, 0, 0);
    m_work_rgn  = CreateRectRgn(0, 0, 0, 0);
    m_work_rgn2 = CreateRectRgn(0, 0, 0, 0);
    m_last_rgn  = CreateRectRgn(0, 0, 0, 0);

    return 1;
}
// ドラッグ終了
SPLITTER::end_drag(){
    if (!m_main_hwnd) return 0;
    if (!m_dragging) return 0;
    m_dragging = 0;
    ReleaseCapture();

    POINT po;
    RECT rc;
    GetRgnBox(m_apply_rgn, &rc);
    SelectObject(m_frame_hdc, m_apply_rgn);
    PatBlt(m_frame_hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PATINVERT);

    LockWindowUpdate(NULL); // DCロック解除
    if (m_frame_hdc) ReleaseDC(m_main_hwnd, m_frame_hdc);   // DC解放

    // リージョン破棄
    DeleteObject(m_apply_rgn);
    DeleteObject(m_work_rgn);
    DeleteObject(m_work_rgn2);
    DeleteObject(m_last_rgn);

    // 移動適用
    GetCursorPos(&po);
    ScreenToClient(m_main_hwnd, &po);
    int a_co, b_co;
    if (m_drag_type & ID_HORZ){
        if (m_drag_limit.top>po.y)    m_blk_y.m_drag_co=m_drag_limit.top;
        if (m_drag_limit.bottom<po.y) m_blk_y.m_drag_co=m_drag_limit.bottom;

        if (m_blk_y.m_drag_row<m_blk_y.m_divide_count){
            a_co=m_blk_y.get_blk_co_front(m_blk_y.m_drag_row);
            b_co=m_blk_y.get_blk_co_rear(m_blk_y.m_drag_row+1);
            m_blk_y.m_blk_pix[m_blk_y.m_drag_row]   = m_blk_y.m_drag_co - a_co;
            m_blk_y.m_blk_pix[m_blk_y.m_drag_row+1] = b_co -m_blk_y.m_drag_co-get_border_thick_y(m_blk_y.m_drag_row);
        }
    }
    if (m_drag_type & ID_VERT){
        if (m_drag_limit.left>po.x)  m_blk_x.m_drag_co=m_drag_limit.left;
        if (m_drag_limit.right<po.x) m_blk_x.m_drag_co=m_drag_limit.right;

        if (m_blk_x.m_drag_row<m_blk_x.m_divide_count){
            a_co=m_blk_x.get_blk_co_front(m_blk_x.m_drag_row);
            b_co=m_blk_x.get_blk_co_rear(m_blk_x.m_drag_row+1);
            m_blk_x.m_blk_pix[m_blk_x.m_drag_row]   = m_blk_x.m_drag_co - a_co;
            m_blk_x.m_blk_pix[m_blk_x.m_drag_row+1] = b_co -m_blk_x.m_drag_co-get_border_thick_x(m_blk_x.m_drag_row);
        }
    }

    recalc_layout();
    return 1;
}
// ブロックサイズ設定X(ピクセル式)
void SPLITTER::set_pix_x(int block_num, int pix){
    if (!m_main_hwnd) return;

    m_blk_x.set_pix(block_num, pix);
    recalc_layout();
}
// ブロックサイズ設定Y(ピクセル式)
void SPLITTER::set_pix_y(int block_num, int pix){
    if (!m_main_hwnd) return;

    m_blk_y.set_pix(block_num, pix);
    recalc_layout();
}
// ブロックサイズ設定X(レート式)
void SPLITTER::set_rate_x(int block_num, double rate){
    if (!m_main_hwnd) return;
    if (rate<0) rate=0;
    if (rate>100) rate=100;

    rate=rate*m_max_rate/100;
    m_blk_x.set_rate(block_num, rate);
}
// ブロックサイズ設定Y(レート式)
void SPLITTER::set_rate_y(int block_num, double rate){
    if (!m_main_hwnd) return;
    if (rate<0) rate=0;
    if (rate>100) rate=100;

    rate=rate*m_max_rate/100;
    m_blk_y.set_rate(block_num, rate);
}
// ドラッグ中
SPLITTER::on_dragging(){
    if (!m_main_hwnd) return 0;
    if (!m_dragging) return 0;
    POINT po;
    RECT rc;

    GetCursorPos(&po);
    ScreenToClient(m_main_hwnd, &po);
    SetRectRgn(m_apply_rgn, 0, 0, 0, 0);
    m_blk_x.m_drag_co = po.x;
    m_blk_y.m_drag_co = po.y;

    int i, t, cx, cy;
    GetClientRect(m_main_hwnd, &rc);
    cx=rc.right -rc.left;
    cy=rc.bottom-rc.top;

    // 水平境界線のドラッグ
    if (m_drag_type & ID_HORZ){
        // 限界点補正
        if (m_drag_limit.top>po.y)    m_blk_y.m_drag_co=m_drag_limit.top;
        if (m_drag_limit.bottom<po.y) m_blk_y.m_drag_co=m_drag_limit.bottom;
        t=get_border_thick_y(m_blk_y.m_drag_row);
        for(i=0;i<=m_blk_x.m_divide_count;i++) {
            // 縦ラインとの交点部分
            if (i<m_blk_x.m_divide_count
                    && (m_border_valid_vert[i][m_blk_y.m_drag_row] || m_border_valid_vert[i][m_blk_y.m_drag_row+1]
                    ||  m_border_valid_horz[i][m_blk_y.m_drag_row] || m_border_valid_horz[i+1][m_blk_y.m_drag_row])
                    )
                add_rgn(m_apply_rgn, m_blk_x.get_blk_co_rear(i), m_blk_y.m_drag_co,
                        m_blk_x.get_blk_co_front(i+1), m_blk_y.m_drag_co+t, m_work_rgn, m_work_rgn2);

            // ブロックの辺の部分
            if (m_border_valid_horz[i][m_blk_y.m_drag_row]){
                add_rgn(m_apply_rgn, m_blk_x.get_blk_co_front(i), m_blk_y.m_drag_co,
                        m_blk_x.get_blk_co_rear(i), m_blk_y.m_drag_co+t, m_work_rgn, m_work_rgn2);
            }
        }
    }

    // 垂直境界線のドラッグ
    if (m_drag_type & ID_VERT){
        // 限界点補正
        if (m_drag_limit.left>po.x)  m_blk_x.m_drag_co=m_drag_limit.left;
        if (m_drag_limit.right<po.x) m_blk_x.m_drag_co=m_drag_limit.right;
        t=get_border_thick_x(m_blk_x.m_drag_row);
        for(i=0;i<=m_blk_y.m_divide_count;i++) {
            // 縦ラインとの交点部分
            if (i<m_blk_y.m_divide_count
                && (m_border_valid_horz[m_blk_x.m_drag_row][i] || m_border_valid_horz[m_blk_x.m_drag_row+1][i]
                ||  m_border_valid_vert[m_blk_x.m_drag_row][i] || m_border_valid_vert[m_blk_x.m_drag_row][i+1])
                )
                add_rgn(m_apply_rgn, m_blk_x.m_drag_co, m_blk_y.get_blk_co_rear(i),
                        m_blk_x.m_drag_co+t, m_blk_y.get_blk_co_front(i+1), m_work_rgn, m_work_rgn2);

            // ブロックの辺の部分
            if (m_border_valid_vert[m_blk_x.m_drag_row][i]){
                add_rgn(m_apply_rgn, m_blk_x.m_drag_co, m_blk_y.get_blk_co_front(i),
                        m_blk_x.m_drag_co+t, m_blk_y.get_blk_co_rear(i), m_work_rgn, m_work_rgn2);
            }
        }
    }


    // 水平・垂直境界線 両ドラッグ時
    if (m_drag_type == ID_CROSS){

        // マウスが隣の(上下左右の)ウィンドウに乗ってるときの描画
        t=get_border_thick_y(m_blk_y.m_drag_row);
        if (m_border_valid_horz[m_blk_x.m_drag_row][m_blk_y.m_drag_row])
            add_rgn(m_apply_rgn, m_blk_x.get_blk_co_rear(m_blk_x.m_drag_row), m_blk_y.m_drag_co,
                    m_blk_x.m_drag_co, m_blk_y.m_drag_co+t, m_work_rgn, m_work_rgn2);

        if (m_border_valid_horz[m_blk_x.m_drag_row+1][m_blk_y.m_drag_row])
            add_rgn(m_apply_rgn, m_blk_x.m_drag_co, m_blk_y.m_drag_co,
                    m_blk_x.get_blk_co_front(m_blk_x.m_drag_row+1), m_blk_y.m_drag_co+t, m_work_rgn, m_work_rgn2);

        if (m_border_valid_vert[m_blk_x.m_drag_row][m_blk_y.m_drag_row])
            add_rgn(m_apply_rgn, m_blk_x.m_drag_co, m_blk_y.get_blk_co_rear(m_blk_y.m_drag_row),
                    m_blk_x.m_drag_co+t, m_blk_y.m_drag_co, m_work_rgn, m_work_rgn2);

        if (m_border_valid_vert[m_blk_x.m_drag_row][m_blk_y.m_drag_row+1])
            add_rgn(m_apply_rgn, m_blk_x.m_drag_co, m_blk_y.m_drag_co,
                    m_blk_x.m_drag_co+t, m_blk_y.get_blk_co_front(m_blk_y.m_drag_row+1), m_work_rgn, m_work_rgn2);

    }

    // 反転による矩形描画
    CombineRgn(m_work_rgn, m_last_rgn, m_apply_rgn, RGN_XOR);
    GetRgnBox(m_work_rgn, &rc);
    SelectObject(m_frame_hdc, m_work_rgn);
    PatBlt(m_frame_hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PATINVERT);

    CombineRgn(m_last_rgn, m_apply_rgn, NULL, RGN_COPY);
    return 1;
}
// マウス左ボタン押下
SPLITTER::on_lbuttondown(){
    if (m_drag_stopping) return 0;  // ドラッグ後のドラッグ硬直中
    if (m_dragging) return 0;   // 既にドラッグ中
    return start_drag();
}
// タイマ
SPLITTER::on_timer(UINT id){
    POINT po;
    KillTimer(m_main_hwnd, id);
    if (m_drag_stopping){
        m_drag_stopping = 0;
        renew_cursor();
        GetCursorPos(&po);
        SetCursorPos(po.x, po.y);
        return 1;
    }
    return 0;
}
// マウス左ボタン押上
SPLITTER::on_lbuttonup(){
    if (!m_dragging) return 0;  // ドラッグしてなければ無処理
    m_drag_stopping = 1;
    SetTimer(m_main_hwnd, WM_LBUTTONDOWN, 100, StaticSplitTimerProc);
    renew_cursor();
    return end_drag();
}
// n番目の境界の厚さ取得(X)
SPLITTER::get_border_thick_x(int n){
    return m_blk_x.get_border_thick(n);
}
// n番目の境界の厚さ取得(Y)
SPLITTER::get_border_thick_y(int n){
    return m_blk_y.get_border_thick(n);
}
// n番目の境界の厚さ設定(X)
void SPLITTER::set_border_thick_x(int n, int thick){
    return m_blk_x.set_border_thick(n, thick);
}
// n番目の境界の厚さ設定(Y)
void SPLITTER::set_border_thick_y(int n, int thick){
    return m_blk_y.set_border_thick(n, thick);
}
// 水平境界線の有効かどうか
SPLITTER::is_valid_border_horz(int num){
    if (num<0 || num>=m_blk_y.m_divide_count) return 0;
    for(int i=0;i<(m_blk_x.m_divide_count+1);i++) if (m_border_valid_horz[i][num]) return 1;
    return 0;
}
// 垂直境界線の有効かどうか
SPLITTER::is_valid_border_vert(int num){
    if (num<0 || num>=m_blk_x.m_divide_count) return 0;
    for(int i=0;i<(m_blk_y.m_divide_count+1);i++) if (m_border_valid_vert[num][i]) return 1;
    return 0;
}
// マウス移動
SPLITTER::on_mousemove(){
    if (!m_main_hwnd) return 0;

    // ドラッグ中
    if (m_dragging) return on_dragging();
    // 非ドラッグ中
    renew_cursor();
    return 0;
}
// マウスカーソルの状態
void SPLITTER::renew_cursor(){
    HCURSOR hcursor;
    POINT po;
    int x, y, cursor_type;

    if (m_drag_stopping){
        hcursor = LoadCursor(NULL, IDC_APPSTARTING);
    }
    else {
        GetCursorPos(&po);
        ScreenToClient(m_main_hwnd, &po);
        x=m_blk_x.get_row_by_pos(po.x);
        y=m_blk_y.get_row_by_pos(po.y);
        cursor_type=0;
        if (x>=0 && is_valid_border_vert(x)) cursor_type |= ID_VERT;
        if (y>=0 && is_valid_border_horz(y)) cursor_type |= ID_HORZ;

        switch(cursor_type){
        case ID_HORZ:  hcursor = LoadCursor(NULL, IDC_SIZENS);  break;
        case ID_VERT:  hcursor = LoadCursor(NULL, IDC_SIZEWE);  break;
        case ID_CROSS: hcursor = LoadCursor(NULL, IDC_SIZEALL);break;
        default : hcursor = m_main_def_hcursor;
        }
    }
    SetClassLong(m_main_hwnd, GCL_HCURSOR, (LONG)hcursor);
};

// ウィンドウサイズ変更時
void SPLITTER::on_size(){
    if (!m_main_hwnd) return ;
    renew_size();
}
// ウィンドウサイズ更新
void SPLITTER::renew_size(){
    if (IsIconic(m_main_hwnd)) return ;

    RECT rc;
    GetClientRect(m_main_hwnd, &rc);
    m_blk_x.renew_win_size(rc.right - rc.left);
    m_blk_y.renew_win_size(rc.bottom - rc.top);
    recalc_layout();
}

// 子ウィンドウ再計算
void SPLITTER::recalc_layout(){
    if (!m_main_hwnd) return ;
    SPLIT_WIN_CHILD *p_sp_win;
    int x, y, cx, cy, right, bottom, is;
    for(is=0;is<m_win_children.size();is++) {
        p_sp_win=m_win_children[is];
        x = m_blk_x.get_blk_co_front(p_sp_win->m_b_x);
        y = m_blk_y.get_blk_co_front(p_sp_win->m_b_y);
        right  = p_sp_win->m_b_x+p_sp_win->m_b_cx-1;
        bottom = p_sp_win->m_b_y+p_sp_win->m_b_cy-1;
        cx = m_blk_x.get_blk_co_rear(right)-x;
        cy = m_blk_y.get_blk_co_rear(bottom)-y;

        SetWindowPos(m_win_children[is]->m_hwnd, NULL, x, y, cx, cy, 0);
    }
    InvalidateRect(m_main_hwnd, NULL, 1);
}
// ブロック区切りの描画
void SPLITTER::on_block_paint(){
    if (!m_main_hwnd) return ;
    RECT rc;
    int ix, iy;
    HDC hdc;
    PAINTSTRUCT ps;
    hdc = BeginPaint(m_main_hwnd , &ps);
    HPEN hpen = (HPEN)GetStockObject(BLACK_PEN);
    HBRUSH hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);
    SelectObject(hdc, hpen);

    rc.left = rc.top = rc.right = rc.bottom = 0;
    for(iy=0;iy<(m_blk_y.m_divide_count+1);iy++) {
        rc.left = rc.right = 0;
        rc.bottom += m_blk_y.m_blk_pix[iy];
        for(ix=0;ix<(m_blk_x.m_divide_count+1);ix++) {
            rc.right  += m_blk_x.m_blk_pix[ix];
            MoveToEx(hdc, rc.left, rc.top, NULL);
            LineTo(hdc, rc.right, rc.top);      LineTo(hdc, rc.right, rc.bottom);
            LineTo(hdc, rc.left, rc.bottom);    LineTo(hdc, rc.left, rc.top);
            if (ix<m_blk_x.m_divide_count) rc.right  += get_border_thick_x(ix);
            rc.left = rc.right;
        }
        if (iy<m_blk_y.m_divide_count) rc.bottom += get_border_thick_y(iy);
        rc.top = rc.bottom;
    }
    rc.left = rc.top = rc.right = rc.bottom = 0;
    for(iy=0;iy<m_blk_y.m_divide_count;iy++) {
        rc.left = rc.right = 0;
        rc.top += m_blk_y.m_blk_pix[iy];
        rc.bottom = rc.top + get_border_thick_y(iy);
        for(ix=0;ix<(m_blk_x.m_divide_count+1);ix++) {
            rc.right = rc.left + m_blk_x.m_blk_pix[ix];
            if (m_border_valid_horz[ix][iy]) FillRect(hdc, &rc, hbr);
            if (ix<m_blk_x.m_divide_count) rc.left = rc.right + get_border_thick_x(ix);
        }
        rc.top += get_border_thick_y(iy);
    }
    rc.left = rc.top = rc.right = rc.bottom = 0;
    for(iy=0;iy<(m_blk_y.m_divide_count+1);iy++) {
        rc.left = rc.right = 0;
        rc.bottom = rc.top + m_blk_y.m_blk_pix[iy];
        for(ix=0;ix<m_blk_x.m_divide_count;ix++) {
            rc.left += m_blk_x.m_blk_pix[ix];
            rc.right = rc.left + get_border_thick_x(ix);
            if (m_border_valid_vert[ix][iy]) FillRect(hdc, &rc, hbr);
            rc.left += get_border_thick_x(ix);
        }
        rc.top = rc.bottom + get_border_thick_y(iy);
    }
    EndPaint(m_main_hwnd, &ps);
}

#endif // _SPLIT_WIN_H_






サンプルCPPコードその1

split_win_01-1.cpp


#include "split_win.h"

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
        static HWND child_1, child_2, child_3, child_4;
        static SPLITTER split;
        int style;
        HINSTANCE hins;

        switch (msg) {
        case WM_CREATE:
                hins = GetModuleHandle(NULL);
                style = WS_CHILD | WS_BORDER | WS_VISIBLE;
                child_1 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_2 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_3 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_4 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                split.create(hwnd, 2, 2);
                split.set_auto_hook(WndProc);
                split.add_child(child_1, 0,0,1,1);
                split.add_child(child_2, 0,1,1,1);
                split.add_child(child_3, 1,0,1,1);
                split.add_child(child_4, 1,1,1,1);
                break;
        case WM_DESTROY:        PostQuitMessage(0);                     break;
        }
        return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow ) {
        HWND hwnd;
        MSG msg;
        WNDCLASS winc;

        winc.style              = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
        winc.lpfnWndProc        = WndProc;
        winc.cbClsExtra = winc.cbWndExtra       = 0;
        winc.hInstance          = hInstance;
        winc.hIcon              = LoadIcon(NULL , IDI_APPLICATION);
        winc.hCursor            = LoadCursor(NULL , IDC_ARROW);
        winc.hbrBackground      = (HBRUSH)(COLOR_BTNFACE+1);
        winc.lpszMenuName       = NULL;
        winc.lpszClassName      = TEXT("split_frame");

        if (!RegisterClass(&winc)) return -1;

        winc.hbrBackground      = (HBRUSH)GetStockObject(WHITE_BRUSH);
        winc.lpszClassName      = TEXT("split_child");
        winc.lpfnWndProc        = DefWindowProc;
        if (!RegisterClass(&winc)) return -1;

        hwnd = CreateWindow(
                        TEXT("split_frame") , TEXT("スプリットウィンドウのテスト") ,
                        WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
                        CW_USEDEFAULT, CW_USEDEFAULT, 240, 200,
                        NULL , NULL , hInstance , NULL
        );

        if (hwnd == NULL) return -1;

        while(GetMessage(&msg , NULL , 0 , 0)) DispatchMessage(&msg);
        return msg.wParam;
}





サンプルCPPコードその2

split_win_01-2.cpp

#include "split_win.h"

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
        static HWND child_1, child_2, child_3, child_4, child_5, child_6;
        static SPLITTER split;
        int style;
        HINSTANCE hins;

        switch (msg) {
        case WM_CREATE:
                hins = GetModuleHandle(NULL);
                style = WS_CHILD | WS_BORDER | WS_VISIBLE;
                child_1 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_2 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_3 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_4 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_5 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_6 = CreateWindow("split_child", NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                split.create(hwnd, 5, 3);
                split.set_auto_hook(WndProc);
                split.add_child(child_1, 0,0,4,2);
                split.add_child(child_2, 0,2,1,1);
                split.add_child(child_3, 4,0,1,1);
                split.add_child(child_4, 1,2,2,1);
                split.add_child(child_5, 3,2,1,1);
                split.add_child(child_6, 4,1,1,2);
                break;
        case WM_DESTROY:        PostQuitMessage(0);                     break;
        }
        return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow ) {
        HWND hwnd;
        MSG msg;
        WNDCLASS winc;

        winc.style              = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
        winc.lpfnWndProc        = WndProc;
        winc.cbClsExtra = winc.cbWndExtra       = 0;
        winc.hInstance          = hInstance;
        winc.hIcon              = LoadIcon(NULL , IDI_APPLICATION);
        winc.hCursor            = LoadCursor(NULL , IDC_ARROW);
        winc.hbrBackground      = (HBRUSH)(COLOR_BTNFACE+1);
        winc.lpszMenuName       = NULL;
        winc.lpszClassName      = TEXT("split_frame");

        if (!RegisterClass(&winc)) return -1;

        winc.hbrBackground      = (HBRUSH)GetStockObject(WHITE_BRUSH);
        winc.lpszClassName      = TEXT("split_child");
        winc.lpfnWndProc        = DefWindowProc;
        if (!RegisterClass(&winc)) return -1;

        hwnd = CreateWindow(
                        TEXT("split_frame") , TEXT("スプリットウィンドウのテスト") ,
                        WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
                        CW_USEDEFAULT, CW_USEDEFAULT, 240, 200,
                        NULL , NULL , hInstance , NULL
        );

        if (hwnd == NULL) return -1;

        while(GetMessage(&msg , NULL , 0 , 0)) DispatchMessage(&msg);
        return msg.wParam;
}






以下はテストコードです
有効な境界線が黒くなってます。

split_win_01-3.cpp

#include "split_win.h"

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
        static HWND child_1, child_2, child_3, child_4;
        static SPLITTER split;
        HINSTANCE hins;
        int style;

        switch (msg) {
        case WM_CREATE:
                hins = GetModuleHandle(NULL);
                style = WS_CHILD | WS_BORDER | WS_VISIBLE;
                child_1 = CreateWindow(TEXT("split_child"), NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_2 = CreateWindow(TEXT("split_child"), NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_3 = CreateWindow(TEXT("split_child"), NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                child_4 = CreateWindow(TEXT("split_child"), NULL, style, 0, 0, 0, 0, hwnd, NULL, hins, NULL);
                split.create(hwnd, 10,  8);
                split.set_auto_hook(WndProc);
                split.add_child(child_1, 1,2,4,3);
                split.add_child(child_2, 6,0,2,2);
                split.add_child(child_3, 7,2,2,4);
                split.add_child(child_4, 2,6,5,2);
        //      split.set_rate_x(0, 20);
                break;
        case WM_PAINT:split.on_block_paint();           break;  // テスト用コード
        case WM_DESTROY:        PostQuitMessage(0);             break;
        }
        return DefWindowProc(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow ) {
        HWND hwnd;
        MSG msg;
        WNDCLASS winc;

        winc.style              = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
        winc.lpfnWndProc        = WndProc;
        winc.cbClsExtra = winc.cbWndExtra       = 0;
        winc.hInstance          = hInstance;
        winc.hIcon              = LoadIcon(NULL, IDI_APPLICATION);
        winc.hCursor            = LoadCursor(NULL, IDC_ARROW);
        winc.hbrBackground      = (HBRUSH)GetStockObject(WHITE_BRUSH);
        winc.lpszMenuName       = NULL;
        winc.lpszClassName      = TEXT("split_frame");

        if (!RegisterClass(&winc)) return -1;

        winc.hbrBackground      = (HBRUSH)GetStockObject(WHITE_BRUSH);//(HBRUSH)GetStockObject(GRAY_BRUSH);
        winc.lpszClassName      = TEXT("split_child");
        winc.lpfnWndProc        = DefWindowProc;
        if (!RegisterClass(&winc)) return -1;

        hwnd = CreateWindow(
                        TEXT("split_frame"), TEXT("スプリットウィンドウのテスト"),
                        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                        CW_USEDEFAULT, CW_USEDEFAULT, 480, 320,
                        NULL, NULL, hInstance, NULL
        );

        if (hwnd == NULL) return -1;

        while(GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
        return msg.wParam;
}


 004-番外2  前へ←  ホームへ  →次へ  006-01