VC++ MFCに印刷機構を組み込む手順の解説

下記の画像はこの説明に使用する簡易アプリケ-ションです、質問はコメント欄に記載して下さい。基本のメッセ-ジマツプの記載から説明し印刷機構の使用コ-ドとプログラムの流れも、お見せ致します。皆さんやはり動画では応用する事は困難だと思います大切なのは皆さんが悩みながら調査して実際の動作を確認しながら覚えて行ってもらいたい、皆さん是非マスタ-して下さい。

基本アプリケ-ション.MFC VC++用プロジェクト

メッセージハンドラーの構成

この基本アプリケ-ション.プロジェクトを4万5千円で販売します

応用範囲は非常に高くノウハウ満載です、貴方のアプリケ-ション開発に必要な基本機能が既に組み込みが出来ております、私宛にメールを下さる方コメント欄に書き込み連絡してください。

使用しているクラス

クラス構成::

  • APPクラス
  • シングルドキュメント.クラス
  • メインフレ-ム.クラス
  • フォ-ムビュ-クラス

上記のクラスを使用しています、これらの各クラスは互いに隔離されて安全性がかくほされています、しかしこの隔離されていることがアプリケ-ションの開発を困難にしている要因になります、これらで参照するデータはドキュメントクラス内に実装する必要が有るのですがウィンドウズアプリケ-ションでは多数の画面が切り替わる為にデータ配置が重要になり、各フレ-ム内にメモリ-配列を確保する事は出来ない、何故ならば絶えず泡の様に出来ては消えて実態が無くなる事で例外のオンパレ-ドに皆さんが遭遇する事になります。

フォ-ムビュ-定義を見る

フォ-ムビュ-ヘッダ-ファイルには以下の様に記載されています。これらのコードはプロジェクト作成時とは全く異なります。これらを説明するのは非常に広範囲になる為に難しいです。

// ControlPracticeView.h : ControlPracticeView クラスのインターフェイス
//

pragma once

include “afxcmn.h”

class ControlPracticeView : public CFormView
{
protected: // シリアル化からのみ作成します。
ControlPracticeView();
DECLARE_DYNCREATE(ControlPracticeView)

public:
enum{ IDD = IDD_CONTROLPRACTICE_FORM };
////////////////////////////////////////////////////////////////
CArray arrayPassDirHandl;
CRect PeparEriaSize;
CEdit ctRecipiMem;

int crmCount;
CString keepPrinData;

// 属性
public:
CControlPracticeDoc* GetDocument() const;
////////////////////////////////////////////////////////////////
void CStringDataMoveToStaticEriyaReset();
void CStringDataMoveToStaticEriya(CString vs,int item,int isub);
////////////////////////////////////////////////////////////////
CArray arrayDirectoryList;//ツリ-コントロ-ルに表示する項目を保存

// 操作
public:
////////////////////////////////////////////////////////////////
CString SearchFile(CString strFolder);
bool TreeMenberChck(CString vn);
////////////////////////////////////////////////////////////////

// オーバーライド
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV サポート
virtual void OnInitialUpdate(); // 構築後に初めて呼び出されます。

//========================================================================
//印刷関係の定義 此処で印刷機能を追加しています
protected:
void MyPrinteDrwTypeV(CDC* pDC, CPrintInfo* pInfo);
void MyPrinteDrwTypeSecoundV(CDC* pDC, CPrintInfo* pInfo);
void MyPrinteDrwTypeH(CDC* pDC, CPrintInfo* pInfo);
void MyPrinteDrwTypeSecoundH(CDC* pDC, CPrintInfo* pInfo);

void PrintPageHeader(CDC* pDC, CPrintInfo* pInfo, CString& strHeader);
void SetPageSize(CSize size);


virtual BOOL OnPreparePrinting(CPrintInfo* pInfo) ;
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnDraw(CDC* /*pDC*/);
virtual void OnPrint(CDC* pDC, CPrintInfo* pInfo);

public:
virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
//========================================================================

// 実装
public:
virtual ~ControlPracticeView();
void List1RowListControl(CDC* pDC,int nItem);

ifdef _DEBUG

virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;

endif

protected:
virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
virtual BOOL PreTranslateMessage(MSG* pMsg);

// 生成された、メッセージ割り当て関数
protected:
DECLARE_MESSAGE_MAP()
public:
CListCtrl CtlistControl1;
public:
afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
CTreeCtrl ctTreeCtr1;
afx_msg void OnBnClickedNo();
afx_msg void OnBnClickedOk();
};

