エンターを押すと、特定のコマンドボタンが押ささるプログラムを作っているのですが、エンターを押すとフォーカスがセットされているコマンドボタンが押ささってしまいます。
特定のコマンドボタンって言っても、1個のコマンドボタンなんですがなんかいい方法ありますか?

それから、キーボードの矢印キーで、並んであるコマンドボタンにフォーカスを移動させたいのですがいい方法ありますか?
TabIndexの関係だと思うのですが、上キーを押すと、すぐ上のボタンではなく右にいったり左にいったり・・・

どうか教えてください。
お願いします

A 回答 (4件)

質問1.エンターを押すと、特定のコマンドボタンが押ささるプログラム


質問2.キーボードの矢印キーで、並んであるコマンドボタンにフォーカスを移動

まず最初に、、、
質問が二つ以上になる時は、別スレッドでお願いします。


質問2についてのサンプルです。
TabIndexを使用してフォーカスが順次移動するのは、知っての通りです。
VBの仕様を捻じ曲げなければなりません。ならばOSからVBに処理が渡る直前に、そのOSから届くイベントを処理しちゃいましょう。フックという方法を使用しました。これを使用すると、特定のイベントタイプを監視できます。


最初にコマンドボタンを25個、フォーム1に貼り付けます。
0,1,2,3,4
5,3,7,8,9
....
...
   ...24
といったようにコントロール配列にしてください。

下記のコードを貼り付け実行してください。
フォームのキャプションに注目すると
「フックしていません」
となっているはずです。[Enter]か[クリック]をすることにより
「フックしています」
になります。
その状態の時にカーソルを押すと、望みの結果が得られると思います。





-----Form1ここから-----
Option Explicit

Private Declare Function UnhookWindowsHookEx Lib "user32.dll" (ByVal hHook As Long) As Long
Private Declare Function SetWindowsHookEx Lib "user32.dll" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long

Private Const WH_KEYBOARD = 2

Private Sub Command1_Click(Index As Integer)
  'フック中でない時
  If g_lngHook = 0 Then
    '(キーボードからの入力を)フックする
    g_lngHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, 0&, App.ThreadID)
    Me.Caption = "フック中です"
    
  'フック中の時
  Else
    'フックを解除してあげる
    Call UnhookWindowsHookEx(g_lngHook)
    g_lngHook = 0
    Me.Caption = "フックしていません"
  End If
End Sub

Private Sub Command1_GotFocus(Index As Integer)
  '現在のフォーカスを持つコマンドボタンのインデックスを得る
  g_intIndex = Index
End Sub

Private Sub Form_Activate()
  If Me.Tag = "これから起動する" Then
    Command1(0).SetFocus
    Me.Tag = ""
  End If
End Sub

Private Sub Form_Load()
  Me.Tag = "これから起動する"
  Me.Caption = "フックしていません"
End Sub

Private Sub Form_Unload(Cancel As Integer)
  'フックした状態で終了しようとした時、フックを解除する
  If g_lngHook <> 0 Then
    Call UnhookWindowsHookEx(g_lngHook)
  End If
End Sub
-----Form1ここまで-----

-----標準モジュールここから-----
Option Explicit

Private Declare Function CallNextHookEx Lib "user32.dll" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Public g_lngHook  As Long   'フックプロシージャのハンドル
Public g_intIndex  As Integer '現在のフォーカスを持つコマンドボタンのインデックス

