日曜日にBCB!



Do It Yourselfでひとつプログラムでも作ってみませんか。


第11話「Digital Design Technologyらしく その1」

Digital Design Technologyアイコン前回で一応寿分割の開発は一段落しました。しかしDDTらしいアクセサリとままだまだ言えません。私はいくつかオンラインソフトを公開しているので、既存ユーザーが「DDTならこの機能はある」と期待されている機能がいくつかあります。Digital Design Technologyは「ちょっと小粋なWindowsアクセサリ」を開発ポリシーにしていますので、全てのアクセサリに共通した機能を寿分割にも実装します。それは、 です。Digital Design Technologyらしい機能を公開するのはちょっと気が引けます。小粋で便利な機能ですから、内緒にしておきたいのですが、ここまで続けてきた寿分割の開発です。太っ腹で公開してしまいましょう。


常に前に表示

BCBのフォームには FormStyle と言うプロパティーがあり、これを fsStayOnTop にしておくと常に前に表示できます。ところがBCB3のオンラインヘルプには「実行時に FormStyle の値を変更することはお勧めできません。」とちょっと曖昧なことが書いてあります。以前のプログラムではこのプロパティーを実行時に変更していたのですが、正しく前に表示できないことがありました。そこで情報源から調べたところAPI関数のSetWindowPos関数で正常に実現できることがわかりました。今のDDTのソフトウェアは以下のマクロを使って通常表示と常に前に表示を切替えています。
// 常に前に表示
void FormOnTop(HWND hWnd){ ::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
// 通常表示
void FormNonTop(HWND hWnd){ ::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
切り替えが必要なところで、
通常→前 FormOnTop(切替えるウィンド->Handle);
前→通常 FormNonTop(切替えるウィンド->Handle);
としています。寿分割の「表示」メニューにチェックマーク付きで「常に前に表示」を追加し、これに対してコールバック関数で上記処理を入れます。またツールバーにもボタンを追加しましょう。ここまでお付き合い頂いた方には実装手順は簡単ですよね。

Caption Name 内容
「表示(V)」 ViewMNU 表示に関するメニュー。
  「ツールバー(T)」 ToolBarMNU ツールバーの表示を切り替える。チェックメニュー
  「ステータスバー(B)」 StatusBarMNU ステータスバーの表示を切り替える。チェックメニュー
  「-」 SEP31 メニューを見やすくするセパレータ。
  「常に前に表示(U)」 StayOnTopMNU 通常・常に前に表示を切り替える。チェックメニュー


メニュー 有効イメージ 無効イメージ コメント
表示/常に前に表示 前表示有効イメージ 前表示無効イメージ 無効イメージは実際には表示されません

ツールバーに「常に前に表示」ボタンとセパレータを一つ追加します。 「常に前に表示」ツールバー追加
また、「常に前に表示」ボタンはチェックボタンですので、 とします。

ではプログラミングです。上記のマクロをメイン画面のヘッダに定義します。これを利用する形でメニュー、ツールバーに共通のコールバック関数StayOnTopMNUClickを実装します。

StayOnTopMNUClick関数

//---------------------------------------------------------------------------
void __fastcall TMainWND::StayOnTopMNUClick(TObject *Sender)
{
    TMenuItem *ITEM = dynamic_cast<TMenuItem*>(Sender);    // メニューコントロール取得
    if (ITEM!=NULL){                                // メニューが選択された
        ITEM->Checked = (!ITEM->Checked);           // メニューチェックの反転
        StayOnTopBTN->Down = ITEM->Checked;         // ボタンチェック反転
    }
    TToolButton *BTN = dynamic_cast<TToolButton*>(Sender);    // ボタンコントロール取得
    if (BTN!=NULL){                                 // ボタンが選択された
        StayOnTopMNU->Checked = BTN->Down;          // メニューチェック←ボタンチェック
    }
    if (StayOnTopMNU->Checked) FormOnTop(MainWND->Handle);  // 常に前に表示
    else                       FormNonTop(MainWND->Handle); // 通常表示
}
//---------------------------------------------------------------------------
とても簡単ですね。


メニュー非表示

WIndowsの標準Look&Feelから言うとメニュー(メインメニュー)を非表示にするのはあまり薦められません。しかし、実際に使っているとほとんどがツールバーやポップアップメニュー操作で済ませて、メニューを操作することは非常に少なくなります。だったら、メニュー非表示も選択できるようにしよう、と言うのがDDTのポリシーです。DDTのソフトウェアの性質上、他のソフトウェアと同じに使うことが多いので、画面サイズはできるだけ小さくしています。ドクターUnits同TEではこのポリシーです。TipCalは電卓アクセサリですから、さらにサイズを極力小さくしたいのでポップアップメニューしかありません。異体字転も同様の理由ですが、将来はメニューやツールバーをつけようかなとも思っています。別段「不便だ」との意見も頂いていないのでそのままでもいいかとも思っています。もしご意見があれば クリックするとメーラーを起動しま までご連絡ください。優先的に対応させていただきます。

さて、メニューを非表示にするにはどうするのでしょうか? ツールバーやステータスバーにはVisibleプロパティーがあり、これをtrue...表示、false...非表示とすれば切り替えられます。一方メニューはメイン画面のMenuプロパティーでメニューコントロールを指定...表示、NULL...非表示とすれば切り替えられます。実際にはメイン画面のメニューがある/ないと切り替えているわけです。うまく活用すればメインメニューを複数から選択できると言うことです。実装手順はツールバーと同様簡単です。メニューの追加から行います。

Caption Name 内容
「表示(V)」 ViewMNU 表示に関するメニュー。
  「メニュー(M)」 MenuMNU メニューの表示を切り替える。チェックメニュー
  「ツールバー(T)」 ToolBarMNU ツールバーの表示を切り替える。チェックメニュー
  「ステータスバー(B)」 StatusBarMNU ステータスバーの表示を切り替える。チェックメニュー
  「-」 SEP31 メニューを見やすくするセパレータ。
  「常に前に表示(U)」 StayOnTopMNU 通常・常に前に表示を切り替える。チェックメニュー

さて、ここで2つの矛盾が生じます。 ツールバー境界線 もうひとつ問題が生じます。ツールバーとメニューの境界には境界線があります。メニューが非表示でツールバーが表示の場合、この境界線が残ってしまい、見た目が悪くなります。ToolBarコントロールの境界線プロパティEdgeBordersは実行時に変更しても正常に更新されません。Windowsの仕様なのかBCBのバグなのか私にははっきりしませんが、仕方がないのでちょっと小細工をします。ツールバーのEdgeBordersプロパティからebTopを削除し上側の境界を表示させなくします。その上でメニューとツールバーの間にベベルコントロールベベルコントロールを配置し、これで境界線を表示します。ベベルコントロールのプロパティーは以下のように設定します。
メニューとツールバーを排他的に表示させるため、両方のコールバック関数を共通化します。コールバック関数名もわかりやすくするために
MenuBarMNUClickと変更します。

改造MenuBarMNUClick関数(旧名ToolBarMNUClick関数)

//---------------------------------------------------------------------------
void __fastcall TMainWND::MenuBarMNUClick(TObject *Sender)
{
    TMenuItem *MNU = (TMenuItem*)Sender;    // メニューオブジェクト取得
    MNU->Checked = (!MNU->Checked);         // メニューチェックの反転
    if (!MNU->Checked){
        if (MNU->Name=="MenuMNU")    ToolBarMNU->Checked = true;   // ツールバーチェック
        if (MNU->Name=="ToolBarMNU") MenuMNU->Checked = true;      // メニューチェック
    }
    if (MenuMNU->Checked) MainWND->Menu = MainMNU;    // メニュー表示切替え
    else                  MainWND->Menu = NULL;
    ToolBAR->Visible = ToolBarMNU->Checked;           // ツールバー表示切替え

    SeparateBVL->Visible = MenuMNU->Checked && ToolBarMNU->Checked;  // ツールバー境界線表示
}
//---------------------------------------------------------------------------


フォ

TipCalフォント可変(MS Pゴシック9ポイント vs Ticago 14ポイント) Windowsの画面のプロパティーで「デザイン」の項目に「ウィンドの文字」がありますが、そのフォントを指定することはできません。これはWindowsのシステムデフォルトフォントに固定されているためです。システムデフォルトフォントはMSゴシックの12ポイントが標準でした(Windows95のメモ帳のフォントサイズがWindows標準です)。寿分割の分割ファイル一覧のフォントはMS Pゴシック9ポイントとしています。寿分割はその点ではWindowsの標準Look&Feelに則っていないと言えます。しかし、最近のWindowsで12ポイントの文字を表示しているアプリケーションを見つけることが難しくなっています。裏返して言えばフォントサイズを標準化する意味が薄れてきています。DDTのソフトウェアのほとんどはフォントを変更できます。ZipFinderでフォントを可変として、視力に難のあるユーザーから感謝の言葉を頂いたことがあります。異体字転では判別しにくい難字を大きなフォントで表示することにより判別を容易にできるので、私自身も重宝しています。ドクターUnits同TETipCalは私自身も少し大きめのフォントでいつも使っています。かつ、計算ツールですからMS Pゴシックではなく、フリーソフトで有名なTicagoフォントが大好きです。と言うわけで寿分割もフォントを可変とします。ただし、画面のあらゆる部分のフォントを可変にすることはWindowsの仕様上不可能です。寿分割では分割ファイル一覧のフォントを可変とします。

BCBでは多くの表示コントロールはフォント情報を持っています。また、親ウィンドのフォント情報を継承して使用するかどうかをParentFontプロパティーで指示します。寿分割の分割ファイル一覧コントロールも、デフォルトでは親ウィンド(メインウィンド)のフォント情報継承となっていますが、このプロパティーはコントロール独自のフォントを設定すると自動的にfalse(継承しない)となります。一般的にはフォント設定ダイアログを使用します。しかし、Digital Design Technologyでは設定画面で行います。他にも設定項目があるので「設定は一括で行う」のがDDT流です。実際のフォント設定は後の設定で行います。


起動位置を指定

Windowsではプログラム起動時のウィンド位置もフォント同様管理しています。デフォルトではデスクトップ左上から右下に向かってカスケードされてきます。しかし、前回起動した位置に再現されると便利です。DDTのソフトウェアのほとんどはフォント同様起動時の位置を指定できます。

寿分割では他のDDTのソフトウェアと同様に、 で行います。位置情報を記憶するのはWindowsレジストリを使わずに、初期化ファイルを使用します。レジストリの方が流行りというかWindows標準のように思われていますが、一旦レジストリに書きこむと、一般のユーザーでは消去が困難になります。肥大化していくレジストリはOSの動きまで遅くしてしまいます。寿分割のようにちょっとしたアクセサリごときで完全アンインストールが難しいのは個人的には嫌いです。その点、初期化ファイルは消去も簡単です。


設定画面

設定画面

設定画面を設けて、 を行います。設定画面は設計しません。既にDDTのソフトウェアのいくつかは設定画面を持っています。設定画面は他のBCBプロジェクトから必要なものを抽出して作成します。従ってフォント色、フォント修飾までオマケで付いてきます。ここの空間でも設計やプログラミングに関する説明はしません。アルゴリズム的にも大したことはしていませんので、再利用されたい方はどしどしソースリストを読んでください。
ほとんどは簡単なリスト、チェックボックス、ラジオボックスです。ポイントは、 です。

メイン画面から設定画面に設定情報を渡す際、ほとんどは各コントロールのプロパティ(メニュー表示の有無、フォント名、フォントサイズ等)で済むのですが、起動位置情報だけはどのコントロールにも属しません。また、設定画面に個々のコントロールの状態を引数で渡すと、引数が多くなってコーディングミスが発生しやすくなります。私は設定パラメータ構造体を作成し、ここにコントロールの状態や起動位置情報を記憶しています。これもDDTのソフトウェアに共通の手法です。

DDTのソフトウェアではウィンド位置列挙型に画面四隅、前回の位置、管理しない、の6つの列挙を定義しています。
//---------------------------------------------------------------------------
// ウィンド位置列挙
enum enWINLOCATION{
    WL_NA,      // 管理しない
    WL_PP,      // 前回の位置
    WL_LU,      // 左上
    WL_LL,      // 左下
    WL_RU,      // 右上
    WL_RL       // 右下
};
//---------------------------------------------------------------------------
続いて、寿分割の設定パラメータ構造体を決めます。フォント情報や色情報にはVCLのオブジェクトを使用し、メンバを抽象化しておきます。オブジェクト指向設計の基本ですね。
//---------------------------------------------------------------------------
// 設定パラメータ構造体
struct stKotoParam{
    TFont         *ViewFont;        // 表示フォント
    TColor        BGColor;          // 背景色
    bool          MenuVisible;      // メニュー表示
    bool          ToolBarVisible;   // ツールバー表示
    bool          StatusBarVisible; // ステータスバー表示
    enWINLOCATION WinLocation;      // ウィンド位置情報
};
//---------------------------------------------------------------------------
以上をメイン画面のヘッダファイルmain.hに定義しておきます。
では、設定画面のプログラミングに移ります。しかし他のDDTのソフトウェアの設定画面の流用ですから、説明は正直面倒です。ごく簡単に説明しますのでご了承ください。

フォント一覧

初期設定

初期設定では使用可能なフォント一覧を取得します。WindowsAPIのEnumFontFamilies関数とそのコールバック関数を使用します。コールバック関数でフォントリストのアイテムにフォント名と文字セットコードを追加します。コールバック関数は設定画面クラスのメンバ関数とはできないため、EnumFontFamilies関数→コールバック関数(EnumFontFamProcと命名)→フォント名登録メンバ関数(パブリック)の手続きをふみます。
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnCreate(TObject *Sender)
// 設定画面フォーム作成時コールバック
{
    FontNameBOX->Items->Clear();    // フォント名リストアイテムクリア
    ::EnumFontFamilies(GetDC(0), NULL, (FONTENUMPROC)EnumFontFamProc, NULL);   // フォントファミリー列挙
}
//---------------------------------------------------------------------------
int CALLBACK EnumFontFamProc(ENUMLOGFONT *lpelf, NEWTEXTMETRIC *lpntm, int FontType, LPARAM lParam)
// フォント列挙コールバック
{
    SetupDLG->AddFont(AnsiString((char*)lpelf->elfLogFont.lfFaceName), lpelf->elfLogFont.lfCharSet);  // フォント名登録
    return(1);
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::AddFont(AnsiString FontName, int CharSet)
// フォント名登録(パブリック関数)
{
    FontNameBOX->Items->AddObject(FontName, (TObject*)CharSet);    // フォント名、文字コード追加
}
//---------------------------------------------------------------------------

設定画面表示位置

設定画面の表示位置は常にメイン画面の右下に表示しています。この機能も寿分割に特有ではなく、他のDDTソフトウェアを流用したオマケです。設定画面が表示されるタイミングでのコールバック関数OnShowで処理します。
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnShow(TObject *Sender)
{
    TForm *OwnerForm = Application->MainForm;       // メイン画面

    Left = OwnerForm->Left + OwnerForm->Width/2;    // 設定画面はメイン画面の右半分位置
    if ((Left+Width) >Screen->Width) Left = Screen->Width  - Width;  // デスクトップをはみ出る場合は左へ

    Top  = OwnerForm->Top + OwnerForm->Height/2;    // 設定画面はメイン画面の下半分位置
    if ((Top+Height)>Screen->Height) Top = Screen->Height - Height;  // デスクトップをはみ出る場合は上へ
}
//---------------------------------------------------------------------------

設定実行

設定画面はメイン画面からExecute関数を呼び出して実行します。Execute関数はパブリック関数とします。Execute関数では、
を行います。また、設定画面クラスのプライベートメンバとして、
情報 内容
呼出しフォーム 設定画面を呼び出したフォーム。ウィンド移動を要求する先。
フォントサイズ符号 -1=内部レディングあり/+1=内部レディングなし
を持ちます。フォントサイズ符号の意味がわかりにくいかもしれません。VCLのTFontクラスの説明を参考にしてください。
以上2つをTSetupDLGクラスのプライベートメンバに登録します。
class TSetupDLG : public TForm
{
    :
private:     // ユーザー宣言
    TForm *OwnerForm;       // 呼出しフォーム
    int   FontSizeSign;     // 割り当てフォント
    :
設定実行関数Executeのプログラミングです。
//---------------------------------------------------------------------------
bool __fastcall TSetupDLG::Execute(TForm *_OwnerForm, stKotoParam *KotoParam)
// 設定実行
// _OwnerForm (TForm*)       呼出しフォーム
// KotoParam  (stKotoParam*) 寿分割設定パラメータ
// 戻り値     (bool)         true=設定実行/false=設定キャンセル
{
    OwnerForm = _OwnerForm;                                   // 呼出しフォーム登録
    FontSizeSign = (KotoParam->ViewFont->Size < 0 ? -1 : 1);  // フォントサイズ符号

    MenuVisibleCHK->Checked      = KotoParam->MenuVisible;        // メニュー表示チェック設定
    ToolBarVisibleCHK->Checked   = KotoParam->ToolBarVisible;     // ツールバー表示チェック設定
    StatusBarVisibleCHK->Checked = KotoParam->StatusBarVisible;   // ステータスバー表示チェック設定

    FontNameBOX->Text = KotoParam->ViewFont->Name;                // フォント名リスト設定
    FontSizeBOX->Text = Format("%d", OPENARRAY(TVarRec, (abs(KotoParam->ViewFont->Size))));  // フォントサイズリスト設定
    FontBoldCHK->Checked = KotoParam->ViewFont->Style.Contains(fsBold);       // フォントボールドチェック設定
    FontItalicCHK->Checked = KotoParam->ViewFont->Style.Contains(fsItalic);   // フォントイタリックチェック設定

    SetupSample(KotoParam->ViewFont, KotoParam->BGColor);        // フォントサンプル表示
    SetWindowLocation(KotoParam->WinLocation);                   // ウィンド起動位置ラジオボックス設定
    OnPositionGRPClick(PositionGRP);                             // ウィンド位置移動ボタン初期化

    ShowModal();     // モーダル入力

    if (ModalResult==mrOk){    // OKボタンが押されたら
        KotoParam->MenuVisible      = MenuVisibleCHK->Checked;       // メニュー表示登録
        KotoParam->ToolBarVisible   = ToolBarVisibleCHK->Checked;    // ツールバー表示登録
        KotoParam->StatusBarVisible = StatusBarVisibleCHK->Checked;  // ステータスバー表示登録
        KotoParam->ViewFont->Assign(SampleEDT->Font);                // フォント登録
        KotoParam->BGColor = SampleEDT->Color;                       // 背景色登録
        KotoParam->WinLocation = GetWindowLocation();                // ウィンド位置登録
    }

    return(ModalResult==mrOk);       // 設定実行またはキャンセルを返す
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::SetupSample(TFont *ViewFont, TColor BGColor)
// フォント設定サンプル表示
{
    SampleEDT->Font->Assign(ViewFont);                     // サンプルフォント設定
    SampleEDT->Color = BGColor;                            // サンプル背景色設定
    SetColorIndex(FontColorBOX, SampleEDT->Font->Color);   // フォント色リスト設定
    SetColorIndex(BackgroundColorBOX, SampleEDT->Color);   // 背景色リスト設定
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::SetWindowLocation(enWINLOCATION WinLocation)
// ウィンド位置ラジオボックス設定
{
    switch (WinLocation){
        case WL_LU: PositionGRP->ItemIndex = 0; break;  // 左上
        case WL_LL: PositionGRP->ItemIndex = 1; break;  // 左下
        case WL_PP: PositionGRP->ItemIndex = 2; break;  // 前回の位置
        case WL_RU: PositionGRP->ItemIndex = 3; break;  // 右上
        case WL_RL: PositionGRP->ItemIndex = 4; break;  // 右下
        case WL_NA: PositionGRP->ItemIndex = 5; break;  // 管理しない
    }
}
//---------------------------------------------------------------------------
enWINLOCATION __fastcall TSetupDLG::GetWindowLocation()
// ラジオボックスウィンド位置取得
{
    enWINLOCATION WinLocation;    // ウィンド位置

    switch (PositionGRP->ItemIndex){
        case 0: WinLocation = WL_LU;    break;  // 左上
        case 1: WinLocation = WL_LL;    break;  // 左下
        case 2: WinLocation = WL_PP;    break;  // 前回の位置
        case 3: WinLocation = WL_RU;    break;  // 右上
        case 4: WinLocation = WL_RL;    break;  // 右下
        case 5: WinLocation = WL_NA;    break;  // 管理しない
    }
    return(WinLocation);
}
//---------------------------------------------------------------------------

メニュー、ツールバー表示排他処理

メニューとツールバーの表示チェックはどちらかが必ずオンになるように排他処理を行います。
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnVisibleCHKClick(TObject *Sender)
// メニュー、ツールバー表示排他処理
{
    TCheckBox *CHK = (TCheckBox*)Sender;    // 「メニュー」チェックまたは「ツールバー」チェック

    if (!CHK->Checked){    // チェックがオフならば排他処理
        if (CHK->Name == "MenuVisibleCHK")    ToolBarVisibleCHK->Checked = true;
        if (CHK->Name == "ToolBarVisibleCHK") MenuVisibleCHK->Checked    = true;
    }
}
//---------------------------------------------------------------------------

色管理

色管理

フォント色、背景色リストの色管理を行います。色を指定してリストインデックス設定(SetColorIndex関数)、オーナードロー(OnColorBOXDrawItem関数)、リスト変更時の表示サンプル表示処理(OnColorBOXChange関数)を行います。全ての処理はフォント色、背景色で同一の関数を使いますし、当然他のプロジェクトへの再利用を前提にプログラミングします。
色はWidowsの標準16色と、システム色からの17色から選択できるようにしています。フォント色はWindowsシステム色でTColor型のclWindowTextに、背景色は同システム色でclWindowになります。
オーナードローが若干難しいでしょうか。要はリストアイテムを表示する必要が生じた場合、指定の色の矩形と、システム色の場合は指定の色の反転色で「システム」(実際のプログラムは半角カタカナを使用)と描画します。キャンバス、ペン、ブラシのグラフィックの概念を理解している必要がありますが、その手の解説書は世に多く出回っていますので理解は簡単だと思います。蛇足ですが、オーナードローを使うと、Windowsが全てグラフィック処理されていると言うことがわかると思います。単にテキストを表示するだけでも、テキストデータ+フォントデータ→描画データ→キャンバス再描画のグラフィックの大変な手順を踏んでいるのだなと改めて感心します。それも高速なグラフィックハードウェアが開発されているからこそ実現できるわけで、こんなことだけでCPUだけがパソコンの性能ではないと思うのは、もう私が時代遅れなのでしょうか。(^^;
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::SetColorIndex(TWinControl *Control, TColor Color)
// 色を指定してリストインデックス設定
{
    TComboBox *BOX = (TComboBox*)Control;       // リストコントロール
    if (Color==clWindowText) BOX->ItemIndex =  0;   // システム(文字色)
    if (Color==clWindow)     BOX->ItemIndex =  0;   // システム(背景色)
    if (Color==clBlack)   BOX->ItemIndex =  1;  // 黒
    if (Color==clMaroon)  BOX->ItemIndex =  2;  // 茶
    if (Color==clGreen)   BOX->ItemIndex =  3;  // 緑
    if (Color==clOlive)   BOX->ItemIndex =  4;  // オリーブ
    if (Color==clNavy)    BOX->ItemIndex =  5;  // 紺
    if (Color==clPurple)  BOX->ItemIndex =  6;  // 紫
    if (Color==clTeal)    BOX->ItemIndex =  7;  // 青緑
    if (Color==clGray)    BOX->ItemIndex =  8;  // 灰色
    if (Color==clSilver)  BOX->ItemIndex =  9;  // 銀色
    if (Color==clRed)     BOX->ItemIndex = 10;  // 赤
    if (Color==clLime)    BOX->ItemIndex = 11;  // 黄緑
    if (Color==clYellow)  BOX->ItemIndex = 12;  // 黄
    if (Color==clBlue)    BOX->ItemIndex = 13;  // 青
    if (Color==clFuchsia) BOX->ItemIndex = 14;  // 赤紫
    if (Color==clAqua)    BOX->ItemIndex = 15;  // 水色
    if (Color==clWhite)   BOX->ItemIndex = 16;  // 白
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnColorBOXDrawItem(TWinControl *Control, int Index, TRect &Rect, TOwnerDrawState State)
// オーナードロー
{
    TComboBox *BOX = (TComboBox*)Control;    // リストコントロール
    switch (Index){    // リスト番号
        case  0:       // システム
            if (BOX->Name=="FontColorBOX")       BOX->Canvas->Brush->Color = clWindowText;
            if (BOX->Name=="BackgroundColorBOX") BOX->Canvas->Brush->Color = clWindow;
            break;
        case  1:    BOX->Canvas->Brush->Color = clBlack;    break;  // 黒
        case  2:    BOX->Canvas->Brush->Color = clMaroon;   break;  // 茶
        case  3:    BOX->Canvas->Brush->Color = clGreen;    break;  // 緑
        case  4:    BOX->Canvas->Brush->Color = clOlive;    break;  // オリーブ
        case  5:    BOX->Canvas->Brush->Color = clNavy;     break;  // 紺
        case  6:    BOX->Canvas->Brush->Color = clPurple;   break;  // 紫
        case  7:    BOX->Canvas->Brush->Color = clTeal;     break;  // 青緑
        case  8:    BOX->Canvas->Brush->Color = clGray;     break;  // 灰色
        case  9:    BOX->Canvas->Brush->Color = clSilver;   break;  // 銀色
        case 10:    BOX->Canvas->Brush->Color = clRed;      break;  // 赤
        case 11:    BOX->Canvas->Brush->Color = clLime;     break;  // 黄緑
        case 12:    BOX->Canvas->Brush->Color = clYellow;   break;  // 黄
        case 13:    BOX->Canvas->Brush->Color = clBlue;     break;  // 青
        case 14:    BOX->Canvas->Brush->Color = clFuchsia;  break;  // 赤紫
        case 15:    BOX->Canvas->Brush->Color = clAqua;     break;  // 水色
        case 16:    BOX->Canvas->Brush->Color = clWhite;    break;  // 白
    }
    Rect.Left++;    Rect.Top++;     // リストの1ピクセル内側に指定色で矩形を描画
    Rect.Right--;   Rect.Bottom--;
    BOX->Canvas->FillRect(Rect);
    if (Index==0){                  // システム色の場合は反転色で「システム」と描画
        int FontColor;
        if (BOX->Name=="FontColorBOX")       FontColor = ::GetSysColor(COLOR_WINDOWTEXT);
        if (BOX->Name=="BackgroundColorBOX") FontColor = ::GetSysColor(COLOR_WINDOW);
        BOX->Canvas->Font->Color = (TColor)(FontColor ^ 0x0FFFFFF);
        RECT rect;
        rect.left  = Rect.Left;     rect.top = Rect.Top;
        rect.right = Rect.Right;    rect.bottom = Rect.Bottom;
        ::DrawText(BOX->Canvas->Handle, "システム", strlen("システム"), &rect, DT_CENTER);
                                        // 実際のプログラムは半角カタカナを使用しています
    }
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnColorBOXChange(TObject *Sender)
// リスト変更コールバック→表示サンプル更新処理
{
    TComboBox *BOX = (TComboBox*)Sender;    // リストコントロール

    TColor Color;    // フォント色・背景色取得
    switch (BOX->ItemIndex){
        case  0:        // システム
            if (BOX->Name=="FontColorBOX")       Color = clWindowText;
            if (BOX->Name=="BackgroundColorBOX") Color = clWindow;
            break;
        case  1:    Color = clBlack;    break;  // 黒
        case  2:    Color = clMaroon;   break;  // 茶
        case  3:    Color = clGreen;    break;  // 緑
        case  4:    Color = clOlive;    break;  // オリーブ
        case  5:    Color = clNavy;     break;  // 紺
        case  6:    Color = clPurple;   break;  // 紫
        case  7:    Color = clTeal;     break;  // 青緑
        case  8:    Color = clGray;     break;  // 灰色
        case  9:    Color = clSilver;   break;  // 銀色
        case 10:    Color = clRed;      break;  // 赤
        case 11:    Color = clLime;     break;  // 黄緑
        case 12:    Color = clYellow;   break;  // 黄
        case 13:    Color = clBlue;     break;  // 青
        case 14:    Color = clFuchsia;  break;  // 赤紫
        case 15:    Color = clAqua;     break;  // 水色
        case 16:    Color = clWhite;    break;  // 白
    }
    if (BOX==FontColorBOX) SampleEDT->Font->Color = Color;   // サンプルフォント色更新
    if (BOX==BackgroundColorBOX) SampleEDT->Color = Color;   // サンプル背景色更新
}
//---------------------------------------------------------------------------

フォント名、サイズ、ボールド、イタリック

フォントの名前とサイズのリスト、ボールドとイタリックのチェックボックスに対するコールバック処理です。それぞれのコールバックではサンプル表示を更新します。
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnFontNameBOXChange(TObject *Sender)
// フォント名リスト変更コールバック
{
    SampleEDT->Font->Name = FontNameBOX->Text;    // サンプル表示フォント名設定
                                                  // サンプル表示文字コード設定
    SampleEDT->Font->Charset = (Byte)FontNameBOX->Items->Objects[FontNameBOX->ItemIndex];
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnFontSizeBOXChange(TObject *Sender)
// フォントサイズリスト変更コールバック
{
    // サンプル表示フォントサイズ設定
    SampleEDT->Font->Size = FontSizeSign * FontSizeBOX->Text.ToIntDef(SampleEDT->Font->Size);
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnFontBoldCHKClick(TObject *Sender)
// フォントボールドチェック変更コールバック
{
    // サンプルボールド設定
    if (FontBoldCHK->Checked) SampleEDT->Font->Style = SampleEDT->Font->Style << fsBold;
    else                      SampleEDT->Font->Style = SampleEDT->Font->Style >> fsBold;
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnFontItalicCHKClick(TObject *Sender)
// フォントイタリックチェック変更コールバック
{
    // サンプルイタリック設定
    if (FontItalicCHK->Checked) SampleEDT->Font->Style = SampleEDT->Font->Style << fsItalic;
    else                        SampleEDT->Font->Style = SampleEDT->Font->Style >> fsItalic;
}
//---------------------------------------------------------------------------

ウィンド位置選択

ウィンド位置を選択した場合、画面四隅の場合は「今すぐ移動」ボタンを有効にします。「前回の位置」と「管理しない」の場合はボタンを無効にします。また、「今すぐ移動」ボタンが押された場合には、メイン画面(呼出し画面)に移動をメッセージ要求します。
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnPositionGRPClick(TObject *Sender)
{
    switch (PositionGRP->ItemIndex){
        case 0:     // 左上
        case 1:     // 左下
        case 3:     // 右上
        case 4:     // 右下
            MoveNowBTN->Enabled = true;
            break;
        default:
            MoveNowBTN->Enabled = false;
    }
}
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnMoveNowBTNClick(TObject *Sender)
{
    enWINLOCATION WinLocation;

    switch(PositionGRP->ItemIndex){
        case 0: WinLocation = WL_LU;    break;  // 左上
        case 1: WinLocation = WL_LL;    break;  // 左下
        case 3: WinLocation = WL_RU;    break;  // 右上
        case 4: WinLocation = WL_RL;    break;  // 右下
    }
    OwnerForm->Perform(FDM_MOVETOCORNER, (long)WinLocation, 0);
}
//---------------------------------------------------------------------------
メッセージFDM_MOVETOCORNERはメイン画面ヘッダmain.h(WM_USER+3)で定義しておきます。

ヘルプ表示

「ヘルプ」ボタンを押したときに設定画面のヘルプを表示します。事前にヘルプを作って、ヘルプコンテキストIDのID_SETを定義しておきます。
//---------------------------------------------------------------------------
void __fastcall TSetupDLG::OnHelpBTNClick(TObject *Sender)
{
    Application->HelpCommand(HELP_CONTEXT, IDH_SET);     // ヘルプ表示
}
//---------------------------------------------------------------------------
これで設定画面は出来ました。


フォントと起動時位置の設定機能の説明が長くなりました。一回で終わるかと思ったのですが、まだメイン画面からの呼出しと設定条件の保存の話が残っています。ページが長すぎますので、残念ながら次回に説明を繰り越します。

今回のプログラミング行数: 262行
今回までのプログラミング行数: 802行


目次に戻る目次に戻る トップに戻るトップに戻る