VC++ MFC 2022の新しい開発ツ-ルを使います

随分とVC++も様変わりしていたんですね、パイソンも開発できるなんて、しかも無料ですよこんな素晴らしい物は使わなければバチが当たる、考えて見ればMFCでもかなり焦っているのだと思います、何しろMFCとは莫大な資産があり使えない人ばかりが増えるのは間違い無い!高級言語では決してワード及びブレンダ-とかMAYAは作れません絶対に無理です。今後このVC++MFCの世界は稼げる世界になって行きますよ!皆さん大変ですが是非覚えて下さい、私も0~この新しい規格に挑戦します(ボケ防止にね!)。皆さんこのMFC のC++とは皆さんが知る物とは全くの別物ですから例外及びバグ取りさえも出来ないのです、コント-ロルさえも簡単では無いコントロ-ルとはそれ自身が最小単位のウインドウズなのですから、今この日本で果たしてどのくらいの方が使いこなせているのか?私のMFCはもう過去のアプリケ-ションになったようですがドッコイMFCは現在も進歩しているのです。MFCの技術者は使える人間だけが、この言語使えと言っているんですよ皆さん!悔しいでしょう。ダイアログベースのアプリなんて恥ずかしいですよ、ちゃんとCDocumentoを使えなければダメですよ、C#でもだめ!Physonでもダメです、覚えてしまえば貴方の一生分の稼ぎは間違いない世界に入れるんです、私も若ければ良いがもうだめ!ですから死ぬまでに皆さんに伝えたいと思っています。ついて来て下さい!

VC 2022でMFC環境を設定完了

これが無料だとは信じられない、私のMFCは2005ですが今回はMFCが2022へ格上げです。大分違いますが問題は無いでしょう!

右の画面は自動的に作られたファイルの一覧ですが、基本的なMFCクラスが作成されています。VC 2005の場合と同一です。

VC++とC言語で特にMFCクラスでは記載も違えば制御方法も完璧に異なりますデータの扱い又クラス間のやり取りやメッセ-ジの伝達方法も非常に難しい、又これから扱う色々なコントロ-ルとか各クラス間の操作もまるきり違います、とてもこの辺の理解を得るには困難に近い。MFCが時代遅れなんてよく言われますがエクセルとかワ-ド又皆さんが御存知のブレンダ-とかMAYAなどもこの言語で作成されているのです。皆VC++MFCで作成されているんです只理解するには非常に難しいです。C言語などでは相手にされません、とにもかくにも覚悟して勉強しなければ無理です!使いこなすのはね!ダイアログベースのアプリケ-ションなら簡単ですが、各フォームビュ-クラスとかコントロ-ルクラスの制御とかを自由に扱うのは無理です!例外の発生でどうしようもなくなります。

これからVC++2022で一つ一つ実装して手順を示しながら説明して行こうと考えています。

CDocumentクラス

まずはCDocumentクラスから説明します。極論すればアプリケ-ションで使用するデータは全て此処のクラスが保持します、此処で定義されていないデータは各フォームビュが消えてしまった場合このデ-タは無になりますコントロ-ルで使用されていたデータは全て無になります他のクラスではクラスが消えた場合どんなデータも無になります覚えておいて下さい!では各ビュ-クラスから「例DietRemedyDoc* pDoc = GetDocument();」の様にDocumentクラスのアドレスを取得後DietRemedyDocにアクセスを行います、例 DietRemedyDocクラスには下記図の様に定義します、なをこのクラスはアプリが起動中は存在は永続しています。

下記の様にアクセスします。これ以外に手段は有りません、必ず例DietRemedyDoc* pDoc = GetDocument();とアドレスを取得後操作します。

ここらの言語、記載内容から見てもC++文法は保母無いですね!マイクロソフト・ファンデ-ション・クラス(MFC)を使用しているからなんですが、こう言う言語の使い方が主体になります、又各クラスは個別に隠蔽されている互いの参照は出来ません。

VC++ MFC 2022 画面を下記に示します

VEWの分割

下記図の様にして行きます、目的は各シナリを」に沿い」、そうですね紙芝居の様に切り替えて行きます,VEW1にはツリ-コントロ-ルにしてVE2は各コマンドコントロ-ルを配置して行きます、したがってVEWも複数枚必要になります。コントロ-ル等は動的に作成して行きます。

作業概要はですね!まずはVewを3枚フレ-ムクラスで作成して行きます(コントロ-ルは後から追加して行きます)、その後色々とコードを記載して行きます。ビュ-名は取り合えずVew1~vew3と命名していきます、あ!それと最初にメイン・フレ-ム・クラスにコードを記載してスプリット機能を組み込みます、勿論ドキュメント・クラスも使います。CSplitterWndは画面分割用のコードでMainFrameに実装します。

