【VC++】SDIにリストコントロールを追加してイベント処理を実装する

<機能>

(1)MFCのSDIアプリケーションにリストコントロール(CListCtrl)を追加する

(2)リストコントロールをCreate(サイズ・WindowStyle指定)する

(3)リストコントロールのフォントを変更してみる(MS UI Gothic使用)

(4)ヘッダ設定(InsertColumn)、データ設定(InsertItem)を行う

(5)イベントを追加する(WindowProc)

  ・LVN_ITEMCHANGED : リストコントロールに変更があった
  ・LVN_COLUMNCLICK : リストコントロールのヘッダが左クリックされた

 

<実行イメージ>

フォントをMS UI Gothicに変更しヘッダ・データをセット

※データは東京都の市区町村別人口

VisualStudio,MFC,SDI,CListCtrl,実行イメージ,
 

リスト選択により選択行番号と選択行の情報を表示

VisualStudio,MFC,SDI,CListCtrl,LVN_ITEMCHANGED,

項目行左クリックにより選択カラム番号を表示

VisualStudio,MFC,SDI,CListCtrl,LVN_COLUMNCLICK,
 

<動作検証&開発環境>
Visual Studio Community 2017

 

<使い方>

1.MFCアプリケーションでプロジェクトを作成

2.アプリケーションの種類でシングルドキュメントを選択

VisualStudio,MFC,SDI,CListCtrl,アプリケーションの種類,
 

3.ユーザーインターフェイス機能でくクラシックメニューを使用するを選択

※その他の設定は下図参照

VisualStudio,MFC,SDI,CListCtrl,ユーザーインターフェイス機能,
 

4.高度な機能で不要なチェックを外す

VisualStudio,MFC,SDI,CListCtrl,高度な機能,
 

5.プロジェクト構成を確認しソースを追加する

VisualStudio,MFC,SDI,CListCtrl,ソリューション,プロジェクト構成,
 

6.クラスウィザードにてCChileViewクラスにOnCreateハンドラーを追加

※OnCreateでリストコントロールを生成しデータを設定する

VisualStudio,MFC,SDI,CListCtrl,クラスウィザード,OnCreate,
 

7.クラスウィザードにてCChileViewクラスにWindowProcハンドラーを追加

※WindowProcでリストコントロールのイベント処理を行う

VisualStudio,MFC,SDI,CListCtrl,クラスウィザード,WindowProc,
 

MainFrm.cpp

//メインフレームのサイズ設定を行う

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;

    cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
         | WS_SYSMENU;

    //cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
    //ウィンドウサイズとクライアント領域を一致させる
    cs.dwExStyle = WS_EX_CLIENTEDGE;
    cs.lpszClass = AfxRegisterWndClass(0);

    //作業領域のサイズを取得
    //画面全体からシステムのタスクバーやアプリケーションのツールバーが占有する領域を除いた部分
    CRect rcSpara;
    SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcSpara, NULL);
    //ウィンドウサイズの設定
    CRect rect(0, 0, 600, 400);
    ::AdjustWindowRectEx(&rect, cs.style, TRUE, cs.dwExStyle);
    //ウィンドウサイズを取得
    cs.cx = rect.Width();
    cs.cy = rect.Height();
   
    //画面中央に表示
    cs.x = rcSpara.left + (rcSpara.Width() - cs.cx) / 2;
    cs.y = rcSpara.top + (rcSpara.Height() - cs.cy) / 2;

    return TRUE;
}

ChildView.h

//フォント変更するためCFontオブジェクトを追加

class CChildView : public CWnd
{


//省略~~


public:
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

private:
    const int D_IDLISTVIEW = 1000;
    void InsertListCtrlItems(CListCtrl *pList);
public:
    virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
    CFont *m_pFont;
};

ChildView.cpp

CChildView::CChildView()
{
    //子ウィンドにフォントをセット
    m_pFont = new CFont;
    LOGFONT logFont;
    logFont.lfHeight = 12;
    logFont.lfWidth = 10;
    logFont.lfEscapement = 0;
    logFont.lfOrientation = 0;
    logFont.lfWeight = FW_DONTCARE;
    logFont.lfItalic = FALSE;
    logFont.lfUnderline = FALSE;
    logFont.lfStrikeOut = FALSE;
    logFont.lfCharSet = DEFAULT_CHARSET;
    logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
    logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    logFont.lfQuality = DEFAULT_QUALITY;
    logFont.lfPitchAndFamily = FF_DONTCARE;
    lstrcpy(logFont.lfFaceName, L"MS UI Gothic");
    m_pFont->CreateFontIndirect(&logFont);
}

CChildView::~CChildView()
{
    //フォントオブジェクトを破棄
    delete m_pFont;
}

/***********************************************************
OnCreate
SDIで子ウィンドウの作成時にリストコントロール(CListCtrl)を生成
***********************************************************/