ifndef _DEBUG // ControlPracticeView.cpp のデバッグ バージョン

inline CControlPracticeDoc* ControlPracticeView::GetDocument() const
{ return reinterpret_cast(m_pDocument); }

endif


MainFrameクラス内からドキュメント.デ-タを参照するには

これが簡単には出来ないんです、画面を切り替えたりする場合にはどうしても現在表示中の各フォ-ムビュ-と同期を取る必要が有りフレ-ムビュ-の状態を知る必要があります。又は色々なメインフレ-ムの現在のコンディションを各フォ-ムビュ-に連絡する事も必要になります、これらのことから別途準備する必要があります。

MainFrm.h : CMainFrame クラスのインターフェイス

// 属性

public:
CDocument* EkGetActiveDocument();

MainFrm.cpp : CMainFrame クラスの実装

下記の関数を使いドキュメントクラス内の特定データのポインタ-を取得して直にアクセスが読み書き可能です。

CDocument* CMainFrame::EkGetActiveDocument()
{
CWnd* pWnd=AfxGetMainWnd();
if (pWnd==NULL) return(NULL);

ASSERT_VALID(pWnd);
ASSERT_KINDOF(CFrameWnd,pWnd);
CFrameWnd* pMainFrame=static_cast>(pWnd); CFrameWnd pActiveFrame=pMainFrame->GetActiveFrame();

if (pActiveFrame==NULL) return(NULL);
return(pActiveFrame->GetActiveDocument());
}


使い方は下記の様に使用します

///////////////////// Vewを切り替えます ///////////////////////////

