集合型

Delphi には、集合型というものがあります。集合型とは、同じ列挙型の集まりのことをいいます。

では、まず列挙型からみてみましょう。例を見てください。

type
  TMonth = (January, February, March, April, May);        

これは、識別子(ここでは、January、February、March、April、May の5つ)を列挙して、それらの値をとることが出来る TMonth という列挙型を定義したことになります。このようにしますと、January、February、March、April、May のそれぞれが TMonth という型の定数であることを意味します。 次の例も見てください。

type
  TMonth = (January, February, March, April, May);

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  i := Ord(January);
  ShowMessage(IntToStr(i));

  i := Ord(February);
  ShowMessage(IntToStr(i));

  i := Ord(March);
  ShowMessage(IntToStr(i));

  i := Ord(April);
  ShowMessage(IntToStr(i));

  i := Ord(May);
  ShowMessage(IntToStr(i));

end;

このように、Ord 関数を使いますと、January から順番に 0、1、2、3、4 の値が返されることになります。列挙型については、単にそれぞれの値を並べて、それらをまとめて一つの名前(型名)を付けているということが分かれば大丈夫です。

それでは、set について見てみましょう。set は最初に言いましたように列挙型の集まりです。

type
  TMonth = (January, February, March, April, May);
  TMonthSet = set of TMonth;

この TMonthSet は、January、February、March、April、May の集まりを値とする TMonthSet という集合型を意味しています。

これは実際に使用する場合、変数として宣言して使います(ここでは TMonthSet 型の変数として)。その際、その変数は January、February、March、April、May の値、つまり TMonth の値を組み合わせて使うことになります。例を見てください。

type
  TMonth = (January, February, March, April, May);
  TMonthSet = set of TMonth;
  
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  MonthSet: TMonthSet; // TMonthSet型の変数を宣言
begin
  MonthSet := [February, April, May]; // MonthSetが3つの値を保持

  if January in MonthSet then
    ShowMessage('含まれています')
  else
    ShowMessage('含まれていません');

  if February in MonthSet then
    ShowMessage('含まれています')
  else
    ShowMessage('含まれていません');

end;

このように、[ ] を使用して、TMonthSet の要素にアクセスします。そして、in 演算子を使用して指定された要素が MonthSet にあるかどうかを調べることが出来ます。

また、この列挙型は Delphi ではけっこう沢山見つけることが出来ます。例えは、TShiftState や TMouseButton などで列挙型を見ることが出来ます。(エディタ上で、適当な場所に TShiftState と入力してヘルプを起動してみてください。ですから、次のようにしても、ちゃんと値が返ってきます。

procedure TForm1.Button2Click(Sender: TObject);
var
  i: Integer;
begin
  i := Ord(ssAlt);
  ShowMessage(IntToStr(i));

  i := Ord(mbLeft);
  ShowMessage(IntToStr(i));

end;

さて、この集合型なんですが、他にも要素を操作できる演算子が用意されています。ここでは、TFontStyles 型を例にしてやってみたいと思います。フォームにラベル( Label )を1つ、チェックボックス( CheckBox )を4つ貼り付けて下さい。

var
  MyFont: TFontStyles;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyFont := [];
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if CheckBox1.Checked then
    Include(MyFont, fsItalic)
  else
    Exclude(MyFont, fsItalic);

  Label1.Font.Style := MyFont;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  if CheckBox2.Checked then
    Include(MyFont, fsUnderline)
  else
    Exclude(MyFont, fsUnderline);

  Label1.Font.Style := MyFont;
end;

procedure TForm1.CheckBox3Click(Sender: TObject);
begin
  if CheckBox3.Checked then
    Include(MyFont, fsBold)
  else
    ExClude(MyFont, fsBold);

  Label1.Font.Style := MyFont;
end;

procedure TForm1.CheckBox4Click(Sender: TObject);
begin
  if CheckBox4.Checked then
    Include(MyFont, fsStrikeOut)
  else
    Exclude(MyFont, fsStrikeOut);

  Label1.Font.Style := MyFont;
end;

ヘルプを見てみますと、TFontStyles は以下のようになっています。

type 
  TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut);
  TFontStyles = set of TFontStyle;

Include、Exclude でそれぞれ要素の追加と削除をしています。(ヘルプもぜひ見てください。)

