DataGridViewでの選択したセルの合計値を計算する方法
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2011/3/1 22:33:50
こんな感じでしょうか。初期状態は
☑ 100
☐ 2000
☑ 30000
☑ 400000
にしているので、合計「430,100」と表示されるかと思います。☐ 2000
☑ 30000
☑ 400000
Public Class Form1
'DataTable の値を合計する場合は、Compute メソッドを使うと便利です。
Private Sub UpdateSummaryLabel()
Dim o As Object = ds.Tables("T").Compute("SUM(値)", "選択=TRUE")
If IsDBNull(o) Then
label1.Text = "選択されていません。"
Else
label1.Text = CDec(o).ToString("#,0") '小数部も必要なら適宜修正
End If
End Sub
'行が削除されたら、計算処理を実行する。
Private Sub dgv_RowsRemoved(ByVal sender As Object, _
ByVal e As DataGridViewRowsRemovedEventArgs) Handles dgv.RowsRemoved
UpdateSummaryLabel() '合計額をラベルに表示する処理
End Sub
'セルの値が変更されたら、計算処理を実行する。
Private Sub dgv_CellValueChanged(ByVal sender As Object, _
ByVal e As DataGridViewCellEventArgs) Handles dgv.CellValueChanged
bs.EndEdit() 'DataGridView → DataSet への反映作業を確定させる。
UpdateSummaryLabel() '合計額をラベルに表示する処理
End Sub
'CheckBox が変更された場合、その行は即座に確定状態にする。
Private Sub dgv_CurrentCellDirtyStateChanged(ByVal sender As Object, _
ByVal e As EventArgs) Handles dgv.CurrentCellDirtyStateChanged
If dgv.CurrentCellAddress.X = 0 Then 'CheckBox 列か否か
If dgv.IsCurrentCellDirty Then '編集作業中か否か
dgv.CommitEdit(DataGridViewDataErrorContexts.Commit)
End If
End If
End Sub
'数値項目に文字列が入力された場合への対処
Private Sub dgv_DataError(ByVal sender As Object, _
ByVal e As DataGridViewDataErrorEventArgs) Handles dgv.DataError
MessageBox.Show(e.Exception.Message, "入力エラー", _
MessageBoxButtons.OK, MessageBoxIcon.Information)
e.ThrowException = False
End Sub
'画面構築。通常はデザイナで設定しておけばOK。
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
If components Is Nothing Then
components = New System.ComponentModel.Container()
End If
bs = New BindingSource(Me.components)
dgv = New DataGridView()
dgv.Dock = DockStyle.Fill
dgv.EditMode = DataGridViewEditMode.EditOnEnter
dgv.AutoGenerateColumns = True
Controls.Add(dgv)
label1 = New Label()
label1.Dock = DockStyle.Top
label1.Text = "0"
label1.TextAlign = ContentAlignment.BottomRight
label1.Font = New Font(Me.Font.FontFamily, 18)
Controls.Add(label1)
ds = New DataSet()
Dim tbl As DataTable = ds.Tables.Add("T")
tbl.Columns.Add("選択", GetType(Boolean))
tbl.Columns.Add("値", GetType(Decimal))
tbl.Rows.Add(True, 100)
tbl.Rows.Add(False, 2000)
tbl.Rows.Add(True, 30000)
tbl.Rows.Add(True, 400000)
tbl.AcceptChanges()
bs.DataSource = ds
bs.DataMember = "T"
dgv.DataSource = bs
dgv.Columns(1).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
'dgv.Columns(1).DefaultCellStyle.Format = "#,0"
UpdateSummaryLabel()
End Sub
Private WithEvents label1 As Label
Private WithEvents dgv As DataGridView
Private WithEvents bs As BindingSource
Private WithEvents ds As DataSet
End Class
投稿者 くらす  (社会人)
投稿日時
2011/3/2 12:35:48
> 魔界の仮面弁士 さま
ご連絡が遅くなり申し訳ございません。
まさしくこの動きが実現させたかったことです。
本当にありがとうございます。
さらにエラー制御等まで考慮していただき
勉強になります。
データテーブルという言葉は耳にしたことがあったのですが
調べてみるとデータベース、データグリッドビューとのやり取りもあり
勉強しないといけないなと思いました。
そこら辺がよく分かっていないので私が作成しているプログラムでは
すでにデータテーブルの宣言をしていたので
魔界の仮面弁士 さまのプログラムと組み合わせるのに
試行錯誤しましたがうまくいきませんでした。
下記に抜粋いたしますのでご確認お願いいたします。
ご連絡が遅くなり申し訳ございません。
まさしくこの動きが実現させたかったことです。
本当にありがとうございます。
さらにエラー制御等まで考慮していただき
勉強になります。
データテーブルという言葉は耳にしたことがあったのですが
調べてみるとデータベース、データグリッドビューとのやり取りもあり
勉強しないといけないなと思いました。
そこら辺がよく分かっていないので私が作成しているプログラムでは
すでにデータテーブルの宣言をしていたので
魔界の仮面弁士 さまのプログラムと組み合わせるのに
試行錯誤しましたがうまくいきませんでした。
下記に抜粋いたしますのでご確認お願いいたします。
Public Class Form
Public dt As New DataTable
Private Sub Form_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim Chk1 As New DataGridViewCheckBoxColumn
Dim Txt6 As New DataGridViewTextBoxColumn
dt.Columns.Add("選択")
dt.Columns.Add("金額")
Chk1.Name = "選択"
Txt6.Name = "金額"
DGV.Columns.Add(Chk1)
DGV.Columns.Add(Txt6)
DGV.Columns("選択").DataPropertyName = "選択"
DGV.Columns("金額").DataPropertyName = "金額"
DGV.Columns(0).ReadOnly = False '選択
DGV.Columns(6).ReadOnly = True '金額
DGV.Columns(6).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
DGV.Columns(6).DefaultCellStyle.Format = "#,0"
DGV.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells
DGV.AllowUserToAddRows = False
DGV.AllowUserToDeleteRows = False
DGV.DataSource = dt
DGV.AutoGenerateColumns = False
'Oracleに接続してDBアクセスしています。
'~略~
Dim i As String = rdr1.Item("AMOUNT")
dt.Rows.Add(False, i ) '選択列にはデフォルトでFalseを入れる。
'~略~
UpdateSummaryLabel()
End Sub
Private Sub dgv_CellValueChanged(ByVal sender As Object, _
ByVal e As DataGridViewCellEventArgs) Handles DGV.CellValueChanged
bs.EndEdit()
UpdateSummaryLabel()
End Sub
Private Sub dgv_CurrentCellDirtyStateChanged(ByVal sender As Object, _
ByVal e As EventArgs) Handles DGV.CurrentCellDirtyStateChanged
If DGV.CurrentCellAddress.X = 0 Then
If DGV.IsCurrentCellDirty Then
DGV.CommitEdit(DataGridViewDataErrorContexts.Commit)
End If
End If
End Sub
Private Sub dgv_DataError(ByVal sender As Object, _
ByVal e As DataGridViewDataErrorEventArgs) Handles DGV.DataError
MessageBox.Show(e.Exception.Message, "入力エラー", _
MessageBoxButtons.OK, MessageBoxIcon.Information)
e.ThrowException = False
End Sub
Private Sub UpdateSummaryLabel()
Dim SumObject As Object = dt.Compute("Sum(金額)", "選択 = True")
If IsDBNull(SumObject) Then
Label.Text = "選択されていません。"
Else
Label.Text = CDec(SumObject).ToString("#,0")
End If
End Sub
End Class
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2011/3/2 13:19:53
> DGV.DataSource = dt
直接割り当てるのではなく、先の私のコードにある
もしも DataTable を直接割り当てたいのであれば、
先の私のコードを以下のように変更する必要があります。
《Sub Form1_Load》
《Sub dgv_CellValueChanged》
直接割り当てるのではなく、先の私のコードにある
bs.DataSource = ds
bs.DataMember = "T"
dgv.DataSource = bs
のように、BindingSource コンポーネントを経由させてください。もしも DataTable を直接割り当てたいのであれば、
先の私のコードを以下のように変更する必要があります。
《Sub Form1_Load》
'-->
'bs.DataSource = ds
'bs.DataMember = "T"
'dgv.DataSource = bs
'--
dgv.DataSource = tbl
'<--
《Sub dgv_CellValueChanged》
'-->
'bs.EndEdit() 'DataGridView → DataSet への反映作業を確定させる。
'---
Dim rowView As DataRowView = TryCast(dgv.Rows(e.RowIndex).DataBoundItem, DataRowView)
If rowView IsNot Nothing Then
rowView.EndEdit() 'DataGridView → DataSet への反映作業を確定させる。
End If
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2011/3/2 16:40:56
> DGV.Columns("選択").DataPropertyName = "選択"
> DGV.Columns("金額").DataPropertyName = "金額"
選択 / 金額列のデータ型は何ですか?
たとえば金額列が String 型の場合、DataTable に対して
.Compute("SUM(金額)", "選択=TRUE")
という問い合わせはできません。金額列が数値項目では無いためです。
> Dim i As String = rdr1.Item("AMOUNT")
> dt.Rows.Add(False, i ) '選択列にはデフォルトでFalseを入れる。
この False, i は、上記の 選択列と金額列なのでしょうか?
> 試行錯誤しましたがうまくいきませんでした。
「うまくいかない」とは、具体的にはどのような結果になってしまっているのでしょうか?
エラーが出るなら発生場所とエラー内容を示してください。
期待動作しないなら、何を期待していて実際にはどうなってしまうのかを。
> DGV.Columns("金額").DataPropertyName = "金額"
選択 / 金額列のデータ型は何ですか?
たとえば金額列が String 型の場合、DataTable に対して
.Compute("SUM(金額)", "選択=TRUE")
という問い合わせはできません。金額列が数値項目では無いためです。
> Dim i As String = rdr1.Item("AMOUNT")
> dt.Rows.Add(False, i ) '選択列にはデフォルトでFalseを入れる。
この False, i は、上記の 選択列と金額列なのでしょうか?
> 試行錯誤しましたがうまくいきませんでした。
「うまくいかない」とは、具体的にはどのような結果になってしまっているのでしょうか?
エラーが出るなら発生場所とエラー内容を示してください。
期待動作しないなら、何を期待していて実際にはどうなってしまうのかを。
投稿者 くらす  (社会人)
投稿日時
2011/3/2 17:41:15
>魔界の仮面弁士さま
返信をいただきありがとうございます。
ご教授いただいたにも関わらずうまくいかず困っていたところ、
更なるご教授ありがとうございます。
教えていただいたDataTable を直接割り当てる方法を試しています。
> DGV.Columns("選択").DataPropertyName = "選択"
> DGV.Columns("金額").DataPropertyName = "金額"
こちらはDecimalに変更しました。
Dim i As Decimal = rdr1.Item("AMOUNT")
> dt.Rows.Add(False, i ) '選択列にはデフォルトでFalseを入れる。
Falseは選択列、iは金額列になります。
この実行結果でUpdateSummaryLabel()が動くと
SumObject = dt.Compute("SUM(金額)", "選択=TRUE")
の部分に
「DataExceptionはハンドルされませんでした。
集約関数Sum()および型:Stringの使用が無効です。」
とエラーが出てしまいます。
下記にプログラムを載せますのでご確認お願いいたします。
返信をいただきありがとうございます。
ご教授いただいたにも関わらずうまくいかず困っていたところ、
更なるご教授ありがとうございます。
教えていただいたDataTable を直接割り当てる方法を試しています。
> DGV.Columns("選択").DataPropertyName = "選択"
> DGV.Columns("金額").DataPropertyName = "金額"
こちらはDecimalに変更しました。
Dim i As Decimal = rdr1.Item("AMOUNT")
> dt.Rows.Add(False, i ) '選択列にはデフォルトでFalseを入れる。
Falseは選択列、iは金額列になります。
この実行結果でUpdateSummaryLabel()が動くと
SumObject = dt.Compute("SUM(金額)", "選択=TRUE")
の部分に
「DataExceptionはハンドルされませんでした。
集約関数Sum()および型:Stringの使用が無効です。」
とエラーが出てしまいます。
下記にプログラムを載せますのでご確認お願いいたします。
投稿者 くらす  (社会人)
投稿日時
2011/3/2 17:48:54
Public Class Form
Public dt As New DataTable
Private Sub Form_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim Chk1 As New DataGridViewCheckBoxColumn
Dim Txt6 As New DataGridViewTextBoxColumn
dt.Columns.Add("選択")
dt.Columns.Add("金額")
Chk1.Name = "選択"
Txt6.Name = "金額"
DGV.Columns.Add(Chk1)
DGV.Columns.Add(Txt6)
DGV.Columns("選択").DataPropertyName = "選択"
DGV.Columns("金額").DataPropertyName = "金額"
DGV.Columns(0).ReadOnly = False '選択
DGV.Columns(6).ReadOnly = True '金額
DGV.Columns(6).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
DGV.Columns(6).DefaultCellStyle.Format = "#,0"
DGV.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells
DGV.AllowUserToAddRows = False
DGV.AllowUserToDeleteRows = False
DGV.DataSource = dt
DGV.AutoGenerateColumns = False
'Oracleに接続してDBアクセスしています。
'~略~
Dim i As Decimal = rdr1.Item("AMOUNT")
dt.Rows.Add(False, i )
'~略~
UpdateSummaryLabel()
End Sub
Private Sub dgv_CellValueChanged(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles DGV.CellValueChanged
Dim rowView As DataRowView = TryCast(Dg_ConversionSuppliers.Rows(e.RowIndex).DataBoundItem, DataRowView)
If rowView IsNot Nothing Then
rowView.EndEdit()
End If
UpdateSummaryLabel()
End Sub
Private Sub dgv_CurrentCellDirtyStateChanged(ByVal sender As Object, _
ByVal e As EventArgs) Handles DGV.CurrentCellDirtyStateChanged
If DGV.CurrentCellAddress.X = 0 Then
If DGV.IsCurrentCellDirty Then
DGV.CommitEdit(DataGridViewDataErrorContexts.Commit)
End If
End If
End Sub
Private Sub dgv_DataError(ByVal sender As Object, _
ByVal e As DataGridViewDataErrorEventArgs) Handles DGV.DataError
MessageBox.Show(e.Exception.Message, "入力エラー", _
MessageBoxButtons.OK, MessageBoxIcon.Information)
e.ThrowException = False
End Sub
Private Sub UpdateSummaryLabel()
Dim SumObject As New Object
SumObject = dt.Compute("Sum(金額)", "選択 = True")
If IsDBNull(SumObject) Then
Label.Text = "選択されていません。"
Else
Label.Text = CDec(SumObject).ToString("#,0")
End If
End Sub
End Class
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2011/3/2 18:10:13
> DGV.Columns("選択").DataPropertyName = "選択"
> DGV.Columns("金額").DataPropertyName = "金額"
> こちらはDecimalに変更しました。
> Dim i As Decimal = rdr1.Item("AMOUNT")
違います。「AMOUT」の型ではなく、DataTable の「金額」列の型です。
> dt.Columns.Add("選択")
> dt.Columns.Add("金額")
これらの記述法は、String 型の列が作成される事になります。
先の私のコードと見比べてみてください。
金額列が文字列であるがゆえに、
> dt.Compute("Sum(金額)", "選択 = True")
の処理が
> 集約関数Sum()および型:Stringの使用が無効です。
の例外を発生させることになるわけです。
> Dim SumObject As New Object
> SumObject = dt.Compute("Sum(金額)", "選択 = True")
ここでの New は無意味です。As Object にしましょう。
> DGV.Columns("金額").DataPropertyName = "金額"
> こちらはDecimalに変更しました。
> Dim i As Decimal = rdr1.Item("AMOUNT")
違います。「AMOUT」の型ではなく、DataTable の「金額」列の型です。
> dt.Columns.Add("選択")
> dt.Columns.Add("金額")
これらの記述法は、String 型の列が作成される事になります。
先の私のコードと見比べてみてください。
金額列が文字列であるがゆえに、
> dt.Compute("Sum(金額)", "選択 = True")
の処理が
> 集約関数Sum()および型:Stringの使用が無効です。
の例外を発生させることになるわけです。
> Dim SumObject As New Object
> SumObject = dt.Compute("Sum(金額)", "選択 = True")
ここでの New は無意味です。As Object にしましょう。
投稿者 くらす  (社会人)
投稿日時
2011/3/2 18:57:37
>魔界の仮面弁士さま
ご教授ありがとうございます。
ご指摘いただいた通り、DataTable の列の型を
dt.Columns.Add("選択", GetType(Boolean))
dt.Columns.Add("金額", GetType(Decimal))
とすることにより解決いたしました。
最初から最後まで本当にありがとうございました。
型については勉強させていただきます。
ご教授ありがとうございます。
ご指摘いただいた通り、DataTable の列の型を
dt.Columns.Add("選択", GetType(Boolean))
dt.Columns.Add("金額", GetType(Decimal))
とすることにより解決いたしました。
最初から最後まで本当にありがとうございました。
型については勉強させていただきます。
標題の件、DataGridViewにおいてチェックボックス列を用意し
チェックが入ってる行の値の合計値を取得したいのですが
色々と試したのですが上手くいきません。
サンプルプログラムを解説付きで頂けたら助かります。
宜しくお願いします。
下記、イメージになります。
選択 値
□レ A
□ B
□レ C
□レ D
合計値=A+C+D
下記は私が書いたプログラムの最終形です。
右往左往しているので纏まっていませんが…。
Private Sub DataGridView1_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
Dim CurrentRow As DataGridViewRow = DataGridView1.Rows(e.RowIndex)
Dim Total() As Integer
For i As Integer = 0 To 1
If CurrentRow.Cells(0).Value = True Then
Total = DataGridView1.CurrentRow.Cells(5).Value
End If
Next
For i As Integer = 1 To Me.DataGridView1.RowCount - 1
If CurrentRow.Cells(0).Value = True Then
Total = Total(i) + DataGridView1.CurrentRow.Cells(5).Value
End If
Next
Label1.Text = Total
End Sub
VB2005を使用しています。