[[20100513233352]] 『VBAでのファイルを更新(閉じる)したい』(はせぴぃ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『VBAでのファイルを更新(閉じる)したい』(はせぴぃ)

 VBAにて「Book1.xls」のユーザフォーム内のコマンドボタン(かマクロ)にて
 自分もVBA初心者なのでよくわかっていないのですが、

 “book2.xls”を開く → “book1.xls”を(保存しないで)閉じる

事をしたいのですが、

  ThisWorkbook.Close False

でできるのはわかるのですが、
book2.xlsの起動時にユーザフォームを開くように設定していると
うまくできません。

 よい方法がございましたらお教え願いませんか?
お願い致します。

 ユーザーフォームが登録してあるブックを閉じたら、
エラーは当然ですね。
閉じないと都合が悪いのですか?
みやほりん

 >book2.xlsの起動時にユーザフォームを開くように設定しているとうまくできません。 
 これだけでの記述ではどんなコードなのかわかりません。
 再現できるBook1.XlsとBook2.Xlsの構成とコードを提示して下さい。
 今、抱えている問題のあるコードを全部掲載するのではなく、
 この掲示板用に簡単に再現できる構成とコードの掲載が必要です。

 それと出来るなら、このような処理をしたい背景も・・・。

 問題自体は、Ontimeメソッドあたりを工夫すれば、できるかもしれません・・・。
 が、プログラムの構造的に難しい構造(他者にとって理解しづらい)になってしまいそうです。
 これって、フェーズチェンジみたいな事がしたいということですもんね!!

 Book1.Xlsを閉じるのではなく、非表示状態にしておくのではいけませんか?

 ichinose


 パソコン素人の方々の操作を想定しているので、
非表示状態だと不都合が生じそうな気がします。

 また、ファイルの共有もしていきたいので閉じてしまいたいです。
(私自身も素人な解答ですいませんm(_ _)m)

コードは

book1内のユーザフォーム1内ボタン1は

Private Sub CommandButton1_Click()
'

    Unload UserForm1
'
    Dim path As String
    path = ThisWorkbook.path
    Workbooks.Open Filename:=path & "book2.xls"
    Range("A1").Select
'
    With Workbooks("book2.xls")
        .Close
    End With
'
(    UserForm2.Show  )
'
End Sub

book2内のオブジェクト内のthisworkbook内に

Private Sub Workbook_Open()
'

   Sheets("sheet1").Select
   UserForm2.Show
'
End Sub

                   (はせぴぃ)


 Book1でBook1に対するCloseメソッドを書き、Book2のUserForm2をLoad
→UserForm2を閉じないとBook1が閉じない
Book2でBook1に対するCloseメソッドを書き、Book2のUserForm2をLoad
→Book1を閉じると、それ以降のコードが実行されない。
 
Book2を開く、Book1を閉じる、までの処理として、
Userform2をLoadするのはWorkbook_Openで実行せずに、ボタンクリックなどの
別処理で行ってはいかがですか?
 
>パソコン素人の方々の操作を想定
私の経験では、便利にしてあげればあげるほど、素人のままでいてくれます。
(みやほりん)(-_∂)b

 >非表示状態だと不都合が生じそうな気がします。 
 どんな不都合でしょうかねえ?? Book2.Xlsのユーザーフォームを閉じたら、Book1のフォームを再び
 表示されるような仕様でいけないのですか?

 >ファイルの共有もしていきたいので閉じてしまいたいです
 これも仕様によりますが、やりようはあると思いますけどねえ・・・・。

 一応、こんなコードにすると、
 >VBAにて「Book1.xls」のユーザフォーム内のコマンドボタン(かマクロ)にて
 >"book2.xls”を開く → “book1.xls”を(保存しないで)閉じる 

 という仕様は実現できます。

 Book1.xls 、book2.xlsは、いずれも新規ブックで試してください。

 Book1.Xlsでは、

 ユーザーフォームをひとつ作成してください(UserForm1)
 このUserForm1には、コマンドボタンをひとつ配置してください(CommandButton1)

 標準モジュールに

 '=========================================================================
 Option Explicit
 Sub test()
    UserForm1.Show
    ThisWorkbook.Close False
 End Sub

 UserForm1のモジュールに

 '========================================================================
 Option Explicit
 Private Sub CommandButton1_Click()
    Application.OnTime Now(), "'" & ThisWorkbook.Path & "\[book2.xls]'!スケジュール"
    Unload Me
 End Sub

 book2.xlsにもユーザーフォームをひとつ作成してください(UserForm2)。
 このUserForm1には、テキストボックスをひとつ配置してください(TextBox1)。
 これは、book1.xlsのUserform1と区別しやすくするためにコントロールを変えました。

 標準モジュールに

 '===========================================================================
 Option Explicit
 Sub スケジュール()
    Application.OnTime Now(), "auto_open"
 End Sub
 '============================================================================
 Sub auto_open()
    UserForm2.Show
 End Sub

 以上です。book1.xls及び、book2.xlsは、同じフォルダに保存してください。

 Excelのマクロセキュリティを「低」に設定(または、デジタル署名して「中」)してbook1.xlsの
 testを実行してみてください。

 Userform1が表示され、コマンドボタンのクリックでbook2.xlsのUserform2が表示され、
 book1.xlsは、閉じます。

 試してみてください。
 私なら、仕様を変えてでも、このようなプログラム構造にはしないと思いますけど・・・。

 ichinose
 誤字訂正


 ichinoseさん、ありがとうございます。
テストしてみたら、出来ました。

 さらに甘えたいのですが、

 book1 ←┬→book2

      ├→book3
      └→book4

のようにbook1とbook2、3、4を相互コントロールさせたいのですが
出来ますでしょうか?
(book2、3、4はbook1と同じ階層内のフォルダにまとめてある)
  −┬−book1
   └−folder1−┬−book2
          ├−book3
          └−book4

>私なら、仕様を変えてでも、このようなプログラム構造にはしないと思いますけど・・・
とはなぜなのか、お聞かせ下さい。

 今後の糧にしたいです。

                          (はせぴぃ)


 前回投稿の

 >UserForm1のモジュールに
 >'========================================================================
 >Option Explicit
 >Private Sub CommandButton1_Click()
 >   Application.OnTime Now(), "'" & ThisWorkbook.Path & "\[book2.xls]'!スケジュール"
 >   Unload Me
 >End Sub

 を
 Private Sub CommandButton1_Click()
    With Workbooks.Open(ThisWorkbook.Path & "\book2.xls")
       Application.Run .Name & "!スケジュール"
    End With
    Unload Me
 End Sub

 こっちに変えてください。そうすると、デジタル署名なしのセキュリティ「中」でよいです。

 >このようなプログラム構造にはしないと思いますけど・・・とはなぜなのか
 ちょっと、大げさでしたね!!でも・・・・。

 プログラム構造の基本って、前にもどこかで記述しましたが、

 前処理 ------> 1回以上のループ処理 ------>終了処理

 という形だと思います。このループ処理が複雑になると他のプロシジャーを呼び出したり、他のプロセスを
 呼び出したりしますが、プログラムの流れは、上記の終了処理にてプログラムが終了する、
 いえ、そのようなプログラム構造にすることが構造化プログラミングです!!

 今回のプログラム構造のようにBook1のプログラムは、終了し、別のブックのプログラムがそのまま起動する
 という構造は、特殊な構造といえます。

 特殊な構造にするなら、それなりの理由が必要だと思うのです。

 例えば、Book1というプログラムの容量があまりにも大きくなりすぎているので、そのままExcel内においてお
 く状態でBook2のプログラムを実行させるより、リソースを開放した方がよい という判断で投稿したような
 プログラム構造にする。
 昔、メモリ容量が少なかった時代に大きいプログラムを開発する手法として、使われていました。

 >非表示状態だと不都合が生じそうな気がします。 

 >ファイルの共有もしていきたいので閉じてしまいたいです

 この二つのことが投稿したような構造にしないと本当に実現できないのか
 もう少し検討した方が良いのではないかということです。
 検討した結果、どうしても というなら、仕方ないですが・・・。

 > book1 ←┬→book2 
 >
 >      ├→book3
 >      └→book4
 >のようにbook1とbook2、3、4を相互コントロールさせたいのですが

 こんな投稿を拝見すると、Book1がメニュー画面でBook2,Book3,Book4でそれぞれ独立した機能を持った
 (VBAプログラムを持った)ブックのプログラムを実行する という仕様が想像されてなりません。
 ならば、Book2,Book3,Book4のぞれぞれの処理が終了後、再びBook1のメニューにもどり、
 終了するなら、このBOOK1のメニュー内のボタンによって終了する仕様ではいけませんか?

 ということです。こういう仕様なら、トップダウンのわかりやすいプログラム構造になります。

 それでも現状仕様がよいというなら、投稿したようなOnTimeメソッドを相互に使えば可能だとは
 思います。例題コードは提示しました(Book1.Xlsを閉じて、Book2.Xlsを起動する方法)。
 相互コントロールというのが、book2.xlsを閉じて、Book1.Xlsを起動する方法なら、逆をやるだけですよね!!

 ichinose


 ichinoseさん、詳しい解説ありがとうございます。

 お話いただいたコードは、まだ試しておりませんが、
元を返すようですが、読ませていただいたところ、
最初におっしゃられた通り"非表示"扱いにしたほうが
よさそうなのですね?

 自分もVBA初心者なのでよくわかっていないのですが、
ネットなどの解説を閲覧していると、
PC初心者(が扱うものを作成している)には
"非表示"を使用するのは難しいのでは?と考えたのでした。

 "非表示"を作成するにあたり、デメリットや
PC初心者が注意する点というのはありますか?

                  (はせぴぃ)


 せっかく回答いただいているものを消さないでください。
「コメント:」の欄から投稿するようにしましょう。
(みやほりん)(-_∂)b

 二つ例を出しますから検討してみてください。

 以下の例を新規ブックで試してください。

 例1 メインユーザーフォーム(Book1.XlsのUserForm1)非表示しない

 まず、book3.xlsからです。ユーザーフォームを一つ作成してください(UserForm3)。
 他のユーザーフォームと区別するためにコマンドボタンを一つ配置します(CommandButton1)。

 標準モジュールに

 '========================================================================
 Option Explicit
 Sub auto_open()
   UserForm3.Show
 End Sub

 UserForm3のモジュールに

 Private Sub CommandButton1_Click()
    Unload Me
 End Sub

 '*************************************************************************
 次にbook2.xlsです。ユーザーフォームを一つ作成してください(UserForm2)。
 UserForm2には、テキストボックス(TextBox1)とコマンドボタン(CommandButton1)
 配置してください。

 標準モジュールに

 '========================================================================
 Option Explicit
 Sub auto_open()
   UserForm2.Show
 End Sub

 UserForm2のモジュールに

 Private Sub CommandButton1_Click()
    Unload Me
 End Sub

 '******************************************************************************************
 最後にbook1.xlsです。ユーザーフォームを作成してください(UserForm1)。

 コマンドボタンを3っつ作成してください。

 CommandButton1 ------------- book2.xlsのUserForm2を表示する
 CommandButton2 ------------- book3.xlsのUserForm3を表示する
 CommandButton3 ------------- UserForm1を閉じる

 標準モジュールに

 '===============================================================================
 Option Explicit
 Sub auto_open()
    UserForm1.Show
    ThisWorkbook.Close False
 End Sub

 UserForm1のモジュールに

 '===============================================================================
 Option Explicit
 Private Sub CommandButton1_Click()
    Dim wn As Window
    For Each wn In ThisWorkbook.Windows
          wn.Visible = False
    Next
    With Workbooks.Open(ThisWorkbook.Path & "\book2.xls")
       Application.Run .Name & "!auto_open"
       DoEvents
       .Close False
    End With
    For Each wn In ThisWorkbook.Windows
       wn.Visible = True
    Next
 End Sub
 '====================================================================
 Private Sub CommandButton2_Click()
    Dim wn As Window
    For Each wn In ThisWorkbook.Windows
          wn.Visible = False
    Next
    With Workbooks.Open(ThisWorkbook.Path & "\book3.xls")
       Application.Run .Name & "!auto_open"
       DoEvents
       .Close False
    End With
    For Each wn In ThisWorkbook.Windows
       wn.Visible = True
    Next
 End Sub
 '============================================================================
 Private Sub CommandButton3_Click()
    Unload Me
 End Sub

 以上です。3ブックとも同じフォルダ上に保存してください。
 一度、Excelを閉じてから、再度、book1.xlsのみ開いてください。

 Userform1が表示されます。

 CommandButton1のクリックで book2.xlsのUserForm2が表示されます。
 UserForm2を閉じると再び、UserForm1がアクティブになります。

 CommandButton2のクリックで book3.xlsのUserForm3が表示されます。
 UserForm3を閉じると再び、UserForm1がアクティブになります。

 CommandButton3のクリックで UserForm1が消えて、book1.xlsも閉じます。

 いかがですか?book1.xlsは、他のブックが呼び出される度に非表示にしていますが、
 UserForm1は、非アクティブになっているだけで表示はされています。

 この手のメニュー方式にする場合、私は殆どこのパターンです(場合によっては、book1.xlsだって、
 非表示にはしません)。

 UserForm1が表示されたままだって、パソコン初心者の方にとって、不都合だとは思いませんが、
 いかがですか?

 例2では、UserForm1を他のブックが呼び出される度に非表示するコードを提示します。

 ichinose@次投稿にて


 例2 メインユーザーフォーム(Book1.XlsのUserForm1)非表示する

 Book2.xlsとBook3.xlsに関しては、前投稿と同じものをコピーして前投稿とは違うフォルダに
 保存してください。

 Book1.xlsだけは新たに作成します。ユーザーフォームを作成してください(UserForm1)。

 コマンドボタンを3っつ作成してください。

 CommandButton1 ------------- book2.xlsのUserForm2を表示する
 CommandButton2 ------------- book3.xlsのUserForm3を表示する
 CommandButton3 ------------- UserForm1を閉じる

 と機能的には同じです。

 標準モジュールに

 '===============================================================================
 Option Explicit
 Sub auto_open()
    Dim wn As Window
    Dim opnbook As String
    Load UserForm1
    With UserForm1
       .Show
       Do Until .clickbtn = 4
          For Each wn In ThisWorkbook.Windows
                wn.Visible = False
          Next
          If .clickbtn = 2 Then
             opnbook = ThisWorkbook.Path & "\book2.xls"
          ElseIf .clickbtn = 3 Then
             opnbook = ThisWorkbook.Path & "\book3.xls"
          End If
          With Workbooks.Open(opnbook)
             Application.Run .Name & "!auto_open"
             DoEvents
             .Close False
          End With
          For Each wn In ThisWorkbook.Windows
             wn.Visible = True
          Next
          .Show
       Loop
    End With
    Unload UserForm1
    ThisWorkbook.Close False
 End Sub

 UserForm1のモジュールに

 '===============================================================================
 Option Explicit
 Public clickbtn As Long 'どのボタンが押されたかを示す 
    '2 CommandButton1が押された 3 CommandButton2が押された 4 CommandButton3が押された 
 '=======================================================================================
 Private Sub CommandButton1_Click()
    clickbtn = 2
    Me.Hide
 End Sub
 '========================================================================================
 Private Sub CommandButton2_Click()
    clickbtn = 3
    Me.Hide
 End Sub
 '========================================================================================
 Private Sub CommandButton3_Click()
    clickbtn = 4
    Me.Hide
 End Sub
 '========================================================================================
 Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode <> 1 Then
       Cancel = True
    End If
 End Sub

 以上です。3ブックとも同じフォルダ上に保存してください。
 一度、Excelを閉じてから、再度、book1.xlsのみ開いてください。

 Userform1が表示されます。

 CommandButton1のクリックで book2.xlsのUserForm2が表示されます。
 このとき、UserForm1は、非表示になります。
 UserForm2を閉じると再び、UserForm1が表示されます。

 CommandButton2のクリックで book3.xlsのUserForm3が表示されます。
 このとき、UserForm1は、非表示になります。
 UserForm3を閉じると再び、UserForm1が表示されます。

 CommandButton3のクリックで UserForm1が消えて、book1.xlsも閉じます。

 UserForm1を表示したままの仕様と非表示する仕様では、こんなにコードが違ってしまいました。
 勿論、理由はありますが、現時点では省略します。

 > "非表示"を作成するにあたり、デメリットや
 >PC初心者が注意する点というのはありますか?
 Book1.Xlsの標準モジュール内に

           With Workbooks.Open(opnbook)
             Application.Run .Name & "!auto_open"
             DoEvents
             .Close False
          End With

 というコードがあります、このDoeventsを入れないと
 私の環境ではI/Oエラーが発生しました。 
 Win2000&Excel2002で確認しています。

 又、この手の手法は、Excel2000から行っていたので Excel2000でも確認しています。
 メニュー方式の2例を投稿しました。

 検討してみてください。

 ichinose

 


 こんにちは。佳です。
 じつはわたしの環境では、最初からはせぴぃさんのコードでちゃんと動いています。
 エクセル97なもので、環境のせいかなと思ったり、
 自分がなにか仕様を読み違えているだろうかと思ったりしています。

 > ネットなどの解説を閲覧していると、
 > PC初心者(が扱うものを作成している)には
 > "非表示"を使用するのは難しいのでは?と考えたのでした。

 こちらはあまり環境に関係ないはなしなので。
 わたしの経験から云わせていただくと
 初心者のユーザーは、ワケの分からないものが見えると混乱します。
 また、見えるはずだと思っているものが見えないときも混乱します。
 なので、非表示は無条件でダメとか、表示は無条件でダメとかは言えないです。
 理想をいえば、ユーザーが見たいものが見たいときに見えるようにするのが一番です。
 まあ、言うは易く行うは難しですが ^^;

 ほかの条件が同じなら、シンプルな作りにするほうがよさそうです。
 初心者のユーザーにも、複雑なものよりシンプルなほうが理解しやすいはずですし
 まんいちコードにまずいところが見つかって修正することになったとき、シンプルなもののほうが楽です。

 どういうものを作ろうとされているのか教えていただけると、もう少し中身のある回答ができるかと思います。

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.