実装された「CSplitterWnd」画面分割用の変数クラスです。実層するには操作手順が重要になります。このCFrameWndクラス(紙芝居の木枠に相当します)はウィンドウズから自動的で起動されメインフォ-ムが画面を分割し、更に分割された所定のエリヤに初期フォ-ムビュ-が組み込みフレ-ムビュ-が起動します。現在はまだフレ-ムビュ-・クラスが存在しない為にコードの記載はまた出来ません。

CMainFrameに追加

CMainFrame.cppの上部にドキュメントクラスを参照する為に「#include “NutrinetAppDoc.h” //追加 ドキュメントクラスの参照」を追加してビルドを行いエラ-が発生していないかの確認を行います。

CDocument* EkGetActiveDocument();をCMainFrame 。CMainFrame .hに追加します、この追加した関数は非常に大きな役割をしています(ドキュメント・クラスの存在と正当性を確認する私のオリジナル関数で、ドキュメント・クラスのポインタ-を返します)。

CDocument* CMainFrame::EkGetActiveDocument()

FormVewを1本目を作成する

class MFC_Vew1_FrameVew.hとMFC_Vew1_FrameVew.cppが自動的に作成されています。

enum { IDD = IDD_MFC_Vew1_FrameVew };

#include “MFC_Vew1_FrameVew.h”をCMainFrame.cppに記載

作成された#include “MFC_Vew1_FrameVew.h”をCMainFrame::CMainFrame.cppに追加しました、これをVew2~VEW3までクラス作成を繰り返します。下記の図はCMainFrame.cppの上部へ定義しました。

フレ-ムビュ-・クラスを3本作成しました

作成したMFC_Vew1_FrameVew.h~MFC_Vew3_FrameVew.hのファイルを定義した下記画面を良くご覧くださいです。これでメインフレ-ムには各フレ-ムビュ-・クラス(MFC_Vew1_FrameVew.cpp~MFC_Vew3_FrameVew.cpp)への参照が可能になりました。

スプリット画面の現在

文字列だけがVEWに存在しています、これから色々なコントロ-ルw実装して行きます。

どんなにチュ-トリアルが有ろうと貴方には解らない!

色々なチュ-トリアルが多数有っても貴方には解らないと思います、何故か!理屈を理解していないからです。MFCの各クラス構造と各クラス間との連絡方法とか理解不能な個所が沢山有ります。まず最初にこれらを理解する必要が有ります。関数にブレ-クを掛けても駄目なんです、各クラスには表立って見える関係性はないし、又プログラムの流れを掴もうとしてむ無理なんですC++時代とMFC処理の流れが異なるのです。Windowz側から全てのクラスに向けて通信ハンドシェ-クされます。

いや~本当にアプリケ-ションを作成しています

static _TCHARにする理由

「リリ-スバ-ジョン」を意識しているのです。この様にして置けば勝手にロケ-タに移動されず綺麗にこの位置にとどまります。staticとは静的なメモリー位置にこちらから指示します。あ!それとウインドウズは水に浮いた泡の様な物で画面が切り替わればデータも失われるのですから!

初期のリストボックス

必ず記載しなければ行けません(約束事)。

void Vew2Form::OnInitialUpdate()
{
CFormView::OnInitialUpdate(); //これらの関数は必ず必要になります
GetParentFrame()->RecalcLayout(); //これらの関数は必ず必要になります
ResizeParentToFit(); //これらの関数は必ず必要になります

リストコントロ-ル関数の初期化

LV_COLUMN  lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
//============================================================
for (int i = 0; i < 1; i++) {
    lvc.iSubItem = i;
    lvc.pszText = _T("");
    lvc.cx = 200;
    lvc.fmt = LVCFMT_CENTER;
    FoodGroupsName.InsertColumn(i, &lvc);
    }
//============================================================
//============================================================
//============================================================
LV_ITEM     lvi;
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lvi.iSubItem = 0;
for (int i = 0; i < 19; i++) {
    lvi.iItem = i  ;
    lvi.pszText = FoodGroups[i];
    FoodGroupsName.InsertItem(&lvi);
    }

下記のOnDrawItem()に飛んで来れば初期化は成功です

void Vew2Form::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)

OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)の内容です

CANutrinetAppDoc* pDoc = GetDocument();

//========================================================
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rcItem(lpDrawItemStruct->rcItem);
int nItem = lpDrawItemStruct->itemID;

LV_ITEM lvi;
switch (lpDrawItemStruct->CtlID) {
    case IDC_LIST1:
        List1RowListControl(pDC,nItem);
        break;
        }

}

注意する事はアイテム行数分、OnDrawItemが呼ばれると言う事です

