こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

'ユーザーフォーム右上隅の[×]ボタンを表示しない

Excell VBA にて
ユーザーフォーム内に[コマンドボタン]を配置し、このボタンにてユーザーフォームの消去およびその他の作業を行うコードを書い動作させています

ユーザーフォームの右上隅に表示されている[×]ボタンを表示しない(又は消去する)方法をおしえてください

投稿日時 - 2014-10-02 19:00:52

QNo.8776511

すぐに回答ほしいです

質問者が選んだベストアンサー

#3-5,7、cjです。#7お礼欄へのレスです。

> 動作確認の準備ですが1,2迄で出来きました
> 3、のコピー&ペーストする場所ですが、コード表示画面にてユーザーフォームを表示し、そのユーザーフォーム内の部分をダブルクリックして、表示された画面にコードをコピー&ペーストすればよいのでしょうか?、ペーストしたコードの初めの10行ほどが赤字になっています、何処かおかしいでしょうか

大丈夫です。ご指摘の状況は異常ではありません。

"そのユーザーフォーム内の部分をダブルクリック"すると、
Private Sub UserForm_Click()
End Sub
が表示されますよね?その画面(コードペイン)の記述をすべて消してから、
#7のコードを貼り付けます。

"ペーストしたコードの初めの10行ほどが赤字になっています"
おかしくないですから安心してください。
#Ifから#End Ifまで、これは条件付きコンパイルというもので、
Excelのバージョン環境によって、どこかしら構文エラーで赤い字にはなりますが、
VBAはそれらの記述を読み飛ばしますから、動作には影響ないです。
そもそもは、様々なバージョンに自動的に対応させる為の記述です。
気にせずに動作確認して貰っても問題ない筈です。
もし気になるようでしたら、赤い字で書かれている行を
削除しちゃっても構いませんので。
赤い字を削除した場合は、その前後の
#If VBA7 Then
#Else
#End If
の3か所についても、消しちゃって構いません。

取り急ぎの返答でした。

投稿日時 - 2014-10-04 07:40:44

お礼

cj_mover様
ヤッター!! すばらしい!!
Sheet1のイベントプロシージャーに下記を書き込み
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
UserForm1.Show vbModeless
End Sub
赤字の行はそのままで、マクロを実行テストをしました
快調に動作しました
   >↓ 確認  表示された UserForm1 について、
  >閉じるボタンが非表示になっていること、
  >Alt + F4 を押してもユーザーフォームを閉じることが出来ないこと
   >表示直後はCommandButton1が非活性で、
  >CommandButton2を押すとCommandButton1を押せるようになっていること、
  >CommandButton1を押すと、ユーザーフォームが閉じること
  上記項目全て確認しました、OKです
  適切な回答有難うございました、感謝です

投稿日時 - 2014-10-04 11:02:38

このQ&Aは役に立ちましたか?

9人が「このQ&Aが役に立った」と投票しています

回答(8)

ANo.7

#3-5、cjです。#5お礼欄拝見しました。

> テストすることもが出来ません
> 何日か時間をかけて書いてくださったこと勉強します

まずは何より動作確認ですね。
動作確認までは、あまり難しく考える必要ないです。
私のミスで混乱させてしまってるかも知れないので、
テストする方法をシンプルに書いてみます。
この回答だけで完結する内容で、簡単に試せるように書き直しました。

ついでに、閉じるボタンを非表示にする設計の簡単な例として、
◆マークの行を書き加えてみました。
勿論ここに書くのはプロットですから、実際は、
入力内容のチェック処理など他の処理が合間に入る訳ですが、
必要な入力が終り、入力完了ボタンが押されたら、
入力した内容をチェックし、確定しても良いと判断した場合に、
入力内容と集計結果を確認画面に表示してから
入力確定(閉じる)ボタンを表示する、
というような操作の流れを想定しています。

以下、準備
 1.新規のブックに新しくユーザーフォームを挿入
 2、ユーザーフォームにコマンドボタンを2つ配置
   (名前などのプロパティは全てそのまま)
 3、UserForm1 モジュール に下記のコードを丸ごとコピペ
   (記述の全てをそのまま)
 4、標準モジュールあたりに、ユーザーフォーム実行マクロを記述
   (UerForm1.Show または UerForm1.Show vbModeless どちらでも)
