Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


8792 / 13646 ツリー ←次へ | 前へ→

【13756】コントロール 年寄り 04/5/12(水) 19:58 質問[未読]
【13758】Re:コントロール ichinose 04/5/12(水) 22:01 回答[未読]
【13769】大きなサイズのフォーム 年寄り 04/5/13(木) 3:45 質問[未読]
【13771】Re:大きなサイズのフォーム ichinose 04/5/13(木) 8:15 発言[未読]
【13772】Re:大きなサイズのフォーム 年寄り 04/5/13(木) 8:57 お礼[未読]
【30550】Re:大きなサイズのフォーム 年寄り 05/10/30(日) 17:10 質問[未読]
【30570】Re:大きなサイズのフォーム 再送 ichinose 05/10/31(月) 7:37 発言[未読]
【30592】Re:大きなサイズのフォーム 再送 年寄り 05/10/31(月) 16:05 発言[未読]
【30605】Re:大きなサイズのフォーム 再送 年寄り 05/10/31(月) 19:47 発言[未読]
【30607】Re:大きなサイズのフォーム 再送 年寄り 05/10/31(月) 21:06 質問[未読]
【30608】Re:大きなサイズのフォーム 再送 ichinose 05/10/31(月) 21:42 発言[未読]
【30618】Re:大きなサイズのフォーム 再送 年寄り 05/11/1(火) 7:17 お礼[未読]
【30621】Re:大きなサイズのフォーム 再送 年寄り 05/11/1(火) 11:25 質問[未読]
【30622】Re:大きなサイズのフォーム 再送 ichinose 05/11/1(火) 12:16 発言[未読]
【30643】Re:大きなサイズのフォーム 再送 年寄り 05/11/1(火) 19:11 質問[未読]
【30645】Re:大きなサイズのフォーム 再送 ichinose 05/11/1(火) 20:16 発言[未読]
【30651】Re:大きなサイズのフォーム 再送 年寄り 05/11/1(火) 20:48 発言[未読]
【30658】Re:大きなサイズのフォーム 再送 ichinose 05/11/1(火) 22:41 発言[未読]
【31049】Re:大きなサイズのフォーム 再送 年寄り 05/11/10(木) 6:20 質問[未読]
【31050】Re:大きなサイズのフォーム 再送 ichinose 05/11/10(木) 7:53 発言[未読]
【31066】Re:大きなサイズのフォーム 再送 ichinose 05/11/11(金) 8:33 発言[未読]
【31111】Re:大きなサイズのフォーム 再送 年寄り 05/11/11(金) 17:16 発言[未読]
【31170】Re:大きなサイズのフォーム 訂正 ichinose 05/11/14(月) 8:12 発言[未読]
【31172】Re:大きなサイズのフォーム 訂正 年寄り 05/11/14(月) 8:47 発言[未読]

【13756】コントロール
質問  年寄り  - 04/5/12(水) 19:58 -

引用なし
パスワード
   マルチページとタブストリップのすっきりした区別がつきません。

またそれぞれは2ページづつしかないのですか?もし3ページ以上あるのならどのプロパティに触れますか?

フォーム上でのことです。

【13758】Re:コントロール
回答  ichinose  - 04/5/12(水) 22:01 -

引用なし
パスワード
   ▼年寄り さん:
こんばんは。
マルチページやタブストリップオブジェクトは、それぞれPageオブジォクト、Tabオブジェクトのコンテナ、つまり、これらのオブジェクトは、マルチページ、タブストリップを
通して、操作するということを冒頭に記述しておきます。(ほとんど、HELPより)
そして、Pageオブジォクト、Tabオブジェクトは、その集合体であるコレクションのAddメソッドを使用することにより、Page又は、Tabオブジェクトを増やす事が出来ます。

マルチページのページを増やすコード例として、

     MultiPage1.Pages.Add "オブジェクト名", "表示見出し"

又、VBEにて、フォームデザイン時に増やす事もできます。

   マルチページの既存のページのタブを選択し、
   「右クリック」---「新しいページ」

を行って下さい。

タブストリップもほとんど同じです。

>マルチページとタブストリップのすっきりした区別がつきません。

実は、途中まで書き出したのですが、あんまり長くなってしまったので
止めました。

代わりに

http://www.sigoto.co.jp/excel/activex/actmenu04.htm

↑の「マルチページとタブストリップの違い」
を参考にしてみてください。


年寄り さんの他のご質問も拝見させていただきました。
60歳を越えているとの事、本当に頭が下がります。
頑張って下さい。

【13769】大きなサイズのフォーム
質問  年寄り  - 04/5/13(木) 3:45 -

引用なし
パスワード
   すっきりしました。どうもありがとうございます。

フォームのことなのでさらにここで質問を続けさせていただきます。

モニタを外れる程の縦長の大きなサイズのフォームを作ります。フォームのプロパティを開け高さの項目に大きな値を入れます。たくさんのコントロールを置きます。もちろんフォームの底の方にもコントロールがあります。さてVBAでフォームをモニタに出現させます。どうやってモニタの下の部分をスクロールさせますか?

【13771】Re:大きなサイズのフォーム
発言  ichinose  - 04/5/13(木) 8:15 -

引用なし
パスワード
   ▼年寄り さん:
おはようございます。
>
>フォームのことなのでさらにここで質問を続けさせていただきます。
>
>モニタを外れる程の縦長の大きなサイズのフォームを作ります。フォームのプロパティを開け高さの項目に大きな値を入れます。たくさんのコントロールを置きます。もちろんフォームの底の方にもコントロールがあります。さてVBAでフォームをモニタに出現させます。どうやってモニタの下の部分をスクロールさせますか?

UserformのHeightプロパティに大きな数値を設定したと言う事ですよね?

そういう場合もあるのでしょうね(どういう場合にか?というと例が頭に浮かびませんが)。

私がこういう事例で設定する場合、

このHeightプロパティは、画面サイズに収まるような値を設定します。
で、年寄り さんのおっしゃる「大きな値」は、Scrollheightというプロパティに設定します。
尚、近い場所に「Scrollbarsvisible」と「Scrollbars」というプロパティがありますから、これを「2」(Fmscrollbarsvertical)に設定して下さい。

すると、スクロールバーがデザインフォームに表示されます。

上下することでフォームの下にコントロールを配置できます。

この設定でフォームを表示すると、スクロールバーが表示され、バーの上下移動により、
下のコントロールも表示可能となると思います。

ScrollHeightで設定する値が仮想高さ、Heightで設定する値が実高さ
という解釈でいかがでしょうか?

【13772】Re:大きなサイズのフォーム
お礼  年寄り E-MAIL  - 04/5/13(木) 8:57 -

引用なし
パスワード
   有難うございます。
早速試してみることに成功しました。
今後ともお願いいたします。

【30550】Re:大きなサイズのフォーム
質問  年寄り E-MAILWEB  - 05/10/30(日) 17:10 -

引用なし
パスワード
   >尚、近い場所に「Scrollbarsvisible」と「Scrollbars」というプロパティがありますから、これを「2」(Fmscrollbarsvertical)に設定して下さい。
>
>すると、スクロールバーがデザインフォームに表示されます。
>

この場合スクロールバーの上端と下端はユーザーフォーム上のそれと同じになりますね。スクロールバーをユーザーフォーム上の中段にぶら下げて、上下に固定の位置を確保する方法はありますか?そこに他のコントロールを置きたい。

古い話を持ち出しました。

【30570】Re:大きなサイズのフォーム 再送
発言  ichinose  - 05/10/31(月) 7:37 -

引用なし
パスワード
   ▼年寄り さん:
おはようございます。

>この場合スクロールバーの上端と下端はユーザーフォーム上のそれと同じになりますね。スクロールバーをユーザーフォーム上の中段にぶら下げて、上下に固定の位置を確保する方法はありますか?そこに他のコントロールを置きたい。
この文章、何回か読み直したのですが、はっきりと年寄り さんがなさりたい
事が私には把握できませんでした。

が、感です・・・。

おそらくは、シート上でいうウインドウ枠の固定のような事を
したいという解釈です。


だとすれば・・・、

方法として二つほどご紹介します。

準備としては、新規ブックに
ユーザーフォームを
二つ準備してください。
(Userform1とUserform2)


ユーザーフォームのみでコントロールは何も配置しないでください。
ユーザーフォームの大きさやコントロールは、コードで配置します。

方法1
 フレームを使用する方法

Userfrom1のモジュールに

'===============================================================
Private Sub UserForm_Initialize()
  Dim frm As MSForms.Frame
  Dim idx As Long
  With Me
   .Height = 300
   .Width = 420
   End With
  Set frm = Controls.Add("Forms.Frame.1")
  With frm
    .Top = 75
    .Height = 200
    .Width = 400
    .Left = 5
    .Caption = "フレーム"
    .ScrollBars = 2
    .ScrollHeight = 1000
    .SpecialEffect = fmSpecialEffectSunken
    For idx = 1 To 20
     With .Controls.Add("Forms.TextBox.1")
      .Top = (idx - 1) * 50 + 20
      .Left = 30
      End With
     Next
    End With
End Sub

標準モジュールには
'======================================================
sub disp1()
  userform1.show
end sub


これでdisp1を実行してみてください。
この表示イメージがなさりたいことだと思いますが・・・。

要は、フレームオブジェクトにコントロールを貼り付ける方法です。

フレームもユーザーフォームと同じように

>で、年寄り さんのおっしゃる「大きな値」は、Scrollheightというプロパティに設定
>します。
>尚、近い場所に「Scrollbarsvisible」と「Scrollbars」というプロパティがあります
>から、これを「2」(Fmscrollbarsvertical)に設定して下さい。

という設定が出来ます。


本当は、このフレームにバグがなければ、これで良いのですが・・。

http://www.h3.dion.ne.jp/~sakatsu/Excel_Tips03.htm

これを見てください。
フレームには、バグがあるのでフレームにテキストボックスの配置は
お勧めできません。
(オプションボタン等でしたら、これでもOKだと思いますが・・)。


方法2

マルチページを使用する。


userform2のモジュールに

'====================================================================
Private Sub UserForm_Initialize()
  Dim p As Page
  Dim sz As Double
  Dim wk As String
  Dim idx As Long
  With Me
   .Height = 300
   .Width = 420
   End With
  With Controls.Add("Forms.MultiPage.1")
    .Top = 75
    .Left = 5
    .Height = 200
    .Width = (9.75 * 40 + 12) + 0.75
    .Pages.Remove 1
    With .Font
     .Name = "MS ゴシック"
     .Size = 10
     sz = Int(.Size / 0.75) * 0.75
     End With
    Set p = .Pages(0)
    p.Caption = String(Int((Int(.Width / 0.75) * 0.75 - 12.75) / sz), " ")
    wk = p.Caption
   
    Mid(wk, 1, 9) = "マルチページ使用例"
    p.Caption = wk
    p.ScrollBars = 2
    p.ScrollHeight = 1000
    For idx = 1 To 20
     With p.Controls.Add("Forms.TextBox.1")
      .Top = (idx - 1) * 50 + 20
      .Left = 30
      End With
     Next
    End With
