2006年09月29日

自アプリケーションのバージョンを取得

MajorMinorBuildRevision
VB6App.MajorApp.Minor-App.Revison
Label1.Cation = App.Major & "." & App.Minor & "." & App.Revision
VB.NETDim Ver As New Version(Application.ProductVersion)
Ver.MajorVer.MinorVer.BuildVer.Revison
Dim Ver As New Version(Application.ProductVersion)
Label1.Text = Ver.ToString
VB2005Dim Ver As Version = My.Application.Info.Version
Ver.MajorVer.MinorVer.BuildVer.Revison
Label1.Text = My.Application.Info.Version.ToString

追加説明....
posted by なっちゃん at 20:29| 静岡 ????| Comment(0) | TrackBack(0) | VB vs VB.NET | このブログの読者になる | 更新情報をチェックする

DataGridViewの行ヘッダに行番号を表示させるには

以前のTips「DataGridViewの行ヘッダ(列ヘッダ)にContextMenuStripを関連付ける」のサンプル画面に行番号の実例がさりげなく写っていた。
これをご覧になった方からその方法が知りたいという要望があったので今回はこれを紹介する。(コードだけの紹介なのでイメージは上記を参照してください)

注:この方法はサイトを調べてC#のサンプルを見つけ、そこからVB用に直しただけの代物です。但し、Tipsとして公開するにあたり理解しやすいように個々のプロパティを直接引数に配置せず、一旦変数に置き換えてあります。また、行番号の右揃えの方法も追加しました。

その仕組みをみると簡単ではあるが泥臭い(APIで無理やり描画させているような感じの)もので、この程度の機能なら標準プロパティ等で指定できるようにすべきだと思う。

'///// 行ヘッダに行番号を描画 /////
Private Sub dataGridView_RowPostPaint(ByVal sender As Object, _
ByVal e As DataGridViewRowPostPaintEventArgs) _
Handles Me.RowPostPaint
' - 行番号と行の境界(枠)の左上のPOINT(X,Y)を取得
Dim RowNo As Integer = e.RowIndex + 1 '行番号を取得
Dim X as Integer = e.RowBounds.Location.X '行(Row)の境界の左上X座標
Dim Y as Integer = e.RowBounds.Location.Y ' 同上 Y座標

'塗り潰し用ブラシを作成
Using bs As SolidBrush = New SolidBrush(Me.RowHeadersDefaultCellStyle.ForeColor)
'文字列を描画
e.Graphics.DrawString(RowNo.ToString(), _ '行番号文字列
Me.DefaultCellStyle.Font, _ 'フォントを指定
bs, _ 'ブラシを指定
X + 15, Y + 4) '文字出力座標
End Using
End Sub
 
説明すると、DataGridViewの一行分が描画し終わったタイミング(RowPostPaintイベント)で、行ヘッダに直接文字を描画させている。このコードだけで全ての行に行番号を表示することができる。
行削除、行追加を行っても自動で更新(再描画)されるので便利である。

ここで使われる描画メソッド(Graphics.DrawString)はフォームやコントロールに文字列を描画するときに使うものだ。(ヘルプにはフォームに文字を出力するサンプルがいろいろある)
描画位置は文字列の左上を指定するので、文字が行ヘッダの適当な位置に収まるように調整する。(この例では右に15ピクセル、下に4ピクセル移動している)
左上が開始位置なので何もしないと左揃えになる、右揃えや中央揃えにするには文字列の長さを取得して位置を調整する必要がある。
右揃えにする簡単な方法は、DrawStringのオーバーロードでStringFormatを引数に渡すタイプを使う。

'///// 行番号を右揃えで表示させる方法 /////
Private Sub dataGridView_RowPostPaint(ByVal sender As Object, _
ByVal e As DataGridViewRowPostPaintEventArgs) _
Handles Me.RowPostPaint
Dim RowNo As Integer = e.RowIndex + 1
Dim X As Integer = e.RowBounds.Location.X
Dim Y As Integer = e.RowBounds.Location.Y
Dim drawPoint As New Point(X + 35, Y + 4) '右揃え用に位置をずらす
Dim drawFormat As New StringFormat
'このフラグで右から左に出力される。
drawFormat.FormatFlags = StringFormatFlags.DirectionRightToLeft

Using bs As SolidBrush = New SolidBrush(Me.RowHeadersDefaultCellStyle.ForeColor)
e.Graphics.DrawString(RowNo.ToString(), _
Me.DefaultCellStyle.Font, _
bs, _
drawPoint, _
drawFormat)
End Using
End Sub
posted by なっちゃん at 11:36| 静岡 ????| Comment(6) | TrackBack(1) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

