none
印刷ダイアログの「ページ指定」に現在ページを初期値として入れたい。

    質問

  • いつもお世話になっております。arubi-momoと申します。

    開発環境は、Windows7 64bit VisualStudio2010 SP1  MFC です。

    SDIのプロジェクトで、印刷ダイアログを表示して印刷する機能をつけています。

    現在ページを印刷する機能をつけたいのですが、印刷ダイアログに現在ページの選択を追加するにはカスタマイズが必要になります。

    なるべく工数をかけずに機能実現したいということで、ページ指定の開始位置に、初期値として現在ページを表示しておくことで、「ページ指定」を選択するだけで現在ページ印刷ができるような仕様にすることになりました。

    CPrintDialogの初期値は、引数のCPrintInfoを変更することで設定できるのですが、

    ページ指定の「開始ページ」には、初期値として「ドキュメントの最小ページ(MinPage)」が表示されていました。

    そのため、「開始ページ」に「現在ページ」を表示するためには、このMinPageの値を変更する必要があります。

    しかし、MinPageを変更してしまうと色々と弊害がありました。

    まず「すべてのページ」印刷を行った場合、MinPage~Maxpageまでを印刷するため、開始ページが現在ページからになってしまいます。しかしこれは、すべてのページの印刷実行前にMinPageを元の最小ページに戻すことで回避することができました。

    ただもう一つの問題がまだ解決できていません。

    例えば、現在ページが「2」の場合、MinPageを2に変更して印刷ダイアログを表示します。すると、開始ページには「2」と表示されます。

    印刷ダイアログ上で、開始ページを「1」、最終ページを「2」にしてOKボタンを押下した場合、MinPageが2の状態で、開始ページが1となっているため、印刷ダイアログ側で入力チェックがかかっているようで「2~65535 までの数字を入力してください」というエラーメッセージが表示されてしまいます。

    入力チェックはViewに処理が戻ってくる前に行われるため、すべてのページ印刷の時のように回避することができませんでした。

    印刷ダイアログに初期値を設定する方法、もしくは現在ページを簡単に印刷できる方法などがありましたら、ご教示いただきたく投稿いたしました。

    勉強不足で恐縮ですが、何卒、よろしくお願いいたします。

    2018年1月7日 4:28

回答

  • 早速のご返信ありがとうございます。

    こちらでも、初期値として開始ページと終了ページに値を設定すると、自動的に「ページ設定」ラジオボタンが選択状態になってしまう現象を確認しました。どうも手動で開始ページと終了ページに値を設定してもラジオボタンの選択が「ページ設定」に移るのでその処理が動いてしまっているようです。

    そこで、SetDlgItemInt 関数の直後に下記のコードを呼び出すことで、ラジオボタンの選択を「すべて」に移すようにしてはどうでしょうか。(他にもやり方があると思いますが)

    CheckRadioButton(0x420, 0x422, 0x420);
    // 0x420、 0x422 などのコントロール ID は Spy++ で調べました。
    


    ※ 前回投稿のコードも修正しておきます。参考になりましたら幸いです。

    • 回答としてマーク arubi_momo 2018年1月10日 0:44
    2018年1月9日 13:45
  • 印刷ダイアログに初期値を設定する方法ですが、2 つの方法が思いつきました。

    1 つは、CPrintDialog クラスを派生させて、OnInitDialog() にて開始ページを終了ページの値を設定する方法です。

    // ヘッダー
    class CMyPrintDialog : public CPrintDialog
    {
    	DECLARE_DYNAMIC(CMyPrintDialog)
    public:
    	UINT m_uCurrentPage;
    	CMyPrintDialog(UINT uCurrentPage = -1);
    protected:
    	BOOL OnInitDialog();
    	DECLARE_MESSAGE_MAP()
    };
    // コード
    #include "stdafx.h"
    #include "MyPrintDialog.h"
    
    IMPLEMENT_DYNAMIC(CMyPrintDialog, CPrintDialog)
    
    CMyPrintDialog::CMyPrintDialog(UINT uCurrentPage) :
    	CPrintDialog(FALSE)
    {
    	m_uCurrentPage = uCurrentPage;
    	m_pd.Flags &= ~PD_NOPAGENUMS;
    }
    
    BEGIN_MESSAGE_MAP(CMyPrintDialog, CPrintDialog)
    END_MESSAGE_MAP()
    
    BOOL CMyPrintDialog::OnInitDialog()
    {
    	CPrintDialog::OnInitDialog();
    	if (m_uCurrentPage != -1)
    	{
    		SetDlgItemInt(0x480, m_uCurrentPage, 0); // 開始ページを指定
    		SetDlgItemInt(0x481, m_uCurrentPage, 0); // 終了ページを指定
    		CheckRadioButton(0x420, 0x422, 0x420); // ラジオボタンの選択を「すべて」に戻す
    	}
    	return TRUE;
    }
    // 使用例
    CMyPrintDialog dlg(5); // 現在ページを 5 ページ目に設定
    
    // 最小ページと最大ページを指定
    dlg.m_pd.nMinPage = 1;
    dlg.m_pd.nMaxPage = 0xffff;
    
    if (dlg.DoModal() == IDOK)
    {
    	MessageBox(TEXT("印刷処理"));
    }


    もう 1 つは、フックプロシージャーを使って WM_INITDIALOG で初期値を設定する方法です。

    UINT g_nCurrentPage;
    
    UINT_PTR CALLBACK fnPrintHook(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	if (msg == WM_INITDIALOG)
    	{
    		SetDlgItemInt(hWnd, 0x480, g_nCurrentPage, 0); // 開始ページを指定
    		SetDlgItemInt(hWnd, 0x481, g_nCurrentPage, 0); // 終了ページを指定
    		CheckRadioButton(hWnd, 0x420, 0x422, 0x420); // ラジオボタンの選択を「すべて」に戻す
    	}
    	return 0;
    }
    // 使用例
    CPrintDialog dlg(FALSE);
    
    dlg.m_pd.Flags |= PD_ENABLEPRINTHOOK;
    dlg.m_pd.Flags &= ~PD_NOPAGENUMS;
    
    // 最小ページと最大ページを指定
    dlg.m_pd.nMinPage = 1;
    dlg.m_pd.nMaxPage = 0xffff;
    
    // フックプロシージャーとして fnPrintHook 関数を指定
    dlg.m_pd.lpfnPrintHook = fnPrintHook;
    
    // 現在ページを 5 ページ目に設定
    g_nCurrentPage = 5;
    
    if (dlg.DoModal() == IDOK)
    {
    	MessageBox(TEXT("印刷処理"));
    }
    • 編集済み kenjinoteMVP 2018年1月9日 13:53 コードを修正しました。
    • 回答としてマーク arubi_momo 2018年1月10日 0:44
    2018年1月9日 7:02