End Sub

'標準モジュールには
'======================================================
sub disp2()
  userform2.show
end sub


これでdisp2を実行してみてください。

本来、マルチページは複数ページを要して、同じエリアに異なるコントロールを
配置するものですが、上記のコードでは、ページをひとつにしています。

つまり、フレームの代わりにマルチページを使用する方法です。
マルチページもスクロール処理が可能です。
>ページタブもCaptionプロパティに空白を詰めて形を整えました。
>これだとテキストボックスでも使用できると思いますが・・・。


二つともコードでの設定ですが、
これは説明の都合上という意味で
VBEによる事前設定はもちろん可能です。


と思っていましたが、
(というのも先日、マルチページにテキストボックスを配置したコードで
Enterイベントを使用して問題なく作動していたので そう思い違いをしていました)

マルチページでも似たようなバグが発生します。

角田さんの
http://www.h3.dion.ne.jp/~sakatsu/Excel_Tips03.htm

にもちゃんと書いてありました。

結構、ショック・・・。
う〜、マルチページで代役が務まると思っていたので・・・。


ということで、
年寄り さんがなさりたい事が上記の二つ方法であった場合でも
Exitイベントを使う場合は いずれも要注意です。

【30592】Re:大きなサイズのフォーム 再送
発言  年寄り E-MAILWEB  - 05/10/31(月) 16:05 -

引用なし
パスワード
   ご親切に対応していただきまして誠にありがとうございます。

希望していたことはichinoseさんが感じ取っていただいたことと同じです。どうも年を取ると語彙は少なくなるし、独善的になるようで(私だけかな?)いけないですね。上手に表現できずにすみません。

200位の品目があります。品番と品名を頼りに入庫数量(またある時は出庫数量、あるいはその訂正数量)を入力する。品番順に並んだ一覧表の紙から入力します。ところが入力の際、一覧表の行を間違えて飛ばしたりしますね。入力時、現在入力している行の情報をスクロールの中央と、ユーザーフォーム固定の上部の両方に表示します。スクロールの他の部分には、当該行の周辺のデータが表示されます。間違えた場合にその周りを判断して適切な値を直ぐに入れられるようにします。もう一つの固定部分下段には、キャンセルと書込みのコマンドボタンを配置します。

上記のことを要望していました。また上手に伝えることが出来ないでいるかもしれませんね。

>    For idx = 1 To 20
>     With .Controls.Add("Forms.TextBox.1")
>      .Top = (idx - 1) * 50 + 20
>      .Left = 30
>      End With
>     Next
コードで追加されたLabelやTextBoxのCaption、Valueはどうやって取得しますか?
.Left = 30の次の行に .Value = としようとしたのですが?

急に寒くなり、体調を崩しました。返答が遅くなったことを謝ります。

【30605】Re:大きなサイズのフォーム 再送
発言  年寄り E-MAILWEB  - 05/10/31(月) 19:47 -

引用なし
パスワード
   分かりました。
UserForm1では
    frm.Controls(idx).Value
であり、UserForm2では
    p.Controls(idx).Valueや.Captionですね。

それにしてもExcelのバグとは残念ですね。

【30607】Re:大きなサイズのフォーム 再送
質問  年寄り E-MAILWEB  - 05/10/31(月) 21:06 -

引用なし
パスワード
   質問を変えます。

コードで作成したコントロールのイベント(ClickやEnter)は何処にどのように記述しますか?

【30608】Re:大きなサイズのフォーム 再送
発言  ichinose  - 05/10/31(月) 21:42 -

引用なし
パスワード
   ▼年寄り さん:
こんばんは。

>希望していたことはichinoseさんが感じ取っていただいたことと同じです。どうも年を
>取ると語彙は少なくなるし、独善的になるようで(私だけかな?)いけないですね。上
>手に表現できずにすみません。
私も結構な年なんですが、私の場合は、若い頃からボキャブラリ不足でした。
だから、このサイトの投稿もかなり必死なんです。
同じ内容を手を変え、品を変え・・・。
ちょうど、英語があまり話せない人が身振り手振りのボディランゲージで
何とか意思を伝えようとしているのと同じです。

さて、
>質問を変えます。
先にお断りしておきますが、コードでコントロールを配置したのは
あくまでも説明の都合上でこういうコードにがよいという意味ではありません。

VBEでの事前配置も考慮して下さいね!!

一長一短ありますからね!!

200行はちょっと多いかなあ?
まっ、やってみて下さい。駄目なら、スプレッドシートを使う事も考えましょう!!

とりあえず、
>コードで作成したコントロールのイベント(ClickやEnter)は何処にどのように記述しますか?
これについて・・・。
前回のマルチページにテキストボックスを配置した例を使用しますが・・。

その前にイベントを記述するモジュールを確保します。

クラスモジュールを使用します。
クラス名は 規定のClass1とします。
(VBEにて「挿入」---「クラスモジュール」で作成されます)

このクラスモジュールに