LRESULT CMainFrame::OneVewChenger(WPARAM wParam, LPARAM lParam)
{
CDocument* pActiveDoc=EkGetActiveDocument();//現在の有効なドキュメントクラスを取得する
CControlPracticeDoc* pMyDoc;

//======================================================================================
if (pActiveDoc==NULL)
        {
        if(pActiveDoc->IsKindOf(RUNTIME_CLASS(CControlPracticeDoc))){
                    pMyDoc=static_cast<CControlPracticeDoc*>(pActiveDoc);
                    }
        }
//======================================================================================
else if(pActiveDoc->IsKindOf(RUNTIME_CLASS(CControlPracticeDoc))){
        pMyDoc=static_cast<CControlPracticeDoc*>(pActiveDoc);
        }

if((pMyDoc->FormVewNmcer & 0x11)==0x11) {

以下は省略します。


メッセ-ジIDの登録

メッセ-ジIDの登録

ControlPracticeDoc.h : CControlPracticeDoc クラスのインターフェイス

#define ID_VEW_CHENGER (WM_USER + 100)

#define ID_FORM_LEFT_UPDATE_ID_OK_DIS (WM_USER + 101)

#define ID_FORM_RIGHT_UPDATE_ID_OK_DIS (WM_USER + 102)

#define ID_FORM_LEFT_UPDATE_ID_CANCEL_DIS (WM_USER + 103)

#define ID_FORM_RIGHTUPDATE_ID_CANCSL_DIS (WM_USER + 104)

#define ID_FORM_CONTROL_PRAVEW_ID_OK_DIS (WM_USER + 105)

#define ID_FORM_CONTROL_PRAVEWID_CANCSL_DIS (WM_USER + 106)

#define HINT_SIZE_CHENG (WM_USER + 107)


例外の多発で苦しむ

多くの方達がアプリケ-ション開発を終了した時点でリリ-スバ-ジョンに切り替えるのですが此処で遭遇するのが例外として警告とかシステムダウンに遭遇しどうしようもなくなる事が多いのですが何故か?これは開発中はマイクロソフトの強力なデバッガ-がアプリケ-ションプロジェクトを管理してくれているからであり潜在的な異常をすでに持っているから起きるのです多くのこの問題はメモリ-管理の不具合に寄り発生している、この時点では既に手遅れで作り直すしか対応できずしょうがなくデバッグモ-ドで販売するしかない状態になる。

コントロ-ルの本質はウインドウズです

マイクロソフトの言うコントロ-ルとはWindowsを意味しデホルトの状態では何も動かず変化がない、これは非常に難しいですコントロラ-の実装に関する全てのノウハウがこの時点で必要になりますこれらがMFCでの開発を困難にしているようです、試験的に組み立てを行いテストアップは不可能になりあらゆる箇所のクラス内に本格的にコードの記載が必要です。最低でも完璧な動作環境が必要になります、すべてのクラスが連携して動作する必要があります。


私が作成したアプリケ-ションです

多くのコントロ-ルを実装しています、どうですか?皆さん!


印刷ボタンが押された後の流れ

下記のアプリケ-ションで赤枠で囲まれた印刷ボタンが押された時にどの様な流れで印刷が起動するのかを説明しようと思う。

印刷(ボタン操作)

アプリケ-ション画面は左側と右側に分割されていますそうして左側にはツリ-コントロ-ルが表示され右側にはその他の色々なコントロ-ルが配置されています。今此処で印刷ボタンが押された押された時にどの様な動きがあるのでしょうか、最初に下記の関数が呼び出されます。

void RightFormVew::OnBnClickedPrint()

{
CControlPracticeDoc* pDoc = GetDocument(); //現在アクティブなドキュメントクラスを取得します
pDoc->FormVewNmcer |=0x44 ;//現在アクティブなドキュメントクラスに指示コ-ドを記載します
CWnd* pWnd=AfxGetMainWnd() ;//ここはウィンドウズハンドルを取得しなければなりません。
pWnd->SendMessage(ID_VEW_CHENGER);//メインフレ-ムへ向けて指示を発信
}


Mainframeに指示を伝える

上記で発行されたメッセ-ジを受け取る箇所はMainframeの先頭部分に下記の様に記載してあります。

pWnd->SendMessage(ID_VEW_CHENGER);この内容でメインフレ-ムへ向けて指示を発信されたコマンドはOneVewChenger()を起動するのです。

// CMainFrame

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_MESSAGE(ID_VEW_CHENGER,OneVewChenger)//VEWを切り替えます
END_MESSAGE_MAP()

OneVewChenge

LRESULT CMainFrame::OneVewChenger(WPARAM wParam, LPARAM lParam)
{
CDocument* pActiveDoc=EkGetActiveDocument();//現在の有効なドキュメントクラスを取得する
CControlPracticeDoc* pMyDoc;

//======================================================================================
if (pActiveDoc==NULL)
        {
        if(pActiveDoc->IsKindOf(RUNTIME_CLASS(CControlPracticeDoc))){
                    pMyDoc=static_cast<CControlPracticeDoc*>(pActiveDoc);
                    }
        }
//======================================================================================
else if(pActiveDoc->IsKindOf(RUNTIME_CLASS(CControlPracticeDoc))){
        pMyDoc=static_cast<CControlPracticeDoc*>(pActiveDoc);
        }
if((pMyDoc->FormVewNmcer & 0x44)==0x44) { 
        //印刷ボタンが押された時に此処で止まります >>直ぐに返信します
        //リセット 0x44 此処でFormv-vewクラスにメッセ-ジが発行されます
        pMyDoc->FormVewNmcer&=0xbb;pMyDoc->FormVewNmcer&=0xdd;pMyDoc->UpdateAllViews(NULL,IDS_TO_PRINT,this);}
//======================================================================================
return TRUE;

}


メインフレ-ムからの指示を受け起動します

/ ControlPracticeView.cpp : ControlPracticeView クラスの実装

void ControlPracticeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
int cunt=0;
CControlPracticeDoc* pDoc = GetDocument();
//========================================================
switch(lHint){
case ID_FORM_CONTROL_PRAVEW_ID_OK_DIS:
cunt=1;//試験
break ;
case ID_FORM_CONTROL_PRAVEWID_CANCSL_DIS:
cunt=1;//試験
break;
case IDS_TO_PRINT://印刷開始 メインフレ-ムからの指示を受けてこの箇所が起動します
ControlPracticeView::OnFilePrintPreview();
break;
//==============ビューが切り替わりが強要されました==========
case 0:
arrayDirectoryList.RemoveAll();//リセット
SearchFile(_T(“O:\SD I”)) ;
cunt=(int)arrayDirectoryList.GetCount();
break;
}
}


OnFilePrintPreview();

標準的な印刷処理方法をMFCが提供されますが簡単では有りません、又印刷するには用紙のサイズとかモジサイズも指定しなければ行けないのですが範囲は広く例えばBMPの印刷またヘッダ-フッター幅の指定とか、更にはカラ-印刷等々の沢山の処理と関数を自分で用意しなければなりません。

これらの機能はすべて個別に処理する必要が有るのですが次のページで説明します。


VC++ MFCに印刷機構を組み込む手順の解説(2)   

MFC VC++ 印刷機構を組み込む ヘッダ-ファイル内容完全版PDFファイル