VB プログラミング テクニック

BlueWater Logo

Last Update 98/02/02  



 一般

 文字列

 コントロール ( MS 製 )

 コントロール ( サードパーティ製 )

 Windos API

 

 [VB2, VB4, VB5] テキストボックスのカーソル位置
 Text1.SelStart で取得/設定できます。 ついでに、 SelLength と SelText もヘルプで見ておきましょう。 よく使うパターンとして、次のようなものがあります。
   Sub Text1_GotFocus()
        If (0 < Len(Text1.Text)) Then
            Text1.SelStart = 0
            Text1.SelLength = Len(Text1.Text)
        End If
    End Sub

(初出 NIFTY Serve SMSDEV(12) #01815 96/06/11) 

  return to TOP 

 [VB4, VB5] テキストボックスをマウスでドラッグしたい
 テキストボックスに限らず、 コマンドボタンでもフォームでも、 マウスでドラッグできるようにすることが出来ます。 MouseDown で座標を記憶してフラグを立て、 MouseUp でフラグを解除します。 MouseMove では、 フラグを見て動かしてやります。
Private m_fInDragText As Boolean    '** TextBox のドラッグ動作中かどうか
Private m_xTextMouseOrg As Single   '** マウスダウン時の X 座標 (フォーム座標)
Private m_yTextMouseOrg As Single   '** 同じく Y 座標

'-----------------------------------------------------------------------
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, _
                            X As Single, Y As Single)
    m_xTextMouseOrg = X
    m_yTextMouseOrg = Y
    m_fInDragText = True
End Sub

'-----------------------------------------------------------------------
Private Sub Text1_MouseMove(Button As Integer, Shift As Integer, _
                            X As Single, Y As Single)
    If (m_fInDragText) Then
        Dim xDiff As Single, yDiff As Single
        xDiff = X - m_xTextMouseOrg
        yDiff = Y - m_yTextMouseOrg
        '** x/yDiff は、フォームに対するマウスの相対的なズレ。
        '** フォームに対するマウスの相対的な動きが判ったので、
        '** それを追いかけるように TextBox も動かしてやればよい。

        With Text1
            Call .Move((.Left + xDiff), (.Top + yDiff))
        End With
    End If
End Sub

'-----------------------------------------------------------------------
Private Sub Text1_MouseUp(Button As Integer, Shift As Integer, _
                          X As Single, Y As Single)
    m_fInDragText = False
End Sub

※ こちらの VB5 のサンプルコード も御覧ください。 (DragSmpl.lzh 2,111Bytes) 
  フォームとコマンドボタンのドラッグも実装しています。

  return to TOP 

 [VB2, VB4/16] ポインタを使いたい
 変数の格納されているアドレスを取得したい、 ということでしたら、 VB だけでは無理です。 ( API を使った裏技的な方法はあります )
 QuickPakPro ( 販売 : 文化オリエント ) などの Peek 関数を使いましょう。