'============================================================
Public WithEvents txt As MSForms.TextBox
Public id As Long
'======================================================================
Private Sub txt_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = 13 Or KeyCode = 9 Then
   If Not IsNumeric(txt.Text) Then
     MsgBox "数字を指定して!!"
     KeyCode = 0
     End If
   End If
End Sub


では、前回のUserform2のモジュールは、

'=============================================
Dim c_txt(1 To 20) As Class1
'=============================================
Private Sub UserForm_Initialize()
  Dim p As Page
  Dim sz As Double
  Dim wk As String
  Dim idx As Long
  With Me
   .Height = 300
   .Width = 420
   End With
  With Controls.Add("Forms.MultiPage.1")
    .Top = 75
    .Left = 5
    .Height = 200
    .Width = (9.75 * 40 + 12) + 0.75
    .Pages.Remove 1
    With .Font
     .Name = "MS ゴシック"
     .Size = 10
     sz = Int(.Size / 0.75) * 0.75
     End With
    Set p = .Pages(0)
    p.Caption = String(Int((Int(.Width / 0.75) * 0.75 - 12.75) / sz), " ")
    wk = p.Caption
   
    Mid(wk, 1, 9) = "マルチページ使用例"
    p.Caption = wk
    p.ScrollBars = 2
    p.ScrollHeight = 1000
    For idx = 1 To 20
     Set c_txt(idx) = New Class1
     With c_txt(idx)
      .id = idx
      Set .txt = p.Controls.Add("Forms.TextBox.1")
      With .txt
       .Top = (idx - 1) * 50 + 20
       .Left = 30
       End With
      End With
     Next
    End With
End Sub

と変更して下さい。

これで、標準モジュールに

sub main()
 userform2.show
end sub

とし、実行してみて下さい。

提示したコードは、

テキストボックスに数字以外を指定してEnterキー又は、Tabキーを
押すとエラーメッセージを表示するコードです。

確認して下さい。

【30618】Re:大きなサイズのフォーム 再送
お礼  年寄り E-MAILWEB  - 05/11/1(火) 7:17 -

引用なし
パスワード
   ▼ichinose さん:
ありがとうございます。

クラスを使用するのですね。前回にもこのクラスの使用例を示してもらえました。JAVAをかじった時によく理解できない概念でしたが、これでJAVAにも少し手が届きそうです。

目的通りスクロールの範囲にあるラベルをクリックすることにより、固定の部分のコントロールを操作することが出来ました。

それにしても示していただけるコードで、いつもどれほど多くのことを私が手に入れているか。感謝、感謝。

【30621】Re:大きなサイズのフォーム 再送
質問  年寄り E-MAILWEB  - 05/11/1(火) 11:25 -

引用なし
パスワード
   >分かりました。
>UserForm1では
>    frm.Controls(idx).Value
>であり、UserForm2では
>    p.Controls(idx).Valueや.Captionですね。
>

確かにfrmやpの中からはこれで取得できますが、他から(Module1等)からはどうやって取得しますか?

【30622】Re:大きなサイズのフォーム 再送
発言  ichinose  - 05/11/1(火) 12:16 -

引用なし
パスワード
   ▼年寄り さん:
おはようございます。

>>分かりました。
>>UserForm1では
>>    frm.Controls(idx).Value
>>であり、UserForm2では
>>    p.Controls(idx).Valueや.Captionですね。
>>
>
>確かにfrmやpの中からはこれで取得できますが、他から(Module1等)からはどうやって取得しますか?

なるほど、色々と方法はありますが・・・、
http://www.vbalab.net/vbaqa/c-board.cgi?cmd=one;no=30608;id=excel
ここでのコードに追加して・・・、
userform2のモジュールでは

'===============================================================
Dim c_txt(1 To 20) As Class1 'これは、Publicにはできないので・・
'===============================================================
Private Sub UserForm_Initialize()
  Dim p As Page
  Dim sz As Double
  Dim wk As String
  Dim idx As Long
  With Me
   .Height = 300
   .Width = 420
   End With
  With Controls.Add("Forms.MultiPage.1")
    .Top = 75
    .Left = 5
    .Height = 200
    .Width = (9.75 * 40 + 12) + 0.75
    .Pages.Remove 1
    With .Font
     .Name = "MS ゴシック"
     .Size = 10
     sz = Int(.Size / 0.75) * 0.75
     End With
    Set p = .Pages(0)
    p.Caption = String(Int((Int(.Width / 0.75) * 0.75 - 12.75) / sz), " ")
    wk = p.Caption
   
    Mid(wk, 1, 9) = "マルチページ使用例"
    p.Caption = wk
    p.ScrollBars = 2
    p.ScrollHeight = 1000
    For idx = 1 To 20
     Set c_txt(idx) = New Class1
     With c_txt(idx)
      .id = idx
      Set .txt = p.Controls.Add("Forms.TextBox.1", "text" & idx)
      With .txt
       .Top = (idx - 1) * 50 + 20
       .Left = 30
       End With
      End With
     Next
    End With
End Sub
'===========================================================
Property Get f_txt(id As Long) As msforms.TextBox
  Set f_txt = c_txt(id).txt
End Property

としておけば、
例えば、
標準モジュールで

'===============================================================
Sub main()
  UserForm2.Show vbModeless
End Sub


とモーダレスで表示して、最初のテキストボックスに何か入力してください。

入力後、

別の標準モジュールに予め記述した