int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    //ウィンドウサイズを取得
    CFrameWnd *pFrm = GetParentFrame();
    CRect rect;
    pFrm->GetClientRect(&rect);

    //リストコントロール(レポート形式)を配置
    //ウィンドウサイズに対して余白10で配置する
    CListCtrl *pListctrl = new CListCtrl();
    //List-View Window Stylesはデベロッパーセンターを参照
    pListctrl->Create(

        WS_VISIBLE | WS_BORDER | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_REPORT | LVS_SINGLESEL,
        CRect(10, 10, rect.Width()-20, rect.Height()-20), this, D_IDLISTVIEW);
   
    //拡張スタイルを設定
    pListctrl->SetExtendedStyle(pListctrl->GetExtendedStyle() | LVS_EX_FULLROWSELECT);
   
    //リストカラムセッティング
    LV_COLUMN lvclm;
    ZeroMemory(&lvclm, sizeof(LV_COLUMN));
    lvclm.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;

    //インデックス0の列はは常にLVCFMT_LEFTとなる
    //詳細はデベロッパーセンターのRemarks参照
    //lvclm.fmt = LVCFMT_CENTER;
    lvclm.iSubItem = 0;
    lvclm.pszText = L"地域コード";
    lvclm.cx = 130;
    pListctrl->InsertColumn(0, &lvclm);

    lvclm.fmt = LVCFMT_LEFT;
    lvclm.iSubItem = 1;
    lvclm.pszText = L"市区町村名";
    lvclm.cx = 250;
    pListctrl->InsertColumn(1, &lvclm);

    lvclm.fmt = LVCFMT_RIGHT;
    lvclm.iSubItem = 2;
    lvclm.pszText = L"人口(人)";
    lvclm.cx = 150;
    pListctrl->InsertColumn(2, &lvclm);

    //アイテムセット
    InsertListCtrlItems(pListctrl);
    //フォントをセット
    GetDlgItem(D_IDLISTVIEW)->SetFont(m_pFont);

    return 0;
}

/***********************************************************
InsertListCtrlItems
リストコントロールにデータ(東京都市区町村の人口)をセット
***********************************************************/

void CChildView::InsertListCtrlItems(CListCtrl *pList)
{
    TCHAR twk[64];
    int idx=0;
    LVITEM lvitm;

    struct
    {
        int id;
        TCHAR name[128];
        int population;
    }item[]={
        { 13101,_T("東京都 千代田区"),61218 },{ 13102,_T("東京都 中央区"),156256 },
        { 13103,_T("東京都 港区"),253018 },{ 13104,_T("東京都 新宿区"),343533 },
        { 13105,_T("東京都 文京区"),227141 },{ 13106,_T("東京都 台東区"),202947 },
        { 13107,_T("東京都 墨田区"),264229 },{ 13108,_T("東京都 江東区"),510574 },
        { 13109,_T("東京都 品川区"),397710 },{ 13110,_T("東京都 目黒区"),283005 },
        { 13111,_T("東京都 大田区"),728423 },{ 13112,_T("東京都 世田谷区"),921720 },
        { 13113,_T("東京都 渋谷区"),229670 },{ 13114,_T("東京都 中野区"),335745 },
        { 13115,_T("東京都 杉並区"),575841 },{ 13116,_T("東京都 豊島区"),298050 },
        { 13117,_T("東京都 北区"),348547 },{ 13118,_T("東京都 荒川区"),216273 },
        { 13119,_T("東京都 板橋区"),574058 },{ 13120,_T("東京都 練馬区"),731696 },
        { 13121,_T("東京都 足立区"),677514 },{ 13122,_T("東京都 葛飾区"),450846 },
        { 13123,_T("東京都 江戸川区"),691084 },{ 13201,_T("東京都 八王子市"),577910 },
        { 13202,_T("東京都 立川市"),179390 },{ 13203,_T("東京都 武蔵野市"),146381 },
        { 13204,_T("東京都 三鷹市"),190432 },{ 13205,_T("東京都 青梅市"),135789 },
        { 13206,_T("東京都 府中市"),261829 },{ 13207,_T("東京都 昭島市"),111902 },
        { 13208,_T("東京都 調布市"),235243 },{ 13209,_T("東京都 町田市"),434091 },
        { 13210,_T("東京都 小金井市"),123813 },{ 13211,_T("東京都 小平市"),192874 },
        { 13212,_T("東京都 日野市"),188327 },{ 13213,_T("東京都 東村山市"),150180 },
        { 13214,_T("東京都 国分寺市"),124501 },{ 13215,_T("東京都 国立市"),74610 },
        { 13218,_T("東京都 福生市"),58210 },{ 13219,_T("東京都 狛江市"),82357 },
        { 13220,_T("東京都 東大和市"),84664 },{ 13221,_T("東京都 清瀬市"),75377 },
        { 13222,_T("東京都 東久留米市"),116360 },{ 13223,_T("東京都 武蔵村山市"),71651 },
        { 13224,_T("東京都 多摩市"),147691 },{ 13225,_T("東京都 稲城市"),90225 },
        { 13227,_T("東京都 羽村市"),55225 },{ 13228,_T("東京都 あきる野市"),80373 },
        { 13229,_T("東京都 西東京市"),202201 },{ 13303,_T("東京都 西多摩郡瑞穂町"),33102 },
        { 13305,_T("東京都 西多摩郡日の出町"),17404 },{ 13307,_T("東京都 西多摩郡檜原村"),2096 },
        { 13308,_T("東京都 西多摩郡奥多摩町"),5058 },{ 13361,_T("東京都 大島町"),7580 },
        { 13362,_T("東京都 利島村"),343 },{ 13363,_T("東京都 新島村"),2630 },
        { 13364,_T("東京都 神津島村"),1845 },{ 13381,_T("東京都 三宅島三宅村"),2383 },
        { 13382,_T("東京都 御蔵島村"),343 },{ 13401,_T("東京都 八丈島八丈町"),7330 },
        { 13402,_T("東京都 青ヶ島村"),174 },{ 13421,_T("東京都 小笠原村"),3067 },
        0
    };
    for (INT i = 0;; i++)
    {
        if (item[i].id == 0) break;
        ZeroMemory(&lvitm, sizeof(LVITEM));
        lvitm.mask = LVIF_TEXT;
        lvitm.iItem = pList->GetItemCount();
        lvitm.iSubItem = 0;
        ZeroMemory(&twk, sizeof(twk));
        wsprintf(twk, _T("%d"), item[i].id);
        lvitm.pszText = twk;
        idx = ListView_InsertItem(pList->GetSafeHwnd(), &lvitm);
        //idx = pList->InsertItem(&lvitm);
        if (idx == (-1))
        {
            AfxMessageBox(L"InsertItem Error!!",MB_ICONSTOP);
            return;
        }
        ZeroMemory(&lvitm, sizeof(LVITEM));
        lvitm.mask = LVIF_TEXT;
        lvitm.iItem = idx;
        lvitm.iSubItem = 1;
        lvitm.pszText = item[i].name;
        ListView_SetItem(pList->GetSafeHwnd(), &lvitm);
        //pList->SetItem(&lvitm);

        ZeroMemory(&lvitm, sizeof(LVITEM));
        lvitm.mask = LVIF_TEXT;
        lvitm.iItem = idx;
        lvitm.iSubItem = 2;
        ZeroMemory(&twk, sizeof(twk));
        wsprintf(twk, _T("%d"), item[i].population);
        lvitm.pszText = twk;
        ListView_SetItem(pList->GetSafeHwnd(), &lvitm);
        //pList->SetItem(&lvitm);
    }
}