(初出 NIFTY Serve SMSDEV(12) #01416 96/05/11) 

※ VB5 では、 それまで表にでていなかった VarPtr( ), StrPtr( ), ObjPtr( ) という関数が、 オブジェクトブラウザに表示されるようになりました。 実は、 これで変数等のアドレスを取得出来ます。 [2.2]

  return to TOP 

 [VB2 & VB4] ソースを VB4 → VB2 に逆コンバートするには?
 VB4 で追加された余分な情報を削ってやれば、 VB2 で読み込めます。

 ・ *.bas ファイル
ファイルの先頭にある
Attribute VB_Name = "{Module名}"
という行を削除。

 ・ *.frm ファイル
まず、 ファイルの先頭にある
VERSION 4.00
という行を削除。

それから、 各オブジェクトの定義部の最初の行を修正。
以下の、 下線部分を削除します。
Begin VB.Form {フォーム名}

Begin VB.CommandButton {コントロール名}

Begin VB.PictureBox {コントロール名}

Begin VB.TextBox {コントロール名}


最後に、 オブジェクト定義部の後ろにある
Attribute VB_Name = "{フォーム名}"
Attribute VB_Creatable = False
Attribute VB_Exposed = False
を削除。

 ・ *.mak ファイル
もし、 *.mak まで VB4 で上書きしてしまったのなら、 ファイル名だけを並べた VB2 の形式に書き直せばいいのですが、 新規作成してしまったほうが手間が少ないかもしれません。

(初出 NIFTY Serve SMSDEV(12) #01785 96/06/09) 

  return to TOP 

 [VB4/32] リッチテキストボックスの右端で折り返すには
 .RightMargin を .Width より小さく設定してください。
   <--------- .Width ------------->
    <------ .RightMargin ------>
    +------------------------------+
    |_ABCD EFG HIJKL MNO PQRS  _xxx|
    |_あいうえお かきくけこ さ  _xxx|
    |_しす            _xxx|
    +------------------------------+
     ~.SelIndent        ~.SelRightIndent
 上の絵で、 "_" はインデントが設定されていてテキストが表示されない部分、 "xxx" は、 マージンが設定されていてテキストが表示されない部分、 を表します。

 リッチテキストボックスの箱の幅は、 .Width で設定されます。

 箱の中のテキストが表示される部分の幅は、 別に管理するようになっていて、 それが .RightMargin です。 ( ヘルプでは、 右側のマージン指定のように書いてありますが違います。 )

 .Width に対して .RightMargin を大きく設定することも出来て、 その場合は文字を入力していくと、 .RightMargin までスクロールしていってから、 折り返すようになります。
※ これがデフォルトの状態らしいです。

 .RightMargin の範囲内で余白を設定するのが、 .SelIndent と .SelRightIndent で、 これは段落ごと ( 改行までの範囲ごと ) に設定できます。

(初出 NIFTY Serve SMSDEV(12) #02065 96/06/23) 

 return to TOP 

 [VB4/32, VB5] シフト JIS コードとして一定のバイト長の文字列を取り出すには
 VB4/32 以降、 文字列の内部的な扱いが UNICODE になりました。 そのおかげで、 ある長さの文字列を求めた結果が、 VB4/16 までのシフト JIS コードのときと異なります。 これが、 現状では困ったことになる場合が多いようです。
 次のようにすれば、 シフト JIS コードと見なした時のバイト数で文字列を切り出すことができます。 ただし、 切り出した末尾が 2バイトコードの前半であれば、 それは切り捨てるようになっています。
Public Function LeftEx(strSrc As String, _
                       ByVal nLength As Long _
                      ) As String
    LeftEx = ""
    If (1 > Len(strSrc)) Or (1 > nLength) Then
        Exit Function
        '*** (not reached) ***
    End If

    Dim bytBuff() As Byte
    bytBuff = StrConv(strSrc, vbFromUnicode)

    Dim nMinIndex As Long, nMaxIndex As Long
    nMinIndex = LBound(bytBuff)
    nMaxIndex = UBound(bytBuff)

    Dim nBuffLen As Long
    nBuffLen = nMaxIndex - nMinIndex + 1

    If (nLength < nBuffLen) Then
        '* 指定より 1バイト余分に切り出し
        nMaxIndex = nMinIndex + nLength
        ReDim Preserve bytBuff(nMinIndex To nMaxIndex)
        Dim strWork As String

        '* UNICODE に戻してから、末尾1文字をカット
        strWork = StrConv(bytBuff, vbUnicode)
        strWork = Left$(strWork, Len(strWork) - 1)
        LeftEx = strWork
    Else
        LeftEx = strSrc
    End If
End Function
※ こちらの VB5 のサンプルコード も御覧ください。 (LeftEx$.lzh 2,062Bytes)
 

 return to TOP 

 [VB4, VB5] 付属のサードパーティ製コントロールの位置付け
 VB には、 いくつかのサードパーティ製 ActiveX コントロール ( OCX ) が付いてきます。 しかし、 これらはあくまでもオマケです。 自社の売り物に組み込むのは、 避けたほうが良いです。
 これらは、 自社の製品の売り上げ向上を狙って、 サンプル版を MS に提供していると考えるべきものでしょう。 したがって、 バグが多かったり、 重要な機能が省かれていたりします。
 試してみて、 これは良さそうだと思ったら、 その会社に連絡を取りましょう。 そして、 製品版を購入して使用すべきです。
 なお、 プロパティウィンドウの ( About ) 欄の右端にある [...] をクリックすると、 連絡先などが表示されます。 ( 逆に、 ここを見ることで、 サードパーティ製と知れます。 )
 

 return to TOP 

 [VB4/32] DBGrid はバグフィックスされない ?
 DBGrid は、 使えそうな機能をもっているのに、 バグが多くて使えません。 実はTrue DBGrid Standard という名前で、 バグフィックスされたものが提供されています。

<< True DBGrid Standard とは何者か >>

 ようするに、VB4 に付属している DBGrid のバグフィックス版 + α といったもののようで、 同じ会社から販売されている True DBGrid とは別物です。 True DBGrid とは違って、 シートの分割やセルごとの色指定などの機能はないようです。
 製品ラインアップとしては次のようになっています。
    True DBGrid Standard  --- VB4 ユーザーはフリーで使える。
    True DBGrid  --- Standard の上位版。有償。
    TrueGrid Pro  --- VB3 用。
    ( なんてややこしいんでしょ。 (^^; )

 True DBGrid Standard は、 開発元である http://www.apexsc.com/ からダウンロードできます。 16bit/32bit それぞれ約 600KB ずつあります。

(初出 NIFTY Serve SMSDEV(12) #01343 96/05/03)

※ その後、True DBGrid は、 文化オリエントから日本語版が発売されています。
※ 98年 2月いっぱい、文化オリエントのサイトから、 VB4 用の True DBGrid (製品版) が、 無償でダウンロードできます。 [1.31]
 

 return to TOP 

 [VB2, VB4, VB5] Windows API を使うには
 Windows 自体は C/C++ 言語で作られています。 したがって、 その API ( Application Programming Interface ) を利用するには、 やはり C/C++ の知識が前提とされます。 詳しくは、 マイクロソフトのサイトの 「 [VB4 ] Win32 API を使用する場合の注意点 ( ミラーはこちら ) 」 を参照してください。
 ※ したがって、 SDK に書いてあることや、 C/C++ の常識に属することには、 このコーナーではいっさい回答をしないつもりです。

 return to TOP 

 [VB4/32] コンピュータ名の取得
Win32 API の GetComputerName() を使います。
Private Declare Function GetComputerName Lib "Kernel32" _
                Alias "GetComputerNameA" _
                (ByVal Buff As String, _
                 ByRef Size As Long) As Long

Private Const MAX_COMPUTERNAME_LENGTH% = 15

Private Sub Command1_Click()
    Dim sBuff As String
    Dim lBuffLen As Long
    Dim sComputer As String

    lBuffLen = MAX_COMPUTERNAME_LENGTH + 1

    sBuff = Space$(lBuffLen)
    If (0 <> GetComputerName(sBuff, lBuffLen)) Then
        sComputer = StrConv( _
                LeftB$(StrConv(sBuff, vbFromUnicode), _
                    lBuffLen), _
                vbUnicode) '* UNICODEのばかたり〜 (^^;
        '* 2バイト文字が入っていないと確信できるなら、
        '* sComputer = Left$(sBuff, lBuffLen) 'で済みます。
        Call MsgBox("Name=" & sComputer & " (" & lBuffLen & "Byte)")
    End If
End Sub

( 初出 NIFTY Serve SMSDEV(12) #1257 96/04/28 ) 

※ これでは、 SJIS <-> UNICODE の変換が多くなります。 それを減らすには次のようにバイト型配列を使います。

Private Declare Function GetComputerName Lib "Kernel32" _
                Alias "GetComputerNameA" _
                (ByRef Buff As Byte, _
                 ByRef Size As Long) As Boolean
Private Const MAX_COMPUTERNAME_LENGTH% = 15
Private Sub Command1_Click()
    Dim bytBuff() As Byte
    Dim lBuffLen As Long
    Dim sComputer As String

    lBuffLen = MAX_COMPUTERNAME_LENGTH + 1
    ReDim bytBuff(lBuffLen)
    If (0 <> GetComputerName(bytBuff(0), lBuffLen)) Then
        sComputer = StrConv(LeftB$(bytBuff, lBuffLen), vbUnicode)
        Call MsgBox("Name=" & sComputer & " (" & lBuffLen & "Byte)")
    End If
End Sub

( 初出 NIFTY Serve SMSDEV(12) #01263 96/04/28 ) 

 return to TOP 

 [VB4/32] 変数のポインタを扱うには
 基本的には使えないと考えてください。
 裏技的な方法としては、 Win32 API の CharPrev() を使えば、 ある程度のことは可能です。
 例として文字列変数を扱ってみましょう。 ただし、 32bit の VB では、 UNICODE <-> SJIS 変換のため、 DLL へ渡された文字列バッファは DLL から帰ってきた時点で無効になりますから、 バイト型を使う必要があります。
Private Declare Function lCharPrevByteStr Lib "user32" _
                Alias "CharPrevA" _
                (ByRef bStr As Byte, _
                 ByRef bStr As Byte _
                ) As Long
Private Declare Function sCharPrevAdrs Lib "user32" _
                Alias "CharPrevA" _
                (ByVal lVar As Long, _
                 ByVal lVar As Long _
                ) As String

Dim bStr() As Byte
Dim lAdrs As Long
Dim sStr As String

bStr = StrConv("Test" & vbNullChar, vbFromUnicode)
lAdrs = lCharPrevByteStr(bStr(0), bStr(0))  '* bStr() のアドレスを取得
sStr = sCharPrevAdrs(lAdrs, lAdrs)  '* アドレスで指定された文字列を、
                    '* 文字型変数にコピー。
                    '* 返値は、自動的に UNICODE に
                    '* 変換されてしまうことに注意
Debug.Print lAdrs, sStr

( 初出 NIFTY Serve SMSDEV(12) #01442 96/05/12 ) 

 return to TOP 

 [VB4/32] CopyMemory( ) という API は存在するのですか?
 API32WH.HLP には CopyMemory( ) という関数が載っていますが、 VB からは使えません。

 これは、 WINBASE.H で、 #define CopyMemory RtlCopyMemory と定義されてまして、 RtlCopyMemory とは何ぞや、 というと WINNT.H で、
   #define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),\
                            (Source),(Length))
と定義されています。

つまり、 しいて言うなら、 CopyMemory( ) は、 C コンパイラの 標準ライブラリにある、 ということです。 どうあがいても、VB から呼ぶことはできません。

( 初出 NIFTY Serve SMSDEV(12) #01786 96/06/09 ) 


なお、 MoveMemory( ) という API は、 Kernel32 に RtlMoveMemory として存在しています。 これで間に合うことも多いでしょう。
 

 return to TOP 

 [VB4/32] Win32 API で得た日付を Date 型にしたい
Win32 API の FindFirstFile( ) などでは、 時刻情報が FILETIME 型として取得できます。

FILETIME 型の変数を Win32 API の FileTimeToSystemTime( ) に渡して、SYSTEMTIME 型に直してもらうと、 年月日が取得できるので、 あとは DateValue 関数で Date 型に直してもらいましょう。

( 初出 NIFTY Serve SMSDEV(12) #01950 96/06/19 ) 




return to TOP  



Programming のホームへ戻る ホームページへ 戻る
Copyright (C) 1997 biac