'===========================================================
Sub test()
  MsgBox UserForm2.f_txt(1).Text
End Sub


これを実行してみてください
(モーダレスで表示すれば
「ツール」--「マクロ」の手順で testは実行できますよね?)。

最初のテキストボックスの内容が表示されると思います。

他にも方法はありますが、クラスを使っているので
このようにしました。


確認してください

尚、もし うまくいかない場合は、投稿は夜になってしまいます。

【30643】Re:大きなサイズのフォーム 再送
質問  年寄り E-MAILWEB  - 05/11/1(火) 19:11 -

引用なし
パスワード
   >'===========================================================
>Property Get f_txt(id As Long) As msforms.TextBox
>  Set f_txt = c_txt(id).txt
>End Property
>

またまた新しく出てきたこれが何かを調べていました。結局あまりすっきりとはしませんでした。

とりあえず目的としていたことは実現いたしました。固定枠で入力されたデータをスクロールの適切な位置に当てはめることは出来ました。

ところが新たな行き詰まりが出現。手動でスクロールバーの釣鐘を上げ下げしなければ、現在標的とされているコントロールの位置に行かないのです。

【30645】Re:大きなサイズのフォーム 再送
発言  ichinose  - 05/11/1(火) 20:16 -

引用なし
パスワード
   ▼年寄り さん:
こんばんは。
>>'===========================================================
>>Property Get f_txt(id As Long) As msforms.TextBox
>>  Set f_txt = c_txt(id).txt
>>End Property
>>
これは、Userform2に独自のプロパティを作成したことになります。
これにより、
Userform2.f_txt(15) で15番目のテキストボックスが取得できます。

Range("a1").offset(2) なんていうのとよく似ています。

でも、ちょっと難しいでしょうか?
まっ、ちょっとしたきっかけである日突然ピンと来る日がきます。


>またまた新しく出てきたこれが何かを調べていました。結局あまりすっきりとはしませんでした。
>
>とりあえず目的としていたことは実現いたしました。固定枠で入力されたデータをスクロールの適切な位置に当てはめることは出来ました。
>
>ところが新たな行き詰まりが出現。手動でスクロールバーの釣鐘を上げ下げしなければ、現在標的とされているコントロールの位置に行かないのです。

これも引き続きUserform2を例にあげます。
ちょっとだけ又、コードを追加します。

Userform2のモジュールに
'===========================================================
Dim c_txt(1 To 20) As Class1
'===========================================================
Private Sub UserForm_Initialize()
  Dim p As Page
  Dim sz As Double
  Dim wk As String
  Dim idx As Long
  With Me
   .Height = 300
   .Width = 420
   End With
  With Controls.Add("Forms.MultiPage.1", "mltp")
                     '↑マルチページに名前を付けます
    .Top = 75
    .Left = 5
    .Height = 200
    .Width = (9.75 * 40 + 12) + 0.75
    .Pages.Remove 1
    With .Font
     .Name = "MS ゴシック"
     .Size = 10
     sz = Int(.Size / 0.75) * 0.75
     End With
    Set p = .Pages(0)
    p.Caption = String(Int((Int(.Width / 0.75) * 0.75 - 12.75) / sz), " ")
    wk = p.Caption
   
    Mid(wk, 1, 9) = "マルチページ使用例"
    p.Caption = wk
    p.ScrollBars = 2
    p.ScrollHeight = 1000
    For idx = 1 To 20
     Set c_txt(idx) = New Class1
     With c_txt(idx)
      .id = idx
      Set .txt = p.Controls.Add("Forms.TextBox.1")
      With .txt
       .Top = (idx - 1) * 50 + 20
       .Left = 30
       End With
      End With
     Next
    End With
End Sub
'=============================================================
Property Get f_txt(id As Long) As MSForms.TextBox
  Set f_txt = c_txt(id).txt
End Property
'================================================================
Private Sub UserForm_Terminate()
  Erase c_txt() 'フォームでの作業終了時に配列を初期化するコードも追加
End Sub


標準モジュールで
'=========================================================
Sub main()
  UserForm2.Show vbModeless
End Sub


このMain実行後、

別の標準モジュールに

'============================================================
Sub test()
  UserForm2.f_txt(20).SetFocus
End Sub


を実行してみてください。
この例のように目的のコントロールがテキストボックスなら、
Setfocusメソッドの使用で実現できます。


では、この例とは違い、Setfocusメソッドが使用できないコントロールの場合は??


同じく標準モジュールに
'===================================================
Sub test2()
  Dim pg As MSForms.Page
  With UserForm2
    Set pg = .Controls("mltp").Pages(0)
    pg.ScrollTop = .f_txt(20).Top '
    End With
End Sub

なんてすると目的の動作になると思います。

試してみてください。

【30651】Re:大きなサイズのフォーム 再送
発言  年寄り E-MAILWEB  - 05/11/1(火) 20:48 -

引用なし
パスワード
   >'============================================================
>Sub test()
>  UserForm2.f_txt(20).SetFocus
>End Sub
>

私もこれだと思っていてコードを記入していました。
    UserForm2.f_txt(20).s
と打つと自動的にSetFocusを選べるように普通はなりますよね。(確か自動メンバだったかな?)ところが選択できなかったのでダメだと勝手に判断したのでした。なぜこの場合選べないのでしょうか?

残りはまた明日検討します。早寝に徹します。

