質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

4回答

11941閲覧

VBA ダブルクリックイベントのコードを一つにする方法?

Naoko_Coco

総合スコア54

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2019/05/23 06:40

編集2019/05/23 06:42

できるかできないかご教示ください。
VBAにてダブルクリックイベントを書いてます。
これは1シート毎に書かなくてはならないのでしょうか?
書くとしても5枚コピペすればよいだけなので、なんてことはないんですが
5シート分のモジュールができるのはあまり美しくないなぁと思い。
15シートのうちの5シート分に同じダブルクリックイベントを発生させたいのです。
できる様であれば、そのやり方もご教示ください。

VBA

1Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) 2Dim jan As String 3Dim name As String 4Dim i As Long 5Dim r As Long 6Dim sh As Worksheet 7Dim rng As Range 8 9Set sh = Worksheets("couponSku") 10Set rng = ActiveCell 11' B列を選んでいればJanを取得 12 If rng.Column = 2 And rng.Row >= 47 Then 13 jan = Target.Address(False, False) 14 jan = Range(jan).Value 15 r = sh.Range("A1").End(xlDown).Row 16 For i = 2 To r 17 If jan = sh.Cells(i, 1).Value Then 18 jan = sh.Cells(i, 2).Value 19 End If 20 Next 21 Call Google_serch(jan) 22' C列を選んでいればクーポン名取得 23 ElseIf rng.Column = 3 And rng.Row >= 47 Then 24 name = Target.Address(False, False) 25 name = Range(name).Value 26 Call Google_serch(name) 27 End If 28 29End Sub 30

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ワークブックにもダブルクリックイベントありますよね。
今のワークシートに書いてる処理をまるっとワークブックの方のダブルクリックイベントに持っていったらどうでしょうか。

VBA

1Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean) 2’ 今までの処理をコピペ 3End Sub

ただこれだけだと「15シートのうち5シートのみ」の要件は満たせませんから、イベント内冒頭でActiveSheetの名前で判断すればよいかと思います。
本格的な実装にするのであれば他の回答にあるようにクラスを使うことになります。

投稿2019/05/24 02:24

ttyp03

総合スコア16998

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hatena19

2019/05/24 03:28

今回の場合、これがベストの解決法ですね!頭固くなってるわ!
ttyp03

2019/05/30 05:05

まったくスルーされた。悲しい(T_T)
hatena19

2019/05/30 05:08

もっと+をあげたいのですが + ボタンは一回しか押せない(T_T)
ttyp03

2019/05/30 05:10

hatena19氏のおかげで傷は癒えましたw
jawa

2019/05/30 05:53

今回の要件だとこれが一番手っ取り早いですよね。 私が紹介したユーザークラスの方は、フォームに同じ入力チェックをするコントロールをたくさん配置するときとか、ファイルダイアログをひらく参照ボタンなんかをたくさん配置するときなどによく利用しますね。 >hatena19さん マイナスは通知されないので、マイナスとプラスを交互に押せばttyp03さんはたくさんプラスが付いた気になれますよ(違
Naoko_Coco

2019/06/05 04:37

ttyp03さん ごめんなさい!! これが一番簡単でしたね。 ありがとうございます。 こっちに変更します。 いつもアドバイス、ご回答ありがとうございます。
ttyp03

2019/06/05 09:03 編集

ようやく気づいてもらえた! 方法はいろいろありますので、作りやすくメンテナンスも容易なものをお選びください。
Naoko_Coco

2019/06/05 07:59

ttyp03さん いつもありがとうございます。
guest

0

すでにいくつか回答は出ていますので、重箱の隅をつつく話ですがいくつか気になった点を記載しておきます。

Target から Worksheet は取得できる

Rangeオブジェクトには、そのオブジェクトが属しているワークシートを示すWorksheetプロパティがあります。
ワークシートを取得したい場合は、イベントの引数のTargetからTarget.Worksheetで取得した方が良いと思われます。

Worksheets()ActiveSheetと違い、ちゃんと型も明示されていますので扱いやすく、処理としても堅牢になると思われます。

BeforeDoubleClick イベントでも Target.Count が1とは限らない

BeforeDoubleClick イベントでもTargetには複数のセルが含まれる可能性はあります(複数のセルを選択した状態で他のソフトにアクティブを移し、Excelのウィンドウをダブルクリックすると発生しやすい。せっかちな人だとよく起きる)。

質問に記載の処理では、Targetに複数のセルが含まれる場合うまく動作しないため

vba

1If Target.CountLarge <> 1 Then Exit Sub

などをイベント処理の最初に追加しておくと良いと思います。

遠回りなコード

vba

1jan = Target.Address(False, False) 2jan = Range(jan).Value 3 4name = Target.Address(False, False) 5name = Range(bame).Value

上記のコードは以下ではだめでしょうか?

vba

1jan = Target.Value 2 3name = Target.Value

投稿2019/05/23 15:18

imihito

総合スコア2166

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ExcelVBAer

2019/05/24 00:13

複数セルのダブルクリックが出来るなんて初めて知りました!
Naoko_Coco

2019/05/24 01:35

imihitoさん アドバイスありがとうございます。 target.valueで値とれたんですね! また、最初にIF文も追加しました。 ありがとうございます!
guest

0

今回の要件なら、標準モジュールに共通モジュールを書いて、それを各シートから呼び出せはいいかと思います。

もう少し複雑なものなら、クラスモジュールを使うメリットも出てきますが、ダブルクリックの場合は、
それほどメリットはないと思います。

ダブルクリックはアクティブなシートでしか発生しないので、シートはActiveSheetでOK。
ダブルクリックすると、そのセルがアクティブになるので、セルは ActiveCell でOK。

ですので、それを使えば標準モジュールに共通に記述できます。

標準モジュール

vba

1Public Sub CellDoubleClick() 2 Dim sh As Worksheet 3 Dim rng As Range 4 5 Set sh = ActiveSheet 6 Set rng = ActiveCell 7 8 MsgBox sh.Name & "シートの" & rng.Address(False, False) & "セルをダブルクリックしました。" 9 '実際には sh と rng を使った処理を記述 10End Sub

ダブルクリックで処理を実行したいシートのモジュール

vba

1Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) 2 Call CellDoubleClick 3End Sub