/***********************************************************
WindowProc
リストコントロールのイベント処理
LVN_ITEMCHANGED : リストコントロールに変更があった
LVN_COLUMNCLICK : リストコントロールのヘッダが左クリックされた
***********************************************************/

LRESULT CChildView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    LV_DISPINFO *lvdisp;
    NM_LISTVIEW *pNMLV;
    CString cs;
    int idx;

    switch (message)
    {
    case WM_NOTIFY:
       
        //リストコントロールからのメッセージのみ処理する
        if ((int)wParam == D_IDLISTVIEW) {
            lvdisp = (LV_DISPINFO *)lParam;
            pNMLV = (NM_LISTVIEW *)lParam;
            //リストビューを取得
            CListCtrl *pListCtrl = (CListCtrl *)GetDlgItem(D_IDLISTVIEW);
            //選択されている行のインデックスを取得
            idx = pNMLV->iItem;

            switch (lvdisp->hdr.code) {
            case LVN_ITEMCHANGED:
                //選択行の情報を表示する
                if ((pNMLV->uChanged & LVIF_STATE) && (pNMLV->uNewState & LVIS_SELECTED)) {
                    cs.Format(L"%d行目¥r¥n地域コード  [%s]¥r¥n市区町村名  [%s]¥r¥n人口     [%s]",
                        idx+1,pListCtrl->GetItemText(idx, 0),

                        pListCtrl->GetItemText(idx, 1),

                        pListCtrl->GetItemText(idx, 2));
                    AfxMessageBox(cs,MB_ICONINFORMATION);
                }
                break;
            case LVN_COLUMNCLICK:
                //iSubItemを参照してヘッダのクリックされた列を表示する
                cs.Format(L"ヘッダ行の%d列目が左クリックされました", pNMLV->iSubItem+1);
                AfxMessageBox(cs,MB_ICONINFORMATION);
                break;
            }
        }
        break;

    default:
        ;
    }

    return CWnd::WindowProc(message, wParam, lParam);
}

 

よろしければポチッと押してください

プログラマー ブログランキングへ


【VC++】operatorキーワードで演算子をオーバーロードする