【30658】Re:大きなサイズのフォーム 再送
発言  ichinose  - 05/11/1(火) 22:41 -

引用なし
パスワード
   ▼年寄り さん:
こんばんは。


>>'============================================================
>>Sub test()
>>  UserForm2.f_txt(20).SetFocus
>>End Sub
>>
>
>私もこれだと思っていてコードを記入していました。
>    UserForm2.f_txt(20).s
>と打つと自動的にSetFocusを選べるように普通はなりますよね。(確か自動メンバだったかな?)ところが選択できなかったのでダメだと勝手に判断したのでした。なぜこの場合選べないのでしょうか?

f_txtというプロパティは、Textbox(Msforms.Textbox)ですよね。
Setfocusメソッドは、実は、Textboxに付属するメソッドではありません。
StefocusはControlクラスに付属するメソッドです。

TextboxはControlsのメンバーですから、
TextboxとControlの両方のプロパティ、メソッドが使えますが、
f_txtの型は、Textboxと既定したので、Setfocusメソッドが
メンバーリストとして表示されなかったのだと思います。


例のUserform2があるブック開いた状態で

VBEにて、「表示」----「オブジェクトブラウザ」をクリックしてください。
この画面でオブジェクトの「プロパティ」や「メソッド」を
調べることが出来ます。

・<すべてのライブラリ>と書かれているコンボボックスをMsformsに代えてください。

・そのすぐ下のコンボボックスに「Textbox」と入力してEnterキーを押してください。

・検索結果のTextboxを選択すると、Textboxのメンバー一覧が表示されますが、
 Setfocusはないですよね?

・次に「Textbox」と指定したコンボボックスに今度は「Control」と入力して
 Enterキーを押してください。

・検索結果から、クラスが「Control」と表示されたものを選択して見てください。

・メンバー一覧にSetfocusがあると思います。

以上です。

【31049】Re:大きなサイズのフォーム 再送
質問  年寄り E-MAILWEB  - 05/11/10(木) 6:20 -

引用なし
パスワード
   ちょいとダウンしていた。『臭いメシ』ならぬ『不味いメシ』を食わされていた。ノートは持って行ったが、病室ではインターネットが使えない。応答に遅れて大変申し訳ない。とても気になっていた。

質問1
UserFormに直接貼り付けたTextBoxコントロールのイベントと、Classモジュールで今回作成したf_txtというTextbox(Msforms.Textbox)のイベントに違いがあります。Textbox(Msforms.Textbox)のイベントの方が少ない。何故ですか?

質問2
TextBoxコントロールのイベントAfterUpdateとBeforUpdateの区別がはっきりしません。後者がキャンセルを判断して(Cancel = True)コントロールの移動をしないだけならば、後者は前者を包含しているように思える。すなわち前者は必要ないように思えるが?

しかし今回も『ドラえもんのポケット』さながら、『ichinoseさんの魔法の手』(正確には『Excelの宝箱』?)はきっと何かを出すに決まっている。勝手にイベントを作ってしまう?

【31050】Re:大きなサイズのフォーム 再送
発言  ichinose  - 05/11/10(木) 7:53 -

引用なし
パスワード
   ▼年寄り さん:
おはようございます。

>ちょいとダウンしていた。『臭いメシ』ならぬ『不味いメシ』を食わされていた。ノートは持って行ったが、病室ではインターネットが使えない。応答に遅れて大変申し訳ない。とても気になっていた。
急に寒くなってきましたからねえ・・・。
なにせ、本日夕方から子供スケート教室の付き添いです。もう、冬ですね!!
お大事に!!


>
>質問1
>UserFormに直接貼り付けたTextBoxコントロールのイベントと、Classモジュールで今回作成したf_txtというTextbox(Msforms.Textbox)のイベントに違いがあります。Textbox(Msforms.Textbox)のイベントの方が少ない。何故ですか?
はい、おっしゃるとおりです。
特にEnter、Exit、Update(Before,After)とありませんよね?
本当の理由は私もわかりませんが、風の噂ではコンパイラー言語VBとの
格差だとか・・・。
これがあるので私は、Keydownというイベントにてデータチェックを行っている
場合が多いのですが・・・。

UserformのプロパティにActivecontrolというプロパティがあります。
このプロパティでアクティブになっている(フォーカスを持っている)コントロールが
取得できます。このプロパティの中身を監視して変化があったらイベントを発生させる
という手法が考えられますし、私もだいぶ前にそんなコードを見たことがあります。
(Excel2000からは、独自のイベントが作成できますからね)

汎用的に作るには、時間かかるかなあ・・(実用的か否かの検証も大変そう)。

角田さん、作ってないですかあ?


>
>質問2
>TextBoxコントロールのイベントAfterUpdateとBeforUpdateの区別がはっきりしません。後者がキャンセルを判断して(Cancel = True)コントロールの移動をしないだけならば、後者は前者を包含しているように思える。すなわち前者は必要ないように思えるが?

なるほど、微妙なタイミングですからねえ。

1 Beforeupdate

2 Afterupdate

3 Exit

この3つのイベントについてかんがえましょう!!
HELPどおりなら、1,2,3の順序でイベントは
発生します。

Updateイベントは、テキストボックスに変更があった場合、フォーカスが
次に移るタイミングで発生します。つまり、変更がなければ発生しない。

対して、Exitは、変更があろうがなかろうがフォーカスが
次に移るタイミングで発生します。
明らかに1,2と3にはイベントの発生に違いが見られますよね!!