Public Function KeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
              
  Static blnReEnter As Boolean  'キーイベント2重発生防止フラグ
  
  Select Case wParam
    'カーソルキーを押された時
    Case vbKeyRight, vbKeyLeft, vbKeyUp, vbKeyDown
      
      'キーイベント2重発生防止
      If blnReEnter = False Then
        blnReEnter = True
        KeyboardProc = 1
        Exit Function
      End If
      
      'カーソルによる処理分岐
      With Form1
        Select Case wParam
          Case vbKeyRight
            'カーソルが一番右列にある?
            If (g_intIndex Mod 5) = 4 Then
              .Command1(g_intIndex - 4).SetFocus
            Else
              .Command1(g_intIndex + 1).SetFocus
            End If
          Case vbKeyLeft
            'カーソルが一番左列にある?
            If (g_intIndex Mod 5) = 0 Then
              .Command1(g_intIndex + 4).SetFocus
            Else
              .Command1(g_intIndex - 1).SetFocus
            End If
          Case vbKeyUp
            'カーソルが一番上行にある?
            If (g_intIndex < 5) Then
              .Command1(g_intIndex + 20).SetFocus
            Else
              .Command1(g_intIndex - 5).SetFocus
            End If
          Case vbKeyDown
            'カーソルが一番下行にある?
            If (g_intIndex >= 20) Then
              .Command1(g_intIndex - 20).SetFocus
            Else
              .Command1(g_intIndex + 5).SetFocus
            End If
        End Select
      End With
      
      KeyboardProc = 1
      blnReEnter = False
    
    'カーソルキー以外を押された時
    Case Else
      '何もしない
      KeyboardProc = CallNextHookEx(g_lngHook, nCode, wParam, lParam)
      Exit Function
  End Select
End Function
-----標準モジュールここまで-----


・・・で、質問1の方は、これらを応用して、フラグを立てたらできるような気がします。
    • good
    • 0
この回答へのお礼

大変お礼が遅くなりました。申し訳ございません。
とても参考になりました。
ありがとうございました
これからも、何かありましたらよろしくお願いします

お礼日時:2002/02/20 19:07

ふと思ったのですが、オリジナルの処理を求めるのならば、コマンドボタンにこだわらない方がいいかもしれないですね。



いっそのことピクチャボックスにしてしまっては?
EnterとClickと処理を分けたいのであれば、それが一番手っ取り早いような気がするのですが。。。

ピクチャボックスにコマンドボタンの絵を張っておいて、フォーカスを得た時や失った時も必要なのであれば、LostやGotフォーカスで、絵の差し替えをしてあげると、同じような動きになると思います。クリックも反応させたいのであれば、マウスのUpDownMoveで差し替えることになります。

それをユーザコントロールにしておいたら非常に便利だと思いますよ。
    • good
    • 0

コマンドボタンのプロパティに[Default]という項目があります。


(初期値はfalseになってます)

こいつをTrueにすればフォーム上での[Enter]押下をClickイベントが受け取ります。
ボタンに「影」が付きますからよく見てね。



反対にEscを押下した際にClickイベントを発生させるのは プロパティ[Cansel]。

要するに「はい」「いいえ」のようなフォームの場合に、どちらを「主」とするか、
のような設定方法です。


> 並んであるコマンドボタンにフォーカスを移動させたいのですが
アクセスキーを利用した方が簡単でしょう。

Alt+(指定の文字)でフォーカスが移動します。
やり方はCaptionに&(指定の文字)とするだけ。

実行(E) (←カッコ内のEには下線が付く)の場合なら
Captionに 実行(&E)と記述するだけでOK。

見栄えがしますよ!
    • good
    • 0
この回答へのお礼

大変お礼が遅くなりました。申し訳ございません。
何とか、解決いたしました。
これからも、何かありましたらよろしくお願いします

お礼日時:2002/02/20 19:06

KeyDownのイベントで、エンターが押されたときに、行いたい特定の処理をするようにすれば良いと思います。



同様に、矢印キーの場合も、それぞれにフォーカスをセットする(多分SetFocusだったと思う)ようにすれば良いのではないでしょうか
    • good
    • 0
この回答へのお礼

大変お礼が遅くなりました。申し訳ございません。
何とか、解決いたしました。
これからも、何かありましたらよろしくお願いします

お礼日時:2002/02/20 19:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QFORMが開いているかどうかの確認方法

初歩の初歩だと思いますが。。。。

formが開いているかどうかの確認方法を教えてください。プロパティで確認できるのでしょうか?

Aベストアンサー

Form.Visible = True : 表示されている
Form.Visible = False : 表示されていない

でいいと思いますよ~

それとも二重起動禁止の方が知りたいんでしょうか?

QDoEvents関数って何?

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そこで「EXCEL VBA パーフェクトマスター」という本を見たら

for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
DoEvents
next i
unload userform1
と入力すれば解決することがわかりました。

しかし「DoEvents」についてあまり詳しく書いていなかったのでDoEvents関数をヘルプで見ると、
「発生したイベントがオペレーティング システムによって処理されるように、プログラムで占有していた制御をオペレーティング システムに渡すフロー制御関数です。」

