2018年4月30日月曜日

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

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

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

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


(Class Module : SetDBtoTable )

Option Explicit
'指定したDBを読み込み、テーブルで返す。
'----------
'Variable
'----------
Private m_Provider As String
Private m_DataSource As String
Private m_ConnectionString As String
Private m_UserID As String
Private m_Password As String
Private m_RecordCount As Integer
Private m_ColumnCount As Integer
Private m_DataTable() As String  'テーブルデータ格納場所
Private cn As ADODB.Connection
Private rs As ADODB.Recordset
'----------
'Property
'----------
'------------------------------
'DBへアクセスするために必要なProperty群
'------------------------------
'プロバイダ指定。Accessなら"Microsoft.Jet.OLEDB.4.0;"みたいなの
Property Get Provider() As String
  Provider = m_Provider
End Property
Property Let Provider(Provider As String)
  m_Provider = Provider
End Property
'データソース指定。Accessならファイル名
Property Get DataSource() As String
  DataSource = m_DataSource
End Property
Property Let DataSource(DataSource As String)
  m_DataSource = DataSource
End Property
'コネクションストリング。テーブル名だったりSQLだったり
Property Get ConnectionString() As String
  ConnectionString = m_ConnectionString
End Property
Property Let ConnectionString(ConnectionString As String)
  m_ConnectionString = ConnectionString
End Property
'ユーザーID。テストしてないから動くかどうかわからない( ゚-゚)~゚
Property Get UserID() As String
  UserID = m_UserID
End Property
Property Let UserID(UserID As String)
  m_UserID = UserID
End Property
'パスワード。テストしてな(以下略
Property Get Password() As String
  Password = m_Password
End Property
  Property Let Password(Password As String)
m_Password = Password
End Property
'------------------------------
'得たデータを参照するProperty群
'------------------------------
'レコード数
Property Get RecordCount() As Long
  RecordCount = m_RecordCount
End Property
'カラム数
Property Get ColumnCount() As Long
  ColumnCount = m_ColumnCount
End Property
'Value Override群 Start…って思ったら、Overrideできないでやんの( ゚-゚)~゚
Property Get Value() As String()
  Value = m_DataTable
End Property
'Item Override群 Start Default Property指定。Default指定もできないでやんの
Property Get Item(ByVal i As Integer, ByVal j As Integer) As String
  Item = m_DataTable(i, j)
End Property
Property Get Record(ByVal i As Integer) As String()
  Record = m_Record(i)
End Property
Property Get Column(ByVal j As Integer) As String()
  Column = m_Column(j)
End Property
'----------
'Constructor
'----------
Private Sub Class_Initialize()
  Debug.Print ("Constructor:" & TypeName(Me))
  m_Provider = "Microsoft.Jet.OLEDB.4.0;"
End Sub
'----------
'Destructor
'----------
Private Sub Class_Terminate()
  Debug.Print ("Destructor:" & TypeName(Me))
End Sub
'----------
'Method
'----------
'DBにアクセスし、レコード数、カラム数、データ本体を読み込み、Class変数に代入
Public Function OpenDB() As Boolean
  Dim OnOK As Boolean
  OnOK = True
  Set cn = New ADODB.Connection
  Set rs = New ADODB.Recordset
  Dim i As Integer
  Dim j As Integer
  cn.Provider = m_Provider
  '_ConnectionStringが空か確認。空であればエラーを吐きFalseを返してMethod終了
  If m_ConnectionString = "" Then
    Debug.Print ("ERROR:" & TypeName(Me) & ":ConnectionString Property Not Assignment")
    OnOK = False
    OpenDB = OnOK
  End If
  'DataSourceが空か確認。空であればエラーを吐きFalseを返してMethod終了
  If m_DataSource = "" Then
    Debug.Print ("ERROR:" & TypeName(Me) & ":DataSource Property Not Assignment")
    OnOK = False
    OpenDB = OnOK
    Exit Function
  End If
  'DataSource設定
  cn.Properties("Data Source").Value = m_DataSource
  'ID/Passwd設定(試してない
  If m_UserID <> "" Then
    cn.Properties("UserID").Value = m_UserID
  End If
  If m_Password <> "" Then
    cn.Properties("Password").Value = m_Password
  End If