では、
1,2は、

新規ブックに
Userform1を作成し、Textbox1とCommandbutton1を作成してください。
同じように
Userform2を作成し、Textbox1とCommandbutton1を作成してください

Userform1のモジュールに
'============================
Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
  If Not IsNumeric(TextBox1.Text) Then
    MsgBox "数字だけだよ"
    Cancel = True
    End If
End Sub
'=========================
Private Sub UserForm_Initialize()
  TextBox1.Text = "123"
End Sub


Useform2のモジュールに
'===========================================
Dim svcancel As Boolean
'===========================================
Private Sub TextBox1_AfterUpdate()
  If Not IsNumeric(TextBox1.Text) Then
    MsgBox "数字だけ"
    svcancel = True
  Else
    svcancel = False
    End If
End Sub
'==============================================================
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
  Cancel = svcancel
  svcancel = False
End Sub
'==============================================================
Private Sub UserForm_Initialize()
  svcancel = False
  TextBox1.Text = "123"
End Sub


このふたつのユーザーフォームで
TextBox1に数字以外をしてしみてください。
表示の違いとコードをよく見比べてみてください。
Cancel=Trueとしたときの後の動作に違いが出てきます。


>
>しかし今回も『ドラえもんのポケット』さながら、『ichinoseさんの魔法の手』(正確には『Excelの宝箱』?)はきっと何かを出すに決まっている。勝手にイベントを作ってしまう?
あっははは、そんなにすごければ、ここにくる必要もないんですが・・・。

確認してください。

【31066】Re:大きなサイズのフォーム 再送
発言  ichinose  - 05/11/11(金) 8:33 -

引用なし
パスワード
   ▼年寄り さん:
おはようございます。
>>質問1
>>UserFormに直接貼り付けたTextBoxコントロールのイベントと、Classモジュールで今回作成したf_txtというTextbox(Msforms.Textbox)のイベントに違いがあります。Textbox(Msforms.Textbox)のイベントの方が少ない。何故ですか?
>はい、おっしゃるとおりです。
>特にEnter、Exit、Update(Before,After)とありませんよね?
>本当の理由は私もわかりませんが、風の噂ではコンパイラー言語VBとの
>格差だとか・・・。
>これがあるので私は、Keydownというイベントにてデータチェックを行っている
>場合が多いのですが・・・。
>
>UserformのプロパティにActivecontrolというプロパティがあります。
>このプロパティでアクティブになっている(フォーカスを持っている)コントロールが
>取得できます。このプロパティの中身を監視して変化があったらイベントを発生させる
>という手法が考えられますし、私もだいぶ前にそんなコードを見たことがあります。
>(Excel2000からは、独自のイベントが作成できますからね)
>
>汎用的に作るには、時間かかるかなあ・・(実用的か否かの検証も大変そう)。

汎用的ではありません。
アルゴリズムとしてこのようにすればよいのではないかという
例題です。

このトピックで取り上げてきたマルチページにテキストボックス
を実行時作成するコードを例題にします。
汎用的ではありません。
アルゴリズムとしてこのようにすればよいのではないかという
例題です(汎用的にするにはさらなる検証が必要です)

繰り返しになってしいますが、再度コードを全部掲載します。

新規ブックにはコントロールのないユーザーフォーム(Userform2)を作成してください。


まず、クラスモジュール

Class1には、

'====================================
Public WithEvents txt As MSForms.TextBox
Public id As Long
'======================================================================
Private Sub txt_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = 13 Or KeyCode = 9 Then
   If Not IsNumeric(txt.Text) Then
     MsgBox "数字を指定して!!"
     KeyCode = 0
     End If
   End If
End Sub

'↑これは、以前にも掲載したコードです

次に追加でClass2を作成し当該モジュールに
'========================================================
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public 監視 As Boolean
Public p_obj As Object
'========================================
Sub kanshi()
  Dim svctrl As MSForms.Control
  Dim nctrl As MSForms.Control
  Dim ss As MSForms.MultiPage
  Set svctrl = p_obj.ActiveControl
  If UCase(TypeName(svctrl)) = UCase("multipage") Then
   Set p_obj = svctrl.SelectedItem
   Set svctrl = p_obj.ActiveControl
   End If
  監視 = True
  Do While 監視 = True
   Set nctrl = p_obj.ActiveControl
   If nctrl Is Nothing Then
     Exit Do
     End If
   If svctrl.Name <> nctrl.Name Then
     Call act_event(svctrl, nctrl)
     Set svctrl = nctrl
     If UCase(TypeName(svctrl)) = UCase("multipage") Then
      Set p_obj = svctrl.SelectedItem
      Set svctrl = p_obj.ActiveControl
      End If
     svctrl.SetFocus
     End If
   Sleep (100)
   DoEvents
   Loop
  Set svctrl = Nothing
End Sub
'====================================================
Sub kaijo()
  監視 = False
End Sub
'=====================================================
Private Sub Class_Terminate()
  kaijo
  DoEvents
  Set p_obj = Nothing
End Sub
'=======================================================================
Private Sub act_event(f_ctrl As MSForms.Control, n_ctrl As MSForms.Control)
'ここにコントロールが変わったときに行うコードを書きます
  If Not IsNumeric(f_ctrl.Value) Then
   MsgBox "駄目駄目数字入れてくれきゃ"
   Set n_ctrl = f_ctrl
   End If
End Sub