2006年09月28日

VB2005から新たに加えられたMouseイベント

前回のTips用サンプルを作っていたときに偶然見つけたのだが、DoubleClickイベントとは別にMouseDoubleClickイベントなるものがあるのに気が付いた。ヘルプをみたら、.NET Framework2.0つまりVB2005で新たに追加されたものらしい。
どう違うのか、理解しやすいようにバージョン毎のイベントの流れを比較してみる。

ダブルクリックしたときのイベント発生順序
 
VB6 VB.NET VB2005
----------------------------------------------------
1. MouseDown MouseDown MouseDown
2. MouseUp Click Click
3. Click DoubleClick MouseClick
4. DblClick MouseUp MouseUp
5. MouseUp MouseDown
6. DoubleClick
7. MouseDoubleClick
8. MouseUp
----------------------------------------------------

VB6よりVB.NETの方がイベントがスッキリしているが、VB2005になって複雑になった。細かく制御できるわけだがそこまで使うかどうか・・・。

ClickとMouseClick、DoubleClickとMouseDoubleClickの違いは、Mouseと名づけられた方が、純粋にマウスからのイベントだけを処理するものだ。
クリックイベントは、コントロールにフォーカスがあるときEnterキーやSpaceキーでも発生させることができるからだ。キーボードだけで操作したいこともあるからね。
posted by なっちゃん at 15:23| 静岡 ????| Comment(0) | TrackBack(0) | VB vs VB.NET | このブログの読者になる | 更新情報をチェックする

2006年09月26日

イベントの中で他のコントロールのクリックを実行するには

例として、リストボックスの項目を選択・確定する処理で説明する。

一般的には
1.リストボックスの項目をクリックし選択状態にし、
2.ボタンコントロールをクリックして確定する。
の2段階で行う。

これを
1.リストボックスの項目をダブルクリックして選択・確定する。
という1つのイベントで実行させたいことがある。

VB6では以下のようになる。

Private Sub Form_Load()
With List1
.Clear
.AddItem "私"
.AddItem "お父さん"
.AddItem "お母さん"
.AddItem "お兄ちゃん"
.AddItem "お姉ちゃん"
.ListIndex = 0
End With
End Sub
 
'/// 選択したリストの項目を表示 ///
Private Sub Command1_Click()
MsgBox "「" & List1.List(List1.ListIndex) & "」が選ばれました"
End Sub
 
'/// ボタンのクリックを内部で実行 ///
Private Sub List1_DblClick()
Command1_Click '上記のクリックイベントを呼んでいるだけ
End Sub

VB.NET(2005含)になると、VB6のようにイベントプロシージャをそのまま呼ぶことはできない。そこで登場するのが PerformClickメソッド
ヘルプをみると「Clickイベントを発生させる」とある。クリック以外のイベントを発生させるメソッドがないか調べてみたがどうもなさそうだった。

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
With ListBox1
.Items.Clear()
.Items.Add("私")
.Items.Add("お父さん")
.Items.Add("お母さん")
.Items.Add("お兄ちゃん")
.Items.Add("お姉ちゃん")
.SelectedIndex = 0
End With
End Sub
 
'/// 選択したリストの項目を表示 ///
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
MsgBox("「" & ListBox1.SelectedItem & "」が選ばれました")
End Sub
 