また、上のコードは以下のように1つの手続きにしてしまうことも出来ます。 チェックボックスの Tag プロパティを CheckBox1 から、それぞれ 0、1、2、3 としてください。そして、4つのチェックボックスを選択して( 詳しいやり方は、こちらを参考にして下さい )以下のように書きます。

var
  MyFont: TFontStyles;

procedure TForm1.AllCheckBoxClick(Sender: TObject);
begin
  case (Sender as TCheckBox).Tag of

    0:
    if (Sender as TCheckBox).Checked then
      Include(MyFont, fsBold)
    else
      Exclude(MyFont, fsBold);

    1:
    if (Sender as TCheckBox).Checked then
      Include(MyFont, fsItalic)
    else
      Exclude(MyFont, fsItalic);

    2:
    if (Sender as TCheckBox).Checked then
      Include(MyFont, fsUnderline)
    else
      Exclude(MyFont, fsUnderline);

    3:
    if (Sender as TCheckBox).Checked then
      Include(MyFont, fsStrikeOut)
    else
      Exclude(MyFont, fsStrikeOut);

  end; // case

  Label1.Font.Style := MyFont;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyFont := [];
end;

また、MyFont := []; は、空集合を表しています。

集合演算子には、Include、Exclude の他にも、+-* 演算子を使用することが出来ます。

それでは、一旦終了して、「ファイル」→「新規作成」→「アプリケーション」を選択してください。今度は、フォームにはラジオグループ( RadioGroup )を1つ、ラベル( Label )を1つ貼り付けて下さい。そして、以下のように書きます。

type
  TMyFontType = (BoldItalicUnderline, Bold, Italic);

  TForm1 = class(TForm)
    RadioGroup1: TRadioGroup;
    Label1: TLabel;
    procedure RadioGroup1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.RadioGroup1Click(Sender: TObject);
var
  MyFont1, MyFont2, FinalFont: TFontStyles;
begin
  MyFont1 := [fsBold, fsItalic];
  MyFont2 := [fsBold, fsUnderline];

  case TMyFontType(RadioGroup1.ItemIndex) of
    BoldItalicUnderline: FinalFont := MyFont1 + MyFont2;
    Bold:                FinalFont := MyFont1 * MyFont2;
    Italic:              FinalFont := MyFont1 - MyFont2;
  end;

  Label1.Font.Style := FinalFont;

end;

case 文の所は、ちょっと無駄な動きをしているかも知れません。(^^; 次のように書いたほうが、分かりやすいかもしれません。

case RadioGroup1.ItemIndex of
  0: FinalFont := MyFont1 + MyFont2;
  1: FinalFont := MyFont1 * MyFont2;
  2: FinalFont := MyFont1 - MyFont2;
end;

ただ、TMyFontStyle を使用したかったので、今回はこのようにしてみました。またこのようにして、+、-、* 演算子を使います。

+ 演算子は、それぞれの要素を全て含めます。つまり、A と B があり、A + B となっていた場合、A、B に含まれていたもの全てが A + B に含まれることになります。

- 演算子は、A、B があり A - B となっていた場合、A に含まれていて、B に含まれていないものが A - B に含まれることになります。

* 演算子は、A、B があり、A * B となっていた場合、A、B の両方に含まれているものが A * B に含まれることになります。

また、

type
  TMonth = (January, February, March);
  TMonthSet = set of TMonth;

上のコードは、次のように書くことが出来ます。

type
  TMonthSet = set of (January, February, March);    

ちょっと一言:

例えば、フォームにボタンを貼り付ける場合、まずコンポーネントパレットでボタンをクリックしてから、フォームの適当な場所をクリックしてやることでボタンを貼り付けていました。実は、このやり方以外にもボタンを貼り付ける方法があります。 それは、コンポーネントパレット上でフォームに貼り付けたいコンポーネントをダブルクリックするだけで、貼り付けることが出来ちゃいます。( 実は、このやり方を今日、偶然見つけました(^^;。何気なしにダブルクリックしてみると、なんと張り付くではありませんか。このやり方は多分あまり知られていないと思うので、他の人に自慢しちゃいましょう。( あまり知っていても役に立ちませんが(^^; ・・・・・と書き終えたところで、クイックスタートを見てみると、ズバリ載ってました。もしかして知らなかったのは自分だけだったのかも・・。)


up next
Last update: 2002/5/27