- ベストアンサー
ExcelVBA:フォームの最小化ボタンを表示し、閉じるボタン「×」を消す方法
似たような質問をしたのですが、参考URLを元に自分で試してみたのですが、思うようにいかず、理解ができなかったので改めて質問します。 Excelのプログラムで右上にある閉じるボタン「×」を消して、なおかつ最小化ボタンを表示させるにはどのようにしたらよいのでしょうか? 解説付きでよろしくお願いします。 回答よろしくお願いします。
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
タイトルバーで右クリックした場合などは閉じるボタンが有効化されるようです これを捕捉するとなるとWM_NCLBUTONDOWNメッセージなどを処理する事になりそうです ・・・
その他の回答 (7)
- redfox63
- ベストアンサー率71% (1325/1856)
ん~ おかしいですね … 当方は WinXP SP2 + Office2003の環境ですが 一点修正を コード側でEnableMenuItemの最後の引数のMF_DISABLEは MF_DISABLEDの間違いでした m(__)m
お礼
すいません。 FindWindow("ThunderDFrame", "UserForm1")のところで"UserForm1"の名前を変えたので閉じるボタンが有効になっていたようです。そこを変更するのを忘れていました。 これで最小化ボタン有効、閉じるボタン無効に成功しました。 本当は分からないことがいっぱいあるのでお聞きしたいことがたくさんあるのですが、ここまで教えてもらっていただいて、さらにお聞きするのは大変申し訳ないので別の機会にします。 また、インターネットで自分でも調べられることは調べるようにしたいと思いました。 本当にありがとうございました。
- redfox63
- ベストアンサー率71% (1325/1856)
ごめんなさい m(__)m DeleteMenuではうまくいかないようです いろいろ実験していたので誤った情報を書き込んだようです EnableMenuItemを使えばできるようです 標準モジュールに Public Declare Function EnableMenuItem Lib "user32" _ (ByVal hMenu As Long, ByVal wIDEnableItem As Long, ByVal wEnable As Long) As Long Public Const MF_DISABLED = &H2& を追加します Initializeイベントの DeleteMenuをEnableMenuItemに置き換えます EnableMenuItem hSysMenu, SC_CLOSE, MF_BYCOMMAND or MF_DISABLE といった具合です
お礼
今更ですが、お礼の記載が大変遅くなり、申し訳ありません。 ありがとうございました。
補足
追加したのですがやはり閉じるボタンだけ有効になってしまいます。 すいませんがよろしくお願いします。
- redfox63
- ベストアンサー率71% (1325/1856)
> では Integer ではなく Long ではないでしょうか そのとおりです m(__)m いろいろ回答していたので間違えました Ano3の補足への回答ですが DeleteMenuの第2引数が MF_BUCOMMANDになっていますが これは MF_BYCOMMANDにしないとだめですね こういった単純なスペルミスを防ぐためにも『変数宣言の強制』を設定しておいたほうが良いでしょう VBEの画面で ツール > オプションの変数タブ 『変数の宣言を強制する』のチェックをつけておきます 既存のVBAコードについては コードの先頭で Option Explicit といった1行を追加しておきます このようにしておけば 宣言されていない変数(定数)は使用できなくなりますので タイプミスによるバグはほとんど回避が可能になります ただ似たような変数名の打ち間違いまでは面倒見てくれませんので・・・ たとえば dim Hen1, Hen2 hen1 = 1 ' 本来 hen1を判断するところを Hen2とタイプした if Hen2 = 1 then Hen2 = -1 ' Hen3は宣言されていないのでチェックされる Hen3 = Hen2 * 2 end if
お礼
今更ですが、お礼の記載が大変遅くなり、申し訳ありません。 ありがとうございました。
補足
回答ありがとうございます。 なるほど。変数の宣言を強制した方が間違いが酸くなるんですね。勉強になります。 「MF_BYCOMMAND」に変更したのですがやはり、閉じるボタンが有効のままのようです。 「MF_BYCOMMAND」の値が「0」なのですがこれが原因なのでしょうか? 大変お手数ですがよろしくお願いします。
- KenKen_SP
- ベストアンサー率62% (785/1258)
横レス失礼します。。 > Public Declare Function GetSystemMenu Lib "user32" Alias "GetSystemMenuA" _ > (ByVal hWnd As String, _ > ByVal bRevert As Boolean) As Long API の宣言文(API に渡す引数の型を含めて)は、API に関する知識が 深まるまで勝手に変えず、API ビューアや WEB などで紹介されている とおり、そのままコピペして使いましょう。 # これらの情報が絶対に間違っていないとは限りませんが... Alias は意味もわからず付けてはダメです。また、GetSystemMenu の 第一引数 hWnd の型が String 型になってますが、Long 型の誤りかと。 参考URL:WinAPI Database for VB Programmer http://www.winapi-database.com/ Declare Function GetSystemMenu Lib "user32.dll" ( _ ByVal hwnd As Long, _ ByVal bRevert As Long) As Long Declare Function DeleteMenu Lib "user32.dll" ( _ ByVal hMenu As Long, _ ByVal nPosition As Long, _ ByVal wFlags As Long) As Long なお、#3 ご回答ですが、VB.Net 用のものではないかと思われます。VBA では Integer ではなく Long ではないでしょうか。
お礼
そうですね。まだはっきりと知識がないうちは変更せずそのまま使った方がいいようですね。 ありがとうございました。
- redfox63
- ベストアンサー率71% (1325/1856)
Declare宣言の関数名の最後にAをつけるのは ANSI/Unicodeの両方のAPIが存在する場合にどちらを使うのかを明確にするためです FindWindowの参考URLの最後のほうに 『Unicode:Windows NT/2000 は Unicode 版と ANSI 版を実装』と明記されている場合に Aliasで指定します GetSystemMenuはANSI/Unicodeの区別はありませんので Declare Function GetSystemMenu Lib "user32.dll" _ (ByVal hWnd as Integer, ByVal bRevert as Integer) as Integer といった具合の宣言で良いと思います
お礼
今更ですが、お礼の記載が大変遅くなり、申し訳ありません。 ありがとうございました。
補足
なるほど。 オーバーフローしてしまったのでLongに変えて作ってみました。 まだ分からないところがたくさんあるのですが、以下のように作ったところ、最小化ボタンは表示されたのですが「×」が使える状態なのですがどこが間違ってるのでしょうか? 標準モジュール Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _ (ByVal hWnd As Long, ByVal nIndex As Long) As Long Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Public Declare Function DrawMenuBar Lib "user32" _ (ByVal hWnd As Long) As Long Public Declare Function GetSystemMenu Lib "user32.dll" _ (ByVal hWnd As Long, ByVal bRevert As Long) As Long Public Declare Function DeleteMenu Lib "user32" _ (ByVal hMenu As Long, ByVal uPosition As Long, ByVal uFlags As Long) As Long Public Const GWL_STYLE = (-16) 'ウィンドウスタイルを取得 Public Const WS_MINIMIZEBOX = &H20000 '最小化ボタン Dim hSysMenu As Long Public Const MF_BYCOMMAND = &H0& Public Const SC_CLOSE = &HF060& Initializeプロシージャ Private Sub UserForm_Initialize() Dim fRet As Long Dim hWnd As Long Dim fStyle As Long UserForm1.Show vbModeless hWnd = FindWindow("ThunderDFrame", "UserForm1") fStyle = GetWindowLong(hWnd, GWL_STYLE) fStyle = (fStyle Or WS_THICKFRAME Or WS_MINIMIZEBOX) fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle) hSysMenu = GetSystemMenu(hWnd, 0) DeleteMenu hSysMenu, MF_BUCOMMAND, SC_CLOSE fRet = DrawMenuBar(hWnd) End Sub 度々すいません。
- redfox63
- ベストアンサー率71% (1325/1856)
ん~ インターネットがあるのですから調べてみましたか? MicrosoftのMSDNサイトやWinAPIを開設したサイトはたくさんありますよ 『疑問部分を全て説明しろ』と言うのは無理があるのです 最初のほうの Declare文はWinAPIをVBで使えるようにする宣言です FindWindowはどのような引数をとるのかを調べてみると ウィンドウクラス名とウィンドウのタイトルの2つが必要だと解説されているはずです http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpwinui/html/_win32_findwindow.asp これで取得したハンドルを使ってどのウィンドウに対する処理をするのかをWindowsに指示するわけです 『ThunderDFrame』はウィンドウクラス名です 『UserForm1』はユーザーフォームのCaptionプロパティに設定した文字列です 次のGetWindowLongですが タイトルバーに表示するタイトル名や最小化、最大化、閉じるのボタンなどのウィンドウの外観を変更するのに現在の設定を知る必要があるために使うAPIです http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_getwindowlong.asp GetWidowLongには引数nIndexに与えるデータによりさまざまなデータを取得可能なのです 今回は ウィンドウの外観なので GWL_STYLEを与えます ここで取得したデータを使って希望するスタイルにするための演算を行います fStyle = fStyle Or WS_MINIMIZEBOX とします もしも最大化ボタンが有効になっているのであれば そのスタイルを消去しないといけませんのでその場合は fSyle = fStyle And ( Not WS_MAXIMIZEBOX ) といった具合にします 今度は外観を変更するためにWindowsに依頼するAPIを使う必要があります これが SetWidowLongになります http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_setwindowlong.asp SetWindowLong/GetWindowLongは最初のSetとGetが違いと Getがデータを返すので引数は2つ Setはデータを設定するので3つの引数といった違いがあります この2つが対になっていることが理解できるでしょうか その参照URLコードには閉じるボタンの無効化は無いようです 閉じるボタンは ウィンドウの左肩にあるアイコンをクリックすると出る『移動』『サイズ変更』『最小化』『最大化』『閉じる』といったメニュを操作する事になります これをするには 宣言区に以下の3行を追加します Dim hSysMenu as Long Const MF_BYCOMMAND = &H0& Const SC_CLOSE = &HF060& DrawMenuBarを呼び出す前に以下の2行を追加します hSysMenu = GetSystemMenu( hWnd, 0 ) DeleteMenu hSysMenu, MF_BUCOMMAND, SC_CLOSE といった具合に使います http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_getsystemmenu.asp http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_deletemenu.asp ここまでやってからDrawMenuBarを呼び出して変更を反映させます http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_drawmenubar.asp
お礼
今更ですが、お礼の記載が大変遅くなり、申し訳ありません。 ありがとうございました。
補足
回答ありがとうございます。 プログラムにredfox63さんの言うとおりに追加したのですが、「エントリ GetSystemMenuAがDLLファイルuser32内に見つかりません」というエラーが出てしまったのですがこれはWinAPIをVBで使えるようにする宣言が間違ってしまったのでしょうか?以下の通りです。 Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _ (ByVal hWnd As Long, _ ByVal nIndex As Long) As Long Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hWnd As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Public Declare Function DrawMenuBar Lib "user32" _ (ByVal hWnd As Long) As Long Public Declare Function GetSystemMenu Lib "user32" Alias "GetSystemMenuA" _ (ByVal hWnd As String, _ ByVal bRevert As Boolean) As Long Public Declare Function DeleteMenu Lib "user32" Alias "DeleteMenuA" _ (ByVal hMenu As Long, _ ByVal uPosition As Long, _ ByVal uFlags As Long) As Long 新たに「GetSystemMenu」と「DeleteMenu」を追加したのですが、 「Public Declare Function DeleteMenu Lib "user32"」まではいいのですが、 その後ろに「Alias "DeleteMenuA"」をつけるのかつけないのか分かりません。データ型は調べたので合ってると思いますが。 よろしくお願いします。
- redfox63
- ベストアンサー率71% (1325/1856)
何処まで理解できていて 何が理解できていないのかを投稿しましょう WinAPIの使い方をすべて説明するのは困難ですよ 『X』の非表示自体は無理です、無効状態になら出来ますが ・・・ WinAPIで操作するにはまずウィンドウハンドルを取得する必要があります ... FindWindow 次に 最小化、最大化、閉じるボタンの表示、非表示の設定をするにはウィンドウスタイルを変更するAPIを使います ... GetWindowLong/SetWindowLong 最小化、最大化は単独で表示、非表示の切り替えが可能です 閉じるは最小化、最大化、閉じるの3個セットで表示、非表示の切り替えになります 閉じるの無効化をするためにはそのウィンドウのシステムメニューを操作する必要があります ... GetSystemMenu/DeleteMenu/DrawMenuBar
お礼
今更ですが、お礼の記載が大変遅くなり、申し訳ありません。 ありがとうございました。
補足
回答ありがとうございます。 参考URLからコピーしたものなんですが、まず最初に、 標準モジュール Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _ (ByVal hWnd As Long, _ ByVal nIndex As Long) As Long Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hWnd As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Public Declare Function DrawMenuBar Lib "user32" _ (ByVal hWnd As Long) As Long この部分が何をしているのか分かりません。 それから、 標準モジュール Public Const GWL_STYLE = (-16) 'ウィンドウスタイルを取得 Public Const WS_THICKFRAME = &H40000 'ウィンドウのサイズ変更 Public Const WS_MINIMIZEBOX = &H20000 '最小化ボタン Public Const WS_MAXIMIZEBOX = &H10000 '最大化ボタン この部分は恐らく「ウィンドウスタイルを取得」「最小化ボタン」が必要だとは分かります。あとの「ウィンドウのサイズ変更」「最大化ボタン」はこの場合は使用しないので必要ないと思います。 redfox63さんのおっしゃる「ウィンドウハンドルを取得する必要がある」というのは、 UserForm_Initializeプロシージャ Dim fRet As Long Dim hWnd As Long Dim fStyle As Long UserForm1.Show vbModeless 'ユーザーフォームを表示する hWnd = FindWindow("ThunderDFrame", "UserForm1") 'ユーザーフォームのハンドルを取得する fStyle = GetWindowLong(hWnd, GWL_STYLE) 'ウィンドウに関する情報を取得する fStyle = (fStyle Or WS_THICKFRAME Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX) 'Min,Maxメニューボタンを付加する fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle) 'ユーザーフォームに追加したボタンを設定する fRet = DrawMenuBar(hWnd) 'ユーザーフォームのメニューバー外枠を再描画する 「hWnd = FindWindow("ThunderDFrame", "UserForm1")」この部分でしょうか? 一番上の「UserForm1.Show vbModeless 」はいいとして、まず、 「"ThunderDFrame"」の意味が分かりません。それと「"UserForm1"」はオブジェクト名でしょうか? >次に 最小化、最大化、閉じるボタンの表示、非表示の設定をするにはウィンドウスタイルを変更するAPIを使います ... これは、「fStyle = GetWindowLong(hWnd, GWL_STYLE)」この部分でしょうか?ここでも何をしているのか分かりません。 >閉じるの無効化をするためにはそのウィンドウのシステムメニューを操作する必要があります これは、どこの部分を指すのでしょうか? 「fStyle = (fStyle Or WS_THICKFRAME Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX) 」この部分は説明の通りなので「Or WS_MINIMIZEBOX」のみにすればいいというのは分かるんですが。 「fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle)」この部分は全く分かりません。ただ、説明があるのでこの設定は絶対必要だというぐらいです。 「fRet = DrawMenuBar(hWnd)」ここも上記と同じです。 ほとんど分からないのですがすいませんが回答お願いします。
お礼
ありがとうございました。
補足
そのようですね。 すいませんがそれも教えてくれませんか? よろしくお願いします。