
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で質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) vba メモリ節約 3 2022/09/16 21:45
- Visual Basic(VBA) 標準モジュール Public mOnTime As Date Sub sample() '実行プロシ 1 2023/02/22 15:44
- Excel(エクセル) VBAで、㉑という数値が、正しく、入力できない 2 2022/07/26 20:22
- Visual Basic(VBA) batからexeを実行し戻り値を受け取る バッチからEXEの結果を受け取りたいのですが、 下記のバッ 1 2023/07/04 15:13
- Visual Basic(VBA) マクロについて教えてください。 4 2023/06/06 09:06
- Visual Basic(VBA) batからexeを実行し戻り値を受け取る EXEの実行内容の結果によって、戻り値を0か1かで返したい 1 2023/07/04 16:40
- Visual Basic(VBA) VBA This Workbookモジュールを別ファイルにコピーする方法 1 2022/09/14 01:51
- Visual Basic(VBA) Excel・ユーザーフォームの情報を受け渡したい 4 2022/06/08 10:11
- Visual Basic(VBA) マクロについて教えてください。 1 2023/06/06 00:57
- Visual Basic(VBA) パーソナルXLSBのfuctionを呼び出すと「Functionが定義されていません」のエラーになる 2 2022/08/22 22:51
このQ&Aを見た人はこんなQ&Aも見ています
-
エクセルのラベルの値(文字列)を垂直方向で中央揃えにするには?
Excel(エクセル)
-
最小化ボタンで最小化したフォームを最小化から復帰するには?
Visual Basic(VBA)
-
最小化最大化のボタンの表示をVBAで設定できない
その他(Microsoft Office)
-
-
4
ユーザーフォームのテキストボックスに前回入力した値を表示する Excel
Visual Basic(VBA)
-
5
ユーザーフォームを表示中にシートの操作をさせるには
Excel(エクセル)
-
6
最小化のボタンだけ表示したいのですが…
Visual Basic(VBA)
-
7
VBA(エクセル)で自動的にボタンをクリックさせるには
その他(プログラミング・Web制作)
-
8
ExcelVBAでテキストボックスの表示形式を小数点第二位まで表示する方法
Visual Basic(VBA)
-
9
エクセルVBAでUserFormを起動した時
Excel(エクセル)
-
10
excelのInitializeイベントとActivateイベントについて
Excel(エクセル)
-
11
2画面表示でのVBAのボタン押下後のform表示の位置
Excel(エクセル)
-
12
VBAでユーザーフォームを再表示させたい。
Excel(エクセル)
-
13
エクセルVBA テキストボックスに3桁ごとにコンマ
Visual Basic(VBA)
-
14
VBA:ユーザーフォームのマルチページに色を付けたい。
Word(ワード)
-
15
ユーザーフォームをホイールでスクロールする方法(Excel2000VBA)
Excel(エクセル)
-
16
フォームのテキストボックスの値をコピーしたい
Excel(エクセル)
-
17
エクセルVBAでマルチページの切り替え方法の件で
Excel(エクセル)
-
18
VBAのテキストボックスに文字列を貼り付ける方法
Access(アクセス)
-
19
エクセルVBAでテキストボックスに入力があった場合のみ、ワークシートに転記したい
Visual Basic(VBA)
-
20
ExcelVBA EnableプロパティがFalseの時に文字の色を変えたくない
Visual Basic(VBA)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ユーザー定義関数に#NAME?が返...
-
VBAで別モジュールへの変数の受...
-
vba userFormのSubを標準モジュ...
-
モジュールとクラスの違いって...
-
エクセルVBAでシートモジュール...
-
Excel VBA 定義されたプロージ...
-
モジュールからフォームのボタ...
-
VBAで旧字体を異字体に一括で変...
-
大量の標準モジュールを解放す...
-
acwzlibとは?
-
VBAのモジュールについて教えて...
-
'Range'メソッドは失敗しました
-
Excel VBA 『Call』で呼び出す...
-
Excelシート内セル記述の違いに...
-
xoops myAlbum-Pで画像がアッ...
-
VBのフォームモジュールと標準...
-
プログラムでノッチフィルタの...
-
AddressOf と同じ機能を持った...
-
VBIDEで未使用の変数の抽出
-
【Excel VBA】標準モジュールに...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Excel VBAでリンク切れをチェッ...
-
Excel VBAで、ユーザーフォーム...
-
ユーザー定義関数に#NAME?が返...
-
vba userFormのSubを標準モジュ...
-
Excel VBA 定義されたプロージ...
-
モジュールとクラスの違いって...
-
モジュールの最大数はいくつな...
-
VBAで別モジュールへの変数の受...
-
Excel VBA 『Call』で呼び出す...
-
エクセルVBAでシートモジュール...
-
VBでグローバル変数を宣言するには
-
【vba】フォームに書いてあ...
-
SendKeysの使い方について
-
モジュールからフォームのボタ...
-
VBAで旧字体を異字体に一括で変...
-
モジュールとは何ですか
-
ExcelでTelnetを動かしたい
-
標準モジュールを削除したい。(...
-
VBA This Workbookモジュール...
-
Access VBA標準モジュールにつ...
おすすめ情報