例えば行数が20行有ればOnDrawItemには1~20回この関数が呼ばれて来ます、タイムシェアリング処理で行われます。又横線も私が引き反転も私です、私はリストコントロ-ルに含まれる文字列は使用しません必ず外部に(スタティツク・エリヤ)保持します、何故か?このデ-タはビュ-が消えた時にはデータも消えてしまうからです。

表示処理を行う所

///////////////////////////////////////////////////////////////////////////////////////
/////////////////10カラムで代表的な摂取栄養素を表示します//////////////////////
//////////////////////////////////////////////////////////////////////////////////////
void Vew2Form::List1RowListControl(CDC* pDC, int nItem)
{
CANutrinetAppDoc* pDoc = GetDocument();
//=========================================================
COLORREF clrTextSave = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
COLORREF clrBkSave = pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));

CBrush cbrA0, cbrA1, cbrWhit;
//=================色の配色候補です========================
//RGB(255,241,0) RGB(243,152,0) RGB(233,83,131) 
//RGB(143,195,31) RGB(0,153,217) RGB(237,109,70) 
cbrA0.CreateSolidBrush(RGB(0, 153, 217));
cbrA1.CreateSolidBrush(RGB(237, 109, 70));
cbrWhit.CreateSolidBrush(RGB(255, 255, 255));
//=========================================================
CPen      pen;
CPen* pOldPen;
pen.CreatePen(PS_SOLID, 1, LINE_COLOR);
pOldPen = pDC->SelectObject(&pen);
CRect rcAllLabels, lRect, rc;
//==========================================================================================
FoodGroupsName.GetClientRect(rcAllLabels);
//====================================最初に横線を引きます==================================
FoodGroupsName.GetSubItemRect(nItem, 0, LVIR_BOUNDS, lRect);//このアイテムの横幅です
//================横線================
pDC->MoveTo(lRect.left, lRect.bottom);
pDC->LineTo(lRect.right, lRect.bottom);
lRect.top += 1; lRect.bottom -= 1;
if (nItem == 0) {
    pDC->SetTextColor(RGB(255, 255, 255));//文字色は白色です
    pDC->FillRect(lRect, &cbrA0);
    FoodGroupsName.GetSubItemRect(nItem, 0, LVIR_BOUNDS, lRect);//このアイテムの横幅です
    pDC->DrawText(FoodGroups[nItem], -1, lRect, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
}
else{
    pDC->SetTextColor(RGB(0, 0, 0));//文字色は黒色です 
    FoodGroupsName.GetSubItemRect(nItem, 0, LVIR_BOUNDS, lRect);//このアイテムの横幅です
    pDC->DrawText(FoodGroups[nItem], -1, lRect, DT_LEFT | DT_SINGLELINE | DT_VCENTER);
    }
}

印刷機構を組込みましょう(簡単では無いです)

下記のリストは、印刷用紙の設定に使います。

////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void DietRemedyDoc::MakeLogFont( LOGFONT *lf,int he,int mode,int size)
{
//論理フォント構造体をゼロで初期化します(ゼロ埋め)
memset( lf , 0 , sizeof(LOGFONT) );

switch(size){
    case 7 :lf->lfHeight = MS_HE[0] ;break;                      //フォント高さの設定
    case 8 :lf->lfHeight = MS_HE[1] ;break;                      //フォント高さの設定
    case 9 :lf->lfHeight = MS_HE[2] ;break;  
    case 10:lf->lfHeight = MS_HE[3] ;break;                      //フォント高さの設定
    case 11:lf->lfHeight = MS_HE[4] ;break;
    case 12:lf->lfHeight = MS_HE[5] ;break;                      //フォント高さの設定
    case 14:lf->lfHeight = MS_HE[6] ;break; 
    case 16:lf->lfHeight = MS_HE[7] ;break;                      //フォント高さの設定
    case 18:lf->lfHeight = MS_HE[8] ;break; 
    case 20:lf->lfHeight = MS_HE[9] ;break;                      //フォント高さの設定
    case 22:lf->lfHeight = MS_HE[10];break; 
    case 24:lf->lfHeight = MS_HE[11];break;                      //フォント高さの設定
    case 26:lf->lfHeight = MS_HE[12];break; 
    case 28:lf->lfHeight = MS_HE[13];break;                      //フォント高さの設定
    case 30:lf->lfHeight = MS_HE[14];break;                      //フォント高さの設定
    case 32:lf->lfHeight = MS_HE[15];break; 
    case 34:lf->lfHeight = MS_HE[16];break;                      //フォント高さの設定
    }

lf->lfCharSet = SHIFTJIS_CHARSET;       //ここでは日本語文字を使います

switch( mode )
{
case 0:   //MSゴシック体の設定です(固定ピッチフォントで、モダン型です)
          lf->lfPitchAndFamily =  FIXED_PITCH | FF_MODERN;
          lstrcpy(lf->lfFaceName,_T("MS ゴシック"));
          break;

case 1:   //MS Pゴシックの設定です(可変ピッチフォントで、モダン型です)
          lf->lfPitchAndFamily =  VARIABLE_PITCH | FF_MODERN;
          lstrcpy(lf->lfFaceName,_T("MS Pゴシック"));
          break;

case 2:   //MS明朝の設定です(固定ピッチフォントで、ローマン型です)
          lf->lfPitchAndFamily =  FIXED_PITCH | FF_ROMAN;
          lstrcpy(lf->lfFaceName,_T("MS 明朝"));
          break;

case 3:   //MS P明朝の設定です(可変ピッチフォントで、ローマン型です)
          lf->lfPitchAndFamily =  VARIABLE_PITCH | FF_ROMAN;
          lstrcpy(lf->lfFaceName ,_T("MS P明朝"));
          break;
}
return;

}

