[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『Excel2013で複数のブックを開いている時、フォームのボタンで表示するブックを切り替えたいのですが・・・。 』(kuku008110)
Excel2013で複数のブック1~5を開いているときにVBA(ブック5.Activate)を使って、ブック5を前面に持ってきたいのですがうまく行きません。
詳細は、ブック1~5が既に開いている状態で、「ブック1の作業を終了しますか?」というフォームの「終了」ボタンを押すと新しいフォーム(ブック5で行う作業内容や手順の書かれたもの)を最前面に表示し、その背面にブック5を表示したいのですが、現状は、新しいフォームは最前面に表示されるのですが、ブック5は、ちゃんと新しいフォームの背面に表示されるときもあれば、ブック1~4のさらに背面に表示されたり、ブック1の背面に表示されたりとランダムな位置に表示されてしまいます。何か良い方法がございましたら教えて頂きますようお願い致します。
< 使用 Excel:Excel2013、使用 OS:Windows8 >
ブック1~5 と、ユーザーフォームがあるマクロブックの関係ですが、
・ブック1~5 の いずれかがマクロブック? それとも、それらとは別の単独のマクロブックが存在? ・ユーザーフォームはすべて同じマクロブックにある? それともユーザーフォームごとに別のマクロブックにある?
基本的には、ブック.Activate を実行すれば、そのブックが最前面にでるはずです。
上記質問に答えていただくとともに、実際にブックを表示しているコードをすべて、そのまま コピペで アップして、見せてもらえば、皆さんから、いろいろ レスが上がってくると思います。
(β) 2016/04/30(土) 13:45
全てのコードだと長くなりますので一部を載せます、
現在のコード
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
Workbooks("Book5.xlsm").Activate
ActiveWindow.WindowState = xlMaximized
フォーム2.Show vbModeless
Application.ScreenUpdating = True End Sub
(kuku008110) 2016/04/30(土) 14:36
こちらで継続されるなら 質問箱やサロンのほうは、その旨明記して閉じておられることを 強くおすすめします。
で、手順表示用のマクロブックがあって、最初は ブック1.xlsx用のUserForm1を表示して ブック1.xlsx をActiveにしているんだと思いますが そのCommandButton1 で、ブック5.xlsx用のUserForm2 を表示して、ブック5.xlsx をアクティブにしたいということですね?
全体的に、どのブックを表示させたいかのボタンがすべてそろっている、ユーザーフォームを1つだけ用意して それを常に表示しておいて、アクティブにしたいブックに対応するボタンを選ぶといった構成のほうがやりやすいと思いますし ユーザーフォームを使わずとも、これだけなら、タスクバーからブックを選んでもいいと思いますが、さておき。
ところで、実行環境は xl2013 でいいのですか? xl2010(あるいは、それ以前)の環境ですか?
(β) 2016/04/30(土) 14:46
質問箱とサロンの方は終了にします。
実行環境はExcel2013です。
(kuku008110) 2016/04/30(土) 16:06
こちらで、マクロブックに フォーム1 と フォーム2 をつくり、フォーム1にCommandButton1 を配置して ユーザーフォームモジュールに アップされたコードをそのままコピペ。 別途、標準モジュールに
Sub Test() Workbooks("Book1.xlsm").Activate フォーム1.Show vbModeless End Sub
こんなコードを書いて実行。
xl2010とxl2013 で実行しましたが、いずれも
・Book1.xlsmが表示された状態でフォーム1が立ち上がっている。 ・フォーム1のCommandButton1クリックで、Book5.xlsmが表示されフォーム2が立ち上がっている。
こんな状況でした。
ただし、見た目は同じですが、2010までのMDIインターフェースから、2013以降はSDIインターフェースに変わっているので フォーム2が表示されたとき、2010までは、それを動かすと、後ろに(つまり Book5.xlsmとフォーム2の間に)フォーム1が存在していますが 2013では、後ろには何もなく、後ろに隠れたBook1.xlsmの上にフォーム1があります。
いずれにしても、アップされたコードだけであれば、絶対にBook5.xlsmが見えるはずです。
不思議ですねぇ。
(β) 2016/04/30(土) 20:38
当方での試行結果は前述の通りです。
Book5.xlsm の Thisworkbookモジュールに OpenイベントやActivateイベントが書かれているとすれば それをアップしてください。 フォーム2のInitializeイベントやActivateイベントに何か書かれているとしたら、それもアップしてください。
(β) 2016/04/30(土) 23:11
マクロブックのコードを貼り付けますので、何か考えることがありましたら、引き続きよろしくお願いします。
Option Explicit
'v5.9
Public Sub ShowPow()
Dim strKyakuCode As String 'v8.8 検索用 Dim rngFind As Range
On Error GoTo err
' With Application
'v5.5 表示更新の停止 ' .ScreenUpdating = False
'v5.5 EPOW開く Call ExcelOpen(strPath, "EPOW.xls")
With ActiveWindow 'v5.5 最大表示 .WindowState = xlMaximized 'v5.5 改ページプレビュー解除 .View = xlNormalView End With 'v5.5 初期化 Cells.Interior.ColorIndex = xlNone
Select Case ThisWorkbook.m_nIndex Case 400 'v6.2 見本閉じる Call CloseTemplate("ツイスト見本.xls")
'v5.9 見本表示 Call ShowTemplate(ThisWorkbook.Path & "\ワイヤリスト注意点\", "POW並び替え見本.xls")
'v5.9 配線順の確認け Call ShowForm("配線順番の確認", _ "配線順番の確認(線番ごとに大まかに。)", _ " ?@24G", _ " ?A24V", _ " ?B信号線", _ " ?CE", _ " ?D100V→1本線は電気の流れる順番に並び替える", _ " ?E200V→1本線は電気の流れる順番に並び替える", _ " ?Fケーブル", _ " ?G配線済みの線は最後") ' "処理と向きのセルも結合(リスト見本2参照))") ' ' "L , N, L1, N1, 等の順(渡りは別)", _ ' R,S,T,R1,S1,T1,R2,S2,T2,等の順(渡りは別)違う名前のものに注意する。", _ ' "(線種から向きのセルまで結合して 配線済み(テストのみする) を入力、", _ 'v5.8 左寄せ Call SetAlignLeft
Case Else 'v8.1 それ以外の場合
'v8.1 インデックス更新 ThisWorkbook.m_nIndex = 419 'v8.1 手順表示 Call ShowText End Select
err:
'v5.5 表示更新の停止解除 ' .ScreenUpdating = True ' .EnableEvents = True ' .DisplayAlerts = True ' End With
End Sub
'v3.0 ファイルが開いて無ければExcelを開く
Public Function ExcelOpen(strPath As String, strFileName As String) As Boolean
Dim objWorkbook As Workbook 'v0.4 ワークブックオブジェクト変数 Dim bOpen As Boolean 'v3.0 ファイルが開いているか確認用フラグ
'v3.0 初期化 bOpen = False ExcelOpen = False 'v0.7 ファイルが見つからなければメッセージ表示して処理を終了 If Dir(strPath & strFileName) = "" Then
'v6.9 フォームの最前列表示解除 frmText.Kaijyo
MsgBox strPath & strFileName & " が見つかりません。", vbExclamation
'v6.9 フォーム最前列表示に再設定 Call frmText.SetTemae 'v4.4 処理終了 Exit Function End If
With Application 'v0.3 画面表示の動きを停止 ' .ScreenUpdating = False 'v0.2 確認メッセージを非表示 .DisplayAlerts = False 'v2.2 イベントの発生を停止 .EnableEvents = False
'v0.4 変数にブックを順番に格納して処理を繰り返す For Each objWorkbook In Workbooks 'v3.0 "objWorkBook"の省略 With objWorkbook 'v3.0 ファイル名比較 If .Name = strFileName Then 'v3.0 パス比較 If .Path & Application.PathSeparator = strPath Then 'v9.2 手前にセット ' Call SetTemae(.Application.Caption) 'v3.9 ブック選択 .Activate 'v3.0 フラグ更新 bOpen = True Else 'v0.8 変更の確認 If .Saved = False Then 'v6.9 フォームの最前列表示解除 frmText.Kaijyo 'v3.0 保存確認のメッセージ表示 If MsgBox(.FullName & " の変更を保存しますか?", _ vbYesNo + vbQuestion) = vbYes Then 'v0.8 保存して閉じる .Close True 'v6.9 フォーム最前列表示に再設定 Call frmText.SetTemae 'v3.0 ループを抜ける Exit For End If 'v6.9 フォーム最前列表示に再設定 Call frmText.SetTemae End If 'v0.8 保存しないで閉じる .Close False End If 'v3.0 ループ終了 Exit For Else 'v9.2 目的以外のファイルなら後ろへ Windows(.Name).ActivateNext 'v9.2 目的以外のファイルなら通常サイズへ変更 ' .Application.WindowState = xlNormal 'v9.2 ウィンドウを後ろへ設定 ' Call SetUsiro(.Application.Caption) End If End With Next 'v3.0 ファイルが開いてなければファイルを開く If Not bOpen Then Workbooks.Open FileName:=strPath & strFileName End If
'v1.5 ウィンドウを通常サイズで表示 ' ActiveWindow.WindowState = xlNormal 'v1.5 最大表示 ActiveWindow.WindowState = xlMaximized
'v4.4 フラグ更新 ExcelOpen = True
'v2.2 イベントの発生を元に戻す .EnableEvents = True 'v0.2 確認メッセージを非表示解除 .DisplayAlerts = True 'v0.3 画面表示の動きを戻す ' .ScreenUpdating = True End With
End Function
'v5.7 手順表示
Public Function ShowForm(strTitle As String, strText1 As String, Optional strText2 As String = "", _
Optional strText3 As String = "", Optional strText4 As String = "", _ Optional strText5 As String = "", Optional strText6 As String = "", _ Optional strText7 As String = "", Optional strText8 As String = "", _ Optional strText9 As String = "", Optional strText10 As String = "") ' Dim objLabel(9) As Label Dim strText(9) As String
strText(0) = strText1 strText(1) = strText2 strText(2) = strText3 strText(3) = strText4 strText(4) = strText5 strText(5) = strText6 strText(6) = strText7 strText(7) = strText8 strText(8) = strText9 strText(9) = strText10
'v5.7 手順表示、戻り値更新 Call ShowForm2(strTitle, strText)
End Function
'v5.5 手順表示
Private Function ShowForm2(strTitle As String, strText() As String) ', rngColor As Range
'
Dim i As Integer Dim j As Integer
Call SetAlignCenter
'v5.7 フォームのサイズとボタン位置設定 With frmText ' 'v5.5 初期化 .Caption = strTitle For i = LBound(strText) To UBound(strText)
If strText(i) = "" Then Exit For
Select Case i Case 0 With .lbl1 If strText(i) <> "" Then .Visible = True .Caption = strText(i) Else .Visible = False End If End With End Select Next .cmdOK.Top = .lbl1.Top + (.lbl1.Height + 10) * i .Height = .cmdOK.Top + .cmdOK.Height + 40
For i = i To UBound(strText) Select Case i Case 0 With .lbl1 If strText(i) <> "" Then .Visible = True .Caption = strText(i) Else .Visible = False End If End With End Select Next
'v5.5 フォーム表示(モードレス) .Show vbModeless
End With
End Function
ここよりユーザーフォームのコード
Option Explicit
Public m_nRet As Integer 'v8.1 戻り値用変数
'v6.9 フォーム最前列表示用
''v6.9 作業ウインドウのハンドル取得
'Private Declare Function GetForegroundWindow Lib "user32" () As Long
''v6.9 Windowの位置やサイズ、表示を設定するAPI関数
'Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, _
' ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
'v7.0 64ビット対応変更ptrsafe属性追加
'v8.4 64bit対応変更、引数の修正long→longptr
'v6.9 作業ウインドウのハンドル取得するAPI関数
Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As LongPtr
'v8.4 指定名のウインドウハンドル取得するAPI関数
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" ( _
ByVal lpClassName As String, _ ByVal lpWindowName As String) As LongPtr
'v6.9 Windowの位置やサイズ、表示を設定するAPI関数
Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hwnd As LongPtr, ByVal hWndInsertAfter As LongPtr, _
ByVal x As LongPtr, ByVal y As LongPtr, ByVal cx As LongPtr, ByVal cy As LongPtr, ByVal wFlags As LongPtr) As LongPtr
Private Const HWND_TOPMOST As LongPtr = -1 '常に手前にセット
Private Const HWND_TEMAE_SET As LongPtr = 0 '手前(前面)にセット
'Private Const HWND_USIRO_SET As LongPtr= = 1 '後ろにセット(Z オーダーの最後)
Private Const HWND_KAIJYO As LongPtr = -2 '解除(すべての最前面ウィンドウの後ろ)
Private Const SWP_NOSIZE As LongPtr = &H1& 'サイズを設定しない
Private Const SWP_NOMOVE As LongPtr = &H2& '位置を設定しない
Private FORMHANDORU As LongPtr
'v5.5 フォーム表示前
Private Sub UserForm_Initialize()
'v5.6 戻り値初期化 m_nRet = vbCancel Me.SetTemae
End Sub
'最前列表示解除
Public Sub Kaijyo()
FORMHANDORU = FindWindow("ThunderDFrame", Me.Caption) 'v6.9 フォーム最前列表示解除 Call SetWindowPos(FORMHANDORU, HWND_KAIJYO, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
End Sub
Public Sub SetTemae()
FORMHANDORU = FindWindow("ThunderDFrame", Me.Caption) 'v6.9 再表示フォーム表示(モードレス) ' frmText.Show vbModeless 'v6.9 フォーム最前列表示用 Call SetWindowPos(FORMHANDORU, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
End Sub
'v5.5 OKボタンクリック時
Private Sub cmdOK_Click()
'v8.1 押したボタンを保存 m_nRet = vbOK
' 'v5.6 戻り値更新
' m_nRet = vbOK
' 'v5.6 フォーム閉じる
' Unload Me
'
'v5.5 状態フラグ更新 ' m_bOk = True
With ThisWorkbook 'v5.5 フラグ更新 .m_nIndex = .m_nIndex + 1 'v5.5 次のテキスト表示 Call ShowText End With
'v5.5 フォーム閉じる ' Unload Me
End Sub
(kuku008110) 2016/05/06(金) 11:38
なるほど。 ユーザーフォームの表示で、前面に出す、出さないの制御をしておられたんですね。 出先で、モバイルから閲覧していますので、帰宅したらじっくりと読ませてもらいます。
おそらく、このコードは MDI時代に開発され、今のSDIでは、結果的に不具合(コードとして不具合ということではありません)が発生しているのでしょうね。
とりえあず、このAPI処理で、どんな時に何をしたかったか、言葉で説明いただけますか?
(β) 2016/05/06(金) 13:59
まだコードは読んでいません。 というか、お願いしたように、ユーザーフォームの表示を、どのように制御しているのか 『言葉』での説明をお待ちしています。
それまでの、つなぎ(?)で一般論ですけど。
●xl2010までのMDIベースでの1つのエクセル区画のウィンドウの状態
ユーザーフォームウィンドウ2 ユーザーフォームウィンドウ1 ブックウィンドウ2 ブックウィンドウ1 エクセルウィンドウ
このように、まず、エクセルウィンドウが1つだけあって、その上に、開いたブックのウィンドウが 順番に積み重ねられています。 どのブックで呼ぶ出そうがユーザーフォームウィンドウは、ブックウィンドウの上に配置(表示)されます。 で、たとえばユーザーフォーム1を最前面に出したい場合は提示コードでつかっている SetWindowPos 等を使って 表示zオーダを変更したりしていました。
●xl2013以降のSDIベースでの1つのエクセル区画のウィンドウの状態
(経験からのコメントがほとんどですので、不正確な部分あれば御容赦)
まず、エクセルウィンドウとブックウィンドウの関係でいうと、各ブックウィンドウが1つずつ エクセルウィンドウを持ちます。
ブックウィンドウ2 エクセルウィンドウ2 ブックウィンドウ1 エクセルウィンドウ1
で、これらとユーザーフォームウィンドウの関係は、ブックウィンドウの上にユーザーフォームウィンドウが位置するという点では 同じなんですが、問題は、ユーザーフォームが表示された時点の最前面のエクセルウィンドウ内の最前面になるということです。
たとえばブック1が最前面にある状態、つまり
ブックウィンドウ1 エクセルウィンドウ1 ブックウィンドウ2 エクセルウィンドウ2
この状態で、ブック1で、ユーザーフォーム1が表示されると
ユーザーフォームウィンドウ1 ブックウィンドウ1 エクセルウィンドウ1 ブックウィンドウ2 エクセルウィンドウ2
こうなります。
で、次にブック2を最前面に出すと
ブックウィンドウ2 エクセルウィンドウ2 ユーザーフォームウィンドウ1 ブックウィンドウ1 エクセルウィンドウ1
こうなり、この状態でブック1でユーザーフォーム2を表示すると【その時点で一番上のエクセルウィンドウ】の最前面に配置されるようです。
ユーザーフォームウィンドウ2 ブックウィンドウ2 エクセルウィンドウ2 ユーザーフォームウィンドウ1 ブックウィンドウ1 エクセルウィンドウ1
だから、どうなんだといわれそうですが、このような状況になるということを踏まえて、実際には、従来のMDIベースのウィンドウ階層でAPIを使って 何をしたかったのか、それを SDIベースで実現するには、そこをどう対応したらいいのか、それを考える上での材料としてメモしました。
(β) 2016/05/06(金) 18:50
質問への回答をまだいただいていませんが、想像しながら、こちらで試してみた結果、 現在の構えでは、なかなか難問だと感じています。 特に、このコードを 2010以前でも2013以降でも使う可能性があるとしたら、バージョンを判定しながら 異なる制御ロジックを盛り込む必要があり、それは、保守性の観点で、やめたほうがいいと思ったりします。
MDIとSDIについて、ブックウィンドウレベルの話であれば、使いにくいなぁと思うところはあっても それなりに対処できるのですが、これにユーザーフォームウィンドウが絡んだ現象、これが【仕様】なのか それとも SDI化した際の、MSの対処忘れ(バグ)なのかもはっきりしませんので、ある日、急に、パッチが当たって ユーザーフォームウィンドウの場所がMDI当時の場所になるかもしれず、そうすると、現在のありようをベースに手を入れても 無駄になるかもしれませんので。
現在の状況で対応するなら、まったく別の制御に書き換えたほうが得策かなと思っています。 その対処には、どんな時にどんなことをしたいのかを、【言葉】で説明いただければ、お手伝いできるかもしれません。
なお、↑で、ユーザーフォームが【表示】された時点のエクセルウィンドウに帰属してしまうと書きましたが 正しくは【メモリーに読みこまれた時点】のエクセルウィンドウでした。
以下に、この現象を整理するために書いてみたテストコードを参考まで、アップしておきます。 2010以前で実行した場合と2013で実行した場合とで、現象が大きく異なることがわかると思います。 (2016でどうなるのかは、環境がないので検証できていません)
新規ブックに UserForm1〜UserForm5まで作成。UserForm5の名前をMainFormに変更した上で、 MainFormにCommandButton1〜CommandButton5を配置。 CommandButton1〜CommandButton4が、UserForm1〜UserForm4を最前面に出すボタン。 CommandButton5が終了ボタン。
Test を実行してみてください。
別途、Close2 というプロシジャを用意してあります。SDIベースでUserForm2が帰属しているウィンドウのブックを閉じるプロシジャです。 これも、SDI環境とMDI環境で、異なる状況になります。(SDIではUserForm2もなくなります)
●MainFormのユーザーフォームモジュール
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Private Declare Function SetForegroundWindow Lib "user32" _ (ByVal hWnd As Long) As Long Dim hWnd1 As Long, hWnd2 As Long, hWnd3 As Long, hWnd4 As Long
Private Sub CommandButton5_Click() 終了 End Sub
Private Sub CommandButton1_Click() hWnd1 = FindWindow("ThunderDFrame", UserForm1.Caption) SetForegroundWindow hWnd1 End Sub
Private Sub CommandButton2_Click() hWnd2 = FindWindow("ThunderDFrame", UserForm2.Caption) SetForegroundWindow hWnd2 End Sub
Private Sub CommandButton3_Click() hWnd3 = FindWindow("ThunderDFrame", UserForm3.Caption) SetForegroundWindow hWnd3 End Sub
Private Sub CommandButton4_Click() hWnd4 = FindWindow("ThunderDFrame", UserForm4.Caption) SetForegroundWindow hWnd4 End Sub
●標準モジュール
Option Explicit
Dim bk1 As Workbook Dim bk2 As Workbook Dim bk3 As Workbook Dim bk4 As Workbook
Sub Test() MainForm.Show vbModeless Set bk1 = Workbooks.Add UserForm1.Show vbModeless Set bk2 = Workbooks.Add UserForm2.Show vbModeless Set bk3 = Workbooks.Add UserForm3.Show vbModeless Set bk4 = Workbooks.Add UserForm4.Show vbModeless End Sub
Sub 終了() On Error Resume Next Unload UserForm1 Unload UserForm2 Unload UserForm3 Unload UserForm4 Unload MainForm bk1.Close False bk2.Close False bk3.Close False bk4.Close False On Error GoTo 0 End Sub
Sub Close2() bk2.Close False End Sub
(β) 2016/05/07(土) 08:40
編集するブックを開く毎に、操作するフォームを読み直す事で解決できました。
今のところ2013以降でのみ使う予定です。
丁寧な説明をありがとうございました、とても参考になりました。
(kuku008110) 2016/05/09(月) 15:30
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.