Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(指定なし : 指定なし)
フォーム右上「キャンセルボタン」押し下げの検知
投稿日時: 17/10/16 10:17:58
投稿者: S.Kos

みなさま、こんにちは。
 
Sheet1からUserForm1を開く、とします。
このとき、UserForm1右上のペケ印を押し下げてこれを閉じたコトを、Sheet1側で検知したい、と考えます。
 
どんな手法が、最もスマートでしょうか?

回答
投稿日時: 17/10/16 11:14:32
投稿者: mattuwan44

http://www.asahi-net.or.jp/~ef2o-inue/vba_o/sub05_100_050.html
https://ateitexe.com/excelvba-judge-userform-close-button/
  
ども^^
取捨選択はご自分で判断してください^^
 
というか自分で検索した方が早いと思いますよ^^
 
「vba ユーザーフォーム ×ボタン イベント」
で検索してみました

投稿日時: 17/10/16 13:04:54
投稿者: S.Kos

mattuwan44さん、ご教示のほど感謝です
 
お教えいただいたサイトが示す手法(の根幹は)は、Publicな変数を用意して・・・、ですよね。
あちこち彷徨ってもこの手法しかなく、異なる手法は無いかな、と思ったしだいです。
先に、最もスマート、とした所以です。
 

回答
投稿日時: 17/10/16 13:47:59
投稿者: 隠居じーさん

おじゃま致します。
スマートかどうか解りませんが、
参考まで
ユーザーフォームのコードにて
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
  If CloseMode = 0 Then
    Cells(1, 1) = "×で閉"
    'Cancel = 1
  End If
'Cancel = 1のコメントをはずすと×では終了しなくなります。

回答
投稿日時: 17/10/16 14:33:20
投稿者: hatena
投稿者のウェブサイトに移動

S.Kos さんの引用:

お教えいただいたサイトが示す手法(の根幹は)は、Publicな変数を用意して・・・、ですよね。
あちこち彷徨ってもこの手法しかなく、異なる手法は無いかな、と思ったしだいです。
先に、最もスマート、とした所以です。

 
紹介されているサイトでは、複数の方法が提示されてますよね。
Publicな変数を使わない方法も提示されすます。
 
隠居じーさん さんの回答の QueryCloseイベントのCloseModeで判断する方法も紹介さてますね。
 
これもスマートではないということでしょうか。
 

投稿日時: 17/10/16 16:13:45
投稿者: S.Kos

みなさま、重ねてのご教示ありがとうございます。
 
隠居じーさん
> If CloseMode = 0 Then
>    Cells(1, 1) = "×で閉"
>
フォームを開いたシートの側で、そのシート内のセルを「Publicな変数」の代わりにしてる訳ですよね。
 
スマートと記した主旨は、シート内のセルやPublicな変数を介さずに検知できないか、との意でした。

回答
投稿日時: 17/10/16 22:18:03
投稿者: hatena
投稿者のウェブサイトに移動

S.Kos さんの引用:
隠居じーさん
> If CloseMode = 0 Then
>    Cells(1, 1) = "×で閉"
>
フォームを開いたシートの側で、そのシート内のセルを「Publicな変数」の代わりにしてる訳ですよね。

 
違いますよ。
シート内のセルは、QueryCloseイベントのCloseMode引数で判断した結果を格納しているだけです。
(判断結果をどのように利用するか不明なので、一例としてセルに代入しているのです。)
 
シート内のセルやPublicな変数を介さずに
ユーザーフォーム ×ボタンを押してフォームを閉じる時、CloseMode引数が 1 になることで検知できます。
 
 
 

回答
投稿日時: 17/10/17 10:30:59
投稿者: WinArrow
投稿者のウェブサイトに移動

>Sheet1側で検知したい、
↑に関して
具体的な例が示されないから
行き違いが生じているものと思います。

回答
投稿日時: 17/10/17 10:32:40
投稿者: WinArrow
投稿者のウェブサイトに移動

追加
 
>Sheet1からUserForm1を開く、
↑に関しても、具体的には示されていません。

回答
投稿日時: 17/10/17 12:23:46
投稿者: hatena
投稿者のウェブサイトに移動

WinArrow さんの引用:
>Sheet1側で検知したい、
↑に関して
具体的な例が示されないから
行き違いが生じているものと思います。

あっ、そういうことですね。
質問を読み違えていたようです。
 
>Sheet1からUserForm1を開く、
 
モダールで呼び出すか、モードレスで呼び出すかでも変わってきそうです。
 
そのあたりの状況をもう少し具体的に提示してもらえるといいですね。

回答
投稿日時: 17/10/17 13:04:51
投稿者: hatena
投稿者のウェブサイトに移動

'UserForm1
Option Explicit
Public CMode As Integer

Private Sub CommandButton1_Click()
    Unload UserForm1
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    CMode = CloseMode
End Sub

 
Public Function ShowForm() As Integer
    With UserForm1
        .Show
        If .CMode = 0 Then Msgbox "×ボタンで閉じられました"
    End With
End Function

 
 