下記はフォントの設定です、貴重な情報ばかり

//======================================================================
//======================================================================
//======================================================================
static int MS_HE[] = { -7,-8,-9,-10,-11,-12,-13,-15,-16,-19,-21,-24,-27,-29,-32,-35,-37 };//MSゴシック

////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void DietRemedyDoc::MakeLogFont( LOGFONT *lf,int he,int mode,int size)
{
//論理フォント構造体をゼロで初期化します(ゼロ埋め)
memset( lf , 0 , sizeof(LOGFONT) );

switch(size){
    case 7 :lf->lfHeight = MS_HE[0] ;break;                      //フォント高さの設定
    case 8 :lf->lfHeight = MS_HE[1] ;break;                      //フォント高さの設定
    case 9 :lf->lfHeight = MS_HE[2] ;break;  
    case 10:lf->lfHeight = MS_HE[3] ;break;                      //フォント高さの設定
    case 11:lf->lfHeight = MS_HE[4] ;break;
    case 12:lf->lfHeight = MS_HE[5] ;break;                      //フォント高さの設定
    case 14:lf->lfHeight = MS_HE[6] ;break; 
    case 16:lf->lfHeight = MS_HE[7] ;break;                      //フォント高さの設定
    case 18:lf->lfHeight = MS_HE[8] ;break; 
    case 20:lf->lfHeight = MS_HE[9] ;break;                      //フォント高さの設定
    case 22:lf->lfHeight = MS_HE[10];break; 
    case 24:lf->lfHeight = MS_HE[11];break;                      //フォント高さの設定
    case 26:lf->lfHeight = MS_HE[12];break; 
    case 28:lf->lfHeight = MS_HE[13];break;                      //フォント高さの設定
    case 30:lf->lfHeight = MS_HE[14];break;                      //フォント高さの設定
    case 32:lf->lfHeight = MS_HE[15];break; 
    case 34:lf->lfHeight = MS_HE[16];break;                      //フォント高さの設定
    }

lf->lfCharSet = SHIFTJIS_CHARSET;       //ここでは日本語文字を使います

switch( mode )
{
case 0:   //MSゴシック体の設定です(固定ピッチフォントで、モダン型です)
          lf->lfPitchAndFamily =  FIXED_PITCH | FF_MODERN;
          lstrcpy(lf->lfFaceName,_T("MS ゴシック"));
          break;

case 1:   //MS Pゴシックの設定です(可変ピッチフォントで、モダン型です)
          lf->lfPitchAndFamily =  VARIABLE_PITCH | FF_MODERN;
          lstrcpy(lf->lfFaceName,_T("MS Pゴシック"));
          break;

case 2:   //MS明朝の設定です(固定ピッチフォントで、ローマン型です)
          lf->lfPitchAndFamily =  FIXED_PITCH | FF_ROMAN;
          lstrcpy(lf->lfFaceName,_T("MS 明朝"));
          break;

case 3:   //MS P明朝の設定です(可変ピッチフォントで、ローマン型です)
          lf->lfPitchAndFamily =  VARIABLE_PITCH | FF_ROMAN;
          lstrcpy(lf->lfFaceName ,_T("MS P明朝"));
          break;
}
return;

}

厳密にエラ-チェックを行うし、ウオッチドックも勝手に!

素晴らしいですよ!これは、厳しく確認してくれます!、頭にくる程にね!!

“0%sも検出して教えてくれる、本来は0%dが正しい

反転表示も入れました

選択箇所を反転表示しています。結構難しいんですよ!移動して消すのも処理があります、この食材群が選択されると食品名がひょうじされます、参照栄養素値は厚生労働省が公表しているエクセルの表で食材群は18種類存在します、私は糖尿病なので命に係わる重要な物です。

