[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『リストボックスがVBA実行で消える』(しんぽん)
ある結合セルに、別のシートから参照入力するためのリストボックスを
データの入力規則+INDIRECT関数で作成していたのですが、マクロを
実行するとリストボックスを表示させる矢印(セルをクリックすると表示
する矢印)が消えてしまいます。恐らく結合セルを使っているのが悪いと
思われるのですが、帳票のレイアウト上、結合セルを使わざるを得ないので、
何か解決方法は無いでしょうか?宜しくお願い致します。
>マクロを実行するとリストボックスを表示させる矢印(セルをクリックすると表示 >する矢印)が消えてしまいます。
こういうご質問の場合、まず、問題の現象を再現できる手順書を作成してください。 その過程でコードの提示が必要ならそれも提示してください。
ichinose
起こっている現象ですが、sheet1のV3:AF4のセル範囲で以下の結合セルが
あります。
@V3:W4で結合、平成(文字列)を入力
AX3:Y4で結合、データの入力規則で=INDIRECT("sheet2!B3:B9"))を入力。
(B3に24、B4に25、B5に26・・・・、B9に30)
BZ3:Z4で結合、年(文字列)を入力
CAA3:AB4で結合、データの入力規則で=INDIRECT("sheet2!C3:C14"))を入力。
(C3に1、C4に2、C5に3・・・・、C14に12)
DAC3:AC4で結合、月(文字列)を入力
EAD3:AE4で結合、データの入力規則で=INDIRECT("sheet2!D3:D33"))を入力。
(D3に1、D4に2、D5に3・・・・、D33に31)
FAF3:AF4で結合、日(文字列)を入力
これで年月日をリストボックスから数字入力できるようにしていました。
マクロは先日ichinose様に教えていただいたもので、上記セル範囲の下のエリアの
sheet1のD8,D10,D12,D14,D16,D18,D20の7つのセルに、それぞれコマンドボタンを
配置し、それぞれのボタンを押すとI8:BD8,I10:BD10・・・・,I20:BD20の範囲に
sheet3に作図してあるデータ(文字列+矢印)が貼り付きます。
このマクロ実行をすると、なぜかX3,AA3,AD3のこれまであった、セルをクリックすると
現れる矢印が消えてしまい、リストボックスが使えなくなります。
宜しく御願い致します。
>マクロは先日ichinose様に教えていただいたもの でも、最終的にどのコードなのかは、私には、わかりませんよね!! 本当は、どのコードの実行なのかは、明確に記述してほしかったのですが・・・。
前回投稿を眺めて、気になったは、
>'一日目既存のデータを消去(新データ貼り付け範囲のみ) >Dim myRng As Range >Dim sp As Variant >Set myRng = Range(Cells(8, 最左), Cells(8, 56)) >myRng.Select >Selection.ClearContents >For Each sp In ActiveSheet.Shapes >If Not Intersect(Range(sp.TopLeftCell, sp.BottomRightCell), myRng) Is Nothing Then >sp.Delete >End If >Next sp >Set myRng = Nothing
このコードも実行マクロの中に含まれているのであれば、記述された現象になる可能性は あります。
何があぶないかというと、
>For Each sp In ActiveSheet.Shapes >If Not Intersect(Range(sp.TopLeftCell, sp.BottomRightCell), myRng) Is Nothing Then >sp.Delete >End If >Next sp
Shapesコレクションには、入力規則のリストで使われるコンボボックスも含まれてしまいます。 削除する条件に合えば、このコンボボックスも削除されてしまうということです。
For Each sp In ActiveSheet.DrawingObjects
とすれば、今度は、図形コレクションに入力規則のコンボボックスは、コレクションの対象外になります。 尚、spという変数の型もShapeから Objectに変更してください。
まずこれで試してみてください
ichinose
またまた説明不足で誠に申し訳ございませんでした。
以後、気をつけます。コードのほうは完成しましたら
掲載させていただきます。
今回ご指導いただいた内容を試してみましたところ、
なんとっ、リストボックスが消えなくなりました!
感謝感激です!
(但し一度消してしまったリストボックスは再度作成
しても現れず、シートを作り直しました)
このたびは色々とお世話になり、本当にありがとう
ございました。何とお礼を申し上げたらよいやら、
これで目的の帳票(運行指示書)が完成できそうです。
↓
社内(零細企業です・・・)でこの運行指示書(先日の
関越道バス事故発生で作成の徹底が求められている)
の作成には時間がかかるので、作成時間短縮のために
半自動的に作成できるものを作って欲しいとの要望が
あり、今回トライしたという経緯がありました。
●標準モジュール Option Explicit Public Sub form1() '*日目ボタンの座標(Row)をラベルに取得 UserForm1.Controls("LblAddress").Caption = ActiveSheet.Shapes(Application.Caller).TopLeftCell.Row 'フォームのボタンに名前をふる Dim i As Long Dim k As Long With Sheets("便登録") For i = 1 To 20 k = i * 3 + 2 UserForm1.Controls("CommandButton" & i).Caption = .Range("B" & k).Value Next i End With 'フォームを表示 UserForm1.Show End Sub
●ユーザーフォームモジュール Option Explicit Private Sub Kihondosa_Click_Sub(ByVal Index As Integer) 'ユーザーフォームを閉じる UserForm1.Hide '変数の定義 Dim lbn As Long Dim i As Long Dim k As Long Dim st() As Long Dim sk() As Long Dim 最左線 As Long Dim 最右線 As Long Dim 一最左列 As Long Dim 二最右列 As Long Dim 最左 As Long Dim 最右 As Long Dim 一最左セル As Range Dim 二最右セル As Range Dim rng As Range Dim rng1 As Range Dim rng2 As Range Dim myRng As Range Dim myRng1 As Range Dim myRng2 As Range Dim myRng3 As Range Dim sp As Object Dim sp1 As Object Dim sp2 As Object
'ボタン位置のRowを取得(ラベルNo.のプロパティー) lbn = UserForm1.lblAddress.Caption
'便登録シート登録No.Indexの一日目登録データ取り込み Worksheets("便登録").Activate On Error Resume Next Set myRng1 = Range(Cells(Index * 3 + 1, 9), Cells(Index * 3 + 1, 56)) Set rng1 = myRng1.SpecialCells(xlCellTypeConstants)
i = 0 For Each sp1 In ActiveSheet.DrawingObjects If Not Intersect(Range(sp1.TopLeftCell, sp1.BottomRightCell), myRng1) Is Nothing Then i = i + 1 ReDim Preserve st(1 To i) st(i) = sp1.TopLeftCell.Column End If Next sp1
If i <> 0 And Not rng1 Is Nothing Then Set 一最左セル = rng1.Cells(1) 一最左列 = 一最左セル.Column 最左線 = Application.WorksheetFunction.Min(st()) 最左 = Application.WorksheetFunction.Min(一最左列, 最左線) ElseIf i = 0 And Not rng1 Is Nothing Then Set 一最左セル = rng1.Cells(1) 一最左列 = 一最左セル.Column 最左 = 一最左列 ElseIf i <> 0 And rng1 Is Nothing Then 最左線 = Application.WorksheetFunction.Min(st()) 最左 = 最左線 Else MsgBox "1日目の登録データがありません" GoTo Label1 End If
'指示書シートに移動 Worksheets("指示書").Activate '一日目既存のデータを消去(新データ貼り付け範囲のみ) Set myRng = Range(Cells(lbn, 最左), Cells(lbn, 56)) myRng.Select Selection.ClearContents For Each sp In ActiveSheet.DrawingObjects If Not Intersect(Range(sp.TopLeftCell, sp.BottomRightCell), myRng) Is Nothing Then sp.Delete End If Next sp Set myRng = Nothing Set sp = Nothing
'一日目の登録データをコピー Sheets("便登録").Select Range(Cells(Index * 3 + 1, 最左), Cells(Index * 3 + 1, 56)).Copy Sheets("指示書").Select Cells(lbn, 最左).Select ActiveSheet.Paste
Label1:
'7日目ボタンの 二日目登録データ取込みスキップ If lbn = 20 Then GoTo Label2 End If
'便登録シート登録No.Indexの二日目登録データ取り込み Worksheets("便登録").Activate Set myRng2 = Range(Cells(Index * 3 + 2, 9), Cells(Index * 3 + 2, 56)) Set rng2 = myRng2.SpecialCells(xlCellTypeConstants) Set rng = rng2.Areas(rng2.Areas.Count)
k = 0 For Each sp2 In ActiveSheet.DrawingObjects If Not Intersect(Range(sp2.TopLeftCell, sp2.BottomRightCell), myRng2) Is Nothing Then k = k + 1 ReDim Preserve sk(1 To k) sk(k) = sp2.BottomRightCell.Column End If Next sp2
If k <> 0 And Not rng2 Is Nothing Then Set 二最右セル = rng.Cells(rng.Count) 二最右列 = 二最右セル.Column 最右線 = Application.WorksheetFunction.Max(sk()) 最右 = Application.WorksheetFunction.Max(二最右列, 最右線) ElseIf k = 0 And Not rng2 Is Nothing Then Set 二最右セル = rng.Cells(rng.Count) 二最右列 = 二最右セル.Column 最右 = 二最右列 ElseIf k <> 0 And rng2 Is Nothing Then 最右線 = Application.WorksheetFunction.Max(sk()) 最右 = 最右線 Else MsgBox "2日目の登録データがありません" GoTo Label2 End If
'指示書シートに移動 Worksheets("指示書").Activate '二日目既存のデータを消去(新データ貼り付け範囲のみ) Set myRng = Range(Cells(lbn + 2, 9), Cells(lbn + 2, 最右)) myRng.Select Selection.ClearContents For Each sp In ActiveSheet.DrawingObjects If Not Intersect(Range(sp.TopLeftCell, sp.BottomRightCell), myRng) Is Nothing Then sp.Delete End If Next sp Set myRng = Nothing Set sp = Nothing
'二日目の登録データをコピー Sheets("便登録").Select Range(Cells(Index * 3 + 2, 9), Cells(Index * 3 + 2, 最右)).Copy Sheets("指示書").Select Cells(lbn + 2, 9).Select ActiveSheet.Paste Label2: Worksheets("指示書").Activate
End Sub
Private Sub CommandButton1_Click() Call Kihondosa_Click_Sub(1) End Sub Private Sub CommandButton2_Click() Call Kihondosa_Click_Sub(2) End Sub Private Sub CommandButton3_Click() Call Kihondosa_Click_Sub(3) End Sub Private Sub CommandButton4_Click() Call Kihondosa_Click_Sub(4) End Sub Private Sub CommandButton5_Click() Call Kihondosa_Click_Sub(5) End Sub Private Sub CommandButton6_Click() Call Kihondosa_Click_Sub(6) End Sub Private Sub CommandButton7_Click() Call Kihondosa_Click_Sub(7) End Sub Private Sub CommandButton8_Click() Call Kihondosa_Click_Sub(8) End Sub Private Sub CommandButton9_Click() Call Kihondosa_Click_Sub(9) End Sub Private Sub CommandButton10_Click() Call Kihondosa_Click_Sub(10) End Sub Private Sub CommandButton11_Click() Call Kihondosa_Click_Sub(11) End Sub Private Sub CommandButton12_Click() Call Kihondosa_Click_Sub(12) End Sub Private Sub CommandButton13_Click() Call Kihondosa_Click_Sub(13) End Sub Private Sub CommandButton14_Click() Call Kihondosa_Click_Sub(14) End Sub Private Sub CommandButton15_Click() Call Kihondosa_Click_Sub(15) End Sub Private Sub CommandButton16_Click() Call Kihondosa_Click_Sub(16) End Sub Private Sub CommandButton17_Click() Call Kihondosa_Click_Sub(17) End Sub Private Sub CommandButton18_Click() Call Kihondosa_Click_Sub(18) End Sub Private Sub CommandButton19_Click() Call Kihondosa_Click_Sub(19) End Sub Private Sub CommandButton20_Click() Call Kihondosa_Click_Sub(20) End Sub Private Sub CommandButton21_Click() 'フォームを閉じる Unload UserForm1 End Sub
●Sheet1モジュール(入力データをリセットするコマンド) Option Explicit Private Sub CommandButton1_Click() 'リセット下ボタン 'オートシェイプ(矢印等)の削除 Dim lngLeft As Long Dim lngTop As Long Dim lngRight As Long Dim lngBottom As Long Dim objShape As Object
With Range("I8:BD21") lngTop = .Top lngLeft = .Left lngBottom = .Top + .Height lngRight = .Left + .Width End With
For Each objShape In ActiveSheet.DrawingObjects With objShape If lngTop <= .Top And lngLeft <= .Left And _ lngBottom >= .Top + .Height And lngRight >= .Left + .Width Then .Delete End If End With Next '文字列の削除 ActiveSheet.Range("I8", "BD21").Select Selection.ClearContents End Sub
Private Sub CommandButton2_Click() 'リセット上ボタン(文字列削除) ActiveSheet.Range("X3,AA3,AD3,AK3,AN3,V5,AE5,AO5,AV4,AY4,BB4").Select Selection.ClearContents End Sub
ここでの内容が大きく関わっているということでリンク貼っときます。
今回のご質問の >リストボックスを表示させる矢印(セルをクリックすると表示 >する矢印)が消えてしまいます 結構有名な現象なので、この時点で見当はついていましたが、敢えて再現手順書を 記述してください と申し上げました。誰でもが再現できる手順書を記述すること、 繰り返しますが、大事ですよ!!
入力規則のリストのコンボボックスとShape及び、Shapesコレクションについて
入力規則のリストのコンボボックスは、Shapesコレクションに含まれているので、 削除してしまうと、このシートを再度作り直すしかなさそうですね!! 同じような事象にオートフィルタのコンボボックスも該当しますから、注意です。 もっとも2002では、オートフィルタのそれは、再生できます。
コードは、ざっとですが、拝見しました。 仕様などは見ていませんが・・・。 ユーザーフォームも使っているのですね!!
> Private Sub CommandButton1_Click() > Call Kihondosa_Click_Sub(1) >End Sub >Private Sub CommandButton2_Click() > Call Kihondosa_Click_Sub(2) >End Sub
この様な記述が沢山ありますねえ!! このような場合、クラスモジュールを使って 配列コントロールを実現する方法もあります。 まっ、ご自分の判断でこの程度だったら、クラスモジュールを使うほどでもない という結論もあるでしょうから、これはこれでよいでしょうが・・・・。
気になったのは、Kihondosa_Click_Sub内の二つのラベルとGoto文です。
なくてもコードは書けますし、それの方がわかりやすいと思います。 Gotoを使わないで、コードを書き直すことを検討してみてください。
もう一つが同じKihondosa_Click_Sub内の
UserForm1.Hide
このメソッドでユーザーフォームを非表示にしていますが、 その後、再びShow している箇所もUnloadもしていません。 これ、見えないので動作的に同じように見えますが、 Hideは、ユーザーフォームをあくまでも非表示でユーザーフォームというオブジェクトは 残ったままです。処理が完結しているなら、Unload Me を入れた方が良いですよ!!
以上です、気になった点を記述しました。
ichinose
最後までご指導いただき、誠にありがとうございました。
クラスモジュールについてはまだよく理解できていません
ので勉強中です(擬似への脱却を読んでいますが・・・)。
Goto Labelを使わず書き直す方法????
なにとぞ、ヒントをいただけないでしょうか?
UserForm1.Hideは、単に非表示にしていただけなのですね・・・
Unloadに直します。
>Goto Labelを使わず書き直す方法???? 構造化プログラミングの学習をされたらいかがでしょうか? そうすれば、階層構造を作る ということを学びます。
これは、一例です
Private Sub Kihondosa_Click_Sub(ByVal Index As Integer) '変数の定義 Dim lbn As Long Dim 最左 As Long Dim 最右 As Long Dim myRng As Range Dim myRng1 As Range Dim sp As Object
'ボタン位置のRowを取得(ラベルNo.のプロパティー) lbn = UserForm1.LblAddress.Caption
'便登録シート登録No.Indexの一日目登録データ取り込み Worksheets("便登録").Activate On Error Resume Next Set myRng1 = Range(Cells(Index * 3 + 1, 9), Cells(Index * 3 + 1, 56)) 最左 = get_Obj最左右列(myRng1, 1) If 最左 = 0 Then MsgBox "1日目の登録データがありません" Else '指示書シートに移動 Worksheets("指示書").Activate '一日目既存のデータを消去(新データ貼り付け範囲のみ) Set myRng = Range(Cells(lbn, 最左), Cells(lbn, 56)) myRng.Select Selection.ClearContents For Each sp In ActiveSheet.DrawingObjects If Not Intersect(Range(sp.TopLeftCell, sp.BottomRightCell), myRng) Is Nothing Then sp.Delete End If Next sp Set myRng = Nothing Set sp = Nothing '一日目の登録データをコピー Sheets("便登録").Select Range(Cells(Index * 3 + 1, 最左), Cells(Index * 3 + 1, 56)).Copy Sheets("指示書").Select Cells(lbn, 最左).Select ActiveSheet.Paste End If
'便登録シート登録No.Indexの二日目登録データ取り込み Worksheets("便登録").Activate Set myRng1 = Range(Cells(Index * 3 + 2, 9), Cells(Index * 3 + 2, 56)) 最右 = get_Obj最左右列(myRng1, 2) If 最右 = 0 Then MsgBox "2日目の登録データがありません" Else '指示書シートに移動 Worksheets("指示書").Activate '二日目既存のデータを消去(新データ貼り付け範囲のみ) Set myRng = Range(Cells(lbn + 2, 9), Cells(lbn + 2, 最右)) myRng.Select Selection.ClearContents For Each sp In ActiveSheet.DrawingObjects If Not Intersect(Range(sp.TopLeftCell, sp.BottomRightCell), myRng) Is Nothing Then sp.Delete End If Next sp Set myRng = Nothing Set sp = Nothing '二日目の登録データをコピー Sheets("便登録").Select Range(Cells(Index * 3 + 2, 9), Cells(Index * 3 + 2, 最右)).Copy Sheets("指示書").Select Cells(lbn + 2, 9).Select ActiveSheet.Paste End If Worksheets("指示書").Activate End Sub Function get_Obj最左右列(ByVal rng As Range, ByVal LR As Long) As Long 'LR 取得する列番号の種類 1 最左列 2 最右列 ' Dim rng1 As Range Dim st() As Long Dim i As Long Dim sp As Object Dim 列(1 To 2) As Variant '1 セル列 2 図形列 On Error Resume Next Set rng1 = rng.SpecialCells(xlCellTypeConstants) i = 0 For Each sp In rng.Parent.DrawingObjects If Not Intersect(Range(sp.TopLeftCell, sp.BottomRightCell), rng) Is Nothing Then i = i + 1 ReDim Preserve st(1 To i) st(i) = IIf(LR = 1, sp.TopLeftCell.Column, sp.BottomRightCell.Column) End If Next sp get_Obj最左右列 = 0 列(1) = False 列(2) = False If Not rng1 Is Nothing Then 列(1) = IIf(LR = 1, rng1.Cells(1).Column, rng1.Cells(rng.Count).Column) End If If i <> 0 Then If LR = 1 Then 列(2) = Application.Min(st()) Else 列(2) = Application.Max(st()) End If End If If LR = 1 Then get_Obj最左右列 = Application.Min(列()) Else get_Obj最左右列 = Application.Max(列()) End If Erase 列() End Function
Private Sub CommandButton1_Click() Call Kihondosa_Click_Sub(1) Unload Me End Sub
ところで
Set myRng = Range(Cells(lbn, 最左), Cells(lbn, 56)) myRng.Select Selection.ClearContents For Each sp In ActiveSheet.DrawingObjects If Not Intersect(Range(sp.TopLeftCell, sp.BottomRightCell), myRng) Is Nothing Then sp.Delete End If Next sp
ここは、本当にこれでよいのですか? 仮に最左が30だとすると、実行前に列10辺りに値があってもクリアされませんが・・・。
それでよいという仕様ならよいのですが・・・・。
ichinose
追伸 >擬似への脱却を読んでいますが・・・ これは、配列コントロールを実現以外にも色々学べるのでお奨めです。
前投稿のコ−ドについて
今回の場合、同じような処理が複数ないか? 「因数分解の鉄則に共通項をくくれ」というのがあったのを覚えていますか? あれに近いです。ただ、括っても独立した機能を持てないと別プロシジャーには、 できないのですが・・・・。
というのが 着眼点でした。
すると、指定セル範囲内にあるセルの値、図形の中で最左列又は、最右列を 求めている処理コードが殆ど同じで、機能として独立しているので ここの箇所を別プロシジャーにしました。
get_Obj最左右列(ByVal rng As Range, ByVal LR As Long)
機能
指定セル範囲内にあるセルの値、図形の中で最左列又は、最右列を 求める
パラメータ rng 最左又は、最右列を求めるセル範囲 LR 取得指示 1 最左列 2 最右列
Output get_Obj最左右列 最左列又は、最右列 尚、0の場合、 指定セル範囲にデータ及び図形はなし
こんな機能を持つプロシジャーを作ることができました。
でも、まだ同じような処理がありますよね?
これを機能を分割できたり、又は、繰り返し処理に直せそうですが、 そうすると、Kihondosa_Click_Subが半分ぐらいになるかもしれませんよ!!
これは、検討してみてください。
ichinose
再三再四ご教授いただき、誠にありがとうございました。
常に「共通項をくくる意識」が大事なのですね。再度熟読して
勉強させていただきます(FunctionとかGetとか良く分かって
おりません・・・)。 それと、構造化プログラミング、
一度勉強してみます。
仕様の件につきましてはこれでOKです。この運行指示書は
I列からBD列で24時間の30分枠(ひとつのセルが30分)で構成
されており、登録している便の最左が昼の時間帯(Column数が大、
AGからBD)から始まる場合が多く、終わりが翌日の夜中や朝の
時間帯(Column数が小、IからAF)になるため、最左の左側は
データ(前日の後半データ)を残す必要があるためです。
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.