UserForm の Public変数を使わないとなると、クラスモジュールでCloseModeプロパティを実装するぐらいかな。

回答
投稿日時: 17/10/17 13:42:20
投稿者: WinArrow
投稿者のウェブサイトに移動

>Sheet1からUserForm1を開く、

引用:

モダールで呼び出すか、モードレスで呼び出すかでも変わってきそうです。
 

 
モーダル/モードレスもありますが、
シートからユーザーフォームを開く
って、いろいろな方法がありますから、質問者側と回答者側で、同じイメージになりますか?
 
(1)シートのセルをダブルクリック
(2)シートに配置したボタン(図形)に登録したマクロ実行
(3)特定セルの値が変わった時、特定セルにカーソルが移動した時
など・・・いづれもマクロが必要なことはわかりますよね?
 
それと同じ発想ならば
ユーザーフォーム起動マクロ内で閉じたことを検知する
と、考えると、
モーダルの場合は、次の命令に制御が移るから、何も検知しなくてもよ。
しかし、
Me.Hide
でも次の命令に制御が移るので、その判定方法を知りたい
かな?
 
モードレスの場合は、いきなり、次の命令に制御が移るから、
シートで検知という意味がよくわかりません。
 
 
 
 
 
 
 

投稿日時: 17/10/17 15:07:50
投稿者: S.Kos

みなさま、重ねてのご教示、ありがとうございます。
最初の投稿があやふやだったため、混乱を招いてしまったこと、ご容赦ください。
 
以下、現状のコード(もどき)を示しますので、改めてご教示いただけれは幸いです。
 
1. ユーザー定義データ型(構造体)宣言
 Type DataPac
  なんちゃらかんちゃら
  RetCode as Integer
 End Type
 
2. シート側でフォームを開いて、戻りを待つ
 
 Dim dPac as DataPac
 
 UserForm1.Info = dPac
 UserForm1.Show
 dPac = UserForm1.Info <--(※B)
 
3. フォームの構成
 Private fm1Info As DataPac
 
 Property Let Info(arg As DataPac)
    fm1Info = arg
 End Property
 
 Property Get Info() As DataPac
    Info = fm1Info
 End Property
 
 Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = vbFormControlMenu Then
      dPac.RetCode = -1 <--(※A)
    End If
 End Sub
 
これで、
 UserForm1が(ペケボタンで)閉じられたとき、
 dPac.RetCode = -1がセット(※A)され、
 シート側でこの値を見れ(※B)は、検知できる
と考えました。
 
ところが、(※A)が機能しない、つまりセットされない、ようなのです。
回避措置として、
 Cancel = Trueでペケボタンを無効化し
 別個に「閉じる」ボタンを用意し、その中で(※A)を書いています

回答
投稿日時: 17/10/17 17:41:26
投稿者: WinArrow
投稿者のウェブサイトに移動

>1. ユーザー定義データ型(構造体)宣言
は、どこのモジュールに記述しているのでしょうか?
 
 
>2. シート側でフォームを開いて、戻りを待つ
このシート側というのは、シートモジュールということでしょうか?
プロシジャ名まで記述しましょう。
 
 
構造体は、たとえ、広域(Public)宣言しても
データの入っているところを区別して参照する宣言だけで、
データは格納されていません。
 
例えば、自治体コード(5桁として)というのがあったとして、
上2桁を都道府県コード、下3桁を市町村コードとして認識しましょう
という宣言です。
 
データは、それを参照宣言しているデータ側に入っています。
 
 
Type JITITAI
   都道府県 AS string
   市町村 AS string
End Type
 
Private 自治体 As JITITAI
 
つまり、データは 変数:自治体の方に入っています。
 
掲示されたコードでは、異なるモジュールで、Type句を共有しているだけで
データを格納する変数は、Private宣言していますよね。
変数をPublic宣言するならば、標準モジュールを使いましょう。
 

回答
投稿日時: 17/10/17 17:52:58
投稿者: Abyss2

今回の件は「オブジェクトの寿命管理」問題です。
テスト用に新規ブックにて下記コードを実行比較してみてください。
 
【新規ブック】
1)UserFormを追加 -> そこにTextBoxを一つ設置
 
2)標準モジュールに下記ソースを記載する。

public sub main1()
    userform1.show
    msgbox userform1.textbox1.text
end sub

public sub main2()
    dim uf as userform1
    set uf = userform1
    uf.show
    msgbox uf.textbox1.text
end sub

3)main1とmain2を実行し、TextBoxになにか入力。
4)UserFormを閉じる。
 
main1とmain2の違いがお分かりになると思います。
(勿論、QueryCloseメソッド利用の管理も可能ですが)

回答
投稿日時: 17/10/17 18:25:02
投稿者: WinArrow
投稿者のウェブサイトに移動

Abyss2 さんのレスの中で
main2の方は
 
> dim uf as userform1
がミソですね・・・・
 
dim uf as Object
のような定義をすると、
ユーザーフォーム閉じた後は
ユーザーフォームのコントロールは参照できませんね・・・
 
勉強になりました。
 

トピックに返信