スタテイク・エリヤに定義された表示テーブル

リストボックスの追加

これからが大変ややっこしいのです、新しいリストコントロ-ルに挿入して行きます。大きいファイルでエクセルの表から作成しています。

トークンを検出しながら検索して行き,カンマの数で位置を決めて行きます1行分だけで46種類の栄養素項目がが存在します。行数は何百行を超えて行きます。この表の制御はタイムシェアリングで制御され表示して行きます、Windowsは絶対に待機はしてくれません。

MFCの代表的なクラスの役割を理解して下さい

基本クラスのアプリケ-ションクラス、メインフフォームクラス。ドキュメントクラス、ビュ-クラスです、これらの大まかな役割を理解する事が重要になります、各クラスを理解したら各クラスのメッセ-ジハンドラ-の種類とそのハンドラ-の働き等々でC++の動きとは全くの別物です。MFCでは全てのコントロ-ラはウインドウズとして動きウインドウズの理解が必要です(私のHPを良く見て下さい)。実際に動かす所をズバリ貴方にお見せします、他のhpでは無いと思います。現在実際にアプリケ-ションを作成中ですから参考になると思いますよ!

動画を見て覚えられるなら誰も苦労しない!貴方が悩まないとダメ!

上記はト-クンの切りだしの方法です

上記は完成した栄養素を68個の配列に挿入している方法です

エクセルのデータはカンマ毎に区切られ一連の文字列として読み出します、ですが表の上部にはコメントが記載されていますが、そのコメントは不要で無視し栄養素のヵ所を配列に加算して行きます。しかもその行数はランダムに変化します、そこでランダムに1行ずつ取り出して別に保存しています。

構造体の内容です

//======================================================================================
typedef struct FDOOD_DATA {
BOOL frg;
CString FoodGrp;
CString sVal[70];
}s_FoodWerk;

配列の宣言・ドキュメントクラスです

CArray<s_FoodWerk,s_FoodWerk> ms_FoodWerk;//栄養素行デ-タ

関数の本体です

void Vew2Form::lineCorrection()
{
CANutrinetAppDoc* pDoc = GetDocument();
CString val = _T(“”), merk;
//====================================================
s_FoodWerk ms_FoodWerk;
//====================================================
int pos = pDoc->ms_FoodWerk.GetCount();
//============== 不要なト-クンを削除 ================
pDoc->ms_FoodFileReadDeta.Replace(_T(“, ,”), _T(“,”));
pDoc->ms_FoodFileReadDeta.Replace(_T(“,,”), _T(“,”));
//====================================================
int lCunt = 0, corm = 0,Cormn = 0, stk=0;//デ-タの総数は68 次の位置は68カウント加算

ms_FoodWerk.frg =0;
CString  torkn = pDoc->ms_FoodFileReadDeta.Tokenize(_T(","), lCunt);//ファイルから読み出したエクセル表 食材の栄養素
++corm;
while (torkn != "") {
            torkn = pDoc->ms_FoodFileReadDeta.Tokenize(_T(","), lCunt);
            //====================================================
            if (ms_FoodWerk.frg == 1) {//行の開始を判定する 行ラインの中で群番号2桁はユニ-クで行の開始に必ず有る
                        ms_FoodWerk.sVal[Cormn].Format(_T("%s"), _T(""));
                        if (ms_FoodWerk.FoodGrp != torkn) 
                                    ms_FoodWerk.sVal[Cormn++].Format(_T("%s"), torkn);//1行を保持する
                        else {
                                Cormn = 0;
                                pDoc->ms_FoodWerk.Add(ms_FoodWerk);
                                stk=pDoc->ms_FoodWerk.GetCount()  ;
                                ms_FoodWerk.sVal[Cormn++].Format(_T("%s"), torkn);
                                }
                        }
            //===============見出し分は不要です========================
            if ((ms_FoodWerk.frg == 0) && (241 < corm)) {//=====食材群番号、栄養素は此処から始まります====
                        ms_FoodWerk.sVal[Cormn++].Format(_T("%s"), torkn);
                        ms_FoodWerk.frg = 1; ms_FoodWerk.FoodGrp = torkn ;
                        }
            ++corm;
            }

}

プログラム・コードで非常にシンプルに出来ています

CANutrinetAppDoc* pDoc = GetDocument();
s_FoodWerk ms_FoodWerk;
//=========================================================
int siz=pDoc->ms_FoodWerk.GetCount();
if (siz!=0) ms_FoodWerk = pDoc->ms_FoodWerk.GetAt(nItem);

上記は栄養素を組み込む箇所です、え!これだけですか?