クラスモジュールを使う場合

シートが動的に追加されたり、削除されたりする場合で、追加されたシートにもダブルクリックでイベント処理したい場合は、クラスモジュールにするメリットもでてきます。

その場合は、Collection にクラスを格納するようすると、自由に追加、削除できます。

クラスモジュール clsWs

vba

1Option Explicit 2 3Private WithEvents ws As Excel.Worksheet 4 5Public Property Let MySheet(ByVal c As Excel.Worksheet) 6 Set ws = c 7End Property 8 9'シートのダブルクリックイベント 10Private Sub ws_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) 11 Dim Sh As Worksheet 12 Dim rng As Range 13 14 Set Sh = ActiveSheet 15 Set rng = ActiveCell 'Target でもOK 16 17 MsgBox Sh.Name & "シートの" & rng.Address(False, False) & "セルをダブルクリックしました。" 18 '実際には sh と rng を使った処理を記述 19End Sub

ThisWorkbook モジュール

vba

1Option Explicit 2Public MySheets As Collection 3'ブックを開く時 4Private Sub Workbook_Open() 5 Dim cWs As clsWs 6 Dim i As Long 7 8 Set MySheets = New Collection 9 For i = 1 To ThisWorkbook.Worksheets.Count 10 Set cWs = New clsWs 11 cWs.MySheet = ThisWorkbook.Worksheets(i) 12 MySheets.Add cWs, ThisWorkbook.Worksheets(i).CodeName 13 Next 14 15End Sub 16'シートの追加時 17Private Sub Workbook_NewSheet(ByVal Sh As Object) 18 Dim cWs As clsWs 19 Set cWs = New clsWs 20 cWs.MySheet = Sh 21 MySheets.Add cWs, Sh.CodeName 22End Sub 23'シートの削除前 24Private Sub Workbook_SheetBeforeDelete(ByVal Sh As Object) 25 MySheets(Sh.CodeName).MySheet = Nothing 26 MySheets.Remove Sh.CodeName 27End Sub

投稿2019/05/23 12:10

編集2019/05/23 13:37
hatena19

総合スコア33699

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Naoko_Coco

2019/05/24 02:06 編集

hatena19さん ありがとうございます。 でもjawaさんと同じくダブルクリックしても何も起きません。 メッセージボックス出てこないです。。。 完全にTestExcel作成して自分のコードは一切書かず、まるっとコピペしてます。 クラスモジュールに記述するやり方でやってます。
hatena19

2019/05/24 02:23

クラスモジュールの名前は、clsWs にしてますか。 あと、ThisWorkbook モジュールのコードは間違いなく、ThisWorkbook に記述してますか。 してあれば、ブックを開く時に、Workbook_Open が実行されて、ダブルクリックイベントがシートに追加されるはずです。
Naoko_Coco

2019/05/29 03:10

ありがとうございます。 無事にできました。 遅くなってすいません。
guest

0

ベストアンサー

ワークシートイベントをフックするユーザークラスを作成し、ブックを開いた時に各シートをこのクラスにも格納してあげれば可能です。
「ユーザークラスの作成」というと敷居が高く感じられますが、実際のコードはそこまで複雑ではありません。

まずは試してみて、うまく動いたら、なぜこれで目的の動作が実現できたのか調べて理解を深めていけばいいと思います。


例えば以下のようなユーザークラスを作成します。

clsWs

Private WithEvents ws As Excel.Worksheet 'プロパティ設定で対象シートを受け取る Public Property Let MySheet(ByVal c As Excel.Worksheet) Set ws = c End Property 'シートのダブルクリックイベント Private Sub ws_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) MsgBox "DBL!" End Sub