0

    <機能>

    (1)社員ID(int)、社員名(CString)、通勤費支給(BOOL)を持つクラスを定義

    (2)クラスのメンバ変数を operator= でコピーできるようにする

     オブジェクトA = オブジェクトB でメンバ変数をコピー

    (3)クラスインスタンスを動的配列(std::vector)に operator+ で追加する

    (4)追加と同時にソート処理を実施する

     オブジェクトA + オブジェクトB でオブジェクトAの動的配列にオブジェクトBを追加

     オブジェクトAの動的配列を社員IDの昇順でソート(std::sort)

     

    <実行イメージ>

    "出力"ウィンドウに結果を表示します

    ※表示されていない場合は[表示]メニュー→[出力]

    VC,MFC,VisualStudio,operator,sort,演算子のオーバーロード,
     

    <動作検証&開発環境>

    Visual Studio Community 2017

     

    <使い方>

    1.プロジェクトの種類でWindowsデスクトップウィザードを選択

    2.アプリケーションの種類で「コンソールアプリケーション」を選択

    3.共通ヘッダの「MFC」にチェック

    VC,MFC,VisualStudio,operator,sort,演算子のオーバーロード,
     

    4.クラスを追加

     クラス名:CShainClass

     ファイル名:ShainClass.h

     (ShainClass.cppは本サンプルでは使用しません)

    5.ソースを追加

     

    ShainClass.h

    #pragma once
    #include <vector>
    #include <algorithm> //sort
    //社員クラス(CShainClass)
    class CShainClass
    {
    private:
        int iShainID;           //社員ID
        CString strName;    //社員氏名
        BOOL bAllowance;   //通勤手当支給対象
        //全社員情報を格納するvector配列
        std::vector<CShainClass> vShainClass;
        //社員情報を社員IDが小さい順でソートする
        struct sort_shainNo : std::binary_function<CShainClass&, CShainClass&, bool>
        {
            bool operator()(CShainClass &a, CShainClass &b)
            {
                if (a.iShainID < b.iShainID) return true;
                return false;
            }
        };
    public:
        //コンストラクタ(初期化)
        CShainClass() :iShainID(0), strName(""), bAllowance(FALSE) {};
        //デストラクタ
        ~CShainClass() {};
        //set/get
        void SetShainData(int a, CString b, bool c) {
            iShainID = a;
            strName = b;
            bAllowance = c;
        }
        int GetID() { return iShainID; }
        CString GetName() { return strName; }
        bool GetAllowance() { return bAllowance; }
        auto GetBegin() { return vShainClass.begin();}
        auto GetEnd() { return vShainClass.end(); }
        //=演算子をオーバーロード(メンバ変数をコピーする)
        //詳細はDeveloperNetwork参照

        void operator = (CShainClass& shain)
        {
            iShainID = shain.iShainID;
            strName = shain.strName;
            bAllowance = shain.bAllowance;
        }
        //+演算子をオーバーロード(メンバ変数をコピー&ソートする)
        //社員情報を追加(push_back)

        void operator + (CShainClass& shain)
        {
            vShainClass.push_back(shain);
            std::sort(vShainClass.begin(), vShainClass.end(), sort_shainNo());
        }
    };

     

    Main(Project1.cpp)
    #include "stdafx.h"
    #include "Project1.h"
    #include "ShainClass.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif

    // 唯一のアプリケーション オブジェクトです。
    CWinApp theApp;
    using namespace std;
    int main()
    {
        //省略~~
        if (hModule != nullptr)
        {
            if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
            {
                //省略~~
            }
            else
            {
                CString csmsg,cstmp;
               
                //operator= のテスト ここから ///////////////////////
                CShainClass tmp1, tmp2;
                //tmp2に値をセット
                tmp2.SetShainData(99,L"OperatorTest Ichiro",false);
                //tmp1に値にtmp2をコピー
                tmp1 = tmp2;
                //operator= の結果を確認
                cstmp.Format(L"tmp1.iShainID=%d tmp1.strName=%s tmp1.bAllowance=%d¥r¥n¥r¥n",
                                        tmp1.GetID(), tmp1.GetName(), tmp1.GetAllowance());
                csmsg = L"¥r¥n□operator= のテスト¥r¥n" + cstmp;
                //operator= のテスト ここまで ///////////////////////
               
                CShainClass allShain, tmpShain;
                //要素を定義して全社員クラスに追加する
                //追加と同時にソートされる

                tmpShain.SetShainData(71, L"山田太郎", false);
                allShain + tmpShain;
                tmpShain.SetShainData(167, L"鈴木花子", true);
                allShain + tmpShain;
                tmpShain.SetShainData(108, L"佐々木小次郎", true);
                allShain + tmpShain;
                tmpShain.SetShainData(9, L"青木幸子", true);
                allShain + tmpShain;
                //全社員クラスの値を確認(追加&ソート)
                csmsg += L"□全社員クラスの値を確認(operator+ で追加とソート)¥r¥n";
                for (auto itr = allShain.GetBegin(); itr != allShain.GetEnd(); ++itr)
                {
                    CString cwk = itr->GetName();
                    for (int i = cwk.GetLength()*sizeof(TCHAR); i <= 20; i++)
                    {
                        cwk += L" ";
                    }
                   
                    cstmp.Format(L"社員ID[%03d]  社員氏名[%-s]  通勤費支給[%d]¥r¥n",
                                            itr->GetID(),cwk,itr->GetAllowance());
                    csmsg += cstmp;
                }
                TRACE(csmsg);
            }
        }
        else
        {
            //省略~~
        }
        return nRetCode;
    }
     
    よろしければポチッと押してください

    【VC++】エディットボックスに半角英数のみ入力できるようにする

    0

      <機能>

      (1)入力は半角英数のみ、文字数の上限チェックをクラスで実装する

      (2)OnEnChangeで半角英数チェックを行う

      (3)OnKeyDownで入力文字数の上限チェックを行う

      (4)入力制限クラスを複数のエディットボックスに適用する

       

      <実行イメージ>

      半角英数チェックと文字数の上限チェックを行う

      VisualStudio,MFC,VC++,半角英数,入力チェック,クラス,
       

      <動作検証&開発環境>

      Visual Studio Community 2017

       

      <使い方>

      1.ダイアログベースでMFCApplication1プロジェクトを作成します

      VisualStudio,MFC,VC++,アプリケーションの種類,

      2.クラスウィザードでMFCクラスを追加します

      VisualStudio,MFC,VC++,クラスウィザード,
       

      基底クラスに「CEdit」を選択

      クラス名を「CEditTest」とします

      VisualStudio,MFC,VC++,クラスウィザード,クラス追加,
       

      3.クラスウィザードでCEditTestクラスに下記イベントを追加します

      OnEnChange : このイベントで半角英数チェックを行います

      OnKeyDown : このイベントで上限文字数チェックを行います

      VisualStudio,MFC,VC++,イベント,OnEnChange,OnKeyDown,
       

      4.IDD_MFCAPPLICATION1_DIALOGにエディットボックスを2つ追加します

      VisualStudio,MFC,VC++,Edit,
       

      5.追加したエディットボックスにそれぞれメンバ変数を追加します

      ・コントロール変数にチェック

      ・カテゴリ:Control

      ・変数の種類:CEditTest(CEditTestクラスの変数とする)

      ・変数名はそれぞれm_Edit1 、 m_Edit2 とします

      VisualStudio,MFC,VC++,メンバ変数の追加ウィザード,

       

      6.ソースを追加してください

       

      CEditTest.h

      class CEditTest : public CEdit
      {
          DECLARE_DYNAMIC(CEditTest)
      public:
          CEditTest();
          virtual ~CEditTest();
      protected:
          DECLARE_MESSAGE_MAP()
      public:
          afx_msg void OnEnChange();
          afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
      };

       

      CEditTest.cpp

      BEGIN_MESSAGE_MAP(CEditTest, CEdit)
          ON_CONTROL_REFLECT(EN_CHANGE, &CEditTest::OnEnChange)
          ON_WM_KEYDOWN()
      END_MESSAGE_MAP()

      /***********************************************************
      OnEnChange
      エディットコントロールの内容を変更したイベントハンドラ
      半角英数以外の入力があった場合は文字を削除する
      ***********************************************************/

      void CEditTest::OnEnChange()
      {
          CString cs;
          this->GetWindowText(cs);
          //数値チェックを行う
          CString csChk = cs.SpanIncluding(_T("abcdefghujklmnopqrstuvwxyz ¥
                                              ABCDEFGHIJKLMNOPQRSTUVWXYZ ¥
                                              0123456789"));
          //半角英数以外が混ざっていたら取り除いて設定する
          if (csChk != cs) {
              TRACE(L"<<Error>> 半角英数以外が混ざっていました [%s]¥r¥n", cs);
              //半角英数以外の文字を取り除く
              int ichi = csChk.GetLength();
              cs.Replace(cs.Mid(ichi,1),L"");
              this->SetWindowText(cs);
          }
      }

      /***********************************************************
      OnKeyDown
      システムキー以外のキーが押下されたイベントハンドラ
      入力文字数が入力条件を超えていないかチェック
      ***********************************************************/

      void CEditTest::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
      {
          CString cs;
          //入力上限バイト数を取得
          int iLimit = this->GetLimitText();
          //入力済み文字列を取得
          this->GetWindowText(cs);
          TRACE(L"text=[%s] limit/nowlength=%d/%d¥r¥n",cs,iLimit,cs.GetLength());
          //既に入力上限に達しているときは何もしない
          if (cs.GetLength() == iLimit) return;
          CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
      }

       

      MFCApplication1Dlg.h

      #pragma once
      #include "CEditTest.h"
      class CMFCApplication1Dlg : public CDialog
      {
          //〜〜省略〜〜
      private:
          CEditTest m_Edit1;
          CEditTest m_Edit2;
      };

       

      MFCApplication1Dlg.cpp

      BOOL CMFCApplication1Dlg::OnInitDialog()
      {
          CDialog::OnInitDialog();
          //〜〜省略〜〜

          // このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、
          //  Framework は、この設定を自動的に行います。
          SetIcon(m_hIcon, TRUE);   // 大きいアイコンの設定
          SetIcon(m_hIcon, FALSE);  // 小さいアイコンの設定
          //リミットを設定
          m_Edit1.SetLimitText(10);
          m_Edit2.SetLimitText(5);
          return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
      }

      よろしければポチッと押してください

      プログラマー ブログランキングへ


      【VC++】メールスロットで単方向プロセス間通信を行う

      0

        <機能>

        (1)メールスロットクライアントとサーバを作成します

        (2)メールスロットを使って2つのexe間でプロセス間通信を行います

        (3)クライアントは[送信]ボタン押下によりメッセージを送付します

        (4)サーバは受信メッセージをリストボックスに表示します

        (5)クライアント起動時にサーバも起動します

         (サーバからクライアントの起動ななし)

         

        <実行イメージ>

        上の実行ファイルはメールスロットクライアント(MFCApplication1)

        下の実行ファイルはメールスロットサーバ(MFCApplication2)

        MFC,VisualStudio,MailSlot,実行サンプル,
         

        <動作検証&開発環境>
        Visual Studio Community 2017

         

        <使い方>

        1.MFCApplication1プロジェクトを作成します

        2.MFCApplication1ソリューションにMFCApplication2プロジェクトを追加します

         (どちらもダイアログベースです)

         

        サンプルのソリューション構成

        MFCApplication1(ソリューションフォルダ)

         Debug

         MFCApplication1(プロジェクトフォルダ)

         MFCApplication2(プロジェクトフォルダ)

         Release

         MFCApplication1.sln

         

        3.コントロールを追加

        MFCApplication1

        MFC,VisualStudio,MailSlot,送信,
         

        MFCApplication2

        MFC,VisualStudio,MailSlot,受信,
         

        4.メンバ変数を追加

        MFCApplication1

         IDC_EDIT1:

        MFC,VisualStudio,MailSlot,送信,メンバ変数追加,クラスウィザード,
         

        MFCApplication2

         IDC_LIST1:

        MFC,VisualStudio,MailSlot,受信,メンバ変数追加,クラスウィザード,
         

        5.MFCApplication2にイベントを追加

         WM_TIMER(タイマーイベントでメッセージを受信)

         WM_DESTROY(画面終了イベントでメールスロットとタイマー停止)

        MFC,VisualStudio,MailSlot,受信,イベント追加,クラスウィザード,
         

        5.ソースを追加

         

        MFCApplication1(クライアント「送信」側アプリ)

         

        MFCApplication1Dlg.h

        class CMFCApplication1Dlg : public CDialog
        {
        //〜省略〜
        // 実装
        protected:
            HICON m_hIcon;
            // 生成された、メッセージ割り当て関数
            virtual BOOL OnInitDialog();
            afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
            afx_msg void OnPaint();
            afx_msg HCURSOR OnQueryDragIcon();
            DECLARE_MESSAGE_MAP()
        private:
            CString m_sendEdt;
            HANDLE m_mailSlot;
        public:
            afx_msg void OnBnClickedButton1();
        };

         

        MFCApplication1Dlg.cpp

         

        BOOL CMFCApplication1Dlg::OnInitDialog()

        {
            //〜省略〜〜
            //受信側(MFCApplication2.exe)も一緒に起動する
            //※本サンプルでは受信側と送信側が同一フォルダに出力されているものとしますが実行環境に合わせて修正してください

            TCHAR buf[2048];
            ZeroMemory(&buf, sizeof(buf));
            GetModuleFileName(NULL, buf, sizeof(buf));
            size_t ichi = wcslen(buf) - wcslen(L"MFCApplication1.exe");
            //送信側(MFCApplication1.exe)実行ファイル名を受信側(MFCApplication2.exe)に置換
            wmemcpy_s(&buf[ichi],wcslen(buf), L"MFCApplication2.exe", wcslen(L"MFCApplication2.exe")*2);
            //受信側(MFCApplication2.exe)を起動
            ShellExecute(NULL, L"open", buf, NULL, NULL, SW_HIDE);
            //エディットボックスを初期化
            m_sendEdt = L"";
            UpdateData(FALSE);
            return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
        }
         
        /*************************************************
        関数名 OnBnClickedButton1
        機能   送信ボタン押下イベント
        *************************************************/

        void CMFCApplication1Dlg::OnBnClickedButton1()
        {
            CString csError;
            TCHAR cName[256];
            ZeroMemory(&cName,sizeof(cName));
            //エディットボックスの入力値を取得
            UpdateData(TRUE);
            m_sendEdt = m_sendEdt.Trim();
            //メッセージが未入力ならエラーとする
            if (m_sendEdt.IsEmpty())
            {
                AfxMessageBox(L"送信文字列を入力してください",MB_ICONERROR);
                return;
            }
            //コンピュータ名を取得
            //※本サンプルでは同一コンピュータに送信する

            DWORD wksize = sizeof(cName);
            if (!GetComputerName(cName, &wksize))
            {
                AfxMessageBox(L"コンピューター名の取得に失敗しました", MB_ICONERROR);
                return;
            }
            //メールスロットを作成
            //メールスロットの名前は ¥¥mailslot¥¥MailSlot とする

            //詳細はMSDN参照
            CString csSlot;
            csSlot.Format(L"¥¥¥¥%s¥¥mailslot¥¥MailSlot", cName);
            HANDLE hSlot = CreateFile(csSlot, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
                                            NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            if (hSlot == INVALID_HANDLE_VALUE)
            {
                csError.Format(L"MailSlotの作成に失敗しました(ErrorCode=%d)¥r¥n%s",GetLastError(),csSlot);
                AfxMessageBox(csError, MB_ICONERROR);
                return;
            }
            //メッセージの送信
            LPTSTR cMsg = new TCHAR[2048];
            DWORD dwSize;
            DWORD dwWrite;
            BOOL bResult;
            //dwSize = wcslen(cMsg);
            dwSize = wsprintf(cMsg, L"%s", m_sendEdt);
            bResult = WriteFile(hSlot, cMsg, dwSize * 2, &dwWrite, NULL);
            if (!bResult) {
                csError.Format(L"MailSlotの送信に失敗しました(ErrorCode=%d)¥r¥n%s", GetLastError(), csSlot);
                AfxMessageBox(csError, MB_ICONERROR);
            }
            CloseHandle(hSlot);
            delete cMsg;
        }

         

        MFCApplication2(サーバ「受信」側アプリ)

         

        MFCApplication2Dlg.h
        class CMFCApplication2Dlg : public CDialog
        {
        //〜省略〜〜
        // 実装
        protected:
            HICON m_hIcon;
            // 生成された、メッセージ割り当て関数
            virtual BOOL OnInitDialog();
            afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
            afx_msg void OnPaint();
            afx_msg HCURSOR OnQueryDragIcon();
            DECLARE_MESSAGE_MAP()
        private:
            HANDLE m_Slot;
        public:
            afx_msg void OnTimer(UINT_PTR nIDEvent);
            afx_msg void OnDestroy();
        private:
            CListBox m_recvList;
        };
         
        MFCApplication2Dlg.cpp
        BOOL CMFCApplication2Dlg::OnInitDialog()
        {
            CDialog::OnInitDialog();
           
            //〜省略〜〜
           
            //メールスロットを作成
            //メールスロットの名前は ¥¥mailslot¥¥MailSlot とする
            //メッセージの最大長(バイト数):0(任意サイズ)
            //メッセージ読み取りタイムアウト値(ms)
            //詳細はMSDN参照

            m_Slot = CreateMailslot(L"¥¥¥¥.¥¥mailslot¥¥MailSlot", 0, 1000, NULL);
            if (m_Slot == INVALID_HANDLE_VALUE)
            {
                CString csError;
                csError.Format(L"メールスロット作成に失敗しました(ErrorCode=%d)", GetLastError());
                AfxMessageBox(csError, MB_ICONERROR);
                return FALSE;
            }
            //タイマースタート
            //1000(ms)ごとにチェック
            //コールバック関数なし

            SetTimer(DTIMER_ID, 1000, NULL);
            return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
        }
        /*************************************************
        関数名 OnTimer
        機能   タイマーイベントで受信をチェック
        *************************************************/

        void CMFCApplication2Dlg::OnTimer(UINT_PTR nIDEvent)
        {
            TCHAR cMsg[2048];
            DWORD dwRead;
            BOOL bResult;
            CString csMsg;
           
            //タイマー停止
            KillTimer(DTIMER_ID);
            //メッセージがあれば処理する
            MSG msg;
            while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
           
            //メッセージの読み取り
            //詳細はMSDN参照

            ZeroMemory(&cMsg, sizeof(cMsg));
            bResult = ReadFile(m_Slot, cMsg, sizeof(cMsg), &dwRead, NULL);
            if(bResult)
            {
                //リストボックスに表示
                CTime ct;
                ct = CTime::GetCurrentTime();
                csMsg.Format(L"%04d/%02d/%02d %02d:%02d:%02d : %s", ct.GetYear(), ct.GetMonth(),
                    ct.GetDay(), ct.GetHour(), ct.GetMinute(), ct.GetSecond(), cMsg);
                m_recvList.InsertString(-1, csMsg);
                UpdateData(FALSE);
            }else
            {
                LRESULT lrlt = GetLastError();
                if ((lrlt == ERROR_SEM_TIMEOUT) || (lrlt == ERROR_ACCESS_DENIED)) {
                    //メッセージがタイムアウトのときエラーを出さない
                    //別のエラーが出るようならエラーコードを追加する

                }
                else {
                    csMsg.Format(L"MailSlotのメッセージ読み取りに失敗しました(ErrorCode=%d)", lrlt);
                    AfxMessageBox(csMsg, MB_ICONERROR);
                    SetTimer(DTIMER_ID, 1000, NULL);
                }
            }
            //タイマー起動
            SetTimer(DTIMER_ID, 1000, NULL);
            CDialog::OnTimer(nIDEvent);
        }
         
        /*************************************************
        関数名 OnDestroy
        機能   アプリケーションの終了処理
        *************************************************/

        void CMFCApplication2Dlg::OnDestroy()
        {
            CDialog::OnDestroy();
            //タイマー停止
            KillTimer(DTIMER_ID);
            //メールスロットを閉じる
            if (m_Slot != INVALID_HANDLE_VALUE)
            {
                CloseHandle(m_Slot);
            }
        }
         

        よろしければポチッと押してください

        プログラマー ブログランキングへ

         


        【VC++】ピクチャーボックスに画像を表示する

        0

          <機能>

          (1)ピクチャーボックスに直接絵をかきます

          (2)ピクチャーボックスに任意の画像を表示します

            (2)-1.画像を表示する際にピクチャーボックスのサイズに伸縮します

            (2)-2.伸縮画像が劣化しないように伸縮モードを指定します

           

          <実行イメージ>

          上はピクチャーボックスに直接グラデーションを描画

          下はJPEGをピクチャーボックスに表示(伸縮して表示)

          VC,MFC,PICTURECONTROL,伸縮,DC,描画モード,HALFTONE,
           

          <動作検証&開発環境>
          Visual Studio Community 2017

           

          <使い方>

          1.MFCのダイアログベースアプリケーションを作成します

            ※サンプルではプロジェクト名をPictureTestとします

          VC,MFC,PICTURECONTROL,伸縮,DC,ダイアログベース,ウィザード,
           

          2.リソースファイル(PictureTest.rc)を開いて"言語 17、"を""LANGUAGE 17,"に修正

            ※ダイアログベースでビルドエラー参照

          3.ダイアログにコントロールを追加

            ・ピクチャーボックス:IDC_PICTURE1/IDC_PICTURE2

            ・ボタンはIDOKをそのまま使用

          VC,MFC,PICTURECONTROL,伸縮,DC,描画モード,ウィザード,
           

          4.ピクチャーボックスにメンバ変数を追加

            ・IDC_PICTURE1 : m_Picture1(コントロール変数)

            ・IDC_PICTURE2 : m_Picture2(コントロール変数)

          VC,MFC,PICTURECONTROL,伸縮,DC,描画モード,メンバ変数追加ウィザード,
           

          5.メンバ関数setPictureControl()を追加

          VC,MFC,PICTURECONTROL,伸縮,DC,描画モード,メンバ関数追加ウィザード,
           

          6.ONOKのボタン押下イベント追加

          7.ソースを追加

           

          PictureTestDlg.h

          class CPictureTestDlg : public CDialog
          {
              //~~省略~~
          private:
              //ピクチャーコントロールの描画エリア
              RECT rect1, rect2;
              //ピクチャーコントロールへの描画処理
              void setPictureControl();
          public:
              afx_msg void OnBnClickedOk();
              CStatic m_Picture2;
              CStatic m_Picture1;
          };

          PictureTestDlg.cpp

          BOOL CPictureTestDlg::OnInitDialog()

          {

              //~~省略~~

              //ピクチャーコントロールの幅と高さを取得
              m_Picture1.GetWindowRect(&rect1);
              m_Picture2.GetWindowRect(&rect2);

              //~~省略~~
          }


          /*************************************************
          関数名 setPictureControl
          機能   ピクチャーコントールに描画する
          *************************************************/

          void CPictureTestDlg::setPictureControl()
          {
              CDC *cdc;
              int iWidth, iHeight;
              //IDC_PICTURE1にグラデーションを直接描画
              cdc = m_Picture1.GetDC();
              iWidth = rect1.right - rect1.left;
              iHeight = rect1.bottom - rect1.top;
              for (int y = 0; y < iHeight; y++) {
                  for (int x = 0; x < iWidth; x++) {
                      COLORREF clr = RGB(0,x * 0xff / iWidth, 0);
                      SetPixel(cdc->GetSafeHdc(), x,y,clr);
                  }
              }
              //IDC_PICTURE2にファイルを描画
              cdc = m_Picture2.GetDC();
              iWidth = rect2.right - rect2.left;
              iHeight = rect2.bottom - rect2.top;
              //読み込む画像ファイルパス
              TCHAR buf[2048];
              CString cs;
              ZeroMemory(&buf, sizeof(buf));
              GetModuleFileName(NULL, buf, sizeof(buf));
              cs.Format(L"%s",buf);
              cs = cs.Left(cs.ReverseFind('¥¥')) + L"¥¥Sample.jpg";
             
              CImage img;
              HRESULT ret = img.Load(cs);
              if (img.IsNull()) {
                  AfxMessageBox(L"画像の読み込み失敗",MB_ICONERROR);
                  return;
              }
              //StretchBltで描画領域に合わせてリサイズ
              CDC bmpDC;
              CBitmap *cbmp;
              cbmp = CBitmap::FromHandle(img);
              bmpDC.CreateCompatibleDC(cdc);
              CBitmap *oldbmp = bmpDC.SelectObject(cbmp);
              //伸縮すると画像が汚くなるので伸縮モードを指定
              //詳細は
          MSDN参照
              cdc->SetStretchBltMode(STRETCH_HALFTONE);
              //ブラシのずれを防止するためSetBrushOrgExを呼び出す
              cdc->SetBrushOrg(0, 0);
              //画像を伸縮してピクチャーボックスに表示
              //詳細は
          MSDN参照
              cdc->StretchBlt(0,0,iWidth,iHeight,&bmpDC,0,0,img.GetWidth(),img.GetHeight(),SRCCOPY);
              bmpDC.SelectObject(oldbmp);
              //後片付け
              cbmp->DeleteObject();
              bmpDC.DeleteDC();
              ReleaseDC(cdc);
          }

          /*************************************************
          関数名 OnBnClickedOk
          機能   OKボタン押下イベントハンドラ
          *************************************************/

          void CPictureTestDlg::OnBnClickedOk()
          {
              setPictureControl();
          }

          よろしければポチッと押してください

          プログラマー ブログランキングへ



          << | 2/6PAGES | >>

          selected entries

          categories

          calendar

          S M T W T F S
                1
          2345678
          9101112131415
          16171819202122
          23242526272829
          30      
          << June 2019 >>

          profile

          others

          archives