これだけです、だから工夫が大事なのです。皆さん」コ-ドの意味を覚えて下さい!だからHPを作成しているのですから動画なんかで覚えられる訳ないんです。

表示結果

これからエディツト・ボックスとか色々と配置して行きます

上記はコントロ-ルを追加していますが機能は確定していません

大分それらしくご覧ください!これから多数ビュ-を作ります

色々とコントロ-ルを追加中

栄養素バランス・グラフを付加

円を描いている箇所もCListCtrlです、単なるWindowsだと理解できますね!

タブコントロ-ルの配置コードをお見せします

//==========================タブコントロラーをこの画面左上に配置します==========================
CBitmap myBMP;
//==============================================================    
m_imagelist.Create(16, 16, ILC_COLOR, 4, 4);
//==============================================================    
myBMP.LoadBitmapW(IDB_TAB_MENU1); m_imagelist.Add(&myBMP, COLORREF(0)); myBMP.DeleteObject();
myBMP.LoadBitmapW(IDB_TAB_MENU2); m_imagelist.Add(&myBMP, COLORREF(0)); myBMP.DeleteObject();
myBMP.LoadBitmapW(IDB_TAB_MENU3); m_imagelist.Add(&myBMP, COLORREF(0)); myBMP.DeleteObject();
//==============================================================
TC_ITEM tac0; tac0.mask = TCIF_IMAGE | TCIF_TEXT; tac0.iImage = 0;
TC_ITEM tac1; tac1.mask = TCIF_IMAGE | TCIF_TEXT; tac1.iImage = 1;
TC_ITEM tac2; tac2.mask = TCIF_IMAGE | TCIF_TEXT; tac2.iImage = 2;
TC_ITEM tac3; tac3.mask = TCIF_IMAGE | TCIF_TEXT; tac3.iImage = 3;
//==============================================================    
tac0.pszText = _T("食事バランス図") ; TAB_Control.InsertItem(0, &tac0);
tac1.pszText = _T("バランス.グラフ"); TAB_Control.InsertItem(1, &tac1);
tac2.pszText = _T("週間献立ツリー"); TAB_Control.InsertItem(2, &tac2);
tac3.pszText = _T("月間献立ツリー"); TAB_Control.InsertItem(3, &tac3);
//==============================================================
TAB_Control.SetImageList(&m_imagelist);
TAB_Control.MoveWindow(5,1,300,25);
TAB_Control.ShowWindow(SW_SHOW);

メッセ-ジハンドラ-のコード

void Vew3Form::OnNMClickTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
int tabNM=ctTabControl.GetCurSel( ); 
switch(tabNM){
    case 0: //一番左のタブが押された時の処理を記載します
      //以下同文
            break;
    case 1: 
            break;
    case 2: 
            break; 
    case 3: 
            break; 
    }
}

タブ・コントロラ-

タブの初期化は下記の様なコードになります

IDB_TAB_MENU1~IDB_TAB_MENU3は16×16の大きさでBMPでさくせいします。

CBitmap myBMP;
//==============================================================    
m_imagelist.Create(16, 16, ILC_COLOR, 4, 4);
//==============================================================    
myBMP.LoadBitmapW(IDB_TAB_MENU1); m_imagelist.Add(&myBMP, COLORREF(0)); myBMP.DeleteObject();
myBMP.LoadBitmapW(IDB_TAB_MENU2); m_imagelist.Add(&myBMP, COLORREF(0)); myBMP.DeleteObject();
myBMP.LoadBitmapW(IDB_TAB_MENU3); m_imagelist.Add(&myBMP, COLORREF(0)); myBMP.DeleteObject();
//==============================================================
TC_ITEM tac0; tac0.mask = TCIF_IMAGE | TCIF_TEXT; tac0.iImage = 0;
TC_ITEM tac1; tac1.mask = TCIF_IMAGE | TCIF_TEXT; tac1.iImage = 1;
TC_ITEM tac2; tac2.mask = TCIF_IMAGE | TCIF_TEXT; tac2.iImage = 2;
TC_ITEM tac3; tac3.mask = TCIF_IMAGE | TCIF_TEXT; tac3.iImage = 3;
//==============================================================    
tac0.pszText = _T("栄養バランスグラフ")  ; TAB_Control.InsertItem(0, &tac0);
tac1.pszText = _T("食事バランスグラフ"); TAB_Control.InsertItem(1, &tac1);
tac2.pszText = _T("料理写真貼り付け"); TAB_Control.InsertItem(2, &tac2);
tac3.pszText = _T("献立メモ"); TAB_Control.InsertItem(3, &tac3);
//==============================================================
TAB_Control.SetImageList(&m_imagelist);
TAB_Control.MoveWindow(5,1,300,25);
TAB_Control.ShowWindow(SW_SHOW);