次に共通モジュールで、このクラスの変数と、そこに各シートを格納する関数を用意します。

Module1

'ユーザークラスの配列 Public MySheets() As New clsWs '現在あるシートをユーザークラスに格納 Public Sub SetMySheets() ReDim MySheets(ThisWorkbook.Sheets.Count) Dim i As Integer 'ブック内の全シートをユーザークラスに格納する ⇒これでワークシートをダブルクリックしたときにclsWsのダブルクリックイベントが実行される For i = 1 To ThisWorkbook.Sheets.Count MySheets(i).MySheet = ThisWorkbook.Sheets(i) Next End Sub

このSetWorkSheets関数でclsWsに格納されたワークシートでダブルクリックすると、clsWsのダブルクリックイベントに記載した処理が実行されることになります。
必要ならブックを開いた時や、シートが追加されたタイミングでSetWorkSheets関数を実行するといいでしょう。

まずはがんばってみてください。

投稿2019/05/23 07:28

jawa

総合スコア3013

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Naoko_Coco

2019/05/23 08:10

jawaさん 回答ありがとうございます。 クラスモジュールについて教えてください。 jawaさんのコードをまるっとコピペして実行すると、 Public MySheets() As New clsWs の部分で、『ユーザ定義型は定義されてません。』のエラーが出ます。 clsWsの部分をクラスモジュールに書いて、Module1の内容をそのまま書いてます。 書く場所が間違っているのでしょうか? また、1枚目のSheetに対してはダブルクリックで実行しますが、他のSheetをダブルクリックしても何も起こりません。
jawa

2019/05/23 23:56

すみません、説明が足りなかったようです。 clsWsの内容をクラスモジュールに、Module1の内容を標準モジュールに記載します。 そしてclsWsを記述したクラスモジュールの名前をclsWsにします。 ※おそらくこれが漏れているためのエラーと思われます。 ここまでできていればSetMySheets関数を実行することでダブルクリックイベントをフックできるようになると思います。 お試しください。
Naoko_Coco

2019/05/24 01:47

ありがとうございます。 クラスモジュールの名前を変更すればよかったんですね! が、しかし・・・エラーはでなくなりましたが、ダブルクリックしても何も起きないです。。。メッセージボックスも出てきません。 昨日の時点でシートに対しダブルクリックイベント記述したままだったので、実行できましたが今日はダブルクリックイベントコメントアウトにしてます。 なのでjawaさんのコードのみで試してます。
jawa

2019/05/24 03:42

SetMySheets関数は実行されましたか? していなければ、一度「マクロの表示」からSetMySheets関数を実行してみてください。 SetMySheets関数を実行すると、その時点でブックに含まれている全てのシートをclsWsクラス型の変数に格納します。 シートイベントをフックできるようになるのはそれ以降です。 ブックを開いたときに自動で割り当てたいようでしたら、workbook_openイベントでSetMySheets関数を呼ぶようにしておくといいです。
Naoko_Coco

2019/05/29 02:45

遅くなってすいません。 他の作業をしていたため、後回しになってしまいごめんなさい。 で、できました! ありがとうございます。
Naoko_Coco

2019/05/29 08:01

もう少し教えてください。 OpenイベントでSetMySheetsを呼び出してるんですが、時間が経過すると外れてしまうようなんです。 なので、ダブルクリックイベントの先頭にSetMySheetsを呼び出すように書いてるんですが、それでもダブルクリックイベント自体が実行されません。 どうしたら常にダブルクリックイベントを呼び出すことができるようになりますでしょうか?
jawa

2019/05/30 23:30 編集

私もこれまで何度も使ってきた手法で、そういったことは起きたことがなかったのですが。。 どうもVBAのPublic変数は、アプリケーションの終了まで保証されるものでは無い(つまり意図せず解放される可能性がある)ようです。 私もこの質問をうけて調べてみて、初めて知りました。。おそろしい話です。 参考↓ https://seesaawiki.jp/wasure_matsu_program/d/Excel%20VBA%20%3A%20%A5%B0%A5%ED%A1%BC%A5%D0%A5%EB%CA%D1%BF%F4%A4%AC%BE%A1%BC%EA%A4%CB%BD%E9%B4%FC%B2%BD%A4%B5%A4%EC%A4%EB%BB%F6%A4%D8%A4%CE%C2%D0%B1%FE. とりあえず標準モジュールで宣言したワークシート格納用の配列変数などをThisWorkbookに移せば解放されなくなるかも知れません。 手元で現象確認できないのであやふやな情報で申し訳ありませんが、ご確認ください。 なお、今回のようにワークシートのイベントであれば、ttyp03さんからのアドバイスにある通りワークブックに用意されているワークシートイベントでも実現可能です。 ユーザークラスの方が幅広く使えますが、それも選択肢のひとつでしかありませんので、今回はワークブックのイベントで実装するというのも手だと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問