すべての返信

  • 印刷ダイアログに初期値を設定する方法ですが、2 つの方法が思いつきました。

    1 つは、CPrintDialog クラスを派生させて、OnInitDialog() にて開始ページを終了ページの値を設定する方法です。

    // ヘッダー
    class CMyPrintDialog : public CPrintDialog
    {
    	DECLARE_DYNAMIC(CMyPrintDialog)
    public:
    	UINT m_uCurrentPage;
    	CMyPrintDialog(UINT uCurrentPage = -1);
    protected:
    	BOOL OnInitDialog();
    	DECLARE_MESSAGE_MAP()
    };
    // コード
    #include "stdafx.h"
    #include "MyPrintDialog.h"
    
    IMPLEMENT_DYNAMIC(CMyPrintDialog, CPrintDialog)
    
    CMyPrintDialog::CMyPrintDialog(UINT uCurrentPage) :
    	CPrintDialog(FALSE)
    {
    	m_uCurrentPage = uCurrentPage;
    	m_pd.Flags &= ~PD_NOPAGENUMS;
    }
    
    BEGIN_MESSAGE_MAP(CMyPrintDialog, CPrintDialog)
    END_MESSAGE_MAP()
    
    BOOL CMyPrintDialog::OnInitDialog()
    {
    	CPrintDialog::OnInitDialog();
    	if (m_uCurrentPage != -1)
    	{
    		SetDlgItemInt(0x480, m_uCurrentPage, 0); // 開始ページを指定
    		SetDlgItemInt(0x481, m_uCurrentPage, 0); // 終了ページを指定
    		CheckRadioButton(0x420, 0x422, 0x420); // ラジオボタンの選択を「すべて」に戻す
    	}
    	return TRUE;
    }
    // 使用例
    CMyPrintDialog dlg(5); // 現在ページを 5 ページ目に設定
    
    // 最小ページと最大ページを指定
    dlg.m_pd.nMinPage = 1;
    dlg.m_pd.nMaxPage = 0xffff;
    
    if (dlg.DoModal() == IDOK)
    {
    	MessageBox(TEXT("印刷処理"));
    }


    もう 1 つは、フックプロシージャーを使って WM_INITDIALOG で初期値を設定する方法です。

    UINT g_nCurrentPage;
    
    UINT_PTR CALLBACK fnPrintHook(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	if (msg == WM_INITDIALOG)
    	{
    		SetDlgItemInt(hWnd, 0x480, g_nCurrentPage, 0); // 開始ページを指定
    		SetDlgItemInt(hWnd, 0x481, g_nCurrentPage, 0); // 終了ページを指定
    		CheckRadioButton(hWnd, 0x420, 0x422, 0x420); // ラジオボタンの選択を「すべて」に戻す
    	}
    	return 0;
    }
    // 使用例
    CPrintDialog dlg(FALSE);
    
    dlg.m_pd.Flags |= PD_ENABLEPRINTHOOK;
    dlg.m_pd.Flags &= ~PD_NOPAGENUMS;
    
    // 最小ページと最大ページを指定
    dlg.m_pd.nMinPage = 1;
    dlg.m_pd.nMaxPage = 0xffff;
    
    // フックプロシージャーとして fnPrintHook 関数を指定
    dlg.m_pd.lpfnPrintHook = fnPrintHook;
    
    // 現在ページを 5 ページ目に設定
    g_nCurrentPage = 5;
    
    if (dlg.DoModal() == IDOK)
    {
    	MessageBox(TEXT("印刷処理"));
    }
    • 編集済み kenjinoteMVP 2018年1月9日 13:53 コードを修正しました。
    • 回答としてマーク arubi_momo 2018年1月10日 0:44
    2018年1月9日 7:02
  • kenjinoteさま

    いつもお世話になっております。arubi-momoです。

    コードまでいただきまして、ありがとうございます!!

    早速試してみたところ、あと一歩のところで躓いています。

    私がコードをしっかり理解できていないせいと思いますが、ご教示いただければ助かります。

    CPrintDialog の派生クラスを作成する方法で行ってみました。

    dlg.m_pd.Flags |= PD_ENABLEPRINTHOOK;
    dlg
    .m_pd.Flags &= ~PD_NOPAGENUMS;

    この部分は、ダイアログの設定を指定しているのだと思いますが、フックを有効にし、ページ設定に関するコントロールを有効にする、ということをしていると認識しています。

    今回は、ダイアログの初期表示として、

    ・すべてのページが選択されている

    ・ページ設定は未選択状態だが、開始ページに「現在ページ」が初期値として入力されている

    という状態にしたいと考えており、フラグの設定を以下の通り追加してみました。

    dlg.m_pd.Flags |= PD_ENABLEPRINTHOOK;
    dlg.m_pd.Flags &= PD_ALLPAGES;
    //dlg.m_pd.Flags &= ~PD_NOPAGENUMS;

    すると、もともとの印刷ダイアログとは異なるレイアウトのダイアログに変わってしまい、想定通りの動作をしてくれませんでした。Flagsの部分は色々試してみたのですが、開始ページと終了ページに値が入っていると、自動的に「ページ設定」が選択状態になってしまうのでしょうか。。。

    何度も大変恐縮ですが、よろしくお願いいたします。

    2018年1月9日 10:20
  • 早速のご返信ありがとうございます。

    こちらでも、初期値として開始ページと終了ページに値を設定すると、自動的に「ページ設定」ラジオボタンが選択状態になってしまう現象を確認しました。どうも手動で開始ページと終了ページに値を設定してもラジオボタンの選択が「ページ設定」に移るのでその処理が動いてしまっているようです。

    そこで、SetDlgItemInt 関数の直後に下記のコードを呼び出すことで、ラジオボタンの選択を「すべて」に移すようにしてはどうでしょうか。(他にもやり方があると思いますが)

    CheckRadioButton(0x420, 0x422, 0x420);
    // 0x420、 0x422 などのコントロール ID は Spy++ で調べました。
    


    ※ 前回投稿のコードも修正しておきます。参考になりましたら幸いです。

    • 回答としてマーク arubi_momo 2018年1月10日 0:44
    2018年1月9日 13:45
  • kenjinoteさま

    いつもお世話になっております。arubi-momoです。

    ご回答いただき、またコードまで修正いただいてありがとうございます。

    早速試してみたところ、想定通りの動作ができ、解決いたしました!本当に感謝です。

    また、コントロールIDの調べ方までご教示いただき、ありがとうございました。

    実はこの前の返信投稿でそのことを質問しようか悩んで勇気が出ず断念していました。

    恥ずかしながらspy++というツールがあることは知っていましたが、使ったことはありませんでした。どういうときに使えばよいのかも理解していませんでした。調べてみて使ってみます!

    ありがとうございました。今後ともどうぞよろしくお願いいたします。

    2018年1月10日 0:55