On Error GoTo Error_Handler
  cn.Open
'ConnectionString(テーブ名やSQL。DELETEとか書かれても、
'rs.open()のときにReadOnlyで開くからはじけると思う
  rs.Source = m_ConnectionString
  rs.ActiveConnection = cn
  rs.CursorType = ADODB.CursorTypeEnum.adOpenKeyset
  rs.LockType = ADODB.LockTypeEnum.adLockReadOnly
  rs.Open
  m_RecordCount = rs.RecordCount
  m_ColumnCount = rs.Fields.Count
  ReDim m_DataTable(m_RecordCount - 1, m_ColumnCount - 1)
  i = 0
  Do Until rs.EOF
    For j = 0 To m_ColumnCount - 1
      m_DataTable(i, j) = rs.Fields(j).Value
    Next j
    rs.MoveNext
    i = i + 1
  Loop
  OpenDB = OnOK
  Exit Function
  
Error_Handler:
  'Try中のエラーのとき cnとrsのopen、データ取り込み時それぞれで節を分ければError位置が特定できる。はず。
  Debug.Print ("ERROR:" & TypeName(Me) & ":DB or RS Open failed")
  OnOK = False
Error_Handler_End:
  OpenDB = OnOK
End Function
'クローズ。ホントは必要なさそうなんだけど、OpenしたからにはCloseしたくなるのは本能。
'VBAはちゃんとデストラクタくんが動いてくれるのでcallはしない。。
Public Sub CloseDB()
  rs.Close
  cn.Close
  Erase m_DataTable
End Sub
Public Sub putData()
  rs.MoveFirst
  ActiveCell.CopyFromRecordset rs
End Sub
Public Sub putRange(Arg_Range As String, Optional Worksheet As String)
  rs.MoveFirst
  If Worksheet = vbNullString Then
    ActiveSheet.Range(Arg_Range).CopyFromRecordset rs
  Else
    Worksheets(Worksheet).Range(Arg_Range).CopyFromRecordset rs
  End If
End Sub
Public Sub putCells(ByVal Row As Integer, ByVal Col As Integer, Optional ByVal Worksheet As String)
  rs.MoveFirst
  If Worksheet = vbNullString Then
    ActiveSheet.Cells(Row, Col).CopyFromRecordset rs
  Else
    Worksheets(Worksheet).Cells(Row, Col).CopyFromRecordset rs
  
  End If
End Sub
'----------
'Private Function
'----------
'データ要素単体渡し。stringで返す。範囲外のINDEX渡すと怒られるぞ。
Private Function m_Item(ByVal i As Integer, ByVal j As Integer) As String
  m_Item = m_DataTable(i, j)
End Function
'INDEXのRecordの要素全てを、Stringの1元配列型で返す。
Private Function m_Record(ByVal i As Integer) As String()
  Dim ReturnTable() As String
  Dim j As Integer
  ReDim ReturnTable(m_ColumnCount - 1)
  For j = 0 To m_ColumnCount - 1
    ReturnTable(j) = m_DataTable(i, j)
  Next j
  m_Record = ReturnTable
End Function
'INDEXのColumnの要素全てを、Stringの1元配列型で返す。
Private Function m_Column(ByVal j As Integer) As String()
  Dim ReturnTable() As String
  Dim i As Integer
  ReDim ReturnTable(m_RecordCount - 1)
  For i = 0 To m_RecordCount - 1
    ReturnTable(i) = m_DataTable(i, j)
  Next i
  m_Column = ReturnTable
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本体~

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



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

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

'(test class)
Public Sub test(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer)
  Debug.Print a + b + c
End Sub
'(呼び出し)
Private Sub CommandButton2_Click()
  Dim test As New testClass
  test.test 1, 2, 3  '←ココ( ゚-゚)~゚
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化した際の扱いが楽なため。


