Q&A-GUI編 |
Window の表示や入力に関する質問をまとめました。
フォームを常に手前に表示したい
Enter を押したら、次の項目に進みたい
コマンドボタンのキャプションを左詰にする
コモンダイアログを画面中央に表示する
NumLock キーを制御するには
Tabキーを判別するには
解像度に依存しない画面を作成するにはどうしたら良いでしょうか?
Esc キーや キャンセルボタンで長い処理を中断するには
テキストボックスをスムーズにスクロールさせるには
コマンドボタンで矢印キーを制御するには?
GIFファイルのアニメーションを動かすには?
リストビューコントロールで1行全体を選択させるには?
キー入力をクリアするには
コモンダイアログで [キャンセル] ボタンが押されたか判別するには
PopupMenu の外で右ボタンを押しても PopupMenu が閉じないのですが?
MDIフォームの最大化・最小化ボタンを表示させない方法は?
VB5.0 で実行時にコントロールを追加するには?
マウスカーソルがフォームやコントロールから離れた時を知るには?
コモンダイアログのボタンのキャプションを変更するには?
Office
のアシスタントのように、フォームのウィンドウを全てのアプリケーションの手前に表示するにはどうするのですか?
A APIの
SetWindowPos を使用します
まず、標準モジュールに以下の SetWindowPos の定数と宣言を入れます。
Public Const HWND_TOP = 0
Public Const HWND_BOTTOM = 1
Public Const HWND_TOPMOST = (-1)
Public Const HWND_NOTOPMOST = (-2)
Public Const SWP_NOSIZE = &H1&
Public Const SWP_NOMOVE = &H2&
Public Const SWP_NOZORDER = &H4&
Public Const SWP_NOREDRAW = &H8&
Public Const SWP_NOACTIVATE = &H10&
Public Const SWP_FRAMECHANGED = &H20&
Public Const SWP_SHOWWINDOW = &H40&
Public Const SWP_HIDEWINDOW = &H80&
Public Const SWP_NOCOPYBITS = &H100&
Public Const SWP_NOOWNERZORDER = &H200&
Public Const SWP_DRAWFRAME = SWP_FRAMECHANGED
Public Const SWP_NOREPOSITION = SWP_NOOWNERZORDER
Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" ( _
ByVal hwnd As Long, _
ByVal hWndInsertAfter As Long, _
ByVal x As Long, ByVal y As Long, _
ByVal cx As Long, ByVal cy As Long, _
ByVal wFlags As Long) As Long
次にフォームを手前に表示するところで、以下のように、SetWindowPos を呼びます。
lngRet = SetWindowPos( _
Form1.hWnd, _
HWND_TOPMOST, _
0, 0, _
0, 0, _
SWP_SHOWWINDOW Or SWP_NOMOVE Or SWP_NOSIZE)
ここで、最初の引数 Form1.hWnd の Form1
は、手前に表示したいフォームのオブジェクト名です。
元に戻す場合は、2番目の HWND_TOPMOST を HWND_NOTOPMOST
にして、呼び出します。
ちなみに、最後のパラメータを以下のようにすれば、ウィンドウをアクティブにしないで表示することができます。
SWP_NOACTIVATE Or SWP_SHOWWINDOW Or SWP_NOMOVE Or SWP_NOSIZE
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
複数のテキストボックスやコンボボックスが並んでいるアプリケーションで、Enter
キーを押したら次の TabIndex
の項目にフォーカスが移動するようにするにはどうしたら良いでしょうか?
A SendKeys
でできますが、ちょっと注意してください
一部のサイトでは親フォームの KeyPreview を True にして、KeyPress イベントに次のようなコードを記述するように紹介しています。
Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
SendKeys "{Tab}"
KeyAscii = 0
End If
End Sub
ただし、この方法では幾つかのトラブルが報告されています(Visual Basic5.0での報告です)。代表的なものとして
・IMEのモードが正しく切り替わらない。
・Num Lock が ON、OFF する。
このトラブルを回避する為に、以下のようなAPIを使用することをお勧めします。
'標準モジュールに以下の定数と宣言を入れる
Public Declare Function PostMessage Lib "user32" _
Alias "PostMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Public Const WM_KEYDOWN = &H100
Public Const WM_KEYUP = &H101
Public Const VK_TAB = &H9
'親フォームの KeyPreview を True にして、
'KeyPress イベントに次のようなコードを記述
Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
PostMessage Me.hwnd, WM_KEYDOWN, VK_TAB, 1
PostMessage Me.hwnd, WM_KEYUP, VK_TAB, 1
KeyAscii = 0
End If
End Sub
(注意) Enter
キーによる項目の移動については、Microsoft では、SetFocus
による移動を推奨しています。
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
通常、コマンドボタンのキャプションはセンタリングされていますが、このキャプションを右詰、左詰にすることはできるでしょうか?
A APIの
SetWindowLong でできます。
プロパティでの変更はできませんが、APIの SetWindowLong
と GetWindowLong を組み合わせてできます。
まず、標準モジュールに以下の定義を行います。
Option Explicit
Public Const GWL_STYLE = (-16)
Public Const BS_LEFT = &H100&
Public Const BS_RIGHT = &H200&
Public Const BS_CENTER = &H300&
Declare Function GetWindowLong Lib "user32" _
Alias "GetWindowLongA" ( _
ByVal hwnd As Long, _
ByVal nIndex As Long) As Long
Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" ( _
ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
左詰を行いたい場合は、以下のコードを記述します。
Dim lngStyle As Long
lngStyle = GetWindowLong(cmdTest.hwnd, GWL_STYLE)
lngStyle = SetWindowLong(cmdTest.hwnd, GWL_STYLE, (lngStyle And Not BS_CENTER) Or BS_LEFT)
cmdTest.Refresh
ここで、cmdTest
は左詰を行いたい、コマンドボタンです。また、最後に Refresh
が必要です。
右詰を行いたい場合は、以下のコードを記述します。
Dim lngStyle As Long
lngStyle = GetWindowLong(cmdTest.hwnd, GWL_STYLE)
lngStyle = SetWindowLong(cmdTest.hwnd, GWL_STYLE, (lngStyle And Not BS_CENTER) Or BS_RIGHT)
cmdTest.Refresh
ここで、cmdTest
は右詰を行いたい、コマンドボタンです。最後に Refresh
が必要です。
同様に、元のセンタリングに戻したい場合、最後のパラメータを BS_CENTER
にすれば、センタリングになります。
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
VB
標準のコントロールを使用してコモンダイアログを表示すると、画面の左上に表示されますが、画面の中央に表示するにはどうしたら良いでしょうか?
A VB
のバージョンにより異なります
コモンダイアログを画面中央に表示するには、VB6.0 より
コモンダイアログのオートメーションオブジェクトが添付されて、プロパティの設定でできるようになりましが、VB5.0
では、APIを使用しないと画面中央に表示できません。
■ VB5.0 の場合
APIを使用する場合、コモンダイアログは親となる
Window を指定できます。親の Windows
指定したダイアログは、親のウィンドウの左上に表示されます。標準のコモンダイアログコントロールは、この親となるウィンドウがディスクトップなので、画面の左上に表示されてしまいます。
ここでは、親のウィンドウの左上に表示されることを利用して、コモンダイアログを画面中央に表示します。
まず、標準モジュールに以下の定義を行います。
Option Explicit
' API で使用する定数の宣言(VB 標準の定義と同じなので、
' VB 標準の定義を使用してもかまいません)
Public Const OFN_READONLY = &H1
Public Const OFN_OVERWRITEPROMPT = &H2
Public Const OFN_HIDEREADONLY = &H4
Public Const OFN_NOCHANGEDIR = &H8
Public Const OFN_SHOWHELP = &H10
Public Const OFN_NOVALIDATE = &H100
Public Const OFN_ALLOWMULTISELECT = &H200
Public Const OFN_EXTENSIONDIFFERENT = &H400
Public Const OFN_PATHMUSTEXIST = &H800
Public Const OFN_FILEMUSTEXIST = &H1000
Public Const OFN_CREATEPROMPT = &H2000
Public Const OFN_SHAREAWARE = &H4000
Public Const OFN_NOREADONLYRETURN = &H8000
Public Const OFN_NOTESTFILECREATE = &H10000
Type OPENFILENAME
lStructSize As Long
hwndOwner As Long
hInstance As Long
lpstrFilter As String
lpstrCustomFilter As String
nMaxCustFilter As Long
nFilterIndex As Long
lpstrFile As String
nMaxFile As Long
lpstrFileTitle As String
nMaxFileTitle As Long
lpstrInitialDir As String
lpstrTitle As String
flags As Long
nFileOffset As Integer
nFileExtension As Integer
lpstrDefExt As String
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" ( _
pOpenfilename As OPENFILENAME) As Long
ここで、実際にコモンダイアログを表示する、コードを記述するのですが、その前に、コモンダイアログを表示したい位置にダミーのフォームを作成しておきます。仮にこのフォームのオブジェクト名を
frmDummy とします。
コモンダイアログを表示するタイミングで以下のコードを記述します。
Dim ofn As OPENFILENAME
With ofn
.lStructSize = LenB(ofn)
' hwndOwner に ダミーのフォーム の hWnd を指定します。
.hwndOwner = frmDummy.hWnd
.lpstrFilter = "すべてのファイル(*.*)" & vbNullChar & "*.*" & vbNullChar & _
"テキストファイル(*.txt)" & vbNullChar & "*.txt" & vbNullChar & vbNullChar
.nFilterIndex = 1
.lpstrFile = Space(255) & vbNullChar
.nMaxFile = 256
.lpstrInitialDir = "C:\"
.lpstrTitle = "Win32 API ファイルを選択"
.flags = OFN_READONLY
End With
' 親フォームを一時的に Enable = False
Me.Enabled = False
If GetOpenFileName(ofn) Then
' OKが押された場合
Dim i As Integer
' ファイル名の後ろの Null をカットする
i = InStr(ofn.lpstrFile, vbNullChar)
Debug.Print Left$(ofn.lpstrFile, i - 1)
Else
Debug.Print "Cancel"
End If
' 親フォームを Enable = True に戻す
Me.Enabled = True
ここで、注意点が幾つかあります。
● hwndOwner に ダミーのフォーム の hWnd を指定してください。
● lpstrFilter には、フィルタ文字列を設定してますが、コモンダイアログコントロールのように "|" で区切る代わりに、vbNullChar で区切ってください。また、最後の文字は vbNullChar & vbNullChar としてください。
● GetOpenFileName で、コモンダイアログを表示する前に、親フォームの Enable を False としてください。これを行わないと、コモンダイアログ表示中に親フォームを操作できてしまいます。GetOpenFileName から戻ってきたら Enable を True に戻してください。
● 取得したファイル名の最後は vbNullChar
で終了しますので、以降の文字はカットしてください。
● lpstrFile の最後は、vbNullChar
で終了してください。
同様に、「フォントの設定」「色の設定」等でも、コモンダイアログを中央に表示することができます。
Update 1999/06/17
: API の GetOpenFileName を呼ぶ場合に、lpstrFile のバッファの最後に
vbNullChar
をセットするように修正。これを行わないと、NT4.0のバージョンによっては動作しません。
(MSの以下のサイトを参考 -- 文書番号: J048273
-- http://www.asia.microsoft.com/japan/support/kb/articles/j048/2/73.htm)
■ VB6.0 の場合
最初に、この情報は Microsoft
のサポート対象外の情報であるので注意してください。でも、サポート内の情報もサポートしてもらった覚えはありませんが(^^;
VB6.0
からは、ダイアログオートメーションオブジェクトというオブジェクトが使用できるようになりました。このオブジェクトを使用できるようにするには、以下の手順を行ってください。
1. Visual Studio 6.0 の Disk3 の
\Common\Tools\Vb\UnSupprt\DlgObj から DLGOBJS.REG
をシステムディレクトリにコピーしてください。(一般的に Win95
は C:\Windows\System、 WinNT は、C:\WinNT\System32)
(注意)DLGOBJS.REGは、Visual
Studio 6.0 を購入した人だけ再配布可能です。
2. エクスプローラでコピーした DLGOBJS.REG を、右クリックして[統合]を選択してください。
3. VBを起動して、コモンダイアログを組込むプロジェクトを読込んでください。
4. メニューの [プロジェクト]-[参照設定]を選択して、「参照設定ダイアログ」から「Microsoft
Dialog Automation Object」をチェックにしてください。
あとは、以下のようなコーディングを記述してください。
Dim objChooseFile As New ChooseFile
With objChooseFile
.hWnd = Me.hWnd
.Filters.Add ("すべてのファイル (*.*):*.*")
.Filters.Add ("テキスト ファイル (*.txt):*.txt")
.Directory = "C:\"
.Title = "DlgObj ファイルを選択"
.HideReadOnly = True
.Save = False
.Center = True
End With
If objChooseFile.Show Then
Debug.Print objChooseFile.filename
Else
Debug.Print "Cancel"
End If
コーディングを見て分かるように、.Center = True
だけで、ダイアログを画面の中央に表示する事ができます。
他のコモンダイアログにについて調べる場合、残念ながら
ダイアログオートメーションオブジェクのHELPファイルはありませんが、プロパティ名はほぼ
標準のコモンダイアログコントロールと同じですので、オブジェクトブラウザで見れば容易に理解できるでしょう。
(参考)ソフトバンク発行「Inside
Windows 1999年2月号」の「VBブレイクスルー」
(注意)この項目の内容は、Visual
Basic5.0(SP3)、Visual Basic6.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
Numlock キーの ON/OFF
を制御するには、どうしたら良いでしょうか?
A GetKeyState
と keybd_event のAPIでできます
Numlock キーの ON/OFF を制御と言っても、単純に ON/OFF
を繰り返すだけでなく、「常に ON にしたいか、常に OFF
にしたい」といった要望が多いようです。これを行うには、現在のキーの状態を調べる
GetKeyState と キーの状態を変更する keybd_event
を組み合わせます。
まず、標準モジュールに以下の定義を行います。
Option Explicit
Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Declare Sub keybd_event Lib "user32" ( _
ByVal bVk As Byte, _
ByVal bScan As Byte, _
ByVal dwFlags As Long, _
ByVal dwExtraInfo As Long)
Public Const VK_NUMLOCK = &H90
Public Const VK_CAPITAL = &H14
Public Const KEYEVENTF_KEYUP = &H2
Numlock キーを ON にしたい場合、以下のコードを作成します。
If GetKeyState(VK_NUMLOCK) = 0 Then
keybd_event VK_NUMLOCK, 0, 0, 0
keybd_event VK_NUMLOCK, 0, KEYEVENTF_KEYUP, 0
End If
Numlock キーを OFF にしたい場合、以下のコードを作成します。
If GetKeyState(VK_NUMLOCK) <> 0 Then
keybd_event VK_NUMLOCK, 0, 0, 0
keybd_event VK_NUMLOCK, 0, KEYEVENTF_KEYUP, 0
End If
GetKeyState(VK_NUMLOCK)
の戻り値をチェック方法を変更しているのが、わかると思います。
また、CapsLock の状態を変更する場合には、VK_NUMLOCK
の代わりに、VK_CAPITAL を指定するだけで変更できます。
(注意)この項目の内容は、Visual
Basic5.0(SP3)、Visual Basic6.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
フォームの KeyPress イベント等で、Tab
キーが押されたかどうかを判別するには、どうしたら良いでしょうか?
A TabStop
を全て False か GetKeyState のAPIでできます
デフォルトで Tab キーは、VBによって処理される為に、KeyPress
イベント等では判別する事ができません。これを判別するには、以下のような方法があります。
■ TabStop を全て False にする場合
まず、フォーム上にある全ての TabStop を False
にしてください。ボタンなどを含めフォーム上の TabStop が1つでも
True だと、判別はできません。
あとは、各コントロールやフォームの KeyPress イベント で Tab
キーが判別できます。
試しに、フォームオブジェクトに以下のコードを入力してみてください。
'フォームの KeyPreview を True にして、
'KeyPress イベントに次のようなコードを記述
Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyTab Then
Debug.Print "Tab"
KeyAscii = 0
End If
End Sub
上記のコードを実行すると、Tabキーを押すごとに、イミディエート・ウィンドウに
"Tab"と表示されるはずです。
■ GetKeyState のAPIを使用する場合
まず、標準モジュールに以下の定義を行います。
Option Explicit
Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Public Const VK_TAB = &H9
フォーム上の TabStop を False にしない場合は、 KeyPress イベント で Tab キーを判別することはできません。そこで、タイマーコントロールや各コントロールのイベント(LostFocus 等)が発生した時点で、以下のAPIを呼びます。
Dim intState As Integer
intState = GetKeyState(VK_TAB) And &HFE
ここで、GetKeyState の戻り値は、上位1ビットがキーが押されている場合には1、押されていない場合0となり、下位1ビットがキーが押されるごとにトグルします。従って
And &HFE の演算で intState が 0
の場合は、Tabが押されてない状態、 <>0
の場合は押されている状態となります。
他のキーを判別する場合は、APIビューワにて、VK_
の定数を検索して GetKeyState に検索した定数を指定してください。
(注意)この項目の内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
Q 解像度に依存しない画面を作成するにはどうしたら良いでしょうか?
VBでアプリケーションを作成したら、インストールしたPCの解像度によって、画面の表示が異なります、どうしたら良いでしょうか?
A ScaleMode
によって異なります
基本的に、Visual Basic
ではコントロールのサイズや位置に、デフォルトで Twip
という ScaleMode
を使用しています。この単位は、画面解像度に依存しない実寸の大きさをあらわす単位で、1センチは567twip、1インチは1,440twip
になります。この単位を使用した場合、
画面の解像度により、1ドットの画素の大きさが異なります。例えば、ある解像度で1ドットが15twip
の場合や、12twip の場合があります。従って、同じ3000twip
でも
200ドットの場合や250ドット場合がありまが、画面に表示される実寸は同じになります。
また、 ScaleMode には、Pixcel
という単位もあります。この単位は、1ドットが1pixcel
に対応しているので、解像度が異なってもドット数では同じ大きさとなりますが、実寸は異なります。
つまり解像度に依存しない為には、このどちらかの ScaleMode
に統一する必要があります。(その他の ScaleMode
でも同様に統一する必要があります)
それぞれの ScaleMode
で作成する場合には、幾つかの注意が必要です。
■ ScaleMode が Twip の場合
1. Twip
で異なった解像度アプリケーションを作成する場合、全てのフォームやコントロールの
ScaleMode を Twip に統一してください。
2. 解像度によって同じ Twip
でも微妙に大きさが異なる場合があります。例えば、1ドットが15twip
の場合、36twip も 30Twip も2ドットですが、1ドットが12twip
の場合、36twip は3ドット、 30Twip
は2ドットとなります。このため、大きさを揃えたいコントロールの幅や高さは、twip数を完全に同じにしてください。
(例えば、テキストとコンボボックスは、デフォルトで並べると同じ大きさに見えますが、Height
のTwip数が異なる場合があります。)
3.
フォントはシステムフォントを使用すると、解像度の指定で「大きいフォント」や「小さいフォント」を使用した場合に違った大きさになります。「MSゴシック」等を指定するとほぼ同じ大きさになりますが、やはり解像度により異なりますので、フォントを使用しているコントロールは、余裕を見てやや大きめに作成してください。
4.
コントロールによっては、フォントに依存したサイズになる場合や、解像度によってフォームのサイズを変更したい場合は、以下の用なコーディングで解像度ごとに処理を分けてください。
Private Sub Form_Load()
Select Case Screen.TwipsPerPixelX
Case 12
Form1.Width = 360
Form1.Height = 240
Case 15
Form1.Width = 450
Form1.Height = 300
End Select
End Sub
Screen.TwipsPerPixelX と Screen.TwipsPerPixelY は、解像度によって変更される1ドットあたりの
Twip の幅と高さを返してくれます。
■ ScaleMode が Pixcel の場合
1. Pixcel
で異なった解像度アプリケーションを作成する場合、全てのフォームやコントロールの
ScaleMode を Pixcel に統一してください。
2. フォームに貼り付けられたコントロールは
Pixcel 単位で幅や高さを指定できますが、フォームの場合は、Pixcel
で指定することができないので、以下のようなコーディングでフォームの幅や高さのドット数を固定にしてください。
Private Sub Form_Load()
' 360X240ドットに固定
Form1.Width = Screen.TwipsPerPixelX * 360
Form1.Height = Screen.TwipsPerPixelY * 240
End Sub
3. Twip
の場合と同様、フォントはシステムフォントを使用すると、解像度の指定で「大きいフォント」や「小さいフォント」を使用した場合に違った大きさになります。「MSゴシック」等を指定するとほぼ同じ大きさになりますが、やはり解像度により異なりますので、フォントを使用しているコントロールは、余裕を見てやや大きめに作成してください。
■ 共通の注意事項
● 画面の大きさは、一番低い解像度の画面サイズ(640X480)を想定すれば全ての画面サイズに入ります。
● カラーは Windows 標準の 16 色 (vbBlack、vbBlue、vbCyan など)
を使用してください。
●
ダイアログなどは、位置を固定せずに、以下のような関数を作成して、画面の中央や左上に表示してください。(VB5.0
からは、StartUpPosition プロパティで指定できる)
'フォームを画面の中央に表示する
Public Sub ShowFormToCenter(frmTarget As Form)
frmTarget.Left = (Screen.Width - frmTarget.Width) / 2
frmTarget.Top = (Screen.Height - frmTarget.Height) / 2
End Sub
●
複数の解像度に対応した市販のコントロールもあります。それらを利用するもの良いでしょう。
(注意)この項目の内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
Q Esc キーや キャンセルボタンで長い処理を中断するには
印刷や技術計算で、長い処理を行っているの時に ESCキーや
キャンセルのボタンを押して、中断させるには?
A フラグと
DoEvents で中断を判定します
まず、標準モジュールなどに、フラグを1つ宣言します。
Public m_bAbort As Boolean
次に、長い処理の中でフラグを判定して、True なら処理を終了するようにします。
Private Sub Start_Click()
m_bAbort = False
Do
If m_bAbort = True Then Exit Sub
:
'処理を記述
:
DoEvents
Loop
End Sub
ここで、ループ中に DoEvents を入れるのがこつです。
最後に、ESCキーや キャンセルのボタンが押された時に
フラグを True にすれば完了です。
Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyEscape Then
m_bAbort = True
KeyAscii = 0
End If
End Sub
Private Sub Stop_Click()
m_bAbort = True
End Sub
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
テキストボックスにログデータのようなデータを追加して、最後の行を表示させる為に
SelStart
を行っていますが、テキストボックスへの書きこみのたびにスクロールバーがちらついたりして、あまり見栄えがよくありません。スムーズにスクロールさせる方法はないでしょうか?
A API
の SendMessage でスクロールさせます
スムーズにスクロールさせるには、SendMessage という API
で EM_LINESCROLL を指定すれば、スムーズにスクロールできます。
まず、標準モジュールに以下の定義を行います。
Option Explicit
Const EM_LINESCROLL = &HB6
Declare Function SendMessage Lib "User32" Alias _
"SendMessageA" _
(ByVal hWnd As Long, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Long) As Long
次に、スクロールさせたい時に以下の様に API を使用します。
Private Sub Command1_Click()
Dim i As Integer
For i = 0 To 10000
Text1.Text = Text1.Text & Str$(i) & vbCrLf
SendMessage Text1.hWnd, EM_LINESCROLL, 0, 1&
DoEvents
Next
End Sub
この時の Text1.hWnd
は、スクロールさせたいテキストボックスの hWnd
プロパティを指定してください。また、ループに DoEvents
が必要な事も注意してください。
ちなみに、MSのサイトの以下の情報を参考にしました。(1999/4/27
のアドレスです、見つからない場合は、検索で文書番号の J043517 を検索してください)
http://www.asia.microsoft.com/japan/support/kb/articles/j043/5/17.htm
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
コマンドボタンでは、矢印キーを押しても、KeyDown、KeyPress
のイベントが発生しません。どうしたら矢印キーを判別できるでしょうか?
A LostFocus
で API の GetKeyState で判別できます
コマンドボタンのイベントは発生しませんが、コマンドボタンから抜ける時にキーボードの状態を判別することができます。
まず、標準モジュールに以下の定義を行います。
Option Explicit
Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Public Const VK_LEFT = &H25
Public Const VK_UP = &H26
Public Const VK_RIGHT = &H27
Public Const VK_DOWN = &H28
コマンドボタンの LostFocus で以下のような方法で、キーを判別できます。
Dim intState As Integer
intState = GetKeyState(VK_LEFT) And &HFE
ここで、GetKeyState の戻り値は、上位1ビットがキーが押されている場合には1、押されていない場合0となり、下位1ビットがキーが押されるごとにトグルします。従って
And &HFE の演算で intState が 0 の場合は LEFT
が押されてない状態、 <>0
の場合は押されている状態となります。
サンプルとして、5つのボタンを作成して、それぞれ、cmdCenter、cmdLeft、cmdRight、cmdUp、cmdDown
とします。cmdCenter
で左、右、上、下の矢印キーが押された場合に、cmdLeft、cmdRight、cmdUp、cmdDown
に移動させるには、次のようにします。
Private Sub cmdCenter_LostFocus()
If GetKeyState(VK_LEFT) And &HFE Then
cmdLeft.SetFocus
ElseIf GetKeyState(VK_UP) And &HFE Then
cmdUp.SetFocus
ElseIf GetKeyState(VK_RIGHT) And &HFE Then
cmdRight.SetFocus
ElseIf GetKeyState(VK_DOWN) And &HFE Then
cmdDown.SetFocus
End If
End Sub
他のキーを判別する場合は、APIビューワにて、VK_
の定数を検索して GetKeyState に検索した定数を指定してください。
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
アニメーションの入ったGIFファイルをピクチャーボックスに表示させても、アニメーションが動きません。アニメーションが動くようにするにはどうしたらよいでしょうか?
A WebBrowserコントロールを使います
WebBrowser コントロールは、GIFを再生させる機能を持っています。
まず、VBのメニューから [プロジェクト]-[コンポーネント]を選択して、[Microsoft
Internet Control] をチェックすると、WebBrowser
コントロールがツールボックスに表示されます。
あとは、WebBrowser コントロールをフォームに貼りつけて、Form_Load
で以下のような命令を実行します。
WebBrowser1.Navigate "D:\Temp\Anime.Gif"
ここで、WebBrowser1は、WebBrowser
コントロールのオブジェクト名、 "D:\Temp\Anime.Gif"
は、動かしたいGIFのファイル名です。
スクロールバーがちょっと邪魔になりますが、フレームなどを貼りつけて隠せばOKです(^^
(注意)WebBrowserコントロールは
Microsoft、GIFファイルの圧縮技術は、米国UNISYS
がライセンスを取得しています。作成したコントロールを配布する場合は、ライセンス情報に気をつけてください。
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
Q リストビューコントロールで1行全体を選択させるには?
通常、リストビューコントロールの項目を選択すると、先頭の項目しか選択されません。これを1行全体を選択させるには、どうしたらよいでしょうか?
A API
の SendMessage を使用します
一行全体を選択させるには、まず、標準モジュールに以下の定義を行います。
Option Explicit
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hWnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Any) As Long
Public Const LVM_FIRST = &H1000
Public Const LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54
Public Const LVM_GETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 55
Public Const LVS_EX_FULLROWSELECT = &H20
後は、リストビューを表示する前に、以下のプログラムを実行します。
Dim r As Long
r = SendMessage(ListView1.hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0&, ByVal 0&)
r = r Or LVS_EX_FULLROWSELECT
r = SendMessage(ListView1.hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0&, ByVal r)
ここで、ListView1 はリストビューのオブジェクト名です。
以降、リストビューの項目が選択されると、1行全体が選択されます。
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
キー入力の先行入力をクリアするにはどうしたら良いでしょうか?
A API
の PeekMessage を使用します
キー入力の先行入力をクリアするには、Windows
のキー入力メッセージをクリアすれば実現できます。
このメッセージを削除するには、 PeekMessage という API
を使用します。
PeekMessage
を使用するには、まず、以下の宣言を標準モジュールに入れます。
Type POINTAPI
X As Long
Y As Long
End Type
Type MSG
hWnd As Long
message As Long
wParam As Long
lParam As Long
time As Long
pt As POINTAPI
End Type
Public Const PM_REMOVE = &H1
Public Const PM_NOREMOVE = &H0
Public Const WM_KEYFIRST = &H100
Public Const WM_KEYLAST = &H108
Public Const WM_MOUSEFIRST = &H200
Public Const WM_MOUSELAST = &H20A
Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" ( _
lpMsg As MSG, _
ByVal hWnd As Long, _
ByVal wMsgFilterMin As Long, _
ByVal wMsgFilterMax As Long, _
ByVal wRemoveMsg As Long) As Long
これで、PeekMessage を使用する準備ができました。
後は、キー入力をクリアしたい所に、以下のコーディングを追加するだけです。
Dim m As MSG
Do While PeekMessage(m, Me.hWnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)
Loop
ここで、Me.hWnd の Me
はキー入力を行うフォームのオブジェクト名です。また、WM_KEYFIRST,
WM_KEYLAST は、メッセージの範囲を指定しています。PM_REMOVE
は取得したメッセージを削除します。
また、WM_KEYFIRST, WM_KEYLASTの代わりに、WM_MOUSEFIRST、WM_MOUSELAST
を使用すれば、マウスでの入力を削除することもできます。
さらに、PM_REMOVE の代わりに PM_NOREMOVE
を指定すれば、メッセージを削除せずに、入力があったかどうかを判別することもできます。
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
Q コモンダイアログで [キャンセル] ボタンが押されたか判別するには
コモンダイアログで [キャンセル] ボタンが押された場合、ShowOpen
の戻り値では判別できません。どうしたらよいでしょうか?
A
プロパティの CancelError を True に設定してください。
まずは、コモンダイアログコントロールのプロパティ CancelError
を True に設定してください。これを True
に設定すると、ShowOpen 等を実行して コモンダイアログで [キャンセル]
ボタンが押されるとエラーが発生します。エラーの状態を Err.Number
で判別するか On Error Goto で分岐すれば判別できます。
以下はサンプルです。
On Error GoTo ErrCancel
With CommonDialog1
.Flags = cdlOFNFileMustExist Or cdlOFNHideReadOnly
.DialogTitle = "ファイルを選択"
.Filter = "TEXT ファイル(*.txt)|*.txt|全てのファイル(*.*)|*.*"
.DefaultExt = ".txt"
.ShowOpen
MsgBox .filename & "が選択されました"
Exit Sub
End With
ErrCancel:
MsgBox "キャンセル が押されました"
Exit Sub
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
Q PopupMenu の外で右ボタンを押しても PopupMenu が閉じないのですが?
PopupMenu
メソッドでポップアップメニューを表示した後に、ポップアップメニューの範囲外を右ボタンで押しても、ポップアップメニューが閉じません。このままだと、右ボタンを使用して連続してポップアップメニューを表示することができません。どうすれば良いでしょうか?
A PopupMenu
メソッドの flags に vbPopupMenuRightButton を指定します
flags に vbPopupMenuRightButton を指定すると、ポップアップメニューの項目をマウスの左または右のボタンをクリックしたときに反応するようになります。また、ポップアップメニューの範囲外を右ボタンでクリックすると、ポップアップメニューが閉じます。
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
PopupMenu mnuEdit, vbPopupMenuRightButton
End Sub
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
Q MDIフォームの最大化・最小化ボタンを表示させない方法は?
MDIフォームの最大化・最小化ボタンを表示させないには、なにか良い方法がありますか?
A
SetWindowLong という API でできます
コマンドボタンのキャプションを左詰にするでも紹介したように、プロパティに無い設定を行う場合に、この
SetWindowLong と GetWindowLong
を使うことで実現できることがよくあります。
詳細に付いては、Microsoft
の以下のサイトを参考にしてください。(1999/7/16
のアドレスです、見つからない場合は、検索で文書番号のJ042454 を検索してください)
http://www.asia.microsoft.com/japan/support/kb/articles/j042/4/54.htm
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
VBの6.0では、Control.Add
を使用して、実行時にフォームにコントロールを追加できますが、VB5.0で同様なことができるのでしょうか?
A
コントロール配列を Load で追加することができます
VBの6.0では、Controls.Add を使用して、動的にコントロールを追加することができますが、VB5.0で同様なことを行いたい場合には、追加したいコントロールを予め配列にしておく必要があります。後は、Load ステートメントで要素を追加することができます。
Load Label1(2)
Label1(2).Caption = "Label2"
Label1(2).Left = 100
Label1(2).Top = 100
Label1(2).Visible = True
また、VBの6.0の Controls.Add
の使い方は、MSDN等で検索してみてください。Dr. GUI
が教えてくれますよ(^^
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
Q マウスカーソルがフォームやコントロールから離れた時を知るには?
マウスカーソルが、フォームやコントロールから離れたのを知るにはどうしたらよいのでしょうか?
A SetCapture
ReleaseCapture で知ることができます
通常、マウスの動きは MouseMove イベントで知ることができますが、マウスが離れるとイベントが発生しなくなり、マウスの位置を知ることができません。そこで、APIの
SetCapture
を使用すると、マウスカーソルがフォームやコントロールを離れた場合も、イベントが取得できるようになります。ただし、マウスカーソルが離れても他のコントロールにイベントが発生しなくなります。そこで、必要な処理が終わったならば、ReleaseCapture
というAPIを実行して、マウスカーソルを開放します。
以下は、フォーム上にマウスカーソルが移動した場合に、フォームの背景を黒に設定し、マウスカーソルが離れた場合に、元の色に戻すサンプルです。
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If 0 <= X And X <= Me.ScaleWidth And 0 <= Y And Y <= Me.ScaleHeight Then
Me.BackColor = vbBlack
SetCapture Me.hwnd
Else
Me.BackColor = vbButtonFace
ReleaseCapture
End If
End Sub
以下は、宣言部です。標準モジュールに入れてください。
Option Explicit
Declare Function SetCapture Lib "user32" (ByVal hwnd As Long) As Long
Declare Function ReleaseCapture Lib "user32" () As Long
(注意)このページの内容は、Visual
Basic5.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。
コモンダイアログの[OK]ボタンや[キャンセル]ボタンのキャプションを「開く」や「取消」といった文字にするにはどうしたら良いでしょうか?
A
API を使用します。
コモンダイアログのキャプションの文字を変更するには、APIのフック関数を使用します。
早速サンプルを見てみましょう!
まず、標準モジュールに以下の定義を行います。
Option Explicit
' API で使用する定数の宣言(VB 標準の定義と同じなので、
' VB 標準の定義を使用してもかまいません)
Public Const OFN_READONLY = &H1
Public Const OFN_OVERWRITEPROMPT = &H2
Public Const OFN_HIDEREADONLY = &H4
Public Const OFN_NOCHANGEDIR = &H8
Public Const OFN_SHOWHELP = &H10
Public Const OFN_NOVALIDATE = &H100
Public Const OFN_ALLOWMULTISELECT = &H200
Public Const OFN_EXTENSIONDIFFERENT = &H400
Public Const OFN_PATHMUSTEXIST = &H800
Public Const OFN_FILEMUSTEXIST = &H1000
Public Const OFN_CREATEPROMPT = &H2000
Public Const OFN_SHAREAWARE = &H4000
Public Const OFN_NOREADONLYRETURN = &H8000
Public Const OFN_NOTESTFILECREATE = &H10000
Public Const OFN_ENABLEHOOK = &H20
Public Const WM_INITDIALOG = &H110
Public Const IDOK = 1
Public Const IDCANCEL = 2
Type OPENFILENAME
lStructSize As Long
hwndOwner As Long
hInstance As Long
lpstrFilter As String
lpstrCustomFilter As String
nMaxCustFilter As Long
nFilterIndex As Long
lpstrFile As String
nMaxFile As Long
lpstrFileTitle As String
nMaxFileTitle As Long
lpstrInitialDir As String
lpstrTitle As String
flags As Long
nFileOffset As Integer
nFileExtension As Integer
lpstrDefExt As String
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" ( _
pOpenfilename As OPENFILENAME) As Long
Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" ( _
ByVal hWnd As Long, _
ByVal lpString As String _
) As Long
Declare Function GetDlgItem Lib "user32" ( _
ByVal hDlg As Long, _
ByVal nIDDlgItem As Long _
) As Long
' フック関数
Public Function fnHook(ByVal hWnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
If uMsg = WM_INITDIALOG Then
' OKボタンを変更
SetWindowText GetDlgItem(hWnd, IDOK), "読込み"
' キャンセルボタンを変更
SetWindowText GetDlgItem(hWnd, IDCANCEL), "取消"
End If
fnHook = 0
End Function
Public Function GetAddress(ByVal lngAddress As Long) As Long
GetAddress = lngAddress
End Function
コモンダイアログを表示するタイミングで以下のコードを記述します。
Dim ofn As OPENFILENAME
With ofn
.lStructSize = LenB(ofn)
.hwndOwner = Me.hWnd
.lpstrFilter = "すべてのファイル(*.*)" & vbNullChar & "*.*" & vbNullChar & _
"テキストファイル(*.txt)" & vbNullChar & "*.txt" & vbNullChar & vbNullChar
.nFilterIndex = 1
.lpstrFile = Space(255) & vbNullChar
.nMaxFile = 256
.lpstrInitialDir = "C:\"
.lpstrTitle = "Win32 API ファイルを選択"
' フック関数のアドレスを設定しています。
.lpfnHook = GetAddress(AddressOf fnHook)
.flags = OFN_READONLY Or OFN_ENABLEHOOK
End With
If GetOpenFileName(ofn) Then
' OKが押された場合
Dim i As Integer
' ファイル名の後ろの Null をカットする
i = InStr(ofn.lpstrFile, vbNullChar)
Debug.Print Left$(ofn.lpstrFile, i - 1)
Else
Debug.Print "Cancel"
End If
ここで、注意点が幾つかあります。
● 標準モジュールの fnHook という関数で、キャプションを変更しています。関数内のSetWindowText というAPIの"読込み"と"取消"が変更する文字です。
● lpstrFilter には、フィルタ文字列を設定してますが、コモンダイアログコントロールのように "|" で区切る代わりに、vbNullChar で区切ってください。また、最後の文字は vbNullChar & vbNullChar としてください。
● 取得したファイル名の最後は vbNullChar
で終了しますので、以降の文字はカットしてください。
● lpstrFile の最後は、vbNullChar
で終了してください。
(注意)このページの内容は、Visual
Basic6.0(SP3)
を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意)
ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。