- - PR -
DataGridViewで文字単位でフォントを変える (DataGridViewRichTextBoxColumnの実装)
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-01-26 18:59
DataGridViewの文字単位でセル単位でフォントを変えるサンプルはたくさんあるのですが、
文字単位で変えるものはさっぱり見つかりません。 どうもRichTextBoxを配置できるようにDataGridViewColumnを継承したクラスを実装しなければならないようです。 (もっと簡単な方法があれば教えて下さい) http://msdn2.microsoft.com/ja-jp/library/7tas5c80(VS.80).aspx を参考にしてやってみたのですが、全く描画されません。 このサンプルは、「テキストボックスの表示機能を再度実装しなくてもすむように、DataGridViewCellクラスを直接継承するのではなくDataGridViewTextBoxCellクラスから派生します」 とあるので、この部分が原因だと思うのですが、そのテキストボックスの表示機能を再度実装するにはどのようにしたらいいのでしょうか? よろしくお願いします。 Public Class DataGridViewRichTextBoxColumn Inherits DataGridViewColumn Public Sub New() MyBase.New(New DataGridViewRichTextBoxCell) End Sub Public Overrides Property CellTemplate() As System.Windows.Forms.DataGridViewCell Get Return MyBase.CellTemplate End Get Set(ByVal value As System.Windows.Forms.DataGridViewCell) If Not value Is Nothing AndAlso Not value.GetType.IsAssignableFrom(GetType(DataGridViewRichTextBoxCell)) Then Throw New InvalidCastException("Must be a DataGridViewRichTextBoxCell") End If MyBase.CellTemplate = value End Set End Property End Class Public Class DataGridViewRichTextBoxCell Inherits DataGridViewCell Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, ByVal initialFormattedValue As Object, ByVal dataGridViewCellStyle As System.Windows.Forms.DataGridViewCellStyle) MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle) Dim ctrl As RichTextBoxEditingControl = CType(DataGridView.EditingControl, RichTextBoxEditingControl) ctrl.Text = CType(Me.Value, String) End Sub Public Overrides Property ValueType() As System.Type Get Return GetType(String) End Get Set(ByVal value As System.Type) MyBase.ValueType = value End Set End Property Public Overrides ReadOnly Property EditType() As System.Type Get Return GetType(RichTextBoxEditingControl) End Get End Property End Class Public Class RichTextBoxEditingControl Inherits RichTextBox Implements IDataGridViewEditingControl Private _dataGridView As DataGridView Private _rowIndex As Integer Private _valueChanged As Boolean = False Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As System.Windows.Forms.DataGridViewCellStyle) Implements System.Windows.Forms.IDataGridViewEditingControl.ApplyCellStyleToEditingControl Me.Font = dataGridViewCellStyle.Font Me.ForeColor = dataGridViewCellStyle.ForeColor Me.BackColor = dataGridViewCellStyle.BackColor End Sub Public Property EditingControlDataGridView() As System.Windows.Forms.DataGridView Implements System.Windows.Forms.IDataGridViewEditingControl.EditingControlDataGridView Get Return _dataGridView End Get Set(ByVal value As System.Windows.Forms.DataGridView) _dataGridView = value End Set End Property Public Property EditingControlFormattedValue() As Object Implements System.Windows.Forms.IDataGridViewEditingControl.EditingControlFormattedValue Get Return Me.Text End Get Set(ByVal value As Object) If TypeOf value Is [String] Then Me.Text = value.ToString End If End Set End Property Public Property EditingControlRowIndex() As Integer Implements System.Windows.Forms.IDataGridViewEditingControl.EditingControlRowIndex Get Return _rowIndex End Get Set(ByVal value As Integer) _rowIndex = value End Set End Property Public Property EditingControlValueChanged() As Boolean Implements System.Windows.Forms.IDataGridViewEditingControl.EditingControlValueChanged Get Return _valueChanged End Get Set(ByVal value As Boolean) _valueChanged = value End Set End Property Public Function EditingControlWantsInputKey(ByVal keyData As System.Windows.Forms.Keys, ByVal dataGridViewWantsInputKey As Boolean) As Boolean Implements System.Windows.Forms.IDataGridViewEditingControl.EditingControlWantsInputKey Return True End Function Public ReadOnly Property EditingPanelCursor() As System.Windows.Forms.Cursor Implements System.Windows.Forms.IDataGridViewEditingControl.EditingPanelCursor Get Return MyBase.Cursor End Get End Property Public Function GetEditingControlFormattedValue(ByVal context As System.Windows.Forms.DataGridViewDataErrorContexts) As Object Implements System.Windows.Forms.IDataGridViewEditingControl.GetEditingControlFormattedValue Return Me.Text End Function Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) Implements System.Windows.Forms.IDataGridViewEditingControl.PrepareEditingControlForEdit End Sub Public ReadOnly Property RepositionEditingControlOnValueChange() As Boolean Implements System.Windows.Forms.IDataGridViewEditingControl.RepositionEditingControlOnValueChange Get Return False End Get End Property End Class Public Class Form1 Private _view As New DataGridView Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim view As DataGridView = _view Me.Controls.Add(view) view.Dock = DockStyle.Fill Dim col As New DataGridViewRichTextBoxColumn view.Columns.Add(col) view.RowCount = 5 For Each row As DataGridViewRow In view.Rows row.Cells(0).Value = "aiueo" Next End Sub End Class | ||||||||||||
|
投稿日時: 2007-01-26 21:57
書いて頂いたコードで、編集モードのときはRichTextBoxのようなものが
表示されているようですが、編集モードでない状態のセルで、 RichTextBoxで設定された文字色等をそのまま表示したいということでしょうか? DataGridViewTextBoxColumnには、文字ごとにフォント色を変えるような機能はありませんので、 Paintメソッドをオーバーライドして、自分で描画するくらいしか思いつきませんが… | ||||||||||||
|
投稿日時: 2007-01-26 23:45
KIさん、ありがとうございます。
>RichTextBoxで設定された文字色等をそのまま表示したいということでしょうか? そうです。 >Paintメソッドをオーバーライドして、自分で描画するくらいしか思いつきませんが… 私もこの様なことが出来ないかと思ったのですが、 オブジェクトブラウザを見てもTextBoxにオーバーライドできるPaintメソッドはないようです OnPaintをオーバーライドして,e.Graphics.DrawString(〜としてみても何もおきません | ||||||||||||
|
投稿日時: 2007-01-27 01:59
頑張ってはみたのですが…あと一歩のところでわからなくなりました。
描画はDataGridViewCellのPaintメソッドのオーバーライドで行えます。 しかし、問題はEditingControlとDataGridViewCellの間で渡す値の方かも知れません。 書式情報等を含めた情報をやりとりする必要がありますので、 RichTextBoxのTextではなくRtfを渡すようにしました。 あとは、RtfをどうやってImageに変換するかというところです。 RichTextBoxからイメージを取得できれば早いと思うのですが… 少々長くなりますが、現在のコードです。
また何か思いついたら書き込みたいと思います。 | ||||||||||||
|
投稿日時: 2007-01-27 15:39
KIさん、ありがとうございます。
描画の方法など、とても参考になりました。 個人的に、標準でプロパティが用意されているべき機能だと思うのですが、 相当難しそうですね。 今回の件だけでなく、このコントロールには悩まされることも多く、 これを使わずに済む別の方法を考えてみます。 ありがとうございました! [ メッセージ編集済み 編集者: hei 編集日時 2007-01-27 16:21 ] | ||||||||||||
|
投稿日時: 2007-01-27 16:53
実際に書式付きのデータをDataGridViewで編集・表示するような局面が 現実問題として多いとは私には思えません。 もしかして、書式の編集をDataGridView内で行わず、 単純に文字色を部分的に変えたいだけだったのでしょうか? それでしたら、もっと単純にCellのPaintメソッドをオーバーライドするだけで 出来るかもしれませんね。
同感です。 今回このコントロールをメインに使ったシステムの仕事をしたのですが、 いろいろと動作制御で悩まされたりすることが多かったです。 便利な機能は多そうですし、使いこなせればいいとは思っているのですが… たぶんまだ勉強不足なんでしょうね。 | ||||||||||||
|
投稿日時: 2007-01-28 00:23
行ごとに正規表現にマッチした文字を強調する、ということがしたいのですが、 KIさんのコードを参考にして、少し出来ました。 Public Class CustomColumn Inherits DataGridViewColumn Public Sub New() MyBase.New(New CustomCell()) End Sub Public Overrides Property CellTemplate() As DataGridViewCell Get Return MyBase.CellTemplate End Get Set(ByVal value As DataGridViewCell) If Not (value Is Nothing) AndAlso _ Not value.GetType().IsAssignableFrom(GetType(CustomCell)) _ Then Throw New InvalidCastException("Must be a CustomCell") End If MyBase.CellTemplate = value End Set End Property End Class Public Class CustomCell Inherits DataGridViewTextBoxCell Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle, ByVal cellBounds As System.Drawing.Rectangle, ByVal rowIndex As Integer, ByVal cellState As System.Windows.Forms.DataGridViewElementStates, ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, ByVal paintParts As System.Windows.Forms.DataGridViewPaintParts) MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts) '背景の描画 If paintParts And DataGridViewPaintParts.Background = DataGridViewPaintParts.Background Then Using cellBackGround As New SolidBrush(cellStyle.BackColor) graphics.FillRectangle(cellBackGround, cellBounds) End Using End If '境界線の描画 If paintParts And DataGridViewPaintParts.Border = DataGridViewPaintParts.Border Then PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle) End If '描画エリアを計算 Dim drawArea As Rectangle = cellBounds Dim drawAdjustment As Rectangle = Me.BorderWidths(advancedBorderStyle) drawArea.X += drawAdjustment.X drawArea.Y += drawAdjustment.Y drawArea.Height -= drawAdjustment.Height drawArea.Width -= drawAdjustment.Width Dim strValue As String = value.ToString Dim font As New Font("MS UI Gothic", 15, FontStyle.Bold Or FontStyle.Italic) graphics.DrawString(strValue, font, Brushes.Red, drawArea.X, drawArea.Y) End Sub Public Overrides ReadOnly Property EditType() As Type Get Return GetType(CustomCell) End Get End Property Public Overrides ReadOnly Property ValueType() As Type Get Return GetType(String) End Get End Property Public Overrides ReadOnly Property DefaultNewRowValue() As Object Get Return Nothing End Get End Property End Class Public Class Form1 Private _view As New DataGridView Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim view As DataGridView = _view Me.Controls.Add(view) view.Dock = DockStyle.Fill Dim col As New CustomColumn view.Columns.Add(col) view.RowCount = 5 For Each row As DataGridViewRow In view.Rows row.Cells(0).Value = "aiueo" Next End Sub End Class このようにすることで文字の色を制御できましたが、 部分的に変える場合は、フォントなどが変わるたびに 座標を計算しなおしてそれぞれのFontやBrushを渡して graphics.DrawStringメソッドを呼ばなければならない、と思いました。 RichTextBoxなら、文字位置を特定してフォントを指定すれば後はRichTextBoxの内部で座標の計算などをやってくれますが、 この処理を自分で実装する、ということでしょうか? 私の力では改行の位置などを求めるのは非常に難しいと思ったのですが、 もっと簡単に出来る方法はありますか? あと、このコードでは、セルを編集した時にエラーが発生します。 単にDataGridViewTextBoxCellを継承しているので、InitializeEditingControlをオーバーライドする必要はないと思うのですが・・・ もし私の手におえないようなら、別な方法を考えなければなりませんが、 できるならやりたいと思います。 諦めるかもしれないのでざっとでかまいません。 お手数をおかけしますが、ご教授よろしくお願いします。 | ||||||||||||
|
投稿日時: 2007-01-28 01:26
この2行、こちらではエラーになりました。(Option Strictのせいだと思いますが) 私が提示したコードでは括弧がついていたと思います。
おそらくそれしかないと思います。 改行が含まれるならSplitとかで区切って、 文字列の描画位置はMeasureStringで計算するしか思いつきません。 面倒ですが出来ないこともないような気はします。
InitializeEditingControlとかでなく、EditTypeプロパティの実装に問題があります。 EditTypeはEditingControlの型を返さなくてはなりませんが、 DataGridViewCellの型を返していますよね。 |