'/// ボタンのクリックイベントを発生させる ///
Private Sub ListBox1_DoubleClick(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles ListBox1.DoubleClick
Button1.PerformClick()
End Sub
posted by なっちゃん at 20:35| 静岡 ????| Comment(0) | TrackBack(0) | VB vs VB.NET | このブログの読者になる | 更新情報をチェックする

2006年09月22日

DataGridViewの行ヘッダ(列ヘッダ)にContextMenuStripを関連付ける

VB6で使っていたメニューの仕様が.NETになってから大きく変わった。
メニューのデザインが直感的にわかるようになり、右クリックでポップアップするメニュー(ショートカットメニューとかコンテキストメニュー(ContextMenu)と呼ばれる)はフォームやコントロール毎にプロパティーに指定することで簡単に表示できるようになった。

DataGridViewのContextMenuStripプロパティに、作成したContextMenuStripコントロールを関連付けるとすべてのセル・ヘッダ上でショートカットメニューが表示されてしまう。
行ヘッダや列ヘッダで、それぞれの別のショートカットメニューを表示させるには実行時に以下の処理を追加する。

Private Sub AddContextMenu()
'-- 行ヘッダにContextMenuStrip1を関連付け
For Each row As DataGridViewRow In DataGridView1.Rows
row.HeaderCell.ContextMenuStrip = ContextMenuStrip1
Next
'-- 列ヘッダにContextMenuStrip2を関連付け
For Each column As DataGridViewColumn In DataGridView1.Columns
column.HeaderCell.ContextMenuStrip = ContextMenuStrip2
Next
End Sub

画面は合成イメージ
行ヘッダ・列ヘッダにショートカットメニューを関連付け
posted by なっちゃん at 10:30| 静岡 ????| Comment(3) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

2006年09月21日

DataGridViewの列毎に数字のみ入力許可を与える方法

前回、列毎にIMEを制御する方法を紹介したので、今度はIMEをOFFにした上で数値(0〜9)だけを許可する方法を紹介する。

この方法では前回のソースを再利用している。それというのも現在の列番号を取得するのに必要だからである。

普通のTextBoxコントロールであれば、通常のKeyPressイベント内で制御すれば良いのだが、DataGridViewでそれをやってもCell内のKeyPressイベントを拾ってはくれない。これはDataGridViewのセルにはTextBox・ComboBoxなどいくつものスタイルがあって、それぞれのタイプ別にイベントを持っているからである。

Private colNo, rowNo As Integer
'DataGridViewのTextBoxセルを宣言
Private TextEditCtrl As DataGridViewTextBoxEditingControl
 
'//// 列毎にIMEを制御 ///////
Private Sub DataGridView1_CellEnter(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles DataGridView1.CellEnter
colNo = e.ColumnIndex '現在の列番号
rowNo = e.RowIndex '現在の行番号
Select Case e.ColumnIndex
Case 0, 4, 11
'この列は日本語入力ON
DataGridView1.ImeMode = Windows.Forms.ImeMode.Hiragana
Case 1 To 3, 5 To 10
'この列はIME無効(半角英数のみ)
DataGridView1.ImeMode = Windows.Forms.ImeMode.Disable
End Select
End Sub
 
'///// DataGridViewの編集コントロールが表示された時に //////
'///// KeyPressイベントを関連付け //////
Private Sub DataGridView1_EditingControlShowing( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) _
Handles DataGridView1.EditingControlShowing
TextEditCtrl = CType(e.Control, DataGridViewTextBoxEditingControl)
AddHandler TextEditCtrl.KeyPress, AddressOf TextEditCtrl_KeyPress
End Sub
 
'///// TextBoxセル内でのKeyPressイベント //////
Private Sub TextEditCtrl_KeyPress(ByVal sender As Object, _
ByVal e As KeyPressEventArgs)
Select Case colNo '現在の列番号
Case 2, 3, 6 '数値のみ許可
Select Case e.KeyChar
Case Chr(Keys.Back) 'BackSpace
Case Chr(Keys.D0) To Chr(Keys.D9) '数値キー
'テンキー用は不要(コメント参照)
'Case Chr(Keys.NumPad0) To Chr(Keys.NumPad9)
'小数点(.)を許可したい場合は
'Case Chr(Keys.Decimal) を追加
Case Else
'上記キー以外は処理しないようにする
'(Delete,Enter,Tabなどは有効)
e.Handled = True
End Select
End Select
End Sub
 
'////// 編集が終わったタイミングでKeyPressイベントの関連付けを解除 /////
Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles DataGridView1.CellEndEdit
RemoveHandler TextEditCtrl.KeyPress, AddressOf TextEditCtrl_KeyPress
End Sub
posted by なっちゃん at 16:44| 静岡 ????| Comment(9) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

Parameters の使用上の注意(ADO.NET)

SQLステートメントでパラメータを使用する場合にParametersプロパティに値をセットするが、連続してSQLを実行する場合、事前にパラメータの内容を消しておかないと同じ内容で処理されてしまうので注意する。
最初これに気が付かず、何故エラーするのか大いに迷ったことがある。

(Dim cmd As New OleDbCommand)
 
For i = 0 To 2
With Item(i)
cmd.CommandText = "insert into hoge_tb values(?,?,?)"
cmd.Parameters.Clear() 'これが無いとItem(0)の内容が3回登録されてしまう。
cmd.Parameters.Add("id", OleDbType.Integer).Value = .id
cmd.Parameters.Add("no", OleDbType.SmallInt).Value = i
cmd.Parameters.Add("namae", OleDbType.VarWChar).Value = .Name
cmd.ExecuteNonQuery()
End With
Next i
posted by なっちゃん at 14:44| 静岡 ????| Comment(8) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

2006年09月12日

DataGridViewで列毎にIMEを制御するには

CellEnterイベントで列毎にImeModeを指定する

Private Sub DataGridView1_CellEnter(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles DataGridView1.CellEnter
'---- 列番号を調べて制御 ------
Select Case e.ColumnIndex
Case 0, 4, 11
'この列は日本語入力ON
DataGridView1.ImeMode = Windows.Forms.ImeMode.Hiragana
Case 1 To 3, 5 To 10
'この列はIME無効(半角英数のみ)
DataGridView1.ImeMode = Windows.Forms.ImeMode.Disable
End Select
End Sub

CellEnterイベント・・・現在のセルが変更されたとき、またはこのコントロールが入力フォーカスを受け取ったときに発生
posted by なっちゃん at 20:12| 静岡 ?J| Comment(0) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

TextBoxコントロールのよく使うプロパティ・メソッド比較

VB6VB.NET(VB2005)
コントロールに入力フォーカスを移すText1.SetForcusTextBox1.Forcus()
選択されたテキストの開始点を設定(取得)Text1.SelStart=0TextBox1.SelectionStart=0
選択されたテキストの文字数を設定(取得)Text1.SelLength=10TextBox1.SelectionLength=10
選択されたテキストの内容を設定(取得)Text1.SelText="hoge"TextBox1.SelectedText="hoge"
指定した位置のテキストを選択(該当なし)TextBox1.Select(0,10)
これは下の2行と同じ
TextBox1.SelectionStart=0
TextBox1.SelectionLength=10
コントロールの全てテキストを選択(該当なし)TextBox1.SelectAll()
posted by なっちゃん at 14:36| 静岡 ?J| Comment(0) | TrackBack(0) | VB vs VB.NET | このブログの読者になる | 更新情報をチェックする

2006年09月08日

Erase ステートメントの違い

VB2005でデータベースからExecuteReaderでデータを読み込み、配列に代入するルーチンを作ったがなぜかアプリケーションエラーが発生する。(下図)

エラー画面

DBからのデータ取得はこれまでさんざんやってきた作業なのでコードに問題があるとは思えなくVB2005(ADO.NET 2.0)になってDataReaderのクラスが変わったのかなと思って調べてみたのだが、特にそれらしい記載はない。コードも代入する直前まで問題なく動いているので原因がなかなか判らなかった。

こうした場合エラーの原因は意外なところにあるもので、今回の場合ADO.NETの使い方ではなく代入先の配列の使い方にあった。
代入しようとする配列(変数のタイプは構造体)がNothingになっていたのだ。
えー、ちゃんと初期化してあるし、なんで?と思ったが確かにNothingになっている(下図)

エラー時のコード

何故Nothingになってたのか考えてみたところ、直前にEraseしているのが原因らしい。
実はVB6ではこれで問題なく動いていたのだ。ところがVB2005(VB.NETでも同じ)ではEraceの動きが違っている。

VB6のヘルプを見るとEraceの機能は
静的配列[Dim hoge(5) 添字を指定して宣言]
・・・変数を初期化(数値は0に、文字列は"")してくれる。
動的配列[Dim hoge() 添字を未指定にして宣言する]
・・・メモリを開放。その後ReDimする必要あり。

VB2005でもVB6と同様に静的配列の初期化を想定していたのだ。しかしVB6とは違い自動で初期化してくれなかった(^^;
※VB6ではこの初期化の機能が大変便利で、構造体の内部変数を初期化するのに、Eraseで一回で済むようわざわざ配列にしたくらいである。

VB2005のヘルプには「各配列変数に Nothing 値を割り当てるのと同じ結果になります」とある。サンプルは下のようになっている。
Dim threeDimArray(9, 9, 9), twoDimArray(9, 9) As Integer
Erase threeDimArray, twoDimArray
ReDim threeDimArray(4, 4, 9)

※VB6では静的配列をReDimできないのに、VB.NETではできてしまう!

これで直した結果、エラーは無くなった。(下図)

修正後のコード
posted by なっちゃん at 15:30| 静岡 ????| Comment(0) | TrackBack(0) | VB vs VB.NET | このブログの読者になる | 更新情報をチェックする

2006年09月04日

VB2005でMainプロシージャから起動させるには

VB.NETではプロジェクトのプロパティで選択できたのに(図1)、VB2005では「Sub Main」が出てこない(図2)。何がいけないのかとあちこち調べたがどこにも出てない。
あちこちいじっているうち、「アプリケーションフレームワークを有効にする」を解除したら現われた(図3)。
分ってしまえば何でもないことだが、こういったことが一番やっかいである。やれやれ(- -;

図1:VB.NET2003のプロパティ
VB.NET2003のプロパティ


図2:VB2005のプロパティ(既定値)
VB2005のプロパティ(既定値)


図3:VB2005のプロパティ(修正)
VB2005のプロパティ(修正)
posted by なっちゃん at 18:29| 静岡 ????| Comment(0) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする