2018年4月30日月曜日

AccessアクセスClassをVBAに移植してみた~Class本体~

けっこー大変だったorz
書式を直すだけなら、ふつーに正規表現とかでぱたぱたと出来たのだけど、
なにしろボクはVBAのお約束を知らない。
参照渡しをSetにするとかゆーのは、あちこちで見かけたので問題なかったのだけど、
まさか、引数を渡すのに括弧つけちゃダメな言語があったとはっ!と…
あとアレだ。Class内部のコーディングのミスを、
呼び出し側のPropertyの設定ミスとしてエラー吐くのはどうよ。
そこカプセル化しちゃダメだよね?てなトコロ。
Openさせたときにエラー吐かせて拾おうとしたら、
Class内部でのエラー回避処理には引っかからず、
Open Method読んでるトコでエラー吐くし。内部でのチェック意味ねー( ゚-゚)~゚

仕上がりはけっこーおざなり。
とりあえず動いたからいいや的な作りなので、丸写しで追求しないか、
使いやすいようカスタマイズしてください( ゚-゚)~゚

参考:AccessアクセスClassをVBAに移植してみた~呼び出し側~


(Class Module : SetDBtoTable )

  1. Option Explicit
  2. '指定したDBを読み込み、テーブルで返す。
  3. '----------
  4. 'Variable
  5. '----------
  6. Private m_Provider As String
  7. Private m_DataSource As String
  8. Private m_ConnectionString As String
  9. Private m_UserID As String
  10. Private m_Password As String
  11. Private m_RecordCount As Integer
  12. Private m_ColumnCount As Integer
  13. Private m_DataTable() As String 'テーブルデータ格納場所
  14. Private cn As ADODB.Connection
  15. Private rs As ADODB.Recordset
  16. '----------
  17. 'Property
  18. '----------
  19. '------------------------------
  20. 'DBへアクセスするために必要なProperty群
  21. '------------------------------
  22. 'プロバイダ指定。Accessなら"Microsoft.Jet.OLEDB.4.0;"みたいなの
  23. Property Get Provider() As String
  24. Provider = m_Provider
  25. End Property
  26. Property Let Provider(Provider As String)
  27. m_Provider = Provider
  28. End Property
  29. 'データソース指定。Accessならファイル名
  30. Property Get DataSource() As String
  31. DataSource = m_DataSource
  32. End Property
  33. Property Let DataSource(DataSource As String)
  34. m_DataSource = DataSource
  35. End Property
  36. 'コネクションストリング。テーブル名だったりSQLだったり
  37. Property Get ConnectionString() As String
  38. ConnectionString = m_ConnectionString
  39. End Property
  40. Property Let ConnectionString(ConnectionString As String)
  41. m_ConnectionString = ConnectionString
  42. End Property
  43. 'ユーザーID。テストしてないから動くかどうかわからない( ゚-゚)~゚
  44. Property Get UserID() As String
  45. UserID = m_UserID
  46. End Property
  47. Property Let UserID(UserID As String)
  48. m_UserID = UserID
  49. End Property
  50. 'パスワード。テストしてな(以下略
  51. Property Get Password() As String
  52. Password = m_Password
  53. End Property
  54. Property Let Password(Password As String)
  55. m_Password = Password
  56. End Property
  57. '------------------------------
  58. '得たデータを参照するProperty群
  59. '------------------------------
  60. 'レコード数
  61. Property Get RecordCount() As Long
  62. RecordCount = m_RecordCount
  63. End Property
  64. 'カラム数
  65. Property Get ColumnCount() As Long
  66. ColumnCount = m_ColumnCount
  67. End Property
  68. 'Value Override群 Start…って思ったら、Overrideできないでやんの( ゚-゚)~゚
  69. Property Get Value() As String()
  70. Value = m_DataTable
  71. End Property
  72. 'Item Override群 Start Default Property指定。Default指定もできないでやんの
  73. Property Get Item(ByVal i As Integer, ByVal j As Integer) As String
  74. Item = m_DataTable(i, j)
  75. End Property
  76. Property Get Record(ByVal i As Integer) As String()
  77. Record = m_Record(i)
  78. End Property
  79. Property Get Column(ByVal j As Integer) As String()
  80. Column = m_Column(j)
  81. End Property
  82. '----------
  83. 'Constructor
  84. '----------
  85. Private Sub Class_Initialize()
  86. Debug.Print ("Constructor:" & TypeName(Me))
  87. m_Provider = "Microsoft.Jet.OLEDB.4.0;"
  88. End Sub
  89. '----------
  90. 'Destructor
  91. '----------
  92. Private Sub Class_Terminate()
  93. Debug.Print ("Destructor:" & TypeName(Me))
  94. End Sub
  95. '----------
  96. 'Method
  97. '----------
  98. 'DBにアクセスし、レコード数、カラム数、データ本体を読み込み、Class変数に代入
  99. Public Function OpenDB() As Boolean
  100. Dim OnOK As Boolean
  101. OnOK = True
  102. Set cn = New ADODB.Connection
  103. Set rs = New ADODB.Recordset
  104. Dim i As Integer
  105. Dim j As Integer
  106. cn.Provider = m_Provider
  107. '_ConnectionStringが空か確認。空であればエラーを吐きFalseを返してMethod終了
  108. If m_ConnectionString = "" Then
  109. Debug.Print ("ERROR:" & TypeName(Me) & ":ConnectionString Property Not Assignment")
  110. OnOK = False
  111. OpenDB = OnOK
  112. End If
  113. 'DataSourceが空か確認。空であればエラーを吐きFalseを返してMethod終了
  114. If m_DataSource = "" Then
  115. Debug.Print ("ERROR:" & TypeName(Me) & ":DataSource Property Not Assignment")
  116. OnOK = False
  117. OpenDB = OnOK
  118. Exit Function
  119. End If
  120. 'DataSource設定
  121. cn.Properties("Data Source").Value = m_DataSource
  122. 'ID/Passwd設定(試してない
  123. If m_UserID <> "" Then
  124. cn.Properties("UserID").Value = m_UserID
  125. End If
  126. If m_Password <> "" Then
  127. cn.Properties("Password").Value = m_Password
  128. End If
  129. On Error GoTo Error_Handler
  130. cn.Open
  131. 'ConnectionString(テーブ名やSQL。DELETEとか書かれても、
  132. 'rs.open()のときにReadOnlyで開くからはじけると思う
  133. rs.Source = m_ConnectionString
  134. rs.ActiveConnection = cn
  135. rs.CursorType = ADODB.CursorTypeEnum.adOpenKeyset
  136. rs.LockType = ADODB.LockTypeEnum.adLockReadOnly
  137. rs.Open
  138. m_RecordCount = rs.RecordCount
  139. m_ColumnCount = rs.Fields.Count
  140. ReDim m_DataTable(m_RecordCount - 1, m_ColumnCount - 1)
  141. i = 0
  142. Do Until rs.EOF
  143. For j = 0 To m_ColumnCount - 1
  144. m_DataTable(i, j) = rs.Fields(j).Value
  145. Next j
  146. rs.MoveNext
  147. i = i + 1
  148. Loop
  149. OpenDB = OnOK
  150. Exit Function
  151. Error_Handler:
  152. 'Try中のエラーのとき cnとrsのopen、データ取り込み時それぞれで節を分ければError位置が特定できる。はず。
  153. Debug.Print ("ERROR:" & TypeName(Me) & ":DB or RS Open failed")
  154. OnOK = False
  155. Error_Handler_End:
  156. OpenDB = OnOK
  157. End Function
  158. 'クローズ。ホントは必要なさそうなんだけど、OpenしたからにはCloseしたくなるのは本能。
  159. 'VBAはちゃんとデストラクタくんが動いてくれるのでcallはしない。。
  160. Public Sub CloseDB()
  161. rs.Close
  162. cn.Close
  163. Erase m_DataTable
  164. End Sub
  165. Public Sub putData()
  166. rs.MoveFirst
  167. ActiveCell.CopyFromRecordset rs
  168. End Sub
  169. Public Sub putRange(Arg_Range As String, Optional Worksheet As String)
  170. rs.MoveFirst
  171. If Worksheet = vbNullString Then
  172. ActiveSheet.Range(Arg_Range).CopyFromRecordset rs
  173. Else
  174. Worksheets(Worksheet).Range(Arg_Range).CopyFromRecordset rs
  175. End If
  176. End Sub
  177. Public Sub putCells(ByVal Row As Integer, ByVal Col As Integer, Optional ByVal Worksheet As String)
  178. rs.MoveFirst
  179. If Worksheet = vbNullString Then
  180. ActiveSheet.Cells(Row, Col).CopyFromRecordset rs
  181. Else
  182. Worksheets(Worksheet).Cells(Row, Col).CopyFromRecordset rs
  183. End If
  184. End Sub
  185. '----------
  186. 'Private Function
  187. '----------
  188. 'データ要素単体渡し。stringで返す。範囲外のINDEX渡すと怒られるぞ。
  189. Private Function m_Item(ByVal i As Integer, ByVal j As Integer) As String
  190. m_Item = m_DataTable(i, j)
  191. End Function
  192. 'INDEXのRecordの要素全てを、Stringの1元配列型で返す。
  193. Private Function m_Record(ByVal i As Integer) As String()
  194. Dim ReturnTable() As String
  195. Dim j As Integer
  196. ReDim ReturnTable(m_ColumnCount - 1)
  197. For j = 0 To m_ColumnCount - 1
  198. ReturnTable(j) = m_DataTable(i, j)
  199. Next j
  200. m_Record = ReturnTable
  201. End Function
  202. 'INDEXのColumnの要素全てを、Stringの1元配列型で返す。
  203. Private Function m_Column(ByVal j As Integer) As String()
  204. Dim ReturnTable() As String
  205. Dim i As Integer
  206. ReDim ReturnTable(m_RecordCount - 1)
  207. For i = 0 To m_RecordCount - 1
  208. ReturnTable(i) = m_DataTable(i, j)
  209. Next i
  210. m_Column = ReturnTable
  211. End Function

AccessアクセスClassをVBAに移植してみた~呼び出し側~

Overrideとかできなかったので、ちょっと機能縮小気味だけど、
セルのMethodにCopyFromRecordsetなんてのがあって、
OpenしてあるRecordsetからごっそりデータを貼り付けられる。
ソレをメソッド化してみた。

Excel用に追加したMethod。
.putData
 :ActiveSheetのActiveCellを左上としてテーブル貼り付け
.putCells(ByVal Row As Integer, ByVal Col As Integer, Optional ByVal Worksheet As String)
 Worksheets(Worksheet ).Cells(Row,Col)を左上としてテーブル貼り付け
 ※Worksheetを省略すると、ActiveSheetに
.putRange(Arg_Range As String, Optional Worksheet As String)
 Worksheets(Worksheet ).Range(Range)を左上としてテーブル貼り付け
 ※Worksheetを省略すると、ActiveSheetに

クラス本体はこちら:AccessアクセスClassをVBAに移植してみた~Class本体~

呼び出し側
  1. Option Explicit
  2. Sub ボタン1_Click()
  3. Dim DB As SetDBtoTable
  4. Set DB = New SetDBtoTable
  5. DB.DataSource = "\LANDISK1\share\Test.mdb"
  6. DB.ConnectionString = "SELECT ID,Name,Order FROM T_Master ORDER BY Order;"
  7. DB.OpenDB
  8. DB.putData
  9. DB.putCells 16, 5, "Sheet1"
  10. DB.putRange "H36"
  11. DB.CloseDB
  12. End Sub



VBAの複数の引数の渡し方~カッコつけてんじゃねぇよ!~

なんかね、ExcelVBAで、メソッドにうまく引数を渡せなくてハマった。
複数の引数渡すのに『カッコつけちゃダメ』なんてダサすぎだろ( ゚-゚)~゚

  1. '(test class)
  2. Public Sub test(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer)
  3. Debug.Print a + b + c
  4. End Sub
  5. '(呼び出し)
  6. Private Sub CommandButton2_Click()
  7. Dim test As New testClass
  8. test.test 1, 2, 3 '←ココ( ゚-゚)~゚
  9. End Sub
括弧つけると、=を入れろとか、無理矢理動かすと構文エラーとか…
どうやら、()は演算子として処理されるらしい。
だったら、構文の補助みたいんので、括弧表示するなよなー!

…ふと思ったんだけどN88BASICのGOSUB文って引数って渡せたっけ?
今思うと出来なかった気がする…てゆかそもそも構造化言語ですらなかったか。ないな(笑

2018年4月29日日曜日

文字列操作~String.Substring Method~

ちょっとVBの中で文字列操作の必要があったので、
VBAの文字列操作と言えば、LeftやMid関数だよな~書式どーだっけ?
と調べてみたら、Substringなんてゆー便利なMethodが用意されてた。
(たぶん)String型には全部オマケでついてくるんだと思う。

From MSDN
Public Function Substring ( startIndex As Integer, length As Integer) As String

.Substring(何番目から,何文字もってこい)と、ゆーことらしい。

Dim S as String
S = "一二三四五六"
として、
S.Substring(1, 3) '2文字目から3文字抜き出す。
S.Substring(2) '引数省略で、3文字目から最後まで。
S.Substring(0, S.Length - 2) '後ろ2文字削る。なんてコトもできる。
              '(S.LengthはSの文字数

※実行結果は、Debug.Print(S.Substring(1, 3))とかで確認。

漢字一文字も一文字として捉えてる。どっかに比較のオプションがあるかも。
ふつーの配列のINDEX同様、範囲ハズれればOutOfRangeの例外エラーが起こる。

明示的なString変数だけじゃなく、hoge.Name.Substringとかにも使えるので、
なにかと便利そう。

Accessアクセス from VB ~Class化してみるよ~(8:今度こそ完成版)

完成版(でいいや)
.item Propertyでもデータ要素を参照できるようにした。
Default設定し、Class変数(i,j)でも参照できるようにした。
他、書式の統一化、Castの明示可などなど。
ちなみに、データを全てStringにしてるのは、Table化した際の扱いが楽なため。


  1. Option Strict On
  2. '指定したDBを読み込み、テーブルで返す。
  3. Public Class SetDBtoTable
  4. '----------
  5. 'Variable
  6. '----------
  7. Private _Provider As String
  8. Private _DataSource As String
  9. Private _ConnectionString As String
  10. Private _UserID As String
  11. Private _Password As String
  12. Private _RecordCount As Integer
  13. Private _ColumnCount As Integer
  14. Private _DataTable(,) As String 'テーブルデータ格納場所
  15. '----------
  16. 'Property
  17. '----------
  18. '------------------------------
  19. 'DBへアクセスするために必要なProperty群
  20. '------------------------------
  21. 'プロバイダ指定。Accessなら"Microsoft.Jet.OLEDB.4.0;"みたいなの
  22. Public Property Provider As String
  23. Get
  24. Return _Provider
  25. End Get
  26. Set(value As String)
  27. _Provider = value
  28. End Set
  29. End Property
  30. 'データソース指定。Accessならファイル名
  31. Public Property DataSource As String
  32. Get
  33. Return _DataSource
  34. End Get
  35. Set(value As String)
  36. _DataSource = value
  37. End Set
  38. End Property
  39. 'コネクションストリング。テーブル名だったりSQLだったり
  40. Public Property ConnectionString As String
  41. Get
  42. Return _ConnectionString
  43. End Get
  44. Set(value As String)
  45. _ConnectionString = value
  46. End Set
  47. End Property
  48. 'ユーザーID。テストしてないから動くかどうかわからない( ゚-゚)~゚
  49. Public Property UserID As String
  50. Get
  51. Return _UserID
  52. End Get
  53. Set(value As String)
  54. _UserID = value
  55. End Set
  56. End Property
  57. 'パスワード。テストしてな(以下略
  58. Public Property Password As String
  59. Get
  60. Return _Password
  61. End Get
  62. Set(value As String)
  63. _Password = value
  64. End Set
  65. End Property
  66. '------------------------------
  67. '得たデータを参照するProperty群
  68. '------------------------------
  69. 'レコード数
  70. Public ReadOnly Property RecordCount As Long
  71. Get
  72. Return _RecordCount
  73. End Get
  74. End Property
  75. 'カラム数
  76. Public ReadOnly Property ColumnCount As Long
  77. Get
  78. Return _ColumnCount
  79. End Get
  80. End Property
  81. 'Value Override群 Start
  82. Public Overridable ReadOnly Property Value As String(,)
  83. Get
  84. Return _DataTable
  85. End Get
  86. End Property
  87. Public Overridable ReadOnly Property Value(ByVal i As Integer) As String()
  88. Get
  89. Return (_Record(i))
  90. End Get
  91. End Property
  92. Public Overridable ReadOnly Property Value(ByVal i As Integer, ByVal j As Integer) As String
  93. Get
  94. Return (_DataTable(i, j))
  95. End Get
  96. End Property
  97. 'Value Override群 End
  98. 'Item Override群 Start Default Property指定
  99. Default Public Overridable ReadOnly Property Item(ByVal i As Integer, ByVal j As Integer) As String
  100. Get
  101. Return (_DataTable(i, j))
  102. End Get
  103. End Property
  104. Default Public Overridable ReadOnly Property Item(ByVal i As Integer) As String()
  105. Get
  106. Return (_Record(i))
  107. End Get
  108. End Property
  109. 'Item Override群 End
  110. Public ReadOnly Property Record(ByVal i As Integer) As String()
  111. Get
  112. Return (_Record(i))
  113. End Get
  114. End Property
  115. Public ReadOnly Property Column(ByVal j As Integer) As String()
  116. Get
  117. Return (_Column(j))
  118. End Get
  119. End Property
  120. '----------
  121. 'Constructor
  122. '----------
  123. Public Sub New()
  124. Debug.Print("Constructor:" & TypeName(Me))
  125. _Provider = "Microsoft.Jet.OLEDB.4.0;"
  126. End Sub
  127. '----------
  128. 'Destructor
  129. '----------
  130. Private Sub Class_Terminate()
  131. Debug.Print("Destructor:" & TypeName(Me))
  132. End Sub
  133. '----------
  134. 'Method
  135. '----------
  136. 'DBにアクセスし、レコード数、カラム数、データ本体を読み込み、Class変数に代入
  137. Public Function Open() As Boolean
  138. Dim OnOK As Boolean = True
  139. Dim cn As ADODB.Connection
  140. Dim rs As ADODB.Recordset
  141. cn = New ADODB.Connection
  142. rs = New ADODB.Recordset
  143. Dim i As Integer
  144. Dim j As Integer
  145. cn.Provider = _Provider
  146. '_ConnectionStringが空か確認。空であればエラーを吐きFalseを返してMethod終了
  147. If _ConnectionString = Nothing Then
  148. Debug.Print("ERROR:" & TypeName(Me) & ":ConnectionString Property Not Assignment”)
  149. OnOK = False
  150. Return OnOK
  151. End If
  152. 'DataSourceが空か確認。空であればエラーを吐きFalseを返してMethod終了
  153. If _DataSource = Nothing Then
  154. Debug.Print("ERROR:" & TypeName(Me) & ":DataSource Property Not Assignment”)
  155. OnOK = False
  156. Return OnOK
  157. End If
  158. 'DataSource設定
  159. cn.Properties("Data Source").Value = _DataSource
  160. 'ID/Passwd設定(試してない
  161. If _UserID <> Nothing Then
  162. cn.Properties("UserID").Value = _UserID
  163. End If
  164. If _Password <> Nothing Then
  165. cn.Properties("Password").Value = _Password
  166. End If
  167. '_ConnectionString(テーブ名やSQL。DELETEとか書かれても、
  168. 'rs.open()のときにReadOnlyで開くからはじけると思う
  169. Try
  170. cn.Open()
  171. rs.Open(_ConnectionString, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
  172. _RecordCount = rs.RecordCount
  173. _ColumnCount = rs.Fields.Count
  174. _DataTable = New String(_RecordCount - 1, _ColumnCount - 1) {}
  175. i = 0
  176. Do Until rs.EOF
  177. For j = 0 To _ColumnCount - 1
  178. _DataTable(i, j) = CType(rs.Fields(j).Value, String)
  179. Next
  180. rs.MoveNext()
  181. i = i + 1
  182. Loop
  183. rs.Close()
  184. cn.Close()
  185. Catch ex As Exception
  186. 'Try中のエラーのとき cnとrsのopen、データ取り込み時それぞれで節を分ければError位置が特定できる。はず。
  187. Debug.Print("ERROR:" & TypeName(Me) & ":DB or RS Open failed”)
  188. OnOK = False
  189. End Try
  190. Return OnOK
  191. End Function
  192. 'クローズ。ホントは必要なさそうなんだけど、OpenしたからにはCloseしたくなるのは本能。
  193. 'あと、いろいろ頑張って呼ぼうとしたけど出てきてくんないデストラクタくんを呼んでみる。なんもしてないんだけど。
  194. Public Sub close()
  195. _DataTable = Nothing
  196. Call Class_Terminate()
  197. End Sub
  198. '----------
  199. 'Private Function
  200. '----------
  201. '_Item Override群 Start Overridable を書くと『Private と Overridable を組み合わせることはできません。』と怒られる。
  202. 'データ要素単体渡し。stringで返す。範囲外のINDEX渡すと怒られるぞ。
  203. Private Function _Item(ByVal i As Integer, ByVal j As Integer) As String
  204. Return (_DataTable(i, j))
  205. End Function
  206. 'オーバーライドを試してみる。引数が数値一つだけなら、コッチが呼ばれる。
  207. '実動作はRecord()で。
  208. Private Function _Item(ByVal i As Integer) As String()
  209. Return (_Record(i))
  210. End Function
  211. '_Item Override群 End
  212. 'INDEXのRecordの要素全てを、Stringの1元配列型で返す。
  213. Private Function _Record(ByVal i As Integer) As String()
  214. Dim ReturnTable() As String
  215. Dim j As Integer
  216. ReturnTable = New String(_ColumnCount - 1) {}
  217. For j = 0 To _ColumnCount - 1
  218. ReturnTable(j) = _DataTable(i, j)
  219. Next j
  220. Return (ReturnTable)
  221. End Function
  222. 'INDEXのColumnの要素全てを、Stringの1元配列型で返す。
  223. Private Function _Column(ByVal j As Integer) As String()
  224. Dim ReturnTable() As String
  225. Dim i As Integer
  226. ReturnTable = New String(_RecordCount - 1) {}
  227. For i = 0 To _RecordCount - 1
  228. ReturnTable(i) = _DataTable(i, j)
  229. Next i
  230. Return (ReturnTable)
  231. End Function
  232. End Class


<<前

Accessアクセス from VB ~Class化してみるよ~(7.5)

ClassのPropertyに関していろいろと遊んでみた。

・既定のプロパティ(Default宣言)を使うコトで、Property名を省略できる。
 →でもなぜかINDEXが必要…省略できる場合はデータが配列である必要があるぽい。

・オーバーライド&引数の不定数(省略)化
 →引数の数や型が明確に違わないと、うまくオーバーライド出来ない。
  2つのIntegerの引数が、どちらか~や両方vbEmptyである場合に、
  返す型を変えようとしたが、結局うまく行かず。orz
  まぁ確かに、渡す値によって、返す型が違うMethodやPropertyなんて、
  扱いがめんどちいもんなぁ。諦めよう( ゚-゚)~゚
  ちなみに、Overridable と、明示的に宣言できるのも見つけたから、
  コレもしっかりつけよう。

・Option Strictなんてオプションを見つけた。
 Onにすると、勝手にcastするのをやめてくれるらしい(*゚-゚)
 やっぱ型意識しないでできるってのは怖いモンな!って、Onにしてみたら、
 INDEXをIntegerにしやがれ!と怒られまくりました。全部Longにしてた(笑
 てゆか、定数とかSystemが用意してるPropertyは基本Integerな感じだなぁ。
 けっこー、代入で怒られてる。

・vbEmptyはDouble型
 Stringの空判断には使っちゃダメだった。
 今後はStringはNothingで判断しよう。

・Private と Overridable を組み合わせることはできません。
 と、怒られた。Methodに書いたのだけど… なんでだろう

<<前  次>>

2018年4月27日金曜日

エラー回避してみる

Mainフォームにデータソースを設定して、移動ボタンとかで、
カレントレコードが変わったら起こるイベントに、コードを書いた。
UserIdをココに入れなさい。と。
Mainフォームで普通にカレントレコードを移動させてれば、問題なく動く。
よしよし(*゚-゚)

しかし、ボタンから別フォームを呼び出し、その別フォーム側から、
(close時に)MainフォームをRequeryしたら、

『実行時エラー '2113' このフィールドに入力した値が正しくありません。』

が出た。
とりあえず切り分けのため、Debug.Print RecordSet!UserId してみたら、

『実行時エラー  '3021'カレントレコードがありません。』

なんですと!?

そんなわけで、Record数、EOF、BOFを表示してみる。
RecordSet.RecordCount → 7(正常
RecordSet.EOF →False(EOFではない
RecordSet.BOF →False(BOFではない

…正常すぎじゃん( ゚-゚)~゚

こりゃ判断出来ないわってんで、エラー拾ってスルーするようにしました。

  1. Private Sub Form_Current()
  2. '子フォームでRequeryされたとき、カレントレコードが取得できないので回避させる。
  3. On Error Resume Next
  4. Cmb_UserId.Value = Me.Recordset!UserId
  5. Select Case Err.Number
  6. Case 0 '正常
  7. Case 2113 'このフィールドに入力した値が正しくありません。
  8. Case 3021 'カレントレコードがありません。
  9. Case Else
  10. Debug.Print ("ERROR:" & Err.Number)
  11. End Select
  12. On Error GoTo 0
  13. End Sub

ミソは、まず、On Error Resume Next で、『エラーが置きても次へ進む』指定と、
Select文でErr.Numberで、通していいエラー番号ダケをCaseに書き、
それ以外はエラー処理をするコト。
最後に、On Error GoTo 0 で、
『エラーを普通に拾ってくれるモード』に戻さないと楽しいコトになります( ゚-゚)~゚

ただスルーするのはキケンだし、
個人的にイヤ(コッチが重要)なのでこうしました( ゚-゚)~゚

通しちゃダメなその他エラーは、Msgboxで表示させるのが親切かも。
エラーコードからエラー内容を引っ張れるなら、エラーダイヤログと同じよーな動きさせるのも可能かもしれません。めんどちいのでやらないけど(ぇ

追記:
しまった。正常時のエラーコード0のcase書くのを忘れてた(*゚-゚)


Accessアクセス from VB ~Class化してみるよ~(7:あとがき)

なんか、VBAでも使い回しできるようにと思ってVB選んだのに、VBA(VB6準拠?)と、VB.NET(?)じゃ、いろいろ違ってぽん載せできないじゃないか( ゚-゚)~゚

このClassでは、DBの内容を一気にテーブルに引っ張ってきている。
そのため。ドでかいデータを引っ張ってきちゃうと大変なコトになるかもしれない。

ConnectionString 引数をそのまま渡しているので、テーブル名の指定だけでなく、SQLを渡してSELECT文にORDER BYつけてSortさせたり、取り込むFieldを指定できたりもします。

そんなわけで、
現状わからない点

変数(引数)の状態の検査
 →Stringの場合、Nothingと比較するのが適当ぽい。
  Ifを用いる場合は、""と変わらない動作をする(ちからのテスト範囲内では)。
  ちなみに""とvbEmptyとかを見分けるには、StrPtr()を使うといいらしい( ゚-゚)~゚

 設定されていないとか、各種Nullとか文字列に0とか、
 そういう状態を検知するのはどういう方法が確実なんだろうか。
 とりあえず、Open Methodの中で、Nothing、vbNullString、vbEmptyと比べる
 なんてコトをしてみたが、困ったことに全て期待通りに動いちゃってるので…
 isなんちゃら~でもやってることは一緒だろうし。

引数の省略の仕方
 Optionalで、hoge(,1)という書き方は出来た。
 しかし、”第一引数が省略されている”ことが、Overrideで感知できないので、
 今回の実装は諦める。

 多分できると思うんだ。
 hoge(,1)のように、設定の必要がないとか、ソレで別の動きをさせるための書き方。
 Datas()を、オーバーライドで、引数2つで要素(i,j) as String を返す、
 1つだとRecord(i) as String ()を返すギミックを仕掛けたのだけど、
 Datas(,1)と呼ばれたとき、Column(1) as String()を返すよーなコトをしたい。

 …とおもたら、Optionalをみつけた。そのうち試す(ぇ

Methodへの引数の検査
 今回、INDEXとして、数値を渡すのだけれども、ソレが範囲外だった場合、
 VB的にはどんな動作が”普通”なんだろうか。
 チェックし、その場でエラー吐いて全プログラム終了させるか、
 チェックせずOSやコンパイラに任せて実行時エラーを吐かせるのか。
 はたまたゆるいVBらしく、0や最大値に勝手に変更するとか(笑
 とりあえず今回は、INDEXに関するあたりのチェックはしない方向で簡略化した。

ToDo
 Optionalの動作確認【済】
 連想配列(使えるのか?)で、Record(1,"Field名")みたいにしてデータ参照するとかとか
 …SELECT文で呼ばれたときの処理がめんどちいか( ゚-゚)~゚
 DB接続まわりのエラーチェック細分化。
 変数未設定の検出【済】

 こんなもんかな( ゚-゚)~゚


<<前  次>>

2018年4月26日木曜日

Accessアクセス from VB ~Class化してみるよ~(6:呼び出し側)

めんどちいので色付けしない( ゚-゚)~゚
なんか、見やすくするよーなやり方を探してるけど…無い!(ぇ
※追記:ありました(*゚-゚)
google/code-prettifyつかってみてます。

  1. '2元配列のガラだけ用意しSetDBtoTable.Valueでコピって使う
  2. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  3. Dim DataTable As SetDBtoTable
  4. Dim Datas(,) As String
  5. Dim i, j As Long
  6. Dim str_Print As String
  7. DataTable = New SetDBtoTable
  8. DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
  9. DataTable.ConnectionString = "T_Master"
  10. DataTable.Open()
  11. Datas = DataTable.Value
  12. For i = 0 To DataTable.RecordCount - 1
  13. str_Print = ""
  14. For j = 0 To DataTable.ColumnCount - 1
  15. str_Print = str_Print + Datas(i, j) & " : "
  16. Next j
  17. Debug.Print(str_Print)
  18. Next i
  19. DataTable.close()
  20. End Sub
  21. 'Datas Methodでデータを読み出す
  22. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
  23. Dim DataTable As SetDBtoTable
  24. Dim i, j As Long
  25. Dim str_Print As String
  26. DataTable = New SetDBtoTable
  27. DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
  28. DataTable.ConnectionString = "T_Master"
  29. DataTable.Open()
  30. For i = 0 To DataTable.RecordCount - 1
  31. str_Print = ""
  32. For j = 0 To DataTable.ColumnCount - 1
  33. str_Print = str_Print + DataTable.Datas(i, j) & " : "
  34. Next j
  35. Debug.Print(str_Print)
  36. Next i
  37. DataTable.close()
  38. End Sub
  39. '指定した行(この場合は2行目)のRecordを1元配列にもってくる。
  40. Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
  41. Dim DataTable As SetDBtoTable
  42. Dim j As Long
  43. Dim str_Print As String
  44. Dim Rec_data() As String
  45. DataTable = New SetDBtoTable
  46. DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
  47. DataTable.ConnectionString = "T_Master"
  48. DataTable.Open()
  49. Rec_data = DataTable.Datas(1)
  50. str_Print = ""
  51. For j = 0 To DataTable.ColumnCount - 1
  52. str_Print = str_Print + Rec_data(j) & " : "
  53. Next j
  54. Debug.Print(str_Print)
  55. DataTable.close()
  56. End Sub
  57. '指定した列(この場合は2列目)のFieldを1元配列にもってくる。
  58. Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
  59. Dim DataTable As SetDBtoTable
  60. Dim i As Long
  61. Dim str_Print As String
  62. Dim Rec_data() As String
  63. DataTable = New SetDBtoTable
  64. DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
  65. DataTable.ConnectionString = "T_Master"
  66. DataTable.Open()
  67. Rec_data = DataTable.Column(1)
  68. str_Print = ""
  69. For i = 0 To DataTable.RecordCount - 1
  70. str_Print = str_Print + Rec_data(i) & " : "
  71. Next i
  72. Debug.Print(str_Print)
  73. DataTable.close()
  74. End Sub
  75. End Class

<<前  次>>

Accessアクセス from VB ~Class化してみるよ~(5:とりえあず完成版)

20180428追記
なんかいろいろ勘違いしてた。動くけど、メソッドにする必要がないとかいろいろできそうなので、再開発決定

---
とりあえず実用レベルまでできた。

  1. Public Class SetDBtoTable
  2. '----------
  3. 'Variable
  4. '----------
  5. Private _Provider As String
  6. Private _DataSource As String
  7. Private _ConnectionString As String
  8. Private _UserID As String
  9. Private _Password As String
  10. Private _RecordCount As Long
  11. Private _ColumnCount As Long
  12. Private _DataTable(,) As String 'テーブルデータ格納場所
  13. '----------
  14. 'Property
  15. '----------
  16. '------------------------------
  17. 'DBへアクセスするために必要なProperty群
  18. '------------------------------
  19. 'プロバイダ指定。Accessなら"Microsoft.Jet.OLEDB.4.0;"みたいなの
  20. Public Property Provider As String
  21. Get
  22. Return _Provider
  23. End Get
  24. Set(value As String)
  25. _Provider = value
  26. End Set
  27. End Property
  28. 'データソース指定。Accessならファイル名
  29. Public Property DataSource As String
  30. Get
  31. Return _DataSource
  32. End Get
  33. Set(value As String)
  34. _DataSource = value
  35. End Set
  36. End Property
  37. 'コネクションストリング。テーブル名だったりSQLだったり
  38. Public Property ConnectionString As String
  39. Get
  40. Return _ConnectionString
  41. End Get
  42. Set(value As String)
  43. _ConnectionString = value
  44. End Set
  45. End Property
  46. 'ユーザーID。テストしてないから動くかどうかわからない( ゚-゚)~゚
  47. Public Property UserID As String
  48. Get
  49. Return _UserID
  50. End Get
  51. Set(value As String)
  52. _UserID = value
  53. End Set
  54. End Property
  55. 'パスワード。テストしてな(以下略
  56. Public Property Password As String
  57. Get
  58. Return _Password
  59. End Get
  60. Set(value As String)
  61. _Password = value
  62. End Set
  63. End Property
  64. '------------------------------
  65. '得たデータを参照するProperty群
  66. '------------------------------
  67. 'レコード数
  68. Public ReadOnly Property RecordCount As Long
  69. Get
  70. Return _RecordCount
  71. End Get
  72. End Property
  73. 'カラム数
  74. Public ReadOnly Property ColumnCount As Long
  75. Get
  76. Return _ColumnCount
  77. End Get
  78. End Property
  79. 'データの2次元配列の値返し。
  80. 'てゆかPropertyじゃなくMethodにしたほがいくね?
  81. Public ReadOnly Property Value As String(,)
  82. Get
  83. Return _DataTable
  84. End Get
  85. End Property
  86. '----------
  87. 'Constructor
  88. '----------
  89. Public Sub New()
  90. Debug.Print("Constructor:" & TypeName(Me))
  91. _Provider = "Microsoft.Jet.OLEDB.4.0;"
  92. End Sub
  93. '----------
  94. 'Destructor
  95. '----------
  96. Private Sub Class_Terminate()
  97. Debug.Print("Destructor:" & TypeName(Me))
  98. End Sub
  99. '----------
  100. 'Method
  101. '----------
  102. 'DBにアクセスし、レコード数、カラム数、データ本体を読み込み、Class変数に代入
  103. Public Function Open() As Boolean
  104. Dim OnOK As Boolean = True
  105. Dim cn As ADODB.Connection
  106. Dim rs As ADODB.Recordset
  107. cn = New ADODB.Connection
  108. rs = New ADODB.Recordset
  109. Dim i As Integer
  110. Dim j As Integer
  111. cn.Provider = _Provider
  112. '_ConnectionStringが空か確認。空であればエラーを吐きFalseを返してMethod終了
  113. If _ConnectionString = Nothing Then
  114. Debug.Print("ERROR:" & TypeName(Me) & ":ConnectionString Property Not Assignment”)
  115. OnOK = False
  116. Return OnOK
  117. End If
  118. 'DataSourceが空か確認。空であればエラーを吐きFalseを返してMethod終了
  119. If _DataSource = vbNullString Then
  120. Debug.Print("ERROR:" & TypeName(Me) & ":DataSource Property Not Assignment”)
  121. OnOK = False
  122. Return OnOK
  123. End If
  124. 'DataSource設定(テーブ名やSQL。DELETEとか書かれても、rs.open()のときにReadOnlyで開くからはじけると思う
  125. cn.Properties("Data Source").Value = _DataSource
  126. 'ID/Passwd設定(試してない
  127. If _UserID <> vbEmpty Then
  128. cn.Properties("UserID").Value = _UserID
  129. End If
  130. If _Password <> Nothing Then
  131. cn.Properties("Password").Value = _Password
  132. End If
  133. Try
  134. cn.Open()
  135. rs.Open(_ConnectionString, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
  136. _RecordCount = rs.RecordCount
  137. _ColumnCount = rs.Fields.Count
  138. _DataTable = New String(_RecordCount - 1, _ColumnCount - 1) {}
  139. i = 0
  140. Do Until rs.EOF
  141. For j = 0 To _ColumnCount - 1
  142. _DataTable(i, j) = rs.Fields(j).Value
  143. Next
  144. rs.MoveNext()
  145. i = i + 1
  146. Loop
  147. rs.Close()
  148. cn.Close()
  149. Catch ex As Exception
  150. 'Try中のエラーのとき cnとrsのopen、データ取り込み時それぞれで節を分ければError位置が特定できる。はず。
  151. Debug.Print("ERROR:" & TypeName(Me) & ":DB or RS Open failed”)
  152. OnOK = False
  153. End Try
  154. Return OnOK
  155. End Function
  156. 'クローズ。ホントは必要なさそうなんだけど、OpenしたからにはCloseしたくなるのは本能。
  157. 'あと、いろいろ頑張って呼ぼうとしたけど出てきてくんないデストラクタくんを呼んでみる。なんもしてないんだけど。
  158. Public Sub close()
  159. _DataTable = Nothing
  160. Call Class_Terminate()
  161. End Sub
  162. 'データ要素単体渡し。stringで返す。範囲外のINDEX渡すと怒られるぞ。
  163. Public Function Datas(i As Long, j As Long) As String
  164. Return (_DataTable(i, j))
  165. End Function
  166. 'オーバーライドを試してみる。引数が数値一つだけなら、コッチが呼ばれる。
  167. '実動作はRecord()で。
  168. Public Function Datas(i As Long) As String()
  169. Return (Record(i))
  170. End Function
  171. 'INDEXのRecordの要素全てを、Stringの1元配列型で返す。
  172. Public Function Record(i As Long) As String()
  173. Dim ReturnTable() As String
  174. Dim j As Long
  175. ReturnTable = New String(_ColumnCount - 1) {}
  176. For j = 0 To _ColumnCount - 1
  177. ReturnTable(j) = _DataTable(i, j)
  178. Next j
  179. Return (ReturnTable)
  180. End Function
  181. 'INDEXのColumnの要素全てを、Stringの1元配列型で返す。
  182. Public Function Column(j As Long) As String()
  183. Dim ReturnTable() As String
  184. Dim i As Long
  185. ReturnTable = New String(_RecordCount - 1) {}
  186. For i = 0 To _RecordCount - 1
  187. ReturnTable(i) = _DataTable(i, j)
  188. Next i
  189. Return (ReturnTable)
  190. End Function
  191. End Class

<<前  次>>

2018年4月25日水曜日

Accessアクセス from VB ~Class化してみるよ~(4)

RecordCountとColumnCountをRead Only Propeatyとして参照できるようにしてみた。
Class内部にTableもつのなら、Open、Closeにして、メモリ解放できるようにしたほうがいい気がしてきた…。
そろそろマジメにインターフェイスを考えよう。

  1. Public Class SetDBtoTable
  2. '----------
  3. 'Variable
  4. '----------
  5. Private _Provider As String
  6. Private _DataSource As String
  7. Private _ConnectionString As String
  8. Private _UserID As String
  9. Private _Password As String
  10. Private _RecordCount As Long
  11. Private _ColumnCount As Long
  12. ' Private _DataTable[][] As String 'テーブルデータ格納場所
  13. '----------
  14. 'Property
  15. '----------
  16. Public Property Provider As String
  17. Get
  18. Return _Provider
  19. End Get
  20. Set(value As String)
  21. _Provider = value
  22. End Set
  23. End Property
  24. Public Property DataSource As String
  25. Get
  26. Return _DataSource
  27. End Get
  28. Set(value As String)
  29. _DataSource = value
  30. End Set
  31. End Property
  32. Public Property ConnectionString As String
  33. Get
  34. Return _ConnectionString
  35. End Get
  36. Set(value As String)
  37. _ConnectionString = value
  38. End Set
  39. End Property
  40. Public Property UserID As String
  41. Get
  42. Return _UserID
  43. End Get
  44. Set(value As String)
  45. _UserID = value
  46. End Set
  47. End Property
  48. Public Property Password As String
  49. Get
  50. Return _Password
  51. End Get
  52. Set(value As String)
  53. _Password = value
  54. End Set
  55. End Property
  56. Public ReadOnly Property RecordCount As Long
  57. Get
  58. Return _RecordCount
  59. End Get
  60. End Property
  61. Public ReadOnly Property ColumnCount As Long
  62. Get
  63. Return _ColumnCount
  64. End Get
  65. End Property
  66. '----------
  67. 'Constructor
  68. '----------
  69. Public Sub New()
  70. Debug.Print("Constructor:" & TypeName(Me))
  71. _Provider = "Microsoft.Jet.OLEDB.4.0;"
  72. End Sub
  73. '----------
  74. 'Destructor
  75. '----------
  76. Private Sub Class_Terminate()
  77. Debug.Print("Destructor:" & TypeName(Me))
  78. End Sub
  79. '----------
  80. 'Method
  81. '----------
  82. Public Function GetTable() As Boolean
  83. Dim OnOK As Boolean = True
  84. Dim cn As ADODB.Connection
  85. Dim rs As ADODB.Recordset
  86. cn = New ADODB.Connection
  87. rs = New ADODB.Recordset
  88. cn.Provider = _Provider
  89. '_ConnectionStringが空か確認。空であればエラーを吐きFalseを返してMethod終了
  90. If _ConnectionString = Nothing Then
  91. Debug.Print("ERROR:" & TypeName(Me) & ":ConnectionString Property Not Assignment”)
  92. OnOK = False
  93. Return OnOK
  94. End If
  95. 'DataSourceが空か確認。空であればエラーを吐きFalseを返してMethod終了
  96. If _DataSource = vbNullString Then
  97. Debug.Print("ERROR:" & TypeName(Me) & ":DataSource Property Not Assignment”)
  98. OnOK = False
  99. Return OnOK
  100. End If
  101. 'DataSource設定(テーブ名やSQL。DELETEとか書かれても、rs.open()のときにReadOnlyで開くからはじけると思う
  102. cn.Properties("Data Source").Value = _DataSource
  103. 'ID/Passwd設定(試してない
  104. If _UserID <> Nothing Then
  105. cn.Properties("UserID").Value = _UserID
  106. End If
  107. If _Password <> Nothing Then
  108. cn.Properties("Password").Value = _Password
  109. End If
  110. Try
  111. cn.Open()
  112. rs.Open(_ConnectionString, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
  113. _RecordCount = rs.RecordCount
  114. _ColumnCount = rs.Fields.Count
  115. rs.Close()
  116. cn.Close()
  117. Catch ex As Exception
  118. 'Try中のエラーのとき
  119. Debug.Print("ERROR:" & TypeName(Me) & ":DB or RS Open failed”)
  120. OnOK = False
  121. End Try
  122. Return OnOK
  123. End Function
  124. End Class



<<前  次>>




Accessアクセス from VB ~Class化してみるよ~(3.5)

Propertyが空の判定方法。なんとなくわかりました。
パターンは3つ。

  1. Dim Str_Empty As String
  2. If Str_Empty = "" Then
  3. Debug.Print("""""")
  4. End If
  5. If Str_Empty = vbNullString Then
  6. Debug.Print("vbNullString")
  7. End If
  8. If Str_Empty = Nothing Then
  9. Debug.Print("Nothing")
  10. End If

こんな感じ。
真っ先に試した""や、vbNullStringで引っかかってくれなくて、
タダの文字列比較なハズなんだがなぁ…思って、上記のように簡素化したら、
やっぱりタダの文字列比較でした。

きっと、引っかかってたのは、設定しているのといないProperty名を
間違ってたんだろう( ゚-゚)~゚


<<前  次>>



2018年4月24日火曜日

Accessアクセス from VB ~Class化してみるよ~(3)

とりあえず、ClassでDBにアクセス成功。

  1. Public Class SetDBtoTable
  2. '----------
  3. 'Variable
  4. '----------
  5. Private _Provider As String
  6. Private _DataSource As String
  7. Private _ConnectionString As String
  8. ’(PropertyのGet/Set省略)
  9. '----------
  10. 'Constructor
  11. '----------
  12. Public Sub New()
  13. Debug.Print("Constructor:" & TypeName(Me))
  14. _Provider = "Microsoft.Jet.OLEDB.4.0;"
  15. End Sub
  16. '----------
  17. 'Destructor
  18. '----------
  19. Private Sub Class_Terminate()
  20. Debug.Print("Destructor:" & TypeName(Me))
  21. End Sub
  22. '----------
  23. 'Method
  24. '----------
  25. Public Function GetTable() As Boolean
  26. Dim OnOK As Boolean = True
  27. Dim cn As ADODB.Connection
  28. Dim rs As ADODB.Recordset
  29. cn = New ADODB.Connection
  30. rs = New ADODB.Recordset
  31. cn.Provider = _Provider
  32. cn.Properties("Data Source").Value = _DataSource
  33. Try
  34. cn.Open()
  35. rs.Open(_ConnectionString, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
  36. Debug.Print("RecordCount:" & rs.RecordCount)
  37. Debug.Print("column:" & rs.Fields.Count)
  38. rs.Close()
  39. cn.Close()
  40. Catch ex As Exception
  41. OnOK = False
  42. End Try
  43. Return OnOK
  44. End Function
  45. End Class



呼び出し側
  1. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  2. Dim DataTable As SetDBtoTable
  3. DataTable = New SetDBtoTable
  4. DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
  5. DataTable.ConnectionString = "T_Master"
  6. Debug.Print(DataTable.GetTable())
  7. End Sub

無事、レコード件数とカラム数を取得できました。

でも、RecordCountが、読み込んだ数を返す~なんてコト書いてる人がいて、ちょっと不安。
VBAだけの話ならば良いのだけれど。一応MSDNではコレでOKぽい。

ちなみに内容を参照したければ、してみるよ~(2)のように、Untileループしてあげてください。

しかーし、必要なPropertyが設定されていないと実行時にエラーになる。あたり前だけど。
ソレを検知、表示するために、コンストラクタで、Property変数に””を入れて、
Methodで、if _Property <> "" とかで引っ掛けようとしたんだけど、どーもうまくいかない。
Propertyが空だったら~って判定は出来ないモノか。
サブルーチンにして、引数固定にすりゃ、コンパイルの時点で怒られるのに…

ちなみにコンストラクタ、デストラクタで、自分自身を表示…TypeName(Me)…しといた。
できれば実体の変数も表示させたいけど…わかんね( ゚-゚)~゚(ぉぃ

<<前  次>>

Accessアクセス from VB ~Class化してみるよ~(2)


天の声が囁いた。
~ADODBを使いなさい~
なんですと!?

そんなわけでふつーのモジュールで慌てて書き換えてみた。

  1. Private Function Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  2. Dim OnOK As Boolean = True
  3. Dim cn As ADODB.Connection
  4. Dim rs As ADODB.Recordset
  5. Dim i As Integer = 0
  6. cn = New ADODB.Connection
  7. rs = New ADODB.Recordset
  8. cn.Provider = "Microsoft.Jet.OLEDB.4.0;"
  9. cn.Properties("Data Source").Value = "\\LANDISK1\share\Test.mdb"
  10. Try
  11. cn.Open()
  12. rs.Open("T_Master", cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
  13. Do Until rs.EOF
  14. Debug.Print (rs.Fields(1).Value)
  15. rs.MoveNext()
  16. Loop
  17. rs.Close()
  18. cn.Close()
  19. Catch ex As Exception
  20. OnOK = False
  21. Debug.Print ("ERROR")
  22. End Try
  23. Return OnOK
  24. End Function
こっれがさーー、例が無いのよ…
VB6時代のんとか、dao使った例とかはゴロゴロしてるんだけど、
Setステートメントとか、ボク環境の…コレ、VB.net?はSetとかLet廃止~とか…
丸写しで動くモンが全く無くて、結局MSDN読み解いた…

で、トドメは、Recordsetの内容参照方法。
なんか普通に、rs.Fields(0)とか、rs.Fields("名前")とか、rs!名前とかで参照できてるんだよね。Exampleは。
でも何故かできない…で、.netへの変更点で、なんかVB6までは省略出来たPropertyとかを、.netでは、明示的にやんないとダメ…とかなんとか書いてあったの思い出して…

後ろに.valueつけたら動いた(*゚-゚)

まぁおかげで、スペースが入ってるProperty名への文字列設定方法とかみっけたからいっか。
ちなみに、フィールド名で参照するより、Index…数値で参照したほうがDirectなので速いそうです。


<<前  次>>

2018年4月23日月曜日

SetPointが初期化されるアレ

ロジクールのSetPointくんは大変高性能。
アプリ毎に、キーの設定ができたりする。

Windowsのショートカット(Alt+Ctrl+なんちゃら)と組み合わせると、
マウスの戻るボタンでアプリやマクロを起動できたりする。
UWSCと組み合わせたりすると、ゲーム等でも楽できる。

しかし、ソレ以上に、大変アホである。 再起動したりすると、
設定をわすれてくれやがる。
もう10年とかこのバグ放置じゃないかなぁ。

なんかの拍子に、デフォルト設定ファイルから、書き戻してるぽい。
その対策をコチラで書いてくれていて、
入れ直したりするたんびに探すのもアレなんで、セルフでメモ

Explorerで %APPDATA%\Logitech\SetPoint フォルダに移動し、
user.xml を開き、 Ctrl + f → MODEL[検索] =のあとの10進数を16進数に直す。
(電卓アプリのプログラマーモードとかで。頭で出来る人はやってもよし( ゚-゚)~゚

C:\ProgramData\LogiShrd\SetPointP\Devices\PointingDevice フォルダに移動
16進数のフォルダに移動 中の16進数.xmlをバックアップとってから開く。
<AppOverride>行を全て削除。

ちなみにM570の場合は10000AC

以前、利き手の親指の付け根を骨折し、
普通のマウスが持てず、トラックボールにしたんですが、
もう、この形から離れられなくて、
何十年つかってるんだろうかと(大げさ

なので、この程度(?)の不具合があっても使い続けたいと…
でも壊れやすくなってるよーな気がするんですがロジテックさん( ゚-゚)~゚


2018年4月22日日曜日

Accessアクセス from VB ~Class化してみるよ~(1)

最終目的としては、
・Accessのファイルにアクセスしテーブルの情報を持ってくる。
・配列に受け取ることができそーならやってみる。
・できなきゃせめて内部で配列もってINDEXで参照


主税はObject言語での開発経験はない。とゆーか、プログラマであった経験すらない。
Classは作ったことが無いわけでは無いのだけれど、書式なんてさっぱり( ゚-゚)~゚
なので、単機能から徐々に実装していこうと思う。



…ぐぐり中…もまいら、ゴタクはいいんだ。書式よこせ書式。
とりあえずは、ソレ(Object)に対して、値(Property)設定したり、
実行コマンド(Method)用意するだけなんだ。( ゚-゚)~゚
ごく単純な話のハズなんだが、どうして長々小難しく書くんだろう。

そんなわけで結局MSDN( ゚-゚)~゚

  1. Public Class Set_DB_to_Table
  2. Public Function GetTable() As Boolean
  3. Dim OnOK As Boolean = True
  4. Dim ct As System.Data.OleDb.OleDbCommand
  5. Dim reader As System.Data.OleDb.OleDbDataReader
  6. Dim cn As New System.Data.OleDb.OleDbConnection(
  7. "Provider=Microsoft.Jet.OLEDB.4.0;" &
  8. "Data Source=\\LANDISK1\share\Test.mdb;"
  9. )
  10. Try
  11. ct = cn.CreateCommand
  12. ct.CommandText = "SELECT * FROM T_マスター"
  13. cn.Open()
  14. reader = ct.ExecuteReader
  15. While reader.Read() = True
  16. Debug.Print(reader(1))
  17. End While
  18. cn.Close()
  19. Catch ex As Exception
  20. Debug.Print("Error")
  21. OnOK = False
  22. End Try
  23. Return OnOK
  24. End Function
  25. End Class

Class名がなんかVBぽくないな。次から変更しよう。
中身は、VBからAccessにAccessしてみるでやったコトと一緒。
もしエラーがあった場合、OKならTrue、NGならFalseを返してみる変更を加えた。

呼び出し。

  1. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  2. Dim DataTable = New Set_DB_to_Table
  3. Debug.Print(DataTable.GetTable())
  4. End Sub

Providerとファイル名、テーブル名を固定にしてあるからこんだけ。

次はプロパティとして設定できるようにしてみる。

<<前  次>>


VBからAccessにAccessしてみる

やっぱり、Accessって名前はややこしいよね>Title

さて、ライセンスの関係でどのマシンにもAccessが入っている訳じゃない。ことにする。
そこで、共有データとしておいたAccessファイルに対して、
アクセスできるプログラムを書けた方がいいよね。ってコトでやってみる。

AccessやExcelに書いたVBAを流用しやすいよう、VS2017のVBでやってみよう。
とりあえずデータを読んでみるだけのモジュールを書いてみた。

  1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  2. Dim ct As System.Data.OleDb.OleDbCommand
  3. Dim reader As System.Data.OleDb.OleDbDataReader
  4. Dim cn As New System.Data.OleDb.OleDbConnection( _
  5. "Provider=Microsoft.Jet.OLEDB.4.0;" _ 'なんかお約束(ぉぃ
  6. "Data Source=\\LANDISK1\share\Test.mdb;" _ 'Accessのファイル置き場
  7. )
  8. Try
  9. ct = cn.CreateCommand
  10. ct.CommandText = "SELECT * FROM T_マスター"
  11. cn.Open()
  12. reader = ct.ExecuteReader
  13. While reader.Read() = True
  14. Debug.Print(reader(1))
  15. End While
  16. cn.Close()
  17. Catch ex As Exception
  18. Debug.Print("Error")
  19. End Try
  20. End Sub

っち、簡単にできちまった(ぇ
これで、フォームに配置したボタン1をぽちったら、あっさりイミディエイトウィンドウのデバッグに、T_マスターの2番めの要素がだらだらと表示されました。
…デバッグに出すなよオレ( ゚-゚)~゚

せっかくだ。次はコレを、何だっけアレ…クラスだ。class化してみようかな。

  次>>

2018年4月16日月曜日

テキストボックスをラベルみたいに扱う

ボクは閲覧する画面で編集できてしまうなんて仕組みは怖いと思っている。

しかし、帳票フォームやデータシート形式+レコードソースで連結の形は、
大変便利で、使わざるを得ない。てゆか、コレがあるからAccessはタダのRDBではない。

そんなわけで、通常作られるテキストボックスを【コントロールの種類の変更】
してラベルにしてみたら、連結がとけやがりました( ゚-゚)~゚

そこで、TextBoxをLavelのようにしてみよう。ってのがコレ。

  1. Public Sub Txtbox_Like_Lavel(obj As TextBox)
  2. With obj
  3. .TabStop = False
  4. .IMEHold = False
  5. .IMEMode = acImeModeOff
  6. .Locked = True
  7. .Enabled = False
  8. .BackStyle = 0
  9. .BorderColor = 0
  10. .BorderStyle = 0
  11. End With
  12. End Sub

タブストップ外したり、色を変えたり、
入力できないようにプロパティを一括変換しています。
IMEとか関係ないけど、イヤだからOFF( ゚-゚)~゚(なにが?

ワクとか背景とかの色などお好みで変更可。
サイズの統一化とかもプロパティ追加すればOK。

そんなわけで使い方。
まずこのmoduleを、標準モジュールに置きます。
ボクは今後も使うので、CommonModuleって大胆な名前をつけました。

そして、フォームモジュール内から、
  Call Txtbox_Like_Lavel(名前)
※[名前]はコントロール名
てな感じに呼び出すだけ。

ちなみに、一回呼び出して、フォームを保存してしまえば、毎回呼ぶ必要はないので
ってごめんなさい!!VBAで設定できてもフォーム保存で保存されない、
 フォームデザインでしか設定できないプロパティがあります!
 てゆか、たくさんあります!!
 毎回呼び出すか、フォームデザインで頑張ってくださいorz

  1. Private Sub Form_Formatting()
  2. Call Txtbox_Like_Lavel(ID)
  3. Call Txtbox_Like_Lavel(名前)
  4. End Sub

個人的には、とかしておいて、以降どこからも呼ばれないけど、
こんな設定したゼぉぅぃぇ的モジュールをメモ代わりに残しておくのが好みです。

だってほら、フォームビューって、可読性最悪じゃん?( ゚-゚)~゚

2018年4月15日日曜日

日本語と英語のプロパティ名

大人の事情で、ボクはAccess2003で遊んでいる。
2003ではフォームのデザインビューなど、プロパティ名を日本語で表示してある。
もちろん、VBAの中では使えないので、大変使いづらい。
ちなみに、デザインビューでターゲットしてあるオブジェクトの、
英語のプロパティ名が、VBE画面に表示される
ただし、項目数が違ったりする…一体ダレが設計したんだろう( ゚-゚)~゚

ちなみに、大抵のコトは、
ggrks~Accessのプロパティの調べ方メモ
で、わかるのだけど、Modal Propertyは調べきれなかったorz

今は、この、Access2003の15年先をいっている。
現行バージョンはこんなコトはないんだろうなぁ( ゚-゚)~゚(希望的観測

2018年4月14日土曜日

Modal/モーダルフォーム

当然のことながら呼び出したフォームをモーダルモードにすることで(略
そんなわけで、設定を行うフォームを作り、モーダルにしようとしたら、プロパティが見当たらない。

正解から言えば、デザインビューのプルダウンで【フォーム】を選び、
【その他タブ】の中の、【作業ウィンドウ固定】を、【はい】にする。

どこのアホだ。モーダルを作業ウィンドウの固定と訳したのは。
ボクの2時間をかえせ( ゚-゚)~゚
ちなみに、MSDNではModal Property をtrueに。和訳だとモーダルプロパティをはいに。
もう一度いう。ボクの2時間をかえせ( ゚-゚)~゚

2018年4月12日木曜日

【Debug】VBA内でSQLを発行する

T_名前マスター([UserId],[名前],[表示順序])と、ComboBoxがあるとする。

コンボボックスに指定されたUserIdは出力しない例。

  1. Private Sub Exp_SQL_Com()
  2. Dim Str_SQL As String
  3. Dim rs As New ADODB.Recordset
  4.  
  5. 'SQL文を文字列で作ってやる。
  6. Str_SQL = "SELECT UserId, 名前 FROM T_名前マスター WHERE UserId <> " & _
  7. Me!ComboBox.Value & " ORDER BY 表示順序;"
  8.  
  9. 'ちゃんとSQL構文になっているか確認。よく変数名がそのまま出てたり( ゚-゚)~゚
  10. Debug.Print Str_SQL
  11. rs.Open Str_SQL, CurrentProject.Connection
  12. Do Until rs.EOF
  13. Debug.Print rs![名前]
  14. rs.MoveNext
  15. Loop
  16. rs.Close
  17. End Sub

こんな感じに、イミディエイトウィンドウにSQL文や結果を排出。
後から動的に値集合ソースなどを指定するときの確認に便利。かも?

【小技】ComboBox/コンボボックスをYes/No型に連結する

 ボクは基本、閲覧画面とデータ変更画面は明確に分け、ALL or NOTHINGで処理したい人なので、サブ帳票画面で編集とかは、あまり出番はないのだけれど…

ComboBox(デザインビュー)
【コントロールソース】:Yes/No型フィールド名
【値集合タイプ】:値リスト
【値集合タイプ】:-1;はい;0;いいえ
【リスト行数】:2
【連結列】:1

このとき、【リスト幅】を0にすると、1列目の-1/0が表示されないようにできる。

なんとなくできる気がしたからやってみたらできちゃった( ゚-゚)~゚
そのうちなんかで使おう。

ggrks~Accessのプロパティの調べ方メモ

[Access Property コントロール名 日本語プロパティ名]【検索】ぽち
MSDNが引っかかってくるので参考にしてください。

…なんで、フォームデザインビューのプロパティ名を
無理矢理日本語にしてあるんだろう( ゚-゚)~゚

2018年4月11日水曜日

【小技】ComboBox/コンボボックスの既定値

・ComboBox/コンボボックスの既定値
 デフォルトは空っぽ。初期値を指定したいならば、
 固定文字列ならば、【既定値】プロパティに書けば済む。

 値集合ソースから選択したい場合は、
【既定値】プロパティ=["コンボボックス名"].[ItemData](0)
 とすることで、ソースの先頭を表示。
 (0)で先頭、(1)で2番目、…ConboBox.ListCount-1で最終行

 最終行表示例)
 【既定値】プロパティ=["コンボボックス名"].[ItemData]([コンボボックス名].[ListCount]-1)

【VBA】ComboBox.DefaultValue = ComboBox.ItemData(0)

ComboBox/コンボボックスプロパティ


コンボボックス/ComboBox プロパティ

既定値/DefaultValue
 指定しないと空白で表示。
【関連】
 【小技】ComboBox/コンボボックスの既定値

値集合ソース/RowSource値集合タイプ/RowSourceType
 コンボボックスに表示する内容。テーブルやクエリ、;区切り文字列を指定。
 文字列指定:例)”1;男;2;女”(RowSourceType=Value List、ColumnCount=2)
 テーブルiやクエリの場合→
  値集合タイプ/RowSourceTypeに"テーブル/クエリ"/"Table/Query"を指定
  文字列の場合→"値リスト"/"Value List"を指定
  たぶんSQL書いたときに、"フィールドリスト"/"Field List"

列数/ColumnCount
 RowSourceが1行何列あるか。
 でもクエリから持ってくると指定しなくてもうごいてそう。

列幅/ColumnWidths
 表示項目の幅。"6 cm;0;6 cm"などとすると、2列目を非表示にできる。


ToDo
連結列/BoundColumn
 きっと2とか指定すると、ComboBox.Valueが、列2の値になるんじゃないかなぁ?
 そのうちテストする。