コンボボックスをオーナードローする方法を紹介します。
まず、オーナードローしたいコンボボックスのDrawModeプロパティをDrawMode.OwnerDrawFixedまたはDrawMode.OwnerDrawVariableにします。OwnerDrawFixedの場合、項目の高さを個別に変更することができません(つまり、すべての項目が同じ高さとなります)。OwnerDrawVariableを指定した時は、MeasureItemイベントハンドラで項目の高さを個別に指定できます。MeasureItemイベントが発生するのは、DrawModeプロパティがOwnerDrawVariableに指定されている時のみです。
項目の描画はDrawItemイベントハンドラで行います。e.Graphicsで得られるGraphicsオブジェクトに対して具体的な描画を行います。
次に具体的な例を示します。この例では、コンボボックスComboBox1の項目にフォント名のリストを追加し、オーナードローにより、そのフォントで項目のテキストを描画するようにしています。なお、インストールされているフォントを取得する方法はこちらで説明しています。
Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList 'オーナードローを指定 'DrawMode.OwnerDrawVariableを指定した時は、 'MeasureItemが発生する ComboBox1.DrawMode = DrawMode.OwnerDrawFixed '項目の高さを設定 ComboBox1.ItemHeight = 20 'DrawItemイベントハンドラの追加 AddHandler ComboBox1.DrawItem, AddressOf ComboBox1_DrawItem 'フォント名をComboBox1のリストに追加する 'InstalledFontCollectionオブジェクトの取得 Dim ifc As New System.Drawing.Text.InstalledFontCollection 'インストールされているすべてのフォントファミリアを取得 Dim ffs As FontFamily() = ifc.Families Dim ff As FontFamily For Each ff In ffs 'ここではスタイルにRegularが使用できるフォントのみを表示 If ff.IsStyleAvailable(FontStyle.Regular) Then ComboBox1.Items.Add(ff.Name) End If Next ff End Sub 'DrawItemイベントハンドラ '項目を描画する Private Sub ComboBox1_DrawItem(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DrawItemEventArgs) '背景を描画する '項目が選択されている時は強調表示される e.DrawBackground() Dim cmb As ComboBox = CType(sender, ComboBox) '項目に表示する文字列 Dim txt As String If e.Index > -1 Then txt = cmb.Items(e.Index).ToString() Else txt = cmb.Text End If '使用するフォント Dim f As New Font(txt, cmb.Font.Size) '使用するブラシ Dim b = New SolidBrush(e.ForeColor) '文字列を描画する Dim ym As Single = _ (e.Bounds.Height - e.Graphics.MeasureString(txt, f).Height) / 2 e.Graphics.DrawString(txt, f, b, e.Bounds.X, e.Bounds.Y + ym) f.Dispose() b.Dispose() 'フォーカスを示す四角形を描画 e.DrawFocusRectangle() End Sub
private void Form1_Load(object sender, System.EventArgs e) { ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList; //オーナードローを指定 //DrawMode.OwnerDrawVariableを指定した時は、 //MeasureItemが発生する ComboBox1.DrawMode = DrawMode.OwnerDrawFixed; //項目の高さを設定 ComboBox1.ItemHeight = 20; //DrawItemイベントハンドラの追加 ComboBox1.DrawItem += new DrawItemEventHandler(ComboBox1_DrawItem); //フォント名をComboBox1のリストに追加する //InstalledFontCollectionオブジェクトの取得 System.Drawing.Text.InstalledFontCollection ifc = new System.Drawing.Text.InstalledFontCollection(); //インストールされているすべてのフォントファミリアを取得 FontFamily[] ffs = ifc.Families; foreach (FontFamily ff in ffs) //ここではスタイルにRegularが使用できるフォントのみを表示 if (ff.IsStyleAvailable(FontStyle.Regular)) ComboBox1.Items.Add(ff.Name); } //DrawItemイベントハンドラ //項目を描画する private void ComboBox1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e) { //背景を描画する //項目が選択されている時は強調表示される e.DrawBackground(); ComboBox cmb = (ComboBox) sender; //項目に表示する文字列 string txt = e.Index > -1 ? cmb.Items[e.Index].ToString() : cmb.Text; //使用するフォント Font f = new Font(txt, cmb.Font.Size); //使用するブラシ Brush b = new SolidBrush(e.ForeColor); //文字列を描画する float ym = (e.Bounds.Height - e.Graphics.MeasureString(txt, f).Height) / 2; e.Graphics.DrawString(txt, f, b, e.Bounds.X, e.Bounds.Y + ym); f.Dispose(); b.Dispose(); //フォーカスを示す四角形を描画 e.DrawFocusRectangle(); }
上記の例ではOwnerDrawFixedとしていますが、フォントにより項目の高さが異なるため、本来ならばOwnerDrawVariableを使いたいところです。ところが、OwnerDrawVariableによりオーナードローしたコンボボックスは、項目のリストをページ単位で下にスクロールさせた時、なぜか上にスクロールしたような見え方になります。OwnerDrawFixedではこのような現象が起こりません。(.NET Framework 1.1、2.0で確認)
DrawModeをOwnerDrawVariableとした例も紹介しましょう。OwnerDrawVariableとした場合は、ComboBoxのMeasureItemイベントで項目のサイズを指定します。上記コードとの変更点は、DrawModeをOwnerDrawVariableとしたのと、ComboBox1のMeasureItemイベントハンドラを追加した点のみです。
Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList 'オーナードローを指定 'DrawMode.OwnerDrawVariableを指定した時は、 'MeasureItemが発生する ComboBox1.DrawMode = DrawMode.OwnerDrawVariable '項目の高さを設定 ComboBox1.ItemHeight = 20 'DrawItemイベントハンドラの追加 AddHandler ComboBox1.DrawItem, AddressOf ComboBox1_DrawItem AddHandler ComboBox1.MeasureItem, AddressOf ComboBox1_MeasureItem 'フォント名をComboBox1のリストに追加する 'InstalledFontCollectionオブジェクトの取得 Dim ifc As New System.Drawing.Text.InstalledFontCollection 'インストールされているすべてのフォントファミリアを取得 Dim ffs As FontFamily() = ifc.Families Dim ff As FontFamily For Each ff In ffs 'ここではスタイルにRegularが使用できるフォントのみを表示 If ff.IsStyleAvailable(FontStyle.Regular) Then ComboBox1.Items.Add(ff.Name) End If Next ff End Sub 'DrawItemイベントハンドラ '項目を描画する Private Sub ComboBox1_DrawItem(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DrawItemEventArgs) '背景を描画する '項目が選択されている時は強調表示される e.DrawBackground() Dim cmb As ComboBox = CType(sender, ComboBox) '項目に表示する文字列 Dim txt As String If e.Index > -1 Then txt = cmb.Items(e.Index).ToString() Else txt = cmb.Text End If '使用するフォント Dim f As New Font(txt, cmb.Font.Size) '使用するブラシ Dim b = New SolidBrush(e.ForeColor) '文字列を描画する Dim ym As Single = _ (e.Bounds.Height - e.Graphics.MeasureString(txt, f).Height) / 2 e.Graphics.DrawString(txt, f, b, e.Bounds.X, e.Bounds.Y + ym) f.Dispose() b.Dispose() 'フォーカスを示す四角形を描画 e.DrawFocusRectangle() End Sub 'ComboBox1のMeasureItemイベントハンドラ Private Sub ComboBox1_MeasureItem(ByVal sender As Object, _ ByVal e As MeasureItemEventArgs) Dim cmb As ComboBox = CType(sender, ComboBox) Dim txt As String If e.Index > -1 Then txt = cmb.Items(e.Index).ToString() Else txt = cmb.Text End If '使用するフォント Dim f As New Font(txt, cmb.Font.Size) '項目の高さを決定 e.ItemHeight = CInt(e.Graphics.MeasureString(txt, f).Height) End Sub
private void Form1_Load(object sender, System.EventArgs e) { ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList; //オーナードローを指定 //DrawMode.OwnerDrawVariableを指定した時は、 //MeasureItemが発生する ComboBox1.DrawMode = DrawMode.OwnerDrawVariable; //項目の高さを設定 ComboBox1.ItemHeight = 20; //DrawItemイベントハンドラの追加 ComboBox1.DrawItem += new DrawItemEventHandler(ComboBox1_DrawItem); //フォント名をComboBox1のリストに追加する //InstalledFontCollectionオブジェクトの取得 System.Drawing.Text.InstalledFontCollection ifc = new System.Drawing.Text.InstalledFontCollection(); //インストールされているすべてのフォントファミリアを取得 FontFamily[] ffs = ifc.Families; foreach (FontFamily ff in ffs) //ここではスタイルにRegularが使用できるフォントのみを表示 if (ff.IsStyleAvailable(FontStyle.Regular)) ComboBox1.Items.Add(ff.Name); } //ComboBox1のDrawItemイベントハンドラ //項目を描画する private void ComboBox1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e) { //背景を描画する //項目が選択されている時は強調表示される e.DrawBackground(); ComboBox cmb = (ComboBox)sender; //項目に表示する文字列 string txt = e.Index > -1 ? cmb.Items[e.Index].ToString() : cmb.Text; //使用するフォント Font f = new Font(txt, cmb.Font.Size); //使用するブラシ Brush b = new SolidBrush(e.ForeColor); //文字列を描画する float ym = (e.Bounds.Height - e.Graphics.MeasureString(txt, f).Height) / 2; e.Graphics.DrawString(txt, f, b, e.Bounds.X, e.Bounds.Y + ym); f.Dispose(); b.Dispose(); //フォーカスを示す四角形を描画 e.DrawFocusRectangle(); } //ComboBox1のMeasureItemイベントハンドラ private void ComboBox1_MeasureItem(object sender, MeasureItemEventArgs e) { ComboBox cmb = (ComboBox)sender; //項目に表示する文字列 string txt = e.Index > -1 ? cmb.Items[e.Index].ToString() : cmb.Text; //使用するフォント Font f = new Font(txt, cmb.Font.Size); //項目の高さを決定 e.ItemHeight = (int)e.Graphics.MeasureString(txt, f).Height; }