Option Strict On
'指定したDBを読み込み、テーブルで返す。
Public Class SetDBtoTable
    '----------
    'Variable
    '----------
    Private _Provider As String
    Private _DataSource As String
    Private _ConnectionString As String
    Private _UserID As String
    Private _Password As String
    Private _RecordCount As Integer
    Private _ColumnCount As Integer
    Private _DataTable(,) As String  'テーブルデータ格納場所
    '----------
    'Property
    '----------
    '------------------------------
    'DBへアクセスするために必要なProperty群
    '------------------------------
    'プロバイダ指定。Accessなら"Microsoft.Jet.OLEDB.4.0;"みたいなの
    Public Property Provider As String
        Get
            Return _Provider
        End Get
        Set(value As String)
            _Provider = value
        End Set
    End Property
    'データソース指定。Accessならファイル名
    Public Property DataSource As String
        Get
            Return _DataSource
        End Get
        Set(value As String)
            _DataSource = value
        End Set
    End Property
    'コネクションストリング。テーブル名だったりSQLだったり
    Public Property ConnectionString As String
        Get
            Return _ConnectionString
        End Get
        Set(value As String)
            _ConnectionString = value
        End Set
    End Property
    'ユーザーID。テストしてないから動くかどうかわからない( ゚-゚)~゚
    Public Property UserID As String
        Get
            Return _UserID
        End Get
        Set(value As String)
            _UserID = value
        End Set
    End Property
    'パスワード。テストしてな(以下略
    Public Property Password As String
        Get
            Return _Password
        End Get
        Set(value As String)
            _Password = value
        End Set
    End Property
    '------------------------------
    '得たデータを参照するProperty群
    '------------------------------
    'レコード数
    Public ReadOnly Property RecordCount As Long
        Get
            Return _RecordCount
        End Get
    End Property
    'カラム数
    Public ReadOnly Property ColumnCount As Long
        Get
            Return _ColumnCount
        End Get
    End Property
    'Value Override群 Start
    Public Overridable ReadOnly Property Value As String(,)
        Get
            Return _DataTable
        End Get
    End Property
    Public Overridable ReadOnly Property Value(ByVal i As Integer) As String()
        Get
            Return (_Record(i))
        End Get
    End Property
    Public Overridable ReadOnly Property Value(ByVal i As Integer, ByVal j As Integer) As String
        Get
            Return (_DataTable(i, j))
        End Get
    End Property
    'Value Override群 End
    'Item Override群 Start Default Property指定
    Default Public Overridable ReadOnly Property Item(ByVal i As Integer, ByVal j As Integer) As String
        Get
            Return (_DataTable(i, j))
        End Get
    End Property
    Default Public Overridable ReadOnly Property Item(ByVal i As Integer) As String()
        Get
            Return (_Record(i))
        End Get
    End Property
    'Item Override群 End
    Public ReadOnly Property Record(ByVal i As Integer) As String()
        Get
            Return (_Record(i))
        End Get
    End Property
    Public ReadOnly Property Column(ByVal j As Integer) As String()
        Get
            Return (_Column(j))
        End Get
    End Property
    '----------
    'Constructor
    '----------
    Public Sub New()
        Debug.Print("Constructor:" & TypeName(Me))
        _Provider = "Microsoft.Jet.OLEDB.4.0;"
    End Sub
    '----------
    'Destructor
    '----------
    Private Sub Class_Terminate()
        Debug.Print("Destructor:" & TypeName(Me))
    End Sub
    '----------
    'Method
    '----------
    'DBにアクセスし、レコード数、カラム数、データ本体を読み込み、Class変数に代入
    Public Function Open() As Boolean
        Dim OnOK As Boolean = True
        Dim cn As ADODB.Connection
        Dim rs As ADODB.Recordset
        cn = New ADODB.Connection
        rs = New ADODB.Recordset
        Dim i As Integer
        Dim j As Integer
        cn.Provider = _Provider
        '_ConnectionStringが空か確認。空であればエラーを吐きFalseを返してMethod終了
        If _ConnectionString = Nothing Then
            Debug.Print("ERROR:" & TypeName(Me) & ":ConnectionString Property Not Assignment”)
            OnOK = False
            Return OnOK
        End If
        'DataSourceが空か確認。空であればエラーを吐きFalseを返してMethod終了
        If _DataSource = Nothing Then
            Debug.Print("ERROR:" & TypeName(Me) & ":DataSource Property Not Assignment”)
            OnOK = False
            Return OnOK
        End If
        'DataSource設定
        cn.Properties("Data Source").Value = _DataSource
        'ID/Passwd設定(試してない
        If _UserID <> Nothing Then
            cn.Properties("UserID").Value = _UserID
        End If
        If _Password <> Nothing Then
            cn.Properties("Password").Value = _Password
        End If
        '_ConnectionString(テーブ名やSQL。DELETEとか書かれても、
        'rs.open()のときにReadOnlyで開くからはじけると思う
        Try
            cn.Open()
            rs.Open(_ConnectionString, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
            _RecordCount = rs.RecordCount
            _ColumnCount = rs.Fields.Count
            _DataTable = New String(_RecordCount - 1, _ColumnCount - 1) {}
            i = 0
            Do Until rs.EOF
                For j = 0 To _ColumnCount - 1
                    _DataTable(i, j) = CType(rs.Fields(j).Value, String)
                Next
                rs.MoveNext()
                i = i + 1
            Loop
            rs.Close()
            cn.Close()
        Catch ex As Exception
            'Try中のエラーのとき cnとrsのopen、データ取り込み時それぞれで節を分ければError位置が特定できる。はず。
            Debug.Print("ERROR:" & TypeName(Me) & ":DB or RS Open failed”)
            OnOK = False
        End Try
        Return OnOK
    End Function
    'クローズ。ホントは必要なさそうなんだけど、OpenしたからにはCloseしたくなるのは本能。
    'あと、いろいろ頑張って呼ぼうとしたけど出てきてくんないデストラクタくんを呼んでみる。なんもしてないんだけど。
    Public Sub close()
        _DataTable = Nothing
        Call Class_Terminate()
    End Sub
    '----------
    'Private Function
    '----------
    '_Item Override群 Start Overridable を書くと『Private と Overridable を組み合わせることはできません。』と怒られる。
    'データ要素単体渡し。stringで返す。範囲外のINDEX渡すと怒られるぞ。
    Private Function _Item(ByVal i As Integer, ByVal j As Integer) As String
        Return (_DataTable(i, j))
    End Function
    'オーバーライドを試してみる。引数が数値一つだけなら、コッチが呼ばれる。
    '実動作はRecord()で。
    Private Function _Item(ByVal i As Integer) As String()
        Return (_Record(i))
    End Function
    '_Item Override群 End
    'INDEXのRecordの要素全てを、Stringの1元配列型で返す。
    Private Function _Record(ByVal i As Integer) As String()
        Dim ReturnTable() As String
        Dim j As Integer
        ReturnTable = New String(_ColumnCount - 1) {}
        For j = 0 To _ColumnCount - 1
            ReturnTable(j) = _DataTable(i, j)
        Next j
        Return (ReturnTable)
    End Function
    'INDEXのColumnの要素全てを、Stringの1元配列型で返す。
    Private Function _Column(ByVal j As Integer) As String()
        Dim ReturnTable() As String
        Dim i As Integer
        ReturnTable = New String(_RecordCount - 1) {}
        For i = 0 To _RecordCount - 1
            ReturnTable(i) = _DataTable(i, j)
        Next i
        Return (ReturnTable)
    End Function
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ではない

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

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

Private Sub Form_Current()
  '子フォームでRequeryされたとき、カレントレコードが取得できないので回避させる。
  On Error Resume Next
  Cmb_UserId.Value = Me.Recordset!UserId
  Select Case Err.Number
    Case 0      '正常
    Case 2113 'このフィールドに入力した値が正しくありません。
    Case 3021 'カレントレコードがありません。
    Case Else
      Debug.Print ("ERROR:" & Err.Number)
  End Select
  
  On Error GoTo 0
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つかってみてます。

    '2元配列のガラだけ用意しSetDBtoTable.Valueでコピって使う
    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim DataTable As SetDBtoTable
        Dim Datas(,) As String
        Dim i, j As Long
        Dim str_Print As String
        DataTable = New SetDBtoTable
        DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
        DataTable.ConnectionString = "T_Master"
        DataTable.Open()
        Datas = DataTable.Value
        For i = 0 To DataTable.RecordCount - 1
            str_Print = ""
            For j = 0 To DataTable.ColumnCount - 1
                str_Print = str_Print + Datas(i, j) & " : "
            Next j
            Debug.Print(str_Print)
        Next i
        DataTable.close()
    End Sub
    'Datas Methodでデータを読み出す
    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Dim DataTable As SetDBtoTable
        Dim i, j As Long
        Dim str_Print As String
        DataTable = New SetDBtoTable
        DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
        DataTable.ConnectionString = "T_Master"
        DataTable.Open()
        For i = 0 To DataTable.RecordCount - 1
            str_Print = ""
            For j = 0 To DataTable.ColumnCount - 1
                str_Print = str_Print + DataTable.Datas(i, j) & " : "
            Next j
            Debug.Print(str_Print)
        Next i
        DataTable.close()
    End Sub
    '指定した行(この場合は2行目)のRecordを1元配列にもってくる。
    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        Dim DataTable As SetDBtoTable
        Dim j As Long
        Dim str_Print As String
        Dim Rec_data() As String
        DataTable = New SetDBtoTable
        DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
        DataTable.ConnectionString = "T_Master"
        DataTable.Open()
        Rec_data = DataTable.Datas(1)
        str_Print = ""
        For j = 0 To DataTable.ColumnCount - 1
            str_Print = str_Print + Rec_data(j) & " : "
        Next j
        Debug.Print(str_Print)
        DataTable.close()
    End Sub
    '指定した列(この場合は2列目)のFieldを1元配列にもってくる。
    Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
        Dim DataTable As SetDBtoTable
        Dim i As Long
        Dim str_Print As String
        Dim Rec_data() As String
        DataTable = New SetDBtoTable
        DataTable.DataSource = "\\LANDISK1\share\Test.mdb"
        DataTable.ConnectionString = "T_Master"
        DataTable.Open()
        Rec_data = DataTable.Column(1)
        str_Print = ""
        For i = 0 To DataTable.RecordCount - 1
            str_Print = str_Print + Rec_data(i) & " : "
        Next i
        Debug.Print(str_Print)
        DataTable.close()
    End Sub
End Class

<<前  次>>

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

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

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

Public Class SetDBtoTable
    '----------
    'Variable
    '----------
    Private _Provider As String
    Private _DataSource As String
    Private _ConnectionString As String
    Private _UserID As String
    Private _Password As String
    Private _RecordCount As Long
    Private _ColumnCount As Long
    Private _DataTable(,) As String  'テーブルデータ格納場所
    '----------
    'Property
    '----------
    '------------------------------
    'DBへアクセスするために必要なProperty群
    '------------------------------
    'プロバイダ指定。Accessなら"Microsoft.Jet.OLEDB.4.0;"みたいなの
    Public Property Provider As String
        Get
            Return _Provider
        End Get
        Set(value As String)
            _Provider = value
        End Set
    End Property
    'データソース指定。Accessならファイル名
    Public Property DataSource As String
        Get
            Return _DataSource
        End Get
        Set(value As String)
            _DataSource = value
        End Set
    End Property
    'コネクションストリング。テーブル名だったりSQLだったり
    Public Property ConnectionString As String
        Get
            Return _ConnectionString
        End Get
        Set(value As String)
            _ConnectionString = value
        End Set
    End Property
    'ユーザーID。テストしてないから動くかどうかわからない( ゚-゚)~゚
    Public Property UserID As String
        Get
            Return _UserID
        End Get
        Set(value As String)
            _UserID = value
        End Set
    End Property
    'パスワード。テストしてな(以下略
    Public Property Password As String
        Get
            Return _Password
        End Get
        Set(value As String)
            _Password = value
        End Set
    End Property
    '------------------------------
    '得たデータを参照するProperty群
    '------------------------------
    'レコード数
    Public ReadOnly Property RecordCount As Long
        Get
            Return _RecordCount
        End Get
    End Property
    'カラム数
    Public ReadOnly Property ColumnCount As Long
        Get
            Return _ColumnCount
        End Get
    End Property
    'データの2次元配列の値返し。
    'てゆかPropertyじゃなくMethodにしたほがいくね?
    Public ReadOnly Property Value As String(,)
        Get
            Return _DataTable
        End Get
    End Property
    '----------
    'Constructor
    '----------
    Public Sub New()
        Debug.Print("Constructor:" & TypeName(Me))
        _Provider = "Microsoft.Jet.OLEDB.4.0;"
    End Sub
    '----------
    'Destructor
    '----------
    Private Sub Class_Terminate()
        Debug.Print("Destructor:" & TypeName(Me))
    End Sub
    '----------
    'Method
    '----------
    'DBにアクセスし、レコード数、カラム数、データ本体を読み込み、Class変数に代入
    Public Function Open() As Boolean
        Dim OnOK As Boolean = True
        Dim cn As ADODB.Connection
        Dim rs As ADODB.Recordset
        cn = New ADODB.Connection
        rs = New ADODB.Recordset
        Dim i As Integer
        Dim j As Integer
        cn.Provider = _Provider
        '_ConnectionStringが空か確認。空であればエラーを吐きFalseを返してMethod終了
        If _ConnectionString = Nothing Then
            Debug.Print("ERROR:" & TypeName(Me) & ":ConnectionString Property Not Assignment”)
            OnOK = False
            Return OnOK
        End If
        'DataSourceが空か確認。空であればエラーを吐きFalseを返してMethod終了
        If _DataSource = vbNullString Then
            Debug.Print("ERROR:" & TypeName(Me) & ":DataSource Property Not Assignment”)
            OnOK = False
            Return OnOK
        End If
        'DataSource設定(テーブ名やSQL。DELETEとか書かれても、rs.open()のときにReadOnlyで開くからはじけると思う
        cn.Properties("Data Source").Value = _DataSource
        'ID/Passwd設定(試してない
        If _UserID <> vbEmpty Then
            cn.Properties("UserID").Value = _UserID
        End If
        If _Password <> Nothing Then
            cn.Properties("Password").Value = _Password
        End If
        Try
            cn.Open()
            rs.Open(_ConnectionString, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
            _RecordCount = rs.RecordCount
            _ColumnCount = rs.Fields.Count
            _DataTable = New String(_RecordCount - 1, _ColumnCount - 1) {}
            i = 0
            Do Until rs.EOF
                For j = 0 To _ColumnCount - 1
                    _DataTable(i, j) = rs.Fields(j).Value
                Next
                rs.MoveNext()
                i = i + 1
            Loop
            rs.Close()
            cn.Close()
        Catch ex As Exception
            'Try中のエラーのとき cnとrsのopen、データ取り込み時それぞれで節を分ければError位置が特定できる。はず。
            Debug.Print("ERROR:" & TypeName(Me) & ":DB or RS Open failed”)
            OnOK = False
        End Try
        Return OnOK
    End Function
    'クローズ。ホントは必要なさそうなんだけど、OpenしたからにはCloseしたくなるのは本能。
    'あと、いろいろ頑張って呼ぼうとしたけど出てきてくんないデストラクタくんを呼んでみる。なんもしてないんだけど。
    Public Sub close()
        _DataTable = Nothing
        Call Class_Terminate()
    End Sub
    'データ要素単体渡し。stringで返す。範囲外のINDEX渡すと怒られるぞ。
    Public Function Datas(i As Long, j As Long) As String
        Return (_DataTable(i, j))
    End Function
    'オーバーライドを試してみる。引数が数値一つだけなら、コッチが呼ばれる。
    '実動作はRecord()で。
    Public Function Datas(i As Long) As String()
        Return (Record(i))
    End Function
    'INDEXのRecordの要素全てを、Stringの1元配列型で返す。
    Public Function Record(i As Long) As String()
        Dim ReturnTable() As String
        Dim j As Long
        ReturnTable = New String(_ColumnCount - 1) {}
        For j = 0 To _ColumnCount - 1
            ReturnTable(j) = _DataTable(i, j)
        Next j
        Return (ReturnTable)
    End Function
    'INDEXのColumnの要素全てを、Stringの1元配列型で返す。
    Public Function Column(j As Long) As String()
        Dim ReturnTable() As String
        Dim i As Long
        ReturnTable = New String(_RecordCount - 1) {}
        For i = 0 To _RecordCount - 1
            ReturnTable(i) = _DataTable(i, j)
        Next i
        Return (ReturnTable)
    End Function
End Class

<<前  次>>

2018年4月25日水曜日

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

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

Public Class SetDBtoTable
    '----------
    'Variable
    '----------
    Private _Provider As String
    Private _DataSource As String
    Private _ConnectionString As String
    Private _UserID As String
    Private _Password As String
    Private _RecordCount As Long
    Private _ColumnCount As Long
    '    Private _DataTable[][] As String  'テーブルデータ格納場所
    '----------
    'Property
    '----------
    Public Property Provider As String
        Get
            Return _Provider
        End Get
        Set(value As String)
            _Provider = value
        End Set
    End Property
    Public Property DataSource As String
        Get
            Return _DataSource
        End Get
        Set(value As String)
            _DataSource = value
        End Set
    End Property
    Public Property ConnectionString As String
        Get
            Return _ConnectionString
        End Get
        Set(value As String)
            _ConnectionString = value
        End Set
    End Property
    Public Property UserID As String
        Get
            Return _UserID
        End Get
        Set(value As String)
            _UserID = value
        End Set
    End Property
    Public Property Password As String
        Get
            Return _Password
        End Get
        Set(value As String)
            _Password = value
        End Set
    End Property
    Public ReadOnly Property RecordCount As Long
        Get
            Return _RecordCount
        End Get
    End Property
    Public ReadOnly Property ColumnCount As Long
        Get
            Return _ColumnCount
        End Get
    End Property
    '----------
    'Constructor
    '----------
    Public Sub New()
        Debug.Print("Constructor:" & TypeName(Me))
        _Provider = "Microsoft.Jet.OLEDB.4.0;"
    End Sub
    '----------
    'Destructor
    '----------
    Private Sub Class_Terminate()
        Debug.Print("Destructor:" & TypeName(Me))
    End Sub
    '----------
    'Method
    '----------
    Public Function GetTable() As Boolean
        Dim OnOK As Boolean = True
        Dim cn As ADODB.Connection
        Dim rs As ADODB.Recordset
        cn = New ADODB.Connection
        rs = New ADODB.Recordset
        cn.Provider = _Provider
        '_ConnectionStringが空か確認。空であればエラーを吐きFalseを返してMethod終了
        If _ConnectionString = Nothing Then
            Debug.Print("ERROR:" & TypeName(Me) & ":ConnectionString Property Not Assignment”)
            OnOK = False
            Return OnOK
        End If
        'DataSourceが空か確認。空であればエラーを吐きFalseを返してMethod終了
        If _DataSource = vbNullString Then
            Debug.Print("ERROR:" & TypeName(Me) & ":DataSource Property Not Assignment”)
            OnOK = False
            Return OnOK
        End If
        'DataSource設定(テーブ名やSQL。DELETEとか書かれても、rs.open()のときにReadOnlyで開くからはじけると思う
        cn.Properties("Data Source").Value = _DataSource
        'ID/Passwd設定(試してない
        If _UserID <> Nothing Then
            cn.Properties("UserID").Value = _UserID
        End If
        If _Password <> Nothing Then
            cn.Properties("Password").Value = _Password
        End If
        Try
            cn.Open()
            rs.Open(_ConnectionString, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
            _RecordCount = rs.RecordCount
            _ColumnCount = rs.Fields.Count
            rs.Close()
            cn.Close()
        Catch ex As Exception
            'Try中のエラーのとき
            Debug.Print("ERROR:" & TypeName(Me) & ":DB or RS Open failed”)
            OnOK = False
        End Try
        Return OnOK
    End Function
End Class



<<前  次>>




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

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

Dim Str_Empty As String
If Str_Empty = "" Then
  Debug.Print("""""")
End If
If Str_Empty = vbNullString Then
  Debug.Print("vbNullString")
End If
 If Str_Empty = Nothing Then
   Debug.Print("Nothing")
 End If

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

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


<<前  次>>



2018年4月24日火曜日

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

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

Public Class SetDBtoTable
    '----------
    'Variable
    '----------
    Private _Provider As String
    Private _DataSource As String
    Private _ConnectionString As String
’(PropertyのGet/Set省略)
    '----------
    'Constructor
    '----------
    Public Sub New()
        Debug.Print("Constructor:" & TypeName(Me))
        _Provider = "Microsoft.Jet.OLEDB.4.0;"
    End Sub
    '----------
    'Destructor
    '----------
    Private Sub Class_Terminate()
        Debug.Print("Destructor:" & TypeName(Me))
    End Sub
    '----------
    'Method
    '----------
    Public Function GetTable() As Boolean
        Dim OnOK As Boolean = True
        Dim cn As ADODB.Connection
        Dim rs As ADODB.Recordset
        cn = New ADODB.Connection
        rs = New ADODB.Recordset
        cn.Provider = _Provider
        cn.Properties("Data Source").Value = _DataSource
        Try
            cn.Open()
            rs.Open(_ConnectionString, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
            Debug.Print("RecordCount:" & rs.RecordCount)
            Debug.Print("column:" & rs.Fields.Count)
            rs.Close()
            cn.Close()
        Catch ex As Exception
            OnOK = False
        End Try
        Return OnOK
    End Function
End Class



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

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

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

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

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

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

<<前  次>>

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


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

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

Private Function Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  Dim OnOK As Boolean = True
  Dim cn As ADODB.Connection
  Dim rs As ADODB.Recordset
  Dim i As Integer = 0
  cn = New ADODB.Connection
  rs = New ADODB.Recordset
  cn.Provider = "Microsoft.Jet.OLEDB.4.0;"
  cn.Properties("Data Source").Value = "\\LANDISK1\share\Test.mdb"
  Try
      cn.Open()
      rs.Open("T_Master", cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly)
      Do Until rs.EOF
          Debug.Print (rs.Fields(1).Value)
          rs.MoveNext()
      Loop
      rs.Close()
      cn.Close()
  Catch ex As Exception
      OnOK = False
      Debug.Print ("ERROR")
  End Try
  Return OnOK
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( ゚-゚)~゚

Public Class Set_DB_to_Table
  Public Function GetTable() As Boolean
    Dim OnOK As Boolean = True
    Dim ct As System.Data.OleDb.OleDbCommand
    Dim reader As System.Data.OleDb.OleDbDataReader
    Dim cn As New System.Data.OleDb.OleDbConnection(
          "Provider=Microsoft.Jet.OLEDB.4.0;" &
          "Data Source=\\LANDISK1\share\Test.mdb;"
          )
    Try
      ct = cn.CreateCommand
      ct.CommandText = "SELECT * FROM T_マスター"
      cn.Open()
      reader = ct.ExecuteReader
      While reader.Read() = True
        Debug.Print(reader(1))
      End While
      cn.Close()
    Catch ex As Exception
      Debug.Print("Error")
      OnOK = False
    End Try
    Return OnOK
  End Function
End Class

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

呼び出し。

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

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

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

<<前  次>>


VBからAccessにAccessしてみる

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

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

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

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

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

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

  次>>

2018年4月16日月曜日

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

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

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

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

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

Public Sub Txtbox_Like_Lavel(obj As TextBox)
  With obj
    .TabStop = False
    .IMEHold = False
    .IMEMode = acImeModeOff
    .Locked = True
    .Enabled = False
    .BackStyle = 0
    .BorderColor = 0
    .BorderStyle = 0
  End With
End Sub

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

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

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

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

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

Private Sub Form_Formatting()
  Call Txtbox_Like_Lavel(ID)
  Call Txtbox_Like_Lavel(名前)
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は出力しない例。

Private Sub Exp_SQL_Com()
  Dim Str_SQL As String
  Dim rs As New ADODB.Recordset

'SQL文を文字列で作ってやる。
  Str_SQL = "SELECT UserId, 名前 FROM T_名前マスター WHERE UserId  <> " & _
                     Me!ComboBox.Value & " ORDER BY 表示順序;"

'ちゃんとSQL構文になっているか確認。よく変数名がそのまま出てたり( ゚-゚)~゚
  Debug.Print Str_SQL
  rs.Open Str_SQL, CurrentProject.Connection
  Do Until rs.EOF
    Debug.Print rs![名前]
    rs.MoveNext
  Loop
  rs.Close
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の値になるんじゃないかなぁ?
 そのうちテストする。