メッセ-ジハンドラ-

void Vew3Form::OnNMClickTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
CANutrinetAppDoc* pDoc = GetDocument();

int tabNM = TAB_Control.GetCurSel();
switch (tabNM) {
    case 0://栄養バランスグラフ
         IDC1_List.Invalidate();
         break;

    case 1://食事バランスグラフ
        CWnd* pWnd = AfxGetMainWnd();
        if (pDoc->ms_WorkManagement.dbClickJob == 1) pDoc->ms_WorkManagement.dbClickJob = 2;
        else                                         pDoc->ms_WorkManagement.dbClickJob = 1;
        if (pWnd->SendMessage(ID_ONEDAY_OR_ONEDISH_DBCLICK) == TRUE); {
                            if(pDoc->ms_WorkManagement.dbClickJob==2) pDoc->UpdateAllViews(NULL, IDS_VEW2_CHENG, this);
                            if(pDoc->ms_WorkManagement.dbClickJob==1) pDoc->UpdateAllViews(NULL, IDS_VEW4_CHENG, this);
                            }
        break;
    }

//////////////////////////////////////////////////////////////////////////////////////////////
*pResult = 0;
}

HPが大分大きくペ-ジがなりました!ここ等でペ-ジを追加します

私は能書を書くのはやめて!端的に画像とコードを提示します、皆さんは真似して下さい!

リストボックスでの初期化方法、下記記載をコードをご覧ください

//============================================================
//============================================================
//============================================================
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lvi.iSubItem = 0;
for (int i = 0; i < 19; i++) {
lvi.iItem = i ;
lvi.pszText = FoodGroups[i];
FoodGroupsName.InsertItem(&lvi);
}
for (int i = 0; i < 10; i++) {
lvi.iItem = i;
lvi.pszText =(LPWSTR&)_T(“文字列”)  //Cstring型をキャストします
NutrientValues.InsertItem(&lvi);

上記のコードで問題になる箇所!lvi.pszText =文字挿入箇所;ですよね!lvi.pszTextに中々と言うよりも挿入できない、皆さん悩んでいるでしょうね!ですが簡単なんです「lvi.pszText = (LPWSTR&)_T(“”);」の様に( (LPWSTR&))を付加(キャスト)すればいいんです!簡単でしょ!でもこれの説明がほとんど無い現実に驚きます。

最低限必要なイベント・メッセ-ジハンドラ-は?

public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);
afx_msg void OnContextMenu(CWnd* /pWnd/, CPoint /point/);

上記の様に組み込んで起きます

下記のコードはコントロ-ラの制御には絶対必要になります

void Vew2Form::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CANutrinetAppDoc* pDoc = GetDocument();

//========================================================
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rcItem(lpDrawItemStruct->rcItem);
int nItem = lpDrawItemStruct->itemID;

switch (lpDrawItemStruct->CtlID) {
    case IDC_LIST1:
        List1RowListControl(pDC,nItem);
        break;
    case IDC_LIST2:
        List2RowListControl(pDC, nItem);
        break;
    case IDC_LIST4:
        List3RowListControl(pDC, nItem);
        break;
    case IDC_LIST5:
        List4RowListControl(pDC, nItem);
        break;
    }

}

OnMeasureItemはコントロ-ルの行で高さを制御します

void Vew2Form::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
// if (nIDCtl == IDC_LIST10) lpMeasureItemStruct->itemHeight = 380 / 14;
// else if (nIDCtl == IDC_LIST6) lpMeasureItemStruct->itemHeight = 380 / 14;
// if (nIDCtl == IDC_EDIT1) lpMeasureItemStruct->itemData->>itemHeight = 50;
// else if (nIDCtl == IDC_EDIT3) lpMeasureItemStruct->itemHeight = 50;
CFormView::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
}

メインフォ-ムからのOnUpdateコマンドを受け取ります

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

void Vew2Form::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
CANutrinetAppDoc* pDoc = GetDocument();
//==================ビューが切り替わりが強要されました====================
switch (lHint) {
case IDS_VEW2_CHENG:
         OnInitialUpdate();
         break;
case 0:
break;
}
}

コマンドの発行方法

void Vew3Form::OnNMClickTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
CANutrinetAppDoc* pDoc = GetDocument();

int tabNM = TAB_Control.GetCurSel();
switch (tabNM) {
    case 0://栄養バランスグラフ
         IDC1_List.Invalidate();
         break;

    case 1://食事バランスグラフ
        CWnd* pWnd = AfxGetMainWnd();
        if (pDoc->ms_WorkManagement.dbClickJob == 1) pDoc->ms_WorkManagement.dbClickJob = 2;
        else                                         pDoc->ms_WorkManagement.dbClickJob = 1;
        if (pWnd->SendMessage(ID_ONEDAY_OR_ONEDISH_DBCLICK) == TRUE); {
                            if(pDoc->ms_WorkManagement.dbClickJob==2) pDoc->UpdateAllViews(NULL, IDS_VEW2_CHENG, this);
                            if(pDoc->ms_WorkManagement.dbClickJob==1) pDoc->UpdateAllViews(NULL, IDS_VEW4_CHENG, this);
                            }
        break;
    }