準備はここまで、以下確認作業
 5、4で作成したマクロを実行
 ↓ 確認  表示された UserForm1 について、
  閉じるボタンが非表示になっていること、
  Alt + F4 を押してもユーザーフォームを閉じることが出来ないこと
  表示直後はCommandButton1が非活性で、
  CommandButton2を押すとCommandButton1を押せるようになっていること、
  CommandButton1を押すと、ユーザーフォームが閉じること
確認作業ここまで。

下記のコードを丸ごとコピペ、です。

' ' /// UserForm モジュール /// 以下、過不足なくそのままで
Option Explicit

#If VBA7 Then
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
  (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
  (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare PtrSafe Sub SetWindowLong Lib "user32" Alias "SetWindowLongA" _
  (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As LongPtr)
Private Declare PtrSafe Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
#Else
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
  (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
  (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Sub SetWindowLong Lib "user32" Alias "SetWindowLongA" _
  (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long)
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
#End If

Private Const GWL_STYLE As Long = (-16&) ' ウィンドウスタイルを取得するフラグ
Private Const WS_SYSMENU As Long = &H80000 ' 閉じるボタンを表示するフラグ
Private Const CLASSNAME As String = "ThunderDFrame" ' クラス名

Private Sub UserForm_Initialize()
Dim nHwnd As Long
Dim nWindowLong As Long
  nHwnd = FindWindow(CLASSNAME, Caption) ' ウィンドウハンドルを取得する
  nWindowLong = GetWindowLong(nHwnd, GWL_STYLE) ' 既定のウィンドウ属性を取得する
  nWindowLong = (nWindowLong Xor WS_SYSMENU) ' 閉じるボタンを非表示に指定する
  SetWindowLong nHwnd, GWL_STYLE, nWindowLong ' ウィンドウ属性を設定する
  DrawMenuBar nHwnd ' メニューバーを再描画する
  CommandButton1.Caption = "入力確定" ' ◆
  CommandButton2.Caption = "入力完了" ' ◆
End Sub

Private Sub UserForm_Activate()
  CommandButton1.Enabled = False ' ◆
  Repaint ' Userform再表示の度に再描画する
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
  If CloseMode = vbFormControlMenu Then Cancel = 1 ' vba実行コードでのみ閉じることが可能
End Sub

Private Sub CommandButton1_Click()
  Hide
End Sub

Private Sub CommandButton2_Click() ' ◆
  CommandButton1.Enabled = True ' ◆
End Sub ' ◆

' ' ///           ///



> 何日か時間をかけて書いてくださったこと勉強します

いずれにしても、閉じるボタンを非表示にする為には、
API関数を使うのが一番簡単です。
形さえ覚えておけば使うのは難しくないですけれど、
読んで解らないものを使うのは色々気になりますよね。
FindWindow GetWindowLong SetWindowLong なんかは、
使用例も簡単に見つけられますから、
少しずつ、見て覚えていけばいいように思います。

> >注意を一点だけ。
> >閉じるユーザー操作をキャンセルするならば、
> >いちいちUnLoad するような運用は必要ないでしょうし、無駄なので、
> >Hide するような運用に統一してください

>  ご指摘有難うございました、以後きをつけます

"統一してください"は言い過ぎだったかも知れませんが、
Loadの際に描画したユーザーフォームは、
ブックを閉じるまでUnloadする必要が有るか無いかで言えば無いですよね。
その方が簡単そうだから、Unloadするとか、なのでしょうけれど、
今回提示したものは、ユーザーフォームを描画後に
閉じるボタン無しのメニューバーに変更して再描画するものなので、
ユーザーフォームを繰り返し再表示するようなら、
無駄な処理がますます増えてしまう、ということなのです。
偶にしか使わない、とか、暫くは再表示しないであろうから、Unloadする、とか、
そういうことなら、Unloadでもいいとは思いますけれど。
ただ、基本的には、
ShowしたらHide、再びShow、、、のようにして、
_Activate イベント の記述で、再表示時のデータ等の初期化処理をする
ような運用をするのがユーザーフォームだと思っています。
Load→Show→Hide→Show→Hide→Show→Hide→Unload
みたいに使う方がストレスなくエラーフリーだとも思います。

すぐにすべて理解するなんて誰にも無理でしょうし、
別に急ぐ必要ないですから、ボチボチで。
なんか色々ミスっちゃってスイマセンでした。
ご健闘を、、、。

投稿日時 - 2014-10-03 23:35:11

お礼

cj_mover様
>Load→Show→Hide→Show→Hide→Show→Hide→Unload
>みたいに使う方がストレスなくエラーフリーだとも思います。
再度の詳しい説明ありがとうございました、理解できました。

>  1.新規のブックに新しくユーザーフォームを挿入
>  2、ユーザーフォームにコマンドボタンを2つ配置
>    (名前などのプロパティは全てそのまま)
>  3、UserForm1 モジュール に下記のコードを丸ごとコピペ
>    (記述の全てをそのまま)
>  4、標準モジュールあたりに、ユーザーフォーム実行マクロを記述
>    (UerForm1.Show または UerForm1.Show vbModeless どちらでも)
動作確認の準備ですが1,2迄で出来きました
3、のコピー&ペーストする場所ですが、コード表示画面にてユーザーフォームを表示し、そのユーザーフォーム内の部分をダブルクリックして、表示された画面にコードをコピー&ペーストすればよいのでしょうか?、ペーストしたコードの初めの10行ほどが赤字になっています、何処かおかしいでしょうか
よろしくおねがいします

投稿日時 - 2014-10-04 06:27:34

ANo.6

目的がよくわからないのですが、手段に懲りすぎるのもなんだかなーと。

勝手に妄想。(尾ひれも付いていますが)
外れていたら無視で結構です。

[閉じる] コマンドボタンをクリックすると、独自の [終了処理] を実行したのちにフォームが閉じる。
[終了処理] の結果によってはフォームを閉じさせない場合もある。
[×] ボタンでは終了のための処理を挟み込めないと思う。
だから [×] ボタンは非表示にしておきたい。


[閉じる] コマンドボタンと [×] ボタン、利用者にとってはどちらもフォームを閉じたい場合に押すコントロールなので、どちらを押しても同じ処理を行えるよう心掛ける。

フォームの QueryClose イベントはフォームを閉じる可否を決定できるイベントため、最大限活用する。
下記の場合は [閉じる] ボタンではなく、QueryClose イベントの中で [終了処理] を呼び出し、その結果によってフォームを閉じるか閉じないかの判断をしている。

Option Explicit

Private Sub CloseButton_Click()
 Unload Me
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
 If Not (CloseProcess) Then
  Cancel = 1
  MsgBox "奇数秒なので閉じられません"
 End If
End Sub

Private Function CloseProcess() As Boolean
 ' 終了処理
 ' ここに独自の終了処理を書き、無事に終了してフォームを閉じても良いのなら True を返すようにする。
 If (Second(Time) Mod 2 = 0) Then
  ' 閉じても良いので True を返す
  CloseProcess = True
 Else
  ' 閉じられないので False を返す
  CloseProcess = False
 End If
End Function

投稿日時 - 2014-10-03 14:15:58

お礼

x-1919 様
解答ありがとうございます
テストファイルを作成し、ユーザーフォームのプロシージャーにご指摘のコードをコピペしマクロを実行テストをしました
[×]クリックした時、時間によりユーザーフォームが消えたり消えなかったりすること、確認できました。
私は[×]ボタンのないユーザーホームを作りたかったので、目的と異なっていました
しかし解答していただいたプログラム今後の参考にさせていただきます
有難うございました

投稿日時 - 2014-10-04 11:42:39

ANo.5

#3-4、cjです。
すみません、間違いを見逃していました。
#4前段の修正案については、原因の特定を誤っていましたので、
無かったものとしてください。
>  DrawMenuBar nHwnd ' メニューバーを再描画する
この記述は、イキ、です。

ちょっと恥ずかしいのですが、DrawMenuBar関数の宣言が滅茶苦茶でしたので、
APIの宣言部分を条件付きコンパイルごと、差し替え、
でお願いします。
今までエラーにならなかったのが不思議な、ミスでした。

あらためて3環境で動作を確認しました。

' ///
#If VBA7 Then
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
  (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
  (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare PtrSafe Sub SetWindowLong Lib "user32" Alias "SetWindowLongA" _
  (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As LongPtr)
Private Declare PtrSafe Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long ' 訂正部分
#Else
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
  (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
  (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Sub SetWindowLong Lib "user32" Alias "SetWindowLongA" _
  (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long)
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long ' 訂正部分
#End If
' ///

お手間取らせてスミマセンでした。
以上です。

投稿日時 - 2014-10-03 10:23:03

お礼

cj_mover 様
たびたびの回答有難うございます
当方力不足のため書いてくださった事なかなか理解できず
テストすることもが出来ません
何日か時間をかけて書いてくださったこと勉強します

>注意を一点だけ。
>閉じるユーザー操作をキャンセルするならば、
>いちいちUnLoad するような運用は必要ないでしょうし、無駄なので、
>Hide するような運用に統一してください
 
 ご指摘有難うございました、以後きをつけます

投稿日時 - 2014-10-03 21:49:37

ANo.4

#3、cjです。
x32ビット環境向けに、修正案です。

もしかして、#3の記述でうまくいかないことがあれば、
>  DrawMenuBar nHwnd ' メニューバーを再描画する
一旦、この一行分の記述を削除して試してみて下さい。
問題なければ、そのままでも大丈夫です。
この修正は一部の環境でのみ必要なものですが、
もし心配でしたら、予め削除しておいた方がエラーフリーです。
あらためてx32ビット環境(xl2000,xl2003)で動作確認しました。
XP/Excel2000の方では、この記述があるせいで不正終了でした。
(メンテしていないPCなので、そのせいかも知れませんが)

なお、x32|x64ビット環境と、ここで書いているのは、
MS Office(Excel)をインストールする際に
x32ビット版|x64ビット版のどちらを選んでいるか、
ということですので、
OS(Windows)が、x32ビット版|x64ビット版のどちらか、
ということではありませんので、誤解無きよう。

それから念の為ですが、
> Private Declare Function
> Private Declare Sub
Declareの後に(4ヶ所)全角空白が入ってしまっていますが、
これは投稿文編集時のミスです。
通常はこのままでも、
コードペインに貼り付けた時点で正しく書き換えられますが、
書き換えられない環境の場合は修正しておいてくださいませ。

以上、追加補足でした。

投稿日時 - 2014-10-03 10:02:22

ANo.3

こんにちは。

以下のような感じで如何でしょう。
一応、x32|x64互換で書きましたが、x64ビット環境でしか動作確認してません。
x32ビット環境で8年前に書いたものを元に書いているので、
たぶん、だいじょぶ、と思いますが、、、。
閉じるボタンを非表示にする設計は、私も多用していましたから、
ニーズとしては、良く理解できます。

条件付きコンパイルに慣れていないと驚いちゃうかもしれませんが、
#If VBA7 Then から #Else の間の記述が、x64ビット用
#Else から #End If の間の記述が、x32ビット用
です。
不要な記述(#If VBA7 Then ... #Else ... #End If を含む)は
削除して構いません。

注意を一点だけ。
閉じるユーザー操作をキャンセルするならば、
いちいちUnLoad するような運用は必要ないでしょうし、無駄なので、
Hide するような運用に統一してください。

また、ウィンドウ関係の Win32 API は
WEB上でも、情報豊富ですから、
ご自分でもメンテナンス出来るよう努めてください。
コメントに書いた説明以上のことは、ご容赦ください。

動作確認の上、何か不足あれば、補足欄にでも書いてみて下さい。

以下、サンプルです。

' ' /// UserForm モジュール ///

Option Explicit

#If VBA7 Then
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
  (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
  (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare PtrSafe Sub SetWindowLong Lib "user32" Alias "SetWindowLongA" _
  (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As LongPtr)
Private Declare PtrSafe Sub DrawMenuBar Lib "user32" Alias "SetWindowLongA" _
  (ByVal hWnd As Long)
#Else
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
  (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
  (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Sub SetWindowLong Lib "user32" Alias "SetWindowLongA" _
  (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long)
Private Declare Sub DrawMenuBar Lib "user32" Alias "SetWindowLongA" _
  (ByVal hWnd As Long)
#End If

Private Const GWL_STYLE As Long = (-16&) ' ウィンドウスタイルを取得する場合
Private Const WS_SYSMENU As Long = &H80000 ' 閉じるボタンを表示する場合
Private Const CLASSNAME As String = "ThunderDFrame" ' クラス名

Private Sub UserForm_Initialize()
Dim nHwnd As Long
Dim nWindowLong As Long
  nHwnd = FindWindow(CLASSNAME, Caption) ' ウィンドウハンドルを取得する
  nWindowLong = GetWindowLong(nHwnd, GWL_STYLE) ' 既定のウィンドウ属性を取得する
  nWindowLong = (nWindowLong Xor WS_SYSMENU) ' 閉じるボタンを非表示に指定する
  SetWindowLong nHwnd, GWL_STYLE, nWindowLong ' ウィンドウ属性を設定する
  DrawMenuBar nHwnd ' メニューバーを再描画する
End Sub

Private Sub UserForm_Activate()
  Repaint ' Userform再表示の度に再描画する
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
  If CloseMode = vbFormControlMenu Then Cancel = True ' vba実行コードでのみ閉じることが可能
End Sub

Private Sub CommandButton1_Click()
  Hide ' 注意!!Userform は UnLoad するよりも Hide するのが基本です!!
End Sub

投稿日時 - 2014-10-02 22:54:18

ANo.2

No.1です。

>私以外の人がこのソフトを使うと[×]ボタン押して動作不良と思ってしまいますので
>不要な[×]ボタンを削除したいのですが・・・可能でしょうか

紹介したサイトにも書いてあると思いますが、できたとしても結構厄介だと思います。

そこで別案なのですが、
いっそのこと「ユーザーフォーム」の閉じるボタンは操作できないという旨のメッセージを表示させてみてはどうでしょうか?

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
MsgBox "UserForm1画面の[×]ボタンは操作できません", vbExclamation
'↑「UserFom1」の部分はユーザーフォームのCaptionにしておく
Cancel = True
End If
End Sub

のような感じで・・・

簡単に出来る方法があればごめんなさいね。m(_ _)m

投稿日時 - 2014-10-02 22:40:42

お礼

>Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
>If CloseMode = vbFormControlMenu Then
>MsgBox "UserForm1画面の[×]ボタンは操作できません", vbExclamation
>'↑「UserFom1」の部分はユーザーフォームのCaptionにしておく
>Cancel = True
>End If
>End Sub
ご指摘のコード書き込み実行し、メッセージボックスの表示が出ました
[×]ボタンが消せない場合はこの表示があったほうが良いと思いました
有難うございました

投稿日時 - 2014-10-03 20:58:36

ANo.1

こんばんは!

↓のサイトに参考になりそうな内容が載っています。

http://www.moug.net/tech/exvba/0090003.html

この方法だとユーザーフォームのQueryCloseプロシージャーに

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
Cancel = True
End If
End Sub

とすれば「閉じる」ボタンをクリックしてもユーザーフォームを閉じるコトはできません。
※ Alt+F4キー でもユーザーフォームは閉じませんので気を付ける必要があります。

そこでユーザーフォームにコマンドボタンを配置し、

Private Sub CommandButton1_Click()
Unload Me
End Sub

といった感じのコードを記載しておき、
コマンドボタンをクリックしてユーザーフォームを閉じるか
処理が終了した時点でユーザーフォームを閉じるといったコードが必要になると思います。m(_ _)m

投稿日時 - 2014-10-02 19:52:42

お礼

tom04様へ
早速の回答有難うございます
ご指摘のようにユーザーフォームのQueryCloseプロシージャーに
If CloseMode = vbFormControlMenu Then
Cancel = True
End If
を書き込み

ユーザーフォームのコマンドボタンには、
Unload Me の他
別のユーザーフォーム2.show
Worksheets(2).select
等消去以外の処理も同時に行っています

上記にてテストしますと
「閉じる」ボタンをクリックしてもユーザーフォームは閉じなく
コマンドボタンをクリックするとユーザーフォームを閉じ、続いてつぎのコマンド正常に動きます
これでよいのですが、
私以外の人がこのソフトを使うと[×]ボタン押して動作不良と思ってしまいますので
不要な[×]ボタンを削除したいのですが・・・可能でしょうか

ご指摘のサイトこれから読んで見ます

投稿日時 - 2014-10-02 22:16:22

あなたにオススメの質問