Userform2では、
'=====================================================
Dim c_txt(1 To 20) As Class1
Dim c_eve As Class2
'=====================================================
Private Sub UserForm_Activate()
  c_eve.kanshi
End Sub
'======================================================
Private Sub UserForm_Deactivate()
  c_eve.kaijo
End Sub
'===========================================================
Private Sub UserForm_Initialize()
  Dim p As Page
  Dim sz As Double
  Dim wk As String
  Dim idx As Long
  With Me
   .Height = 300
   .Width = 420
   End With
  With Controls.Add("Forms.MultiPage.1", "mltp")
                     '↑マルチページに名前を付けます
    .Top = 75
    .Left = 5
    .Height = 200
    .Width = (9.75 * 40 + 12) + 0.75
    .Pages.Remove 1
    With .Font
     .Name = "MS ゴシック"
     .Size = 10
     sz = Int(.Size / 0.75) * 0.75
     End With
    Set p = .Pages(0)
    p.Caption = String(Int((Int(.Width / 0.75) * 0.75 - 12.75) / sz), " ")
    wk = p.Caption
  
    Mid(wk, 1, 9) = "マルチページ使用例"
    p.Caption = wk
    p.ScrollBars = 2
    p.ScrollHeight = 1000
    For idx = 1 To 20
     Set c_txt(idx) = New Class1
     With c_txt(idx)
      .id = idx
      Set .txt = p.Controls.Add("Forms.TextBox.1")
      With .txt
       .Top = (idx - 1) * 50 + 20
       .Left = 30
       End With
      End With
     Next
    End With
  Set c_eve = New Class2
  Set c_eve.p_obj = Me
End Sub
'=============================================================
Property Get f_txt(id As Long) As MSForms.TextBox
  Set f_txt = c_txt(id).txt
End Property
'================================================================
Private Sub UserForm_Terminate()
  Set c_eve = Nothing
  Erase c_txt() 'フォームでの作業終了時に配列を初期化するコードも追加
End Sub


で標準モジュールに
'=============================================
Sub main()
  UserForm2.Show
End Sub


でれで、Mainを実行してみてください。

テキストボックスに数字以外を入力してEnterキーを押した場合は、
今までどおり"数字を指定して!!"と表示されます。
テキストボックスに数字以外を入力してマウスで別コントロールに移動してください
Class2に記述された"駄目駄目数字入れてくれきゃ"が表示されます。

実際には、これを汎用的なクラスにし、イベントもUserform2の中で
記述できるようにしなければなりません。
「駆使すれば出来るかもしれない」という例題として
確認してください。

【31111】Re:大きなサイズのフォーム 再送
発言  年寄り E-MAILWEB  - 05/11/11(金) 17:16 -

引用なし
パスワード
   ▼ichinose さん:
ご親切にありがとうございますね。

上記の二つについて暫く検証の時間をください。

【31170】Re:大きなサイズのフォーム 訂正
発言  ichinose  - 05/11/14(月) 8:12 -

引用なし
パスワード
   ▼年寄り さん:
おはようございます。
>新規ブックに
>Userform1を作成し、Textbox1とCommandbutton1を作成してください。
>同じように
>Userform2を作成し、Textbox1とCommandbutton1を作成してください
>
>Userform1のモジュールに
>'============================
>Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
>  If Not IsNumeric(TextBox1.Text) Then
>    MsgBox "数字だけだよ"
>    Cancel = True
>    End If
>End Sub
>'=========================
>Private Sub UserForm_Initialize()
  With TextBox1
   .ControlSource = "sheet1!a1"
   .Text = "123"
   End With
>End Sub
>
>
>Useform2のモジュールに
>'===========================================
>Dim svcancel As Boolean
>'===========================================
>Private Sub TextBox1_AfterUpdate()
>  If Not IsNumeric(TextBox1.Text) Then
>    MsgBox "数字だけ"
>    svcancel = True
>  Else
>    svcancel = False
>    End If
>End Sub
>'==============================================================
>Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
>  Cancel = svcancel
>  svcancel = False
>End Sub
>'==============================================================
>Private Sub UserForm_Initialize()
>  svcancel = False
  With TextBox1
   .ControlSource = "sheet1!a1"
   .Text = "123"
   End With
>End Sub
>
>
>このふたつのユーザーフォームで
>TextBox1に数字以外をしてしみてください。
>表示の違いとコードをよく見比べてみてください。
>Cancel=Trueとしたときの後の動作に違いが出てきます。

失礼しました。コードを上記のように訂正しないと
違いがみられません。
(事前にフォームのプロパティを変更していたことを忘れてました)

テキストボックスの変更を反映する前に発生するのがBeforeupdate、
反映後に発生するのがAfterUpdateですよね。

ControlSourceに指定したセルを使用すれば、
BoforeUpdateの場合は、上記の理由で値を元に戻せるのです(Cancel=True時)。

投稿漏れに今の今まで気が付きませんでした。
大変、失礼しました。

【31172】Re:大きなサイズのフォーム 訂正
発言  年寄り E-MAILWEB  - 05/11/14(月) 8:47 -

引用なし
パスワード
   ▼ichinose さん:
やはり?!

実はどう違うか、調べるのに大変苦労していました。

もう片方の、マウスで抜けた際に文字チェックをするコードに感心しています。とても勉強になっております。もう少し調べてから疑問に思う点を質問したいと考えております。その時もよろしくお願いいたします。

8792 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free