右図は最も簡単なスプリッタウィンドウ。左右に1:1に別けたウィンドウです。左に『お気に入り』フォルダのツリー表示、右にブラウザ画面と言う構成ですね。ネットで検索していても、こう言ったウィンドウを見た事ありますよね?例えば、画面左にリンクページを、右に左で指定したリンクを表示するページを開くようなウィンドウです。ページによっては更に画面下に別のウィンドウを作って三画面分割しているような所もございますね。HTMLではこう言った分割ウィンドウを「フレーム」と呼び、<FRAME>タグとして用意されています。また、VCではそれぞれの分割された個々のウィンドウを『ペイン』と呼ぶ事に注意して下さい。
では実際にウィンドウを分割するプログラムを組んでみましょう。作成するスプリッタウィンドウは、右図のような左右分割スプリッタです。
class CMainFrame : public CFrameWnd
{
:
public:
CSplitterWnd m_SplitWndMain; // スプリッタウィンドウ。メンバ関数定義
:
}
|
#include "PaneTestDoc.h" // "PaneTestView.h"ヘッダよりも先にインクルードする。理由は不明だが、順序を逆するとコンパイルエラーが発生する。
#include "PaneTestView.h" // CPaneTestViewクラスのヘッダをインクルード
#include "PaneBView.h" // CPaneBViewクラスのヘッダをインクルード
:
:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
:
:
m_SplitWndMain.CreateStatic( // スプリッタウィンドウの作成
this, // スプリッタウィンドウの親ウィンドウを指定。ここではメインフレームを分割するのでthisを指定。
1, // 行の分割数を指定。ここでは縦分割は無いので1を指定
2); // 列の分割数を指定。ここでは左右に二つ分割なので2を指定
m_SplitWndMain.CreateView( // paneA(ペイン場所1x1)を作成。
0, // スプリッタの行番号を指定
0, // スプリッタの列番号を指定
RUNTIME_CLASS(CPaneTestView), // 指定ペインを管理するViewクラスCPaneTestViewを指定
CSize(20,0), // ペインのサイズ
pContext); // ???。私の腐った脳味噌では何か理解出来ません
m_SplitWndMain.CreateView( // paneB(ペイン場所1x2)を作成。
0, // スプリッタの行番号を指定
1, // スプリッタの列番号を指定
RUNTIME_CLASS(CPaneBView), // paneBを管理するViewクラスCPaneBViewを指定
CSize(0,0), // ペインのサイズ
pContext); // ???
:
:
}
|
尚、MDIアプリケーションの場合も同様です。CChildFrameクラスに、SDIアプリケーションの時同様、OnCreateClientメンバ関数をオーバーライドして、OnCreateClientメンバ関数内に同様のコードを追加して下さい。
#include "PaneTestDoc.h"
#include "PaneTestView.h" // CPaneTestViewクラスのヘッダをインクルード
#include "PaneBView.h" // CPaneBViewクラスのヘッダをインクルード
#include "PaneCView.h" // CPaneCViewクラスのヘッダをインクルード
#include "PaneDView.h" // CPaneDViewクラスのヘッダをインクルード
#include "PaneEView.h" // CPaneEViewクラスのヘッダをインクルード
#include "PaneFView.h" // CPaneFViewクラスのヘッダをインクルード
:
:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
:
:
m_SplitWndMain.CreateStatic(this,2,3); // 2x3のスプリッタウィンドウの作成
m_SplitWndMain.CreateView(0,0,RUNTIME_CLASS(CPaneTestView), CSize(100,0), pContext);
m_SplitWndMain.CreateView(0,1,RUNTIME_CLASS(CPaneBView), CSize(150,70), pContext);
m_SplitWndMain.CreateView(0,2,RUNTIME_CLASS(CPaneCView), CSize(0,0), pContext);
m_SplitWndMain.CreateView(1,0,RUNTIME_CLASS(CPaneDView), CSize(0,0), pContext);
m_SplitWndMain.CreateView(1,1,RUNTIME_CLASS(CPaneEView), CSize(0,0), pContext);
m_SplitWndMain.CreateView(1,2,RUNTIME_CLASS(CPaneFView), CSize(0,0), pContext);
:
:
}
|
では次。変則的なスプリッタウィンドウを作ってみましょう。右図のように、左側に1つ、右側に2つのウィンドウを持つようなスプリッタウィンドウを例にあげてみます。
class CMainFrame : public CFrameWnd
{
:
public:
CSplitterWnd m_SplitWndMain; // メインフレームを左右分割する為に使用するスプリッタウィンドウ(メインスプリッタと仮命名)
CSplitterWnd m_SplitWndSub; // 左右分割されたウィンドウの右ペインを上下分割する為に使用する
// スプリッタウィンドウ(サブスプリッタと仮命名)
:
}
|
#include "PaneTestDoc.h"
#include "PaneTestView.h" // CPaneTestViewクラスのヘッダをインクルード
#include "PaneBView.h" // CPaneBViewクラスのヘッダをインクルード
#include "PaneCView.h" // CPaneCViewクラスのヘッダをインクルード
:
:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
:
:
m_SplitWndMain.CreateStatic( // メインスプリッタを作成
this, // メインスプリッタの親ウィンドウを指定。ここではメインフレームを分割するのでthisを指定
1, // メインスプリッタの行分割数を指定
2); // メインスプリッタの列分割数を指定
m_SplitSub.CreateStatic( // サブスプリッタを作成
&m_SplitWndMain, // サブスプリッタの親ウィンドウはm_wndSplitMain
2, // サブスプリッタの行分割を指定
1, // サブスプリッタの列分割を指定
WS_CHILD | WS_VISIBLE, // サブスプリッタのスタイルを指定
m_SplitWndMain.IdFromRowCol(0,1)); // 子ウィンドウIDを指定。m_SplitWndMainの行0(=1行目)列1(=2列目)のIDを取得してます。多分...
m_SplitWndMain.CreateView( // paneAを作成。
0, // メインスプリッタの行番号を指定
0, // メインスプリッタの列番号を指定
RUNTIME_CLASS(CPaneTestView), // paneAを管理するViewクラスCPaneTestViewを指定。
CSize(20,0), // ペインのサイズ。
pContext); // ???
m_SplitWndSub( // paneBを作成。
0, // サブスプリッタの行番号を指定
0, // サブンスプリッタの列番号を指定
RUNTIME_CLASS(CPaneBView), // paneBを管理するViewクラスCPaneBViewを指定。
CSize(100,0), // ペインのサイズ。
pContext); // ???
m_SplitWndSub( // paneCを作成。
1, // サブスプリッタの行番号を指定
0, // サブンスプリッタの列番号を指定
RUNTIME_CLASS(CPaneCView), // paneCを管理するViewクラスCPaneCViewを指定。
CSize(0,0), // ペインのサイズ。
pContext); // ???
:
:
}
|
#include "RightBottomView.h"
#include "RightTopView.h"
#include "MainFrm.h"
:
:
class CPaneTestView : public CView
{
:
:
public:
CPaneBView* p_paneB; // CPaneBViewクラスへのポインタ
CPaneCView* p_paneB; // CPaneCViewクラスへのポインタ
:
:
}
|
//
#include "MainFrm.h"
:
:
CPaneTestView::OnDraw(CDC *pDC)
{
:
:
p_paneB = (CPaneBView*)((CMainFrame*)AfxGetMainWnd())->m_wndSplitSub.GetPane(0,0);
p_paneC = (CPaneCView*)((CMainFrame*)AfxGetMainWnd())->m_wndSplitSub.GetPane(1,0);
:
:
}
|
p_paneB->GetDC()->TextOut(0,0,"This region is PaneB."); // CView::TestOut関数は基本でしょう。説明端折る。 |
#include "RightBottomView.h"
#include "RightTopView.h"
#include "MainFrm.h"
:
:
class CPaneTestView : public CView
{
:
:
public:
CPaneBView* p_paneB; // CPaneBViewクラスへのポインタ
CPaneCView* p_paneB; // CPaneCViewクラスへのポインタ
:
:
}
|
//
:
:
CPaneTestView::OnDraw(CDC *pDC)
{
POSITION pos; // POSITION型の変数。詳細は勉強不足により不明
CView* pView; // CView*型のポインタ変数
:
:
pos = pDoc->GetFirstViewPosition(); // 先頭にあるViewの位置を検索。但し、「先頭にある」Viewの位置が決してpaneAでは無い事に注意。
// 戻り値はウィンドウの位置。
while (pos != NULL) // posがNULLになるまで、つまり最後のView位置まで検索
{
pView = (CView*)(pDoc->GetNextView(pos)); // View位置を1つずつずらす
if (pView->IsKindOf(RUNTIME_CLASS(CPaneBView))) // CWndBViewクラスを用いるViewの位置にいるならば、
p_paneB=(CPaneBView*)pView; // p_paneBにpViewが持つポインタを渡す
else if (pView->IsKindOf(RUNTIME_CLASS(CPaneCView))) // CWndCViewクラスを用いるViewの位置にいるならば、
p_paneC=(CPaneCView*)pView; // p_paneCにpViewが持つポインタを渡す
}
:
:
}
|