//////////////////////////////////////////////////////////////////////////////////////////////
*pResult = 0;
}

見ずらいですが注意して見て下さい、各IDはリソ-スで登録します。IDS_VEW2_CHENGはフォームビュ-側で受け取りますがOnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)が必要です

ビュ-切り替えコマンドです(重要なコードです)

LRESULT CMainFrame::OneDayOrDishDbClick(WPARAM wParam, LPARAM lParam)
{
CDocument* pActiveDoc = EkGetActiveDocument();
CANutrinetAppDoc* pMyDoc= static_cast>(pActiveDoc); //========================================================================= if (pActiveDoc == NULL) if (pActiveDoc->IsKindOf(RUNTIME_CLASS(CANutrinetAppDoc))) pMyDoc = static_cast>(pActiveDoc);
if (pMyDoc->ms_WorkManagement.ViewNmber == 1) pMyDoc->ms_WorkManagement.ViewNmber = 0;
else pMyDoc->ms_WorkManagement.ViewNmber = 1;
//=========================================================================
CCreateContext context;
context.m_pCurrentDoc = GetActiveDocument();
m_wndSplitter.DeleteView(0,RIGHT_SIDE_PAIN);
//=========================================================================
int xWidth = 1280, yHight = 760;
if (pMyDoc->ms_WorkManagement.dbClickJob == 1) m_wndSplitter.CreateView(0,RIGHT_SIDE_PAIN, RUNTIME_CLASS(Vew4Form),CSize(xWidth,yHight),&context);
else if (pMyDoc->ms_WorkManagement.dbClickJob == 2) m_wndSplitter.CreateView(0,RIGHT_SIDE_PAIN, RUNTIME_CLASS(Vew2Form),CSize(xWidth,yHight),&context);
//===================================================================
m_wndSplitter.RecalcLayout() ;//これが最重要です!
return TRUE;
}

画像も載せておきます、非常に大切なコードです

料理サンプル画像と料理手順を張っけ

HPから料理を選び貼り付けます、更に献立と材料も張っけます。その後材料を右画面から選択して前準備の終了です、但しこれからは多くの現実を知る事に成りますが!料理のカロリ-管理は想像以上に難しいのです。例えばご飯の普通盛で既に300kcal以上あり普通1日総カロリ-は1800kcalぐらいですよねそれを3食で割ると1食当たり600kcalです、ですから残りは300kcalしか有りません!世の中には食事の内容が命に係わる方が沢山います、その方達にはこれが重要なのです!

理想的な食事管理を目指してアプリケ-ションを作ります!

上記のコードはクリップ・ボードから取り込みます

コピ-がテキスト?画像等は自動認識して取り込みます、皆さんこれは便利ですよ!

食材名称は実にでたらめで厚生労働省の食材リストには無い物が多い

実にいい加減です、これでどうやって栄養管理をしているのか?皆目わかりません皆さんこれが現実なのです。食品添加物とか言う前にこれのら方が問題でしょう!いえいえまだこれらはいい方で、ほとんどが感覚的に食材の名前をきめているのでしょう!例えば「片栗粉」ですが有りそうな名前ですが厚生労働省の正式な食材候補リストには存在しては居りません!多分「本来はカタクリの地下茎から作られたデンプンの粉(澱粉)。しかし、大量生産され市場に流通している多くの片栗粉はジャガイモ(馬鈴薯)から …」とかその他の分類でしょう!栄養素が全然異なる。こんな事で正確な食材管理が出来ると皆さん思われますか?でも今もこの食べ物で命に係わる人が大勢いるんですよ!私もその中の1人。

以下は献立例です

材料(3〜4人分)
牛切り落とし肉
150g

小さじ1
片栗粉
大さじ1/2
満願寺唐辛子
4〜5本
かぼちゃ
1/4個
◎水
50cc
◎和風だしの素
小さじ1
◎砂糖
大さ自動選択食材じ2
◎みりん、醤油
各大さじ1

これじゃ~解らないでしょう、しかし総合カロリ-は記載されている!これって、笑うしかないでしょう。この中で唯一厚生労働省の食材リストにあるのは「酒」です!後は同一な名称食材は搭載されていない、病院食はどうしているのか?甚だ疑問です。皆さん結局は自分でやるしかないんです。