http://www.serpress.co.jp/excel/vba047.html
を参考にエクセルのユーザーフォームに
最小化、最大化ボタンを付けたいのですがうまく出来ません。
バージョンは2003です。
リンク先の「作成するモジュール」の中身を標準モジュールにコピペしたら
「vbModeless」が「プロシージャの外では無効です。」になります。
なので、全てをフォームモジュールに貼り付けると
Public Constがエラーになるので
Public Constだけ標準モジュールに貼り付けました。
でもフォームモジュールでも
「vbModeless」
が「プロシージャの外では無効です。」になります。
なにを標準モジュールにはりつけて
何をフォームモジュールにはりつければいいか教えてください。
No.3ベストアンサー
- 回答日時:
#1、cjです。
では、実際の運用例を掲げておきますね。
もうかれこれ8年ぐらい使ってもらっている、という意味では実績ある手法です。
標準モジュールとUserFormモジュールを併せて使う例、ですが、
#こういう書き方を不慣れな人に奨めるつもりはないのですけれどね。
無用な混乱で消化不良になってしまうのは、私の、本意ではありません。
必要がないとお感じになられたら、遠慮なくスルーしてください。
' ' =====================UserFormモジュール====================
Option Explicit
Private Sub UserForm_Initialize()
Call FrmDec(Me)
End Sub
Private Sub UserForm_Activate()
Repaint
End Sub
' ' ===================以上UserFormモジュール==================
' ' =======================標準モジュール======================
Option Explicit
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 Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hWnd As Long) As Long
Private Const GWL_STYLE = (-16)
Private Const WS_THICKFRAME = &H40000
Private Const WS_MINIMIZEBOX = &H20000
Private Const WS_MAXIMIZEBOX = &H10000
Private Const LP_CLASSNAME = "ThunderDFrame"
Sub FrmDec(frm As UserForm)
Dim fRet As Long
Dim hWnd As Long
Dim fStyle As Long
Load frm
With frm
hWnd = FindWindow(LP_CLASSNAME, .Caption)
fStyle = GetWindowLong(hWnd, GWL_STYLE)
fStyle = (fStyle Or WS_THICKFRAME Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX)
fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle)
fRet = DrawMenuBar(hWnd)
End With
End Sub
' ' =====================以上標準モジュール====================
' ' =========呼び出し=========
Sub test7764861c() ' UserFormのオブジェクト名を、正しく指定
UserForm1.Show vbModeless
End Sub
' ' =======以上呼び出し=======
複数のUserFormに適用できるような書き方、というご都合的な面もありますが、
本来標準モジュールに書くべきものを標準モジュールに書く、という到って普通のことをしているだけです。
実際には、他の標準モジュールの記述と混ぜないように、専用の標準モジュールに纏めるべきですね。
確認しておいて欲しいのは、この場合でも「Publicである"必要"はまったくない」ということです。
一応、UserFormモジュールを使わずに標準モジュールだけで完結するシンプルな書き方もありますが、
一長一短、後で、仕様変更したい時とかの対応のし易さなどから、
_Initialize() イベント、_Activate() イベントは併用しておいた方がよい、
というのが私の結論です。
複数のUserFormといっても、多くて2つもあれば、大概のことはできますし、
せいぜい3つ、それ以上はそもそもExcelにとってアウトオブオーダーだと思います。
UserFormひとつであったとしても上記のような運用をした方がよいのは、Controlsの数が多い場合ですね。
何が必要で何が十分かというのは、別に取決めがある訳ではないので、
どうしても"多い"とか抽象的な言い方にはなってしまいますけれど。
で、まぁ、#1の書き方は私も初学の頃に、本を参考に書いていた覚えがあります。
解り易く、扱い易い、オリエンテーション的な答えであって、実践はまた少し違ってたりする、という話です。
また、今回用いたAPI関数については、何か重篤なトラブルを招くようなものではない筈ですから、
API関数に慣れるきっかけという意味では悪くないテーマだと思いますよ。
ただ、#2さんも仰っているように、安易に、いたずらに、APIを使うのは、難がありますね。
本当にその機能が必要なのか、目的を果たすのに他に方法はないのか、よく吟味したほうがよいです。
本当に必要ならAPIに対して消極的になることもないと思いますが、
VBAですからね。VBAやExcelで完結できるものを優先に検討して設計するのがベターではあります。
それから、リンク先のコードについては
> '***** ボタンを表示する処理 ***** < 以降の記述を
Sub Test()
End Sub
のようなプロシージャの内側に収めて使う、ということが省略されている
のは理解されてますでしょうか?
そこらへんで違っていたとして
> プロシージャの外では無効です。
というエラーになるのだろう、というのが#2さんのお考えで、
そういう基本的な事柄を整理できずにAPIを扱うのはやや尚早、というお話なのだと思います。
他の条件でも発動するエラーなので、私には判断付きませんけれど。
さて、本来の質問者さんが必要とする答えとは随分とかけ離れた話に拡がってしまって
却って解りにくくしてしまっているかも知れません。
先々を考えて老婆心からくるアドバイスってことになるのでしょうか。
食べきれない料理が出てきたら、残してもいい、みたいな軽い気持ちで
適当にスルーしてやってくださいませ。
No.4
- 回答日時:
#1,3、cjです。
#3について、2か所訂正です。
> Sub FrmDec(frm As UserForm)
の
> Load frm
を削除。
Sub test7764861c()
を
Sub test7764861c() ' UserFormのオブジェクト名を、正しく指定
Load UserForm1
UserForm1.Show vbModeless
End Sub
に差し換え。
以上のように修正をお願いします。失礼しました。
No.2
- 回答日時:
こんにちは。
>なにを標準モジュールにはりつけて
>何をフォームモジュールにはりつければいいか教えてください。
リンク先のコードは、一部、省略している部分があります。
そのリンク先の作者の考え方は、Win32 APIの宣言は標準モジュールを使う、、
「'***** ボタンを表示する処理 *****」
以降は、UserForm モジュール以外の、どこかのモジュールに、Sub プロシージャか、コマンドボタンにして、中身のコードを貼り付けることです。
厳しいようですが、そのコードをみて、ひと目でこの程度は分からないと、Win32 APIはあまりお勧めできないように思います。
「vbModeless」でUserFormを立ち上げれば、十分ではないでしょうか。
参照先では、
「Excelでユーザーフォームを表示しているときにせっかくのExcelワークシートが参照できない。」と書いてありますが、そんなことはありません。UserFormを画面からずらせばよいだけです。
誰でも、最初はありますし、最初は見よう見まねで試すものだと思います。ただ、問題は、その先に、あまり、Win32 APIやC言語の知識のない方は乱用はしてほしくない、とも個人的には思うのです。Win32 APIの大事な基礎的知識があります。また、Win32 APIは使い方によっては、今お使いのPCに重大なトラブルを発生させる原因にもなりかねません。
コーディング・スタイルについては、VBの場合は、Formモジュールにまとめることが多いのですが、VBAの場合は、少し特殊な事情があって、私の単なる想像なのかもしれませんが、UserForm, Sheet などのVBAを司る部分、いわゆるローカルモジュールは、VBA側のメモリ割り当てが少ないのではないか、という懸念があって、そのモジュール当てるコードの量を制限することがあります。したがって、複雑な操作は、標準モジュールに助けを借りるというようなスタイルにしています。
単独で、UserFormオブジェクトを用いる場合は、標準モジュールは使わないほうが、可読性が上がります。しかし、Win32 APIを使っていて、モノによっては突然のクラッシュ(AppCrash)に見舞われることがあるので、なかなか、ローカルモジュールのみに、あれこれと詰め込むことが出来ないのです。もちろん、標準モジュールに逃した所で、その度合が変わるという実証があるわけではありません。たんなる、感覚的なものだけです。
概して、このWin32 APIの宣言だけを別にして、標準モジュールに単独でまとめてしまうことが多いようです。そのワークブックで、Win32 APIを必要とするものの全体が分かり、重複が避けられるようになります。私自身、そのようにすることを、学びました。
No.1
- 回答日時:
こんにちは。
とりあえず、すべてUserFormモジュールで完結させた方が扱い易いですから、
まとめてみました。
冒頭宣言部分は必ずUserFormモジュールの先頭においてください。
試す時は、新規のブックにUserFormの追加だけしてからの方が紛れがなくて
いいかも知れません。
注意点として、UserFormを右上の×で閉じる分には良いのですが
UserForm1.Hide とか使うようでしたら、最後に必ず Unload UserForm1
で終わるようにしてください。
UserFormモジュールの記述はUserFormの名前やキャプションに依存しない形で
書いてあります。
' ' =====================UserFormモジュール====================
Option Explicit ' 7764861cj
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 Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hWnd As Long) As Long
Private Const GWL_STYLE = (-16)
Private Const WS_THICKFRAME = &H40000
Private Const WS_MINIMIZEBOX = &H20000
Private Const WS_MAXIMIZEBOX = &H10000
Private Const LP_CLASSNAME = "ThunderDFrame"
Private Sub UserForm_Initialize()
Dim fRet As Long
Dim hWnd As Long
Dim fStyle As Long
hWnd = FindWindow(LP_CLASSNAME, Caption)
fStyle = GetWindowLong(hWnd, GWL_STYLE)
fStyle = (fStyle Or WS_THICKFRAME Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX)
fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle)
fRet = DrawMenuBar(hWnd)
End Sub
Private Sub UserForm_Activate()
Repaint
End Sub
' ' ===========================================================
UserFormを表示する記述は以下です。UserForm名は指定を正してください。
' ' ======================
Sub test()
Load UserForm1
UserForm1.Show vbModeless
End Sub
' ' ======================
Load → .Show → .Hide → .Show → .Hide .... → UnLoad (QueryClose)
のような使い方をするならば、
Load UserForm1
は、1回で十分です。
UserForm1.Show vbModeless
だけでも、いいのですけれど、表示を操作したUserFormは
.Show → .Hide → .Show → .Hide ....で使うのが普通ですから、
どこでLoadするのか明示的にした方が良いかと思います。
備考ですが、
手動でリサイズできるというのも却って面倒な面もあります。
もし、リサイズ出来ないようにしたい場合は
fStyle = (fStyle Or WS_THICKFRAME Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX)
を
fStyle = (fStyle Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX)
にするといいでしょう。
蛇足ですが、、、。
私個人は、標準モジュールを使うこともありますが、必要でなければ
UserFormモジュールに纏めたほうがいいと思っています。
ここら辺は考え方が分かれるところかも知れませんが、
必要ないのにPublicを使わない、Privateで十分なものはPrivate、
という考え方です。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
映画のエンドロール観る派?観ない派?
映画が終わった後、すぐに席を立って帰る方もちらほら見かけます。皆さんはエンドロールの最後まで観ていきますか?
-
フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
あなたが普段思っている「これまだ誰も言ってなかったけど共感されるだろうな」というあるあるを教えてください
-
映画のエンドロール観る派?観ない派?
映画が終わった後、すぐに席を立って帰る方もちらほら見かけます。皆さんはエンドロールの最後まで観ていきますか?
-
海外旅行から帰ってきたら、まず何を食べる?
帰国して1番食べたくなるもの、食べたくなるだろうなと思うもの、皆さんはありますか?
-
天使と悪魔選手権
悪魔がこんなささやきをしていたら、天使のあなたはなんと言って止めますか?
-
エクセルのラベルの値(文字列)を垂直方向で中央揃えにするには?
Excel(エクセル)
-
ユーザーフォームを表示中にシートの操作をさせるには
Excel(エクセル)
-
エクセルVBAでマルチページの切り替え方法の件で
Excel(エクセル)
-
-
4
ExcelVBA:フォームの最小化ボタンを表示し、閉じるボタン「×」を消す方法
Visual Basic(VBA)
-
5
[VBA] UserForm を Excel の Window の前面に表示させない方法
その他(プログラミング・Web制作)
-
6
ListView 項目の選択/選択解除について
Visual Basic(VBA)
-
7
Excel VBAでユーザーフォームだけ表示したい
Visual Basic(VBA)
-
8
エクセルVBAでUserFormを起動した時
Excel(エクセル)
-
9
リストビューをスクロールさせるには
Visual Basic(VBA)
-
10
VBA:ユーザーフォームのマルチページに色を付けたい。
Word(ワード)
-
11
【VBAユーザーフォームで閉じるボタンを表示したくない】
Visual Basic(VBA)
-
12
VBAのコマンドボタンの文字列の改行方法は?
Visual Basic(VBA)
-
13
VBAでユーザーフォームを再表示させたい。
Excel(エクセル)
-
14
最小化のボタンだけ表示したいのですが…
Visual Basic(VBA)
-
15
エクセルVBA オプションボタンのチェックを外したい
Excel(エクセル)
-
16
VBAのTextBoxに半角数字のみ入力したい
Visual Basic(VBA)
-
17
ListViewから選択中の文字列を取得
Visual Basic(VBA)
-
18
VBAでマルチページのページ指定方法
Visual Basic(VBA)
-
19
UserForm
Visual Basic(VBA)
-
20
Listviewのデータを上から順番に取得 VBA
Visual Basic(VBA)
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Excel VBAでリンク切れをチェッ...
-
ユーザー定義関数に#NAME?が返...
-
モジュールの最大数はいくつな...
-
【vba】フォームに書いてあ...
-
vba userFormのSubを標準モジュ...
-
Excel VBAで、ユーザーフォーム...
-
VBAで旧字体を異字体に一括で変...
-
Excel VBA 『Call』で呼び出す...
-
グラフのX,Y座標を取得したい
-
シートモジュールで使う変数を...
-
'Range'メソッドは失敗しました
-
ExcelVBA:パブリック オブジェ...
-
VBでグローバル変数を宣言するには
-
ベースモジュールって?
-
ASPでPDFファイルを動的に生成...
-
VBAで別モジュールへの変数の受...
-
VBA This Workbookモジュール...
-
どのファイルを開いた時もマク...
-
EXECEL VBA コマンドボタンか...
-
印刷後メッセージボックスを表...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Excel VBAでリンク切れをチェッ...
-
エクセルVBAでシートモジュール...
-
VBでグローバル変数を宣言するには
-
Excel VBAで、ユーザーフォーム...
-
VBAで旧字体を異字体に一括で変...
-
ユーザー定義関数に#NAME?が返...
-
VBA This Workbookモジュール...
-
Excel VBA 『Call』で呼び出す...
-
【vba】フォームに書いてあ...
-
Access VBA標準モジュールにつ...
-
モジュールの最大数はいくつな...
-
'Range'メソッドは失敗しました
-
vba userFormのSubを標準モジュ...
-
VBAで別モジュールへの変数の受...
-
グラフのX,Y座標を取得したい
-
標準モジュールを削除したい。(...
-
VBAProjectのモジュ...
-
ExcelVBA:パブリック オブジェ...
-
Excel VBA 標準モジュール内で...
-
acwzlibとは?
おすすめ情報