UserForm から、セル範囲を入力する場合に便利な[ RefEdit コントロール]、こいつも
なかなか油断のならない奴だって事を知ってますか?
1. カーソル位置が変!
2. RefEdit でエクセルがコケる(その1) : シートへの書き込み
3. RefEdit でエクセルがコケる(その2) : TabStrip のフォーカス ロスト
4. RefEdit でエクセルがコケる(その3) : 閉じるボタンの禁止処理
5. RefEdit でエクセルがコケる(その4) : RefEdit イベント内でのエラー
6. R1C1形式の環境でRefEdit コントロールを利用する際の注意点
・ [RefEdit.Value ⇒ Rangeオブジェクト]の変換方法 (Rangeプロパティ)
・ [RefEdit.Value ⇒ Rangeオブジェクト]の変換方法 (Evaluateメソッド)
7. Excel2007 のRefEditがExcel2000〜2003でエラーを引き起こす
8. RefEditコントロールを使わないでRefEdit動作を実現する方法 (別ページ)
9. RefEdit 代替手法( クラスモジュール版 Ver 2.40 ) (別ページ)
10. RefEdit コントロールを動的に作成する方法(参照設定が不要)
11. 親&子フォームで、子フォームに RefEdit コントロールを配置した際のトラブル
12. RefEdit で ショートカットキー(Ctrl+Shift+↓ 等) を有効にする方法
13. RefEdit 関連サポート技術情報
[ この場所へのリンク ]
-------------------------------------------------------------------------
RefEdit コントロールの不具合と言えば「カーソルが変な所に出る」というのが有名ですね。
Tab キーで順々にコントロールを移って行って、RefEdit に来た瞬間に、何故かカーソルが
UserForm の左上隅に飛んでしまいます。ところで、その位置って、RefEdit を折り畳んだ時
のカーソル位置とピッタリ同じに見えませんか?
これ、Excel2002(SP2)では直ってますね。後述の[RefEdit]関連サポート技術情報にあるように、Excel2000(SP3)
/Excel2002(SP1)アップデートで[RefEdit]に修正が入っているようですから、その時にでも直したのでしょうか?
でもサポート技術情報には載ってないんですよね。 (2003/11/13追記)
まぁ、こんなのは一寸した御愛嬌で済みますけど、次のはトンデモないですよ!
[ この場所へのリンク ]
-------------------------------------------------------------------------
RefEdit コントロールが原因でエクセルがコケる、トンデモない技 (その1) : シートへの書き込み
RefEdit コントロールを使う処理では【ワークシートへの書き出し】時にExcelがダウンする
場合があります(笑い事では済まないでしょ)。
下記のタイミングで【ワークシートへの書き出し】を行なうと、UserForm が強制的にUnLoad
されます。事前にブレークポイントを設定しておいて、デバッグモードで『続行』を選択すると
”不正な処理を行なったので強制終了”
と表示され、EXCELがダウンします。そのブックは『編集中』となり、再立ち上げをするまでロック
されます。
問題となるイベントタイミングは
『RefEdit の KeyDown 』から
『TextBox の MouseDown 』又は『CommandButton の Enter 』
の間です(TextBox/CommandButton 以外のコントロールでも同様)。イベントの発生順序を
並べると下記の順になりますから、これらのイベントは要注意になります。
(RefEdit)
Enter > MouseDown > MouseUp > KeyDown > Change > KeyUp > ・・・ > Exit →
(TextBox)
→ Enter > MouseDown > MouseUp > KeyDown > Change > KeyUp > ・・・ > Exit
(CommandButton)
→ Enter > MouseDown > MouseUp > Click ・・・ > Exit
とはいえ、次の2点に注意していれば問題は無いでしょう。
(1) RefEdit コントロールのイベントは一切使わない。
(2) RefEdit コントロールを利用する場合は、他の全てのコントロールで[Enter ]イベントは
使わない(マウスで、何処に移るか判りませんからね)。
その問題のイベントでも「ワークシートへの書き出し」が無ければ、何も問題は無いんですが、
そのイベントがマクロコードに載っていると、将来うっかりと「あっ、丁度このイベントマクロが有る
から、ここで書き出してしまえ」というような事も無きにしも非ずで‥‥‥。
そういう事も有り得ますから、RefEdit コントロールを使っている場合は、UserFormモジュールの
先頭に下記のような【注意書き】をコメントしておくのが良いでしょう。
'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
'_/ RefEditを使っているので、RefEditの[イベント全て]と、
'_/ 各コントロールの[Enter]で、ワークシートへの書き出しは厳禁
'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
しかし、この[RefEdit ]コントロールのバグ、標準では使えないコントロールのせいなのか(『その
他のコントロール』で追加)、Excel97 の頃から延々と全く直る気配も無く残っています。
尚、この障害は[ Excel2000 SR1 , Excel2002 SP2 , Excel2007 SP1 ]で確認しています。
(Excel2003 の環境を持ってないので実際に確認はしてませんが、Excel2003 も同じでしょう)
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2004/6/10 追記)
RefEdit コントロールが原因でエクセルがコケる、トンデモない技(その2) : TabStrip のフォーカスロスト
MOUG/VBAに質問があったものですが、試してみたら、確かに、ものの見事にエクセルが
コケました。お見事、というしかないですね > RefEdit 君
「障害の再現方法 (試す場合は、大事なブック等を保存してから行なって下さい)」
(1) UserForm 上に、TabStrip/RefEdit1/RefEdit2/他のコントロール(任意)を配置。
(2) タブオーダーは[RefEdit1→RefEdit2]と連続させる。他は任意。
(3) TabStrip1_Change イベントプロシジャー内に
RefEdit1.Visible = False
RefEdit2.Visible = False
という処理を記述。
(4) UserFormを表示させ、フォーカスを RefEdit1 に置いた状態で、TabStrip のタブを
ワンクリックしてタブを切り換える(→RefEdit1 & 2 が非表示になります)。
(5) UserForm を「閉じるボタン」で閉じて、VBEを覗くと、メニューバー上の実行アイコン
(横向き▲)がグレー状態になっており、未だ「実行中」扱いで、停止アイコン(■)が
が効きません。また、エクセル自体の「閉じるボタン」も効きません。
(6) この無応答状態が続くか、もしくは、セルなどを触っている際にエクセルが異常終了します。
「障害原因について」
この障害には、フォーカスが大きく係わっています。また、TabStrip コントロールが、タブの
ワンクリックでは「フォーカスがTabStrip に移らない」という性質も影響しています。TabStripコン
トロールのタブをワンクリックすると、タブは切り替わりますが、フォーカスを示す点線枠がタブ上
に出ません。もう一度クリックすると、ようやく点線枠が出てフォーカスが移ります。
また、↑の再現Userformでも、以下の条件の何れかの場合にはエクセルがコケる事はありま
せん。
a) ↑のタブオーダーでRefEdit2 にフォーカスが有る。
b) [Visible=False]にするのをRefEdit1 のみとし、RefEdit2は残す。
c) タブオーダーを[RefEdit1 → 他のコントロール → RefEdit2]にする。
この3つのケースは何れも、RefEdit1の非表示によりフォーカスが移ったコントロールが「活きて」
いる状態です。
a)ではRefEdit2の次のコントロールが活きていて、ここにフォーカスが移ります。b)ではRefEdit2
が非表示にならずに残って活きています。 c)では、間に他の活きているコントロールが入ってい
ますので、フォーカスはそのコントロールへ移ります。
即ち、この障害は、
a) フォーカス移動の起こらない「タブ」ワンクリックにより、
b) フォーカスがRefEdit1に残ったままの状態でRefEdit1が非表示にされ、
c) それによって、フォーカスがタブオーダーに従ってRefEdit2 へ移る間もなく、
RefEdit2まで非表示になった為に、
d) フォーカスが宙に浮いた状態となり、
e) その後にUserFormを閉じようとした時に、RefEdit1 もしくは RefEdit2 が
半分活きているような変な状況が発生して、
f) RefEditコントロールのWindow破棄が正常に出来なくなった
という事ではないかと考えられます
この例の場合、TabStrip1_Changeイベントプロシジャーで、[Visible=False]を行なう前に、
TabStrip1.SetFocus
を行なうと障害は発生しません。RefEdit1/2が非表示になる前に、TabStripのタブにフォーカスが
移る(点線枠が出る)為です。
また、TabStrip1_Change の代わりに CommandButton1_Click 等で同じように RefEdit1/2 を非
表示にしても障害は出ません。コマンドボタンではワンクリックでフォーカスもRefEdit1 から Comm
andButton1 へ移りますから、非表示処理は RefEdit1 がフォーカスを失った後に行なわれる為です。
尚、この障害は[ Excel2000 SR1 , Excel2002 SP2 , Excel2007 SP1 ]で確認しています。
(Excel2003 の環境を持ってないので実際に確認はしてませんが、Excel2003 も同じでしょう)
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2006/2/19 追記)
RefEdit コントロールが原因でエクセルがコケる、トンデモない技(その3)
RefEdit コントロール利用フォームで 閉じるボタンを禁止 する際の注意点
巻末のサポート技術情報にも載せてありますが、どうも
[XL2000] ユーザー フォームを閉じられない現象について
の事のようですね。これを読むと「Excel97で出来ていた事 (折り畳んだ RefEdit の閉じるボタン(X)で
UserForm を閉じれる) がExcel2000 になってから出来なくなった」 と書かれていますね。
つまり、Excel2000以降の状態の方が【バグ】であるという認識のようです。
下記のようにして、UserForm の「閉じるボタン(X)」を禁止する事はよくありますね。
バージョンに係わらず、極く普通に、何も問題も無く使えるマクロの筈ですね。ところが、
Private Sub UserForm_QueryClose _
(Cancel As Integer, CloseMode As Integer)
If (CloseMode = vbFormControlMenu) Then
Cancel = True '[X] 閉じるボタン禁止
End If
End Sub
唯一つ、『Excel97 で RefEdit コントロールを使っている』場合に限り大問題が起きます。
RefEdit コントロール入力時に折り畳まれたウィンドウ(下図)にも「閉じるボタン」があります。
この「閉じるボタン」をクリックした場合の動作が、Excel97 と Excel2000以降で異なります。
Excel2000以降では、
その下にあるRefEdit の復帰ボタンをクリックした時と同じ動作です。
即ち、折畳みウィンドウを閉じたら、元のフォームを再表示して、そこへ戻ります。
この時、UserForm_QueryClose イベントは発生しませんので、上記のマクロとは
係わり合いはありません。
Excel97 の場合、
折畳みウィンドウを閉じると同時に、元のフォームも閉じてしまいます。
即ち、UserForm_QueryClose → UserForm_Terminate と進んでUnLoad されます。
ここで上記のマクロにより、QueryClose イベントをキャンセルしていると、どれか有効
なコントロールでの入力待ち状態に移ります(普通なら、RefEdit にフォーカスがある
筈ですから、そこにカーソルが行く筈です)。ところが、Excel97 のRefEdit では、元の
フォームは消えたままで再表示されません(Visible = False 状態でしょうか)。
その結果、恐らく、制御はモーダルフォームのUserFormが握っているが、表示されて
いないので何の操作もできない状況になっているものと思われます。当然、再表示さ
せるような指示も出せません。モーダルですから、シートも触れませんし、コマンド
バーも触れません。つまり何も出来ません。
そこで、RefEdit コントロールを使っているフォームで閉じるボタンの禁止する場合は、バー
ジョンによる切り分けが必要になります。
Private Sub UserForm_QueryClose _
(Cancel As Integer, CloseMode As Integer)
If (CloseMode = vbFormControlMenu) Then
If (Val(Application.Version) > 8) Then
Cancel = True 'Excel2000以降 [X]閉じるボタン禁止
Else
'Excel97では有効にする(RefEditのXボタン対策)
End If
End If
End Sub
(補) 他に、APIを使って[Enabled=False]状態(グレー表示)にする事で「閉じるボタン」
を無効にする方法があります。しかし、元のUserFormと折り畳まれたRefEdit ウィン
ドウのウィンドウクラスを調べると【別物】である事が判ります。つまり、元のUserForm
に対してAPIで無効化しても、折り畳まれたRefEdit ウィンドウには反映されないと
いう事です。
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2010/2/6 追記)
RefEdit コントロールが原因でエクセルがコケる、トンデモない技(その4)
RefEdit コントロールのイベント内での実行時エラー ( MOUGで私が回答したスレッド )
RefEdit コントロールにイベントルーチンを記述している場合には、そのイベント内で実行時
エラーが発生しないようにエラーチェックを厳重に行なう必要があります。
TextBox など通常のコントロールの場合、そのイベントルーチン内で実行時エラーが発生すれば
【実行を止めてVBE に移る・エラーメッセージの表示・エラー発生箇所のハイライト】といった動作を
してくれます。
しかし、RefEdit コントロールの場合には同様のデバッグサポート動作は機能しないようです。RefEdit
コントロールから他のコントロールへフォーカスが移った(RefEdit コントロールの Focus Lost タイミング)
時点で UserForm が異常終了します(エラーメッセージの表示も無く UserForm が消える)。
簡単なサンプルを紹介します。UserForm に TextBox1/TextBox2/RefEdit1 を配置して以下のマクロ
を記述します("Error 424" は擬似的に、[424エラー]を発生させる命令です) 。
UserForm を表示して TextBox2 へ適当に書き込むと、1文字入力した瞬間(Change イベント時)に
Private Sub TextBox2_Change()
Error 424
End Sub
Private Sub RefEdit1_Change()
Error 424
End Sub
実行時エラーが発生して[Error 424] のステップがハイライトされます。
RefEdit1 でセルを選択しても、その瞬間(Change イベント時)にはエラーとはなりませんし、別セルを
選択し直す事も出来ます(この時にもエラーは起きません)。ところが、タブキーを押したり、TextBox1 を
クリックして RefEdit1 からフォーカスが他コントロールへ移った瞬間に UserForm が落ちてしまい
ます。この後は、VBEにて『リセット(■ボタン)』を行なわないと復旧しません。
この障害は、RefEdit コントロールが参照設定で取り込む【外部のコントロール】である事に起因している
ものと思われます。コントロールから Excelアプリケーションへのエラー通知がエラー発生時にリアルタイム
で行なわれず、制御を離れる(Focus Lost )際にしか通知出来ていない設計故に、エラー発生場所など
の情報を十分に引き継ぐ事が出来ないのでしょう。
これは、Excel アプリケーションから見れば、「どこで、どんなエラー」が発生したのか正確な情報が得られ
ないのですから、このまま実行を続けるのは危険性大として、とにかく直ちに止めるしかないという状況なの
でしょう(エラー情報が無いので、ユーザーへのメッセージを出す事も出来ず、コードをハイライト化する事も
出来ず)。
RefEdit コントロールで、この問題に出会う可能性が高いものは
【 RefEdit1.Value (String型)から セルオブジェクト(Range 型)への変換 】
という処理でしょう。この処理には次項で解説している『 Evaluate メソッド 』を使いますが、その際にエラー
判定が行なわれていないと、この障害に出会う事となります。一例としては『 RefEdit1.Value が空文字(Del
キー等で入力内容のクリアなど)』の場合が挙げられます。
ただし、この問題は、RefEdit コントロールのイベントルーチン内で処理している場合の話です。RefEdit
にはイベントルーチンが無く、セルオブジェクトへの変換などを 他のコマンドボタンのクリックイベント内で
行なっている場合などでは、この障害は出ません(普通にエラー表示されます)。
尚、この障害は、RefEdit コントロールに限らず、【参照設定で取り込む外部のコントロール】全般で
起こりうる問題だと思います。外部コントロールを使用する場合には、実行時エラーが起こる可能性のある
処理を入念に洗い出して、エラーを回避できるコードを構築するようにしてください。
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2004/10/2 追記)
R1C1形式の環境でRefEdit コントロールを利用する際の注意点 ( MOUGに私が質問したスレッド )
[ この場所へのリンク ] 〜Rangeオブジェクトへの変換方法(Rangeプロパティ) 〜
RefEdit コントロールで得られるValueプロパティはString 型ですので、そのセルアドレス文字
列からRangeオブジェクトを取得する必要があります。一般に解説されているのは下記のような
方法です。
Dim MyRng As Range
Set MyRng = Nothing
On Error Resume Next
Set MyRng = Range(RefEdit1.Value)
On Error GoTo 0
If (MyRng Is Nothing) Then
MsgBox "セル範囲を選択して下さい"
End if
[A1形式]環境ならば何も問題ないのですが、[R1C1形式]環境では
『RefEdit コントロールのValue も、R1C1形式のアドレス文字列』
となります。ところが、肝心のRange プロパティの引数には【A1形式】しか指定できないので、
R1C1環境で上記マクロを実行した場合、RefEditコントロールでちゃんとセルを選択してもエ
ラー扱いになってしまいます。
同様の機能を提供する「InputBox メソッド(Type:=8)」では、そもそも返却値自体が[Range
オブジェクト]で得られますので、A1形式/R1C1形式という環境の違いには影響されません。
対応策としては、
R1C1形式で得られた文字列をA1形式に変換
してからRangeプロパティを通すという方法が考えられます。変換処理には[ConvertFormula
メソッド]が利用できます。
Dim MyRng As Range
Dim strRng As String
If (RefEdit1.Value = "") Then
MsgBox "セル範囲を選択して下さい"
Else
With Application
If (.ReferenceStyle = xlA1) Then
strRng = RefEdit1.Value
Else
On Error Resume Next
strRng = .ConvertFormula(RefEdit1.Value, xlR1C1, xlA1)
If (Err.Number <> 0) Then
strRng = "" 'Rangeプロパティでエラーにさせる
End If
On Error GoTo 0
End If
End With
Set MyRng = Nothing
On Error Resume Next
Set MyRng = Range(strRng)
On Error GoTo 0
If (MyRng Is Nothing) Then
MsgBox "セル範囲を選択して下さい"
Else
MsgBox "OK:" & MyRng.Address
End If
End If
ちょっと長いですね。ConvertFormula を「使うか(R1C1形式)/使わないか(A1形式)」の判
断と、ConvertFormula へのエラー処理が必要なので、こんなコードになります。
[ この場所へのリンク ] 〜Rangeオブジェクトへの変換方法(Evaluateメソッド) 〜
ところで、セルアドレス文字列をRangeオブジェクトに変換する方法には、Rangeプロパティ
の他に【Evaluateメソッド】というのもあります。このEvaluateメソッドのヘルプには「A1形式の
参照〜」というような事が書かれていますが、R1C1形式でも変換してくれます。そうすると、
上記のように「A1形式なら‥‥、R1C1形式なら‥‥」という風にする必要もありません。
Dim MyRng As Range
Set MyRng = Nothing
On Error Resume Next
Set MyRng = Application.Evaluate(RefEdit1.Value)
On Error GoTo 0
If (MyRng Is Nothing) Then
MsgBox "セル範囲を選択して下さい"
End if
(2006/5/30 補足)
上記で、Evaluateメソッドは
A1形式のアドレス文字でもR1C1形式のアドレス文字でも変換できる
と書きましたが、
[A1形式]環境では、R1C1形式のアドレス文字はエラー
[R1C1形式]環境では、A1形式/R1C1形式どちらのアドレス文字でもOK
という事が判りました。ただし、上記の使用方法では、
[A1形式]環境では、RefEdit がA1形式アドレス文字を返す
[R1C1形式]環境では、RefEdit がR1C1形式アドレス文字を返す
となりますから、
[A1形式]環境でR1C1形式アドレス文字がEvaluateメソッドに渡る
という事は起きませんので問題はありません。
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2008/12/17 追記 , 12/18 修正 , 2009/5/15 MS 回答を記載)
Excel2007のRefEditコントロールがExcel2000〜2003でエラーを引き起こす
RefEditコントロールはExcel2007からバージョンアップされています(セル参照文字列として
扱えるデータが '255文字' から '8KB' へ拡張されました)。Excel2010で更にバージョンアップ
されています(これは、VBA6 から VBA7 へのバージョンアップに伴うものでしょう)。
- 2012/8/12 追記 -
[ Ver. 1 ⇒ Ver. 12 ] へのバージョンアップ は、 2007 ではなく 2003 SP3 において施された事が判りました。
RefEditコントロールの本体である [ RefEdit.dll ] はバージョンによって以下の場所に格納され
ています。マルチインストールの場合には各々のフォルダに存在します。
Excel97 : C:\WINDOWS\system32 (ここは DLL の既定フォルダ(パスの通ったフォルダ)です)
Excel2000 : C:\Program Files\Microsoft Office\Office
Excel2002 : C:\Program Files\Microsoft Office\Office10
Excel2003 : C:\Program Files\Microsoft Office\Office11
Excel2007 : C:\Program Files\Microsoft Office\Office12
Excel2010 : C:\Program Files\Microsoft Office\Office14
注) DLLのバージョン表記はExcel97 と Excel2000〜2003 どちらも [1.0.0.0] ですが、Excel97の
VBAが[Ver.5]であり、RefEditの動作も一部異なりますので、2000〜2003のものとは別物です。
RefEditコントロールを使用すると、[VBE/ツール/参照設定]ダイアログにおいて、RefEditコント
ロールの参照設定が追加されます。参照設定の内容を見ると、RefEdit.dll のフルパスを見る事
ができます。
このRefEditコントロールを使ったブック(参照設定の付いたブック)を、
・ 他のExcelバージョンのPC
または、
・ 同じバージョンのExcelであってもExcelのインストールフォルダのパスが異なっているPC
例) C:\Program Files\Microsoft Office\Office10
C:\Program Files\Microsoft Office2002\Office10
で開いた場合を試すと、バージョンによって扱いが異なる事が判りました。
a) Excel97〜2003で作成したブックを、Excel97〜2003で開く(他バージョン or パス違い)
b) Excel97〜2003で作成したブックを、Excel2007で開く(互換モード)
c) Excel2007で作成した97〜2003互換ブックを、Excel97〜2003で開く
d) Excel2007で作成したブックを、Excel2007で開く(パス違い)
a) , b) , d) の場合には、自動的に、RefEditの参照設定が開いたExcelのパスに変更されており、
エラーも無く、動作に何の問題もありません。
c) の場合には、97と2000〜2003で異なります。
・ Excel2000〜2003で開くと、参照設定のパスが[作成した環境時のまま]となっており、参照
設定ダイアログ内において【参照不可】のフラグが立っています。
・ Excel97で開くと、参照設定が変更され何の問題もありません(これは、VBAが Excel97は
Ver.5、Excel2000〜2007は Ver.6 という違いによるものでしょう)。
- 2012/8/12 追記 -
[ 2003 SP2 ⇒ 2003 SP3 ] のアップデートで RefEdit の バージョン が [ Ver. 1 ⇒ Ver. 12 ] となりました。
したがって、Excel2003 では Service Pack によって症状が分かれますので注意が必要です。
・ 2007 で作成して 2003 SP3 で開く ・・・ エラーなし
・ 2007 で作成して 2003 SP2/SP1/SP無 で開く ・・・ [ 参照不可 ] になる
・ 2003 SP3 で作成して 2003 SP2/SP1/SP無 で開く ・・・ [ 参照不可 ] になる
[参照不可]についてのMicrosoft の回答(2009/5/7)
・Excel2007より、RefEdit の機能が拡張された為に、Excel2003以前のものとは
「タイプライブラリ」の内容が変わりました(255文字→8KB)。
・上位互換であるので、Excel2003以前のRefEdit 付きブックは Excel2007 でも
動作します(低機能(2003以前のRefEdit )は高機能(2007のRefEdit )の中に完
全包含)。
・逆に、Excel2007のRefEdit付きブックをExcel2003以前で開いた場合、高機能
(2007のRefEdit)処理を低機能(2003以前のRefEdit)ではカバー出来ない為、そ
の部分で、予期せぬエラーが起こる可能性が出て来ます。
・これを未然に防ぐ意味で【使用不可】となるように[参照不可]状態にする仕様
になっています。
・したがって、自動的に、この[参照不可]状態を回避する手段はありませんので、
a) マニュアル操作でExcel2003以前のRefEdit を参照設定し直す
b) それで問題なく動作するか動作確認する
という対応がユーザーに求められます。
この【参照不可】の付いた状態のブックですが、実はこのままでもRefEditコントロールを載せた
UserFormは問題なく動作します(これもまた謎のひとつなんですが)。
試しに、UserFormにRefEditコントロールを載せ、
Private Sub UserForm_Click ( )
MsgBox RefEdit1.Value
End Sub
というイベントプロシジャーを書いたブックを用意してテストすると、普通にセル範囲の指定が
できますし、MsgBox も表示されます。
では、ここで問題にしている「エラーを引き起こす」とは何なのでしょう?
上記のイベントマクロを
Private Sub UserForm_Click ( )
MsgBox RefEdit1.Value & Format(Date,"yyyy/m/d")
End Sub
と修正してみます。これを試すと、今度は
「プロジェクトまたはライブラリが見つかりません」
というコンパイルエラーが発生します。VBEでエラー箇所を見ると、Date の部分がハイライト
しています。文法的に全く問題のないマクロです。Date の部分を数値(2000 とか)に変えてみ
ると、今度はFormat の部分がエラーになります。
【参照不可】が、Date などの極当たり前に使える関数をコンパイルエラーにしてしまうというのは、
良くある事です(これはFAQといって良いでしょう。「Date がエラーになります」という質問に対し
ては、『参照不可マークの付いている項目がありませんか』という回答が常套句ですね)。
ここで、このブックをアドイン等のツール頒布で行なう「プロジェクトロック」をしてみるとどうなる
でしょう。この場合には、
「非表示モジュール xxx 内でコンパイルエラーが発生しました」
というエラーメッセージが表示されます。
以上の説明から単に
「Excel2003以前でも使うブックを、Excel2007の互換モードで作成する場合、
RefEdit コントロールは使用できない。元々、非互換だと諦めてRefEdit を使
わないようにするか、セオリー通りに下位バージョンで作成する。」
と締め括って、そこで終わりにしてしまいたくなりますが、ちょっと待ってください。
確かに、複数バージョンで使うブックの作成は下位バージョンで行なうのが基本です。その場合、上
位バージョンでの動作確認を容易にする為に、開発PCでは複数のバージョンのExcelをマルチイ
ンストールしている人が多いのではないでしょうか。
そこで、Excel2000〜2007で使う前提で、Excel2000,2002,2003,2007がマルチインストールされた
PCを使い、Excel2000にてRefEditを使ったブックを作成するとどうなるでしょうか?
マルチインストールされている開発PCでは、どのバージョンで開いても、【参照不可】にはなりませ
んし、当然コンパイルエラーにもなりません。これで「問題は無い」と判断して、Excel2000〜2007が
単独でインストールされている各PCに持って行くと……
・ Excel2007では問題なし
・ Excel2000〜2003では【参照不可】&コンパイルエラー
(開発バージョンと同じExcel2000でもエラーになります)
となります。
これは何故でしょう。ブックを作ったのはExcel2000です。Excel2007で上書き保存はしていません。
Excel2002/2003でもエラーにならないのは確認しました。でも、他のPCではエラーになってしまい
ます。
原因は、マルチインストール環境における、RefEditコントロールの参照設定の有り方です。
マルチインストール環境では、各バージョンのフォルダに個々のRefEdit.dll がありますが、参照設定
に載るのは『最後にインストールされたバージョン』のみです(何れのバージョンのRefEdit.dll も、その
CLSID が同じである為、レジストリに残るのは最後にインストールされたものとなります)。
通常は[古→新]の順でインストールします。したがって、Excel2000〜2007のマルチインストール環境
では、常にExcel2007のRefEdit.dll しか参照設定されません。
つまり、Excel2000でブックを作っても、この場合は参照設定にはExcel2007のRefEdit.dll が入ります。
この為、上で説明したパターン通りのエラーが発生してしまう事となります。開発PCでのExcel2002/
2003でエラーにならないのは、元々そのPCに有るものを(参照可能なパスで)参照しているからです。
以上のことから、このトラブルを回避するには
マルチインストール環境にはExcel2007 を含めない。
動作確認で必要となるExcel2007は別PC(または、Virtual PC )に用意する。
もしくは、
Excel2000〜2007 のマルチインストール環境でマクロ開発を行なった後に、
Excel2000〜2003 の単独インストール環境に持って行き(当然エラーになります)、
参照設定を付け直してエラーを解除したブックを【配布用ブック】として管理する。
という配慮が必要となります。尚、開発PCには単独バージョンしかない(2007以外)という場合には、
そもそも、このような問題は起きませんので何ら気にする必要はありません。
- 2012/8/12 追記 -
[ 2003 SP2 ⇒ 2003 SP3 ] のアップデートで RefEdit の バージョン が [ Ver. 1 ⇒ Ver. 12 ] となりました。
したがって、Excel2003 では Service Pack によって症状が分かれますので注意が必要です。
・ 2007 で作成して 2003 SP3 で開く ・・・ エラーなし
・ 2007 で作成して 2003 SP2/SP1/SP無 で開く ・・・ [ 参照不可 ] になる
・ 2003 SP3 で作成して 2003 SP2/SP1/SP無 で開く ・・・ [ 参照不可 ] になる
[ この場所へのリンク ]
- 2012/9/18 追記 -
他サイト・ブログの記述で、
単に 「バージョン によって REFEDIT.DLL の場所が異なる」 からエラーになる
と誤解される方がいるようですが、「保存場所が異なる」 という事が 直接の理由ではありません。
【新機能を使おうとしているのに、旧機能しかない環境で動かそうとしている】のが理由です。
(1) REFEDIT.DLL は、各バージョンごとに各々の Library フォルダにある。
(2) マルチインストールの場合、何れのバージョンでも、実際に使われる(参照される)のは、最新バージョン
(最後にインストールしたバージョン)のものが共通して使われる(2002で開発しても2007の REFEDIT.DLL 等)。
(3) 〜2003 SP2 (2000,2002) と 2003 SP3〜 (2007,2010) の REFEDIT.DLL はインターフェースが異なる。
(4) 上位互換なので、
「〜2003 SP2 の REFEDIT.DLL 使用」 を指定しているブックは、 「2003 SP3〜 の REFEDIT.DLL」 が
動作している環境でも問題ない
しかし、
「2003 SP3〜 の REFEDIT.DLL 使用」 を指定しているブックは、「〜2003 SP2 の REFEDIT.DLLl」 が
動作している環境では、【機能が足らない】のでエラーになる(予防的にエラーにしている)
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2009/5/23 追記 , 2010/3/30 修正, 2010/4/13 修正, 2010/4/18 修正 , 2010/4/20 修正 , 2011/7/1 修正)
RefEditコントロールを使わずにRefEdit動作を実現する方法 (Excel97は不可)
〜 下記へ移動しました (2010/5/2) 〜
http://addinbox.sakura.ne.jp/Excel_Tips08_2.htm#NonRefEdit
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2010/4/14 追記, 2010/4/18 修正 , 2010/4/20 修正 , 2010/4/23 修正 ,
2010/5/2 修正 , 2010/5/14 修正 , 2010/12/15 修正 , 2010/12/25 BUG修正 , 2011/7/1 修正)
RefEdit 代替手法(クラスモジュール版) (Excel97は不可)
〜 下記へ移動しました (2010/5/2) 〜
http://addinbox.sakura.ne.jp/Excel_Tips08_2.htm#NonRefEditClass
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2012/8/13 追記)
RefEditコントロールを動的に作成する方法
ここ では、RefEdit コントロールを配置すると『RefEdit.dll への参照設定』が付き、それが原因で
Excel バージョン間での共有の際に、【参照不可】によるトラブルが発生する事を解説しました。
デザイン時(VBEでの編集)に RefEdit コントロールを配置せず、UserForm を表示する際に、
動的に RefEdit コントロールを作成するようにプログラムすれば、VBAプロジェクトに『RefEdit.dll
への参照設定』が付きませんので、「参照不可」となる事もありません。
下記のブログに、RefEdit コントロールの動的作成の記事がありました。
Peltier Tech Blog [ New RefEdit Approach - Volunteers Wanted ]
http://peltiertech.com/WordPress/new-refedit-approach-volunteers-wanted/ ( Internet Archive )
(補)このブログのサンプルでは、ラベルコントロールを土台に使い、RefEdit コントロールの表示位置を
[ .Top = Me.Controls ("Label" & i ).Top + 12 ] としています。これは、ラベルコントロールを土台
にしている事が判るよう、ラベルコントロールがRefEditコントロールに隠れずに、一緒に表示される
ようにしているものです。実際の運用では、土台コントロールが隠れるように位置を合わせます。
すみません、勘違いですね。単に、入力フィールド名(ラベル)の 『直下に 固定サイズで作成』
という使い方というだけですね。深読みし過ぎました。(2012/9/7)
これを汎用化できるように、動的作成部分をサブルーチン化しました。
サンプルブック [ RefEdit_Dynamic_Create.xls ] (50KB) 2012/8/13
'RefEdit コントロールの動的作成サンプル
'
' AddinBox / 油断のならないRefEdit 『RefEditコントロールを動的に作成する方法』
' http://addinbox.sakura.ne.jp/Excel_Tips08.htm#DynamicCreate
'
' 参考 : Peltier Tech Blog [New RefEdit Approach - Volunteers Wanted]
' http://peltiertech.com/WordPress/new-refedit-approach-volunteers-wanted/
'
'a) コンボボックスを土台として、コンボボックスと同じ位置・サイズ・フォントで、
' コンボボックスに被せて動的に作成します。土台としてはラベル等でも構わない
' のですが、ボタン部分がありますので、デザイン時に同じような見え方になる
' コンボボックスを使います。
'
'b) 土台のコンボボックスは[Enabled=False]にして、タブ移動/入力処理を無効にします。
'
'c) タブオーダーは、TabIndexにコンボボックスの次の値を設定する事で
' 実行時にRefEditコントロールのタブオーダーが期待通りの位置となるようにします。
'
'd) Frame/MultiPageに作成したRefEditは『キャプション無し』になります。
' (UserFormに作成したRefEditは UserFormのキャプションになります)
'
'e) RefEditへのアクセス処理は Me.Controls("RefEdit1") のように行なう。
'
'f) プロジェクトにRefEdit.dllへの参照設定が無いので、Excelバージョンによる
' [参照不可]問題を気にする必要がない。
'RefEditコントロールオブジェクトの保存用コレクション
Private colRefEdit As Collection
Private Sub UserForm_Initialize()
Set colRefEdit = New Collection
'ComboBox1: RefEdit1
Call Create_RefEdit(Me, ComboBox1)
'ComboBox2(Frame1 内): RefEdit2
Call Create_RefEdit(Frame1, ComboBox2)
'ComboBox3(MultiPage1/Page1 内): RefEdit3
Call Create_RefEdit(MultiPage1.Page1, ComboBox3)
End Sub
Private Sub UserForm_Terminate()
'動的作成 RefEdit オブジェクトの解放
Set colRefEdit = Nothing
End Sub
Private Sub CommandButton1_Click()
MsgBox "RefEdit1.Value = " & Me.Controls("RefEdit1").Value & _
vbCrLf & vbCrLf & _
"RefEdit2.Value = " & Me.Controls("RefEdit2").Value & _
vbCrLf & vbCrLf & _
"RefEdit3.Value = " & Me.Controls("RefEdit3").Value
End Sub
Private Sub Create_RefEdit(ByRef argContainer As Object, _
ByRef argBaseCtrl As MSForms.ComboBox)
' argContainer : RefEditを作成する UserForm/Frame/MultiPage(Page)オブジェクト
' argBaseCtrl : RefEditの土台になるComboBox
' RefEditのコントロール名はComboBoxのTextプロパティ
Dim ctrl As Object
argBaseCtrl.Enabled = False
Set ctrl = argContainer.Controls.Add("RefEdit.Ctrl", argBaseCtrl.Text, True)
With ctrl
.Top = argBaseCtrl.Top
.Left = argBaseCtrl.Left
.Height = argBaseCtrl.Height
.Width = argBaseCtrl.Width
.Font.Name = argBaseCtrl.Font.Name
.Font.Size = argBaseCtrl.Font.Size
.TabIndex = argBaseCtrl.TabIndex + 1
End With
colRefEdit.Add ctrl
Set ctrl = Nothing
End Sub
[ この場所へのリンク ]
-------------------------------------------------------------------------
(2015/9/27 追記)
親&子フォームで、子フォームに RefEdit コントロールを配置した際のトラブル
RefEdit コントロールでセル範囲の選択中は、
(a) RefEdit コントロールを配置しているフォームが Hide される
(b) RefEdit ダイアログのみが表示されて、セル選択を行なう
(c) RefEdit ダイアログを閉じると、Hide されていたフォームが再表示される
という流れになります。
親 & 子フォームの構成で、子フォーム内に RefEdit コントロールを配置した場合も、
親フォーム & 子フォーム が一緒に Hide されて、RefEdit ダイアログにて、何の問題も
無く、セルの選択操作を行なう事ができます。
しかし、この際に何故か、IME のモードが【半角】でロックされてしまいます。
しかも、ユーザーフォームを全て閉じた後も、IME の半角ロック状態は継続し、
エクセルを終了するまで解除されません。
RefEdit コントロールを 子フォームに 配置するのは止めてください。
[ この場所へのリンク ]
-------------------------------------------------------------------------
RefEdit 関連サポート技術情報
[XL2000] RefEdit コントロール使用時にキーボード ショートカットを使用して範囲を指定できない
Excel2000(SP3) および Excel2002(SP1) において修正されたと説明されていますが、
Excel2002(SP2)で確認したところ直っていないですね(Excel2000(SP3)では直っているとの情報を頂きました)。
※ 上記文書に、レジストリの修正によって、RefEdit でショートカットキー を有効にする方法が説明されています。
[XL2000] RefEdit コントロールを使用する複数の Excel インスタンスを開いた場合にマクロ起動時に VBA エラーが発生する
これも Excel2000(SP3) および Excel2002(SP1) にて修正されたとなっていますが、残念ながら私の
[Win98SE]環境ではリソース不足で、再現できるだけのExcel を起動できない為に確認できていません。
[XL2000] ユーザー フォームを閉じられない現象について
これの修正情報は今の所ありません。
MSDN(英語) RefEdit コントロールはモードレスフォームでは使えない
You cannot use a RefEdit control on a modeless user form.
You can use the ShowModal property to set a user form to modal.
[XL2000] UserForm を閉じた後に、 RefEdit コントロール が表示されます ( 英語ページ )
これも、エクセルを終了できなくなる事象のようです。
|
||
角田 桂一 Mail:addinbox@h4.dion.ne.jp CopyRight(C) 2001 Allrights Reserved. |