と書いてあるのですが正直、書いてあることがよくわかりません。

どなたかDoEvents関数について、
もう少しわかりやすく教えていただけませんか。
それから、最初に書いたコードで実行すると
ユーザーフォームの背景が真っ白になってしまう原因も
教えていただけませんか?

よろしくお願いいたします。

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そ...続きを読む

Aベストアンサー

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
    DoEvents
    Cells(i,1) = ""
  Next i
End Sub

Private Sub CommandButton2_Click()
  MsgBox "hoge"
End Sub

っていうフォームのコードがあった場合、
DoEvents を入れることによって、ループ中にユーザーがCommandButton2 を押すことによって CommandButton2 のクリック イベントも動いちゃいます。
CommandButton1 のクリック イベントではループの前に
CommandButton1.Enabled = False
CommandButton2.Enabled = False
を書いてフォーム上の CommandButton を無効にしておき、ループが終わったら
CommandButton1.Enabled = True
CommandButton2.Enabled = True
と書いて CommandButton を有効に戻してください。

これを工夫すれば、CommandButton2 で CommandButton1 のループを途中キャンセルする処理もすることができます。

Private Canceled As Boolean

Private Sub CommandButton1_Click()

  CommandButton2.Enabled = False

  Dim i As Long
  For i = 1 To 50000
    DoEvents

    If Canceled = True Then
      MsgBox "キャンセルしました"
      Exit Sub
    End If

    Cells(i, 1).Value = ""
  Next i
End Sub

Private CommandButton2_Click()
  Canceled = True
End Sub



コードの行頭にあるスペースは見易さのために全角スペースで作成していますので、これをこのままコピペするとエラーになるかもしれません。
コピペするなら行頭の全角スペースを半角スペースに直してください。

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
...続きを読む

QVB上で実行中の無限ループの止め方

今まで、CUIベースのBASICでのプログラムの経験はあるのですが
Visual系のBASICは初心者です。
原因はわかっているのでプログラムの修正はできるのですが
VB上でコンパイルして実行したときに無限ループに陥ってしまって
どうにもプログラムをとめられなくなります。
そんなことがないように、実行前に全てのプロジェクトを保存して
いますので、そんなに実害はないのですが、どうすればとめられるのでしょう・・
今現在は、タスクマネージャーから強制終了させています。

Aベストアンサー

無限ループの一番内側に
DoEvents
を入れておくと、ウィンドウ切替え->デバッガ終了操作が出来ますよ

危なそうなとこにも入れておくと、何かと安心です。

Q文字列にある特定文字の数

こんにちは。

文字列「C:\MYDOCU~1\THINKB~1\THINKB~1\TEMP」に"¥"がいくつ含まれているかを算出したく悩んでいます。どのような方法があるのか、是非アドバイスをください。よろしくお願いします。

** 環境 **
VB6.0(sp5)

Aベストアンサー

ご質問の「文字列」から察するにあるファイルのパス(ドライブ+パス+ファイル名)を
ドライブ+パスとファイル名に分解する、のような使い方をされるのでしょうか?
先の例ですとstrArrey(numArrey)を参照すると「ファイル名のみ」が取得できます。

あと、Splitの反対で「JOIN関数」があります。
なお、Split,JoinはExcel2000以降のVBAでも利用可能です。


'ここから

Dim strArrey() As String
Dim numArrey As Integer

Dim strPath As String

strPath = "C:\MYDOCU~1\THINKB~1\THINKB~1\TEMP"

strArrey() = Split(strPath, "\")

numArrey = UBound(strArrey())

MsgBox "これがファイル名:[" & strArrey(numArrey) & "]"

strArrey(numArrey) = ""

strPath = Join(strArrey(), "\")

MsgBox "これがパス名:[" & strPath & "]"

'ここまで

ご質問の「文字列」から察するにあるファイルのパス(ドライブ+パス+ファイル名)を
ドライブ+パスとファイル名に分解する、のような使い方をされるのでしょうか?
先の例ですとstrArrey(numArrey)を参照すると「ファイル名のみ」が取得できます。

あと、Splitの反対で「JOIN関数」があります。
なお、Split,JoinはExcel2000以降のVBAでも利用可能です。


'ここから

Dim strArrey() As String
Dim numArrey As Integer

Dim strPath As String

strPath = "C:\MYDOCU~1\THINKB~1\THINKB~1...続きを読む

Q他のフォームから別のフォームのサブルーチンを呼び出す

例えばフォームAからフォームBのCommand1_clickというサブルーチンを呼び出そうとすればどのようにすればいいんでしょうか?

私は

Call FormB!Command_click

とフォームAに書きましたがうまくいきませんでした

Aベストアンサー

Command1のClickイベントプロシージャの

Private Sub Command1_Click()
'(・・処理・・)
End sub



Public Sub Command1_Click()
'(・・処理・・)
End sub

に書き換えて下さい(「Private」→「Public」)。
こうすることにより、他のフォームから呼ぶことが可能になります。
ただしこのやり方は奨励しません(※後述)

また、呼び出し方も間違ってます。

Call FormB!Command_click

ではなく、

Call FormB.Command_click

として下さい(「!」→「.」)。

※自動生成するイベントプロシージャの構文を直接いじるのはあまり奨励しません(特に問題は発生しませんが)。
直接イベントプロシージャを呼ぶのではなく、下記のようにしてみてはいかがでしょう。

※下記をFormBに記述

Private Sub Command1_Click()
Call subCommand1Click
End sub

Public Sub subCommand1Click()
'(・・処理・・)
End sub

FormAではこのように呼ぶ
Call FormB.subCommand1Click

Command1のClickイベントプロシージャの

Private Sub Command1_Click()
'(・・処理・・)
End sub



Public Sub Command1_Click()
'(・・処理・・)
End sub

に書き換えて下さい(「Private」→「Public」)。
こうすることにより、他のフォームから呼ぶことが可能になります。
ただしこのやり方は奨励しません(※後述)

また、呼び出し方も間違ってます。

Call FormB!Command_click

ではなく、

Call FormB.Command_click

として下さい(「!」→「.」)。

※自動生成...続きを読む

QAccessVBA  SetFocusとGoToControlが正常に作動しない

重複番号をチェックする機能を作っています。
重複番号が入力されると、エラーメッセージが出て、
OKを押すと番号を入れるテキストボックスにカーソルが移動し、空白にする、
という機能をつけましたが、
何度試してもカーソルが、隣のテキストボックスに移動してしまいます。
(エラーメッセージが出て、空白にするという動作は正常に行われます)

SetFocusとGoToControlで試したのですが、
どちらも駄目でした。
原因が分かりません。
どなたかお分かりになりましたら、教えてください。
コードは下記のとおりです。

Private Sub AMコード_AfterUpdate()
If DCount("AMコード", "Q_AM担当者登録チェック") >= 1 Then
MsgBox ("すでに存在する番号です。別の番号を振りなおしてください。"), vbCritical, "番号重複"
AMコード.SetFocus
AMコード = ""
End If
End Sub

Aベストアンサー

入力チェックはAfterUpdateではなくBeforeUpdateで行います。

Private Sub AMコード_BeforeUpdate(Cancel As Integer)
  If DCount("AMコード", "AM担当者テーブル", "AMコード = '" & AMコード & "'") > 0 Then
    MsgBox ("すでに存在する番号です。別の番号を振りなおしてください。"), vbCritical, "番号重複"
    Cancel = True
    Me.Undo
  End If
End Sub

上記の例ではクエリで判定せず、直接、元のテーブルに対して直接判定を行っています。

なお、BeforeUpdateの中でヘタにSetFocusを使ったり値の代入を行うと、不測のエラーが出たり無限ループに陥るので、やってはいけません。

また、既存レコードを書き替えようとした場合「Cancel = True」で変更を無効にして元の値に戻しても、レコードは「変更あり」の状態なので、重複エラーの表示後にフォーカスの移動を行おうとすると、自分自身が「重複」として判定されて何も出来なくなってしまうので「Me.Undo」で、レコードの変更を取り消す必要があります。

入力チェックはAfterUpdateではなくBeforeUpdateで行います。

Private Sub AMコード_BeforeUpdate(Cancel As Integer)
  If DCount("AMコード", "AM担当者テーブル", "AMコード = '" & AMコード & "'") > 0 Then
    MsgBox ("すでに存在する番号です。別の番号を振りなおしてください。"), vbCritical, "番号重複"
    Cancel = True
    Me.Undo
  End If
End Sub

上記の例ではクエリで判定せず、直接、元のテーブルに対して直接判定を行っています。

なお、BeforeUpdateの中で...続きを読む

QTabIndexの見分け方について

今回の開発では既存のソースで1つのフォームに恐ろしいほどのコントロールが存在します。
その為、TabIndexが順番通りになっているか確認したいのですが、1つ1つのコントロールを見ていたら時間がもったいないと思いますのでなにかいい方法があれば教えてください。
ループでオブジェクト名とインデックスのログをはくようにすれば?と言われたのですが、よくわかっていません。どうかアドバイスお願いします。

もう1点質問なのですが、TabIndexが最後のコントロールから最初のコントロールにタブ移動するのに1回どこかに移動してしまって、2回タブを押下しないと最初のコントロールに戻ってこないです。
なにか原因があるのでしょうか?

以上です。わかりにくい説明ですがご回答お願い致します。

Aベストアンサー

hidekun_84さんの言うとおり、プログラム内でTabIndexを設定したほうが良いと思います。
修正などでコントロールが増えたり減ったりすると、そのたびに設定しなおし、なんて事にもなりますから。
TabIndexの設定はForm_Initializeで設定するのが良いです。

見えない場所にあるものや、フォーカスが来たのが気づかないコントロールがある場合、そのコントロールにフォーカスが行っているだろう状態でプロパティを確認してみてください。正体がわかるはずw
TabStopをFalseにしておけば、タブ移動しなくなりますよ。

QVB6.0-整数と余りを求める

表題の通り、整数と余りを求める関数を教えてほしいです:例:100/60=1余り40
整数:1
余り:40
よろしくお願いいたします。

Aベストアンサー

Dim A,B,C,D as integer
A=100
B=60
C=Int(A/B) <---答は1
D=A mod B

●IntはAをBで割った時の整数部分を求める関数ですが、答が負の場合は
注意が必要です。 例 Int(-100/40)=-2
これを回避する場合 Fixがいいです

●mod は A を B で割った時の余りを求める関数

QVB6,Ifから抜けるには?

If a = b then
  xxx
 If c = d then
   ここ!
 End If
  yyy
End If

zzz

上のここ!から抜け、zzz以降の処理を継続するにはどうすればよいでしょうか?
Exit Subをやってしまうとプロシージャ自体から抜けてしまいます。

Aベストアンサー

(1)下記が、処理順序の都合でできる場合
yyyの処理がc=dに影響しないとき
If a = b then
  xxx
yyy
 If c = d then
   ここ!
else
 End If
End If
zzz
(2)できない場合
If a = b then
  xxx
 If c = d then
   ここ!
   yyy
 else
yyy
 end if
End If
zzz
yyyのコードのステップ数が多い場合、2回記述をサブルーチンか何かを使い回避する。
(3)GoToを使う方法

QアクセスVBAのMe!と[ ]

基本的なことですみません。

アクセスのイベントプロシージャで、Me!ってありますけど、これはどういう意味なんでしょうか?

また、Me!の後に、Me!.~~と書く場合と、Me!.[~~]と書く場合がありますが、どこが違うのでしょうか?

Aベストアンサー

>プロシージャ内で[]を使う場合は、そのフォーム外のオブジェクトを使う場合と考えてよろしいでしょうか?
別のオブジェクトを使う場合だけではありません。
Hensu = Me![Text1]のようにHensuという変数に自身のTest1の値を代入する場合のように。
[]で括られているのがオブジェクト名やコントロール名だよという事。
クエリの抽出条件に存在しない[?]とすれば?というコントロール等が参照できないので?というダイアログが表示されるように?というオブジェクトやコントロールは何?と聞いてくるように。
>フォーム内のオブジェクトの場合はあくまでMe!で良いのでしょうか
Forms.[フォーム名]![コントロール名]やForms![フォーム名]![コントロール名]が構文。
アクティブなフォームが自分自身ならForms![フォーム名]の変わりにMeでもOKですという事。

と言う解釈の方が良いと思います。


人気Q&Aランキング