Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 11 Pro : Microsoft 365)
〇列と〇列は、片方の列に〇を入力したら、片方に自動で〇が付くようにしたい。
投稿日時: 26/04/17 17:13:48
投稿者: ZU-

先ほど、一般で投稿しVBAで回答して貰って問合せについては、解決しました。
最初の質問内容では、作成に問題がありますので、再度よろしくお願いいたします。
  
列は50列 行は100行の表計算です。
 
A列とC列は、片方の列に〇を入力したら、片方に自動で〇が付くようにしたい。
各セルは〇か空欄か何回でも修正できるように式が消えないようにしたい。
 
  
・A3に〇を入力したら、C3に〇が自動で付き、C3に〇したらA3に自動で付き
・B2に〇を入力したら、E2に〇が自動で付き、E2に〇したらB2に自動で付き
 
列の項目内容で、間の列数はまちまちです。
   
上記の条件を満たす方法を伝授をお願いします
  
  
   A   B   C  D   E   F 〜 AB 〜 AF
1 項目A 項目B 項目C・・・・・・・・・・・
2      〇        〇
3 〇        〇
4             〇         〇 
5      〇
6                   〇   〇
 
 
P.S.    
一般での投稿日時: 26/04/17 13:14:28投稿者: んなっと さん
VBAは、仮に入力して 確認できました。ありがとうございました
 

回答
投稿日時: 26/04/17 23:19:59
投稿者: simple

>最初の質問内容では、作成に問題がありますので、再度よろしくお願いいたします。
作成に問題があるというのはどういうことでしょうか。追加説明をお願いします。
単に、一組の列ではなく、複数の組があると言うだけの話ですか?
一般機能の板での回答を、
・複数のペアに拡張する
ことが基本になるものと思います。
 
余談めきますが、そもそも、A列とC列、B列とE列は具体的にどういう種類の内容なんですか?
ゲームかなにかなら、そういうルールかとも思いますが、
表計算でしたら、もう少し他人にも必要性がわかるような具体的な説明をしていただけませんか?
ひょっとしたら別のやりかたがあるかもしれません。
 
> 各セルは〇か空欄か何回でも修正できるように式が消えないようにしたい。
とありますが、一般機能で示されたVBAは、別に「式」は使っていません。
提示されたコードは理解されているのでしょうか?

回答
投稿日時: 26/04/19 15:33:55
投稿者: simple

> 各セルは〇か空欄か何回でも修正できるように式が消えないようにしたい。
これがお望みのことだとすると、それは無理な話です。
 
・式を入力して、さらにその上になんらかの値を入れたい、Excelにはそういう機能はありません。
  式を入れれば、その評価値が値となるので、それとは別の値を入力する余地はありません、
・また、相互に他のセルに依存した式を入れると「循環参照」になることにも注意が必要です。
  (オプションで、「計算方法の設定」を調整する方法もありますが、推奨されません。)
 
そもそもそれらの項目の性質をお聞きしたのは、
"〇"か空白以外の入力は認めないのであれば、二つの列は同一内容になります。
本来それは二つ持つべきではなく、ひとつに絞るべきではないかと思ったからです。
二つ持とうとするから、今回のような作業が発生してしまうのです。
混乱の元なので、その方針には賛成しかねます。
 
(横長の表で離れた位置にある列を、目で参照しやすいところに増幅して持ちたいということですか?
A列とC列に同一内容の列を作るなどということは普通しないと思います。(説明の都合上のなりゆきですか?)
またそんな列がいくつもあるというのもちょっと想像しにくいです。)
   
どうしても二列必要なら、
・入力項目は一つに限定し、
・別のセルではそれを式で参照させ、その計算セルはロックを掛けて保護するという方法が適当でしょう。
 
一般機能板でコメントがありましたVBAでイベントプロシージャを使う方法であれば、
いくらでもコードは示せますが、上記した点を再考することをお薦めします。

投稿日時: 26/04/20 10:43:47
投稿者: ZU-

 
simpleさま
 
お手数をおかけいたしました。
薬品を扱っている法人で、健康診断内容のコースを決める様式で、各社員の内容をチェックするのに時間を要しております。
 
VBAなら各セルの式も消えることなくできるかなと思い投稿してみました。
 
凡例:Cさん
有機溶剤の「あ薬品」を扱っているのに〇をしましたので有機りんの項目に「あ薬品」が
あるので自動で〇が付く。。。逆に有機りんを〇したら有機溶剤の「あ薬品」のセルに〇が付く。
 
 
    A    B    C    D    E      F    ・・・・    M    N     AF
1        有機溶剤    酸等    特定化学物質     -     有機りん        ■■
2        あ薬    い薬    う薬    え薬    い薬    お薬     -     あ薬    う薬     え薬
3    Aさん     〇             〇                    
4    Bさん            〇                         〇
5    Cさん 〇                             〇        
6    Dさん 〇     〇          〇              〇        
7    Eさん            〇                         〇
8    Fさん         〇                         〇    
9    Gさん                     〇                
10    Hさん                     〇     〇            

回答
投稿日時: 26/04/20 11:07:57
投稿者: simple

> VBAなら各セルの式も消えることなくできるかなと思い投稿してみました。
VBAだからといって、式を使ってそういうことができるということはありません。
式があるセルに〇といった文字列を入力したら、式は消えますよ。
 
どうしても式で対応したいのですか?
そうであれば、私はリタイアします。
何度も申し上げますが、できないことを求められても閉口します。
他の回答者の回答をお待ちください。
 
# VBAであれば、特定の列に特定の文字が入力されたら、自動的にそれを関知して
# 他の指定した列のセルに値を設定する、ということができます。
# それが一般機能板で提示されたChangeイベントプロシージャというものです。

投稿日時: 26/04/20 14:43:27
投稿者: ZU-

>>VBAなら各セルの式も消えることなくできるかなと思い投稿してみました。
⇒式があるセルに〇といった文字列を入力したら、式は消えますよ。
※大変失礼いたしました。しかり見直さないで、送信してしまいました。
 
simpleさま
ありがとうございました。

回答
投稿日時: 26/04/21 10:41:38
投稿者: 半平太

>大変失礼いたしました。しかり見直さないで、送信してしまいました。
  
これは、式に拘らず、VBA対応でいいと言う意味ですか? そうだとすると、
何故これが過去形なのかしっくりしないです。(「Changeイベントでお願いします」が妥当では?)
  ↓
  >simpleさま
  >ありがとうございました。
  
>薬品を扱っている法人で、健康診断内容のコースを決める様式で、
>各社員の内容をチェックするのに時間を要しております。
  
詳しい内容は分かりませんが、重要な判定に関連するものと思われます。
  
そうなると、まず現在の表が正しい状態になっているか再確認する必要性を感じます。
また、50列x100行の表を目視チェックすること自体、ちょっとリスキーだなぁとも思います。
  
折角VBAを使うなら、今回の「〇の処理」に留まらず、もっと「各社員の内容をチェックする」作業の
効率化を目指す要望・質問にレベルアップさせた方が有益だと思いますが、いかがですか?

回答
投稿日時: 26/04/21 11:52:50
投稿者: simple

半平太さんコメントありがとうございました。
 
■質問者さんのお気に召さないようですが、持っていても何の役にも立たないものですので、
事前に回答用に用意していたマクロ案(*)を提示して私の区切りとします。
閲覧者の参考になれば幸いです。
((*)見出しが2行になった点など簡単な修正は追加しました。)
 
・対象となる列は、make_dicプロシージャのなかに書き込んであります。(あくまで例示です)
        dic("A") = "C"
        dic("B") = "E"
        dic("D") = "G"
  は、 A列が変更されたらC列にもそれを反映するという設定を意味します。
  次の二行も同様の意味合いです。(B列→E列, D列→G列 と言う意味です)
   
  逆向きの流れ(C列が変更されたらA列に反映)は、
  プログラム側で対応するので、設定は不要です。
  これ以外にもペアの組があれば、追加して下さい。
 
■使い方
・該当のシートのシートモジュールに、提示したコードを一括してコピーして下さい。
・あとは、セルの変更をトリガーにして、値のコピーが自動的に行われます。
・なお、対象となる列のなかで複数セルを同時に変更する場合(複数セルをコピーペイストするとか、
  複数セルを同時に消去する)にも、対応しています。
 
■イベントプロシージャは、それなりに落とし穴がある道具です。
  提示したあとでもトラブルになりがちです。注意してください。
    ・列を挿入・削除したら動作がおかしくなりました、とか(対象列の定義の変更が必要となります)
    ・今まで自動で動いていたものが動かなくなった
       (エラーが発生したときに、Application.EnableEvents が Falseになったままになっている)等々
 
■以下コードです。

Option Explicit

Dim dic As Object
Dim unionR As Range

'ペアとなる列の指定
Sub make_dic()
    Dim e, v$
    Set dic = CreateObject("Scripting.Dictionary")
    dic("A") = "C"  '■適宜修正が必要
    dic("B") = "E"  '■適宜修正が必要
    dic("D") = "G"  '■適宜修正が必要
    For Each e In dic
        v = dic(e)
        dic(v) = e
    Next
    Debug.Print Now(); "created Dictionary "
End Sub

'イベント発生の対象となるセル範囲を設定
Function uRange() As Range
    Dim s As String, key
    For Each key In dic
        s = s & key & "3:" & key & "150,"
    Next
    s = Left(s, Len(s) - 1)
    Set uRange = Range(s)
    Debug.Print Now(); "対象セル範囲設定済み,"; uRange.Address
End Function

'対象セル範囲の変更を、関連セル範囲に自動反映
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim myTarget As Range
    Dim t       As Range
    Dim colname As String

    If dic Is Nothing Then
        make_dic
        Set unionR = uRange()
    End If
    
    Set myTarget = Intersect(unionR, Target)
    If myTarget Is Nothing Then Exit Sub
    For Each t In myTarget
        colname = Split(t.Address, "$")(1)
        Application.EnableEvents = False
        Cells(t.Row, dic(colname)) = t.Value
        Application.EnableEvents = True
    Next
End Sub

Sub 自動転記処理を再開()
    Set dic = Nothing
    Set unionR = Nothing
    Application.EnableEvents = True
End Sub

■なお、ダブルクリックのイベントプロシージャを使えば、
  ・セルが""の状態であれば、"〇"を書き込み、
  ・セルに"〇"が入っていれば、"" で上書き
  と、トグル方式で実行させることも可能でしょう。)
  これも上記のコードと同じ、シートモジュールにコピーペイストします。
'ダブルクリックで、"〇"と""をトグル設定
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
    Dim colname As String

    If dic Is Nothing Then
        make_dic
        Set unionR = uRange()
    End If
    If Intersect(unionR, Target) Is Nothing Then Exit Sub

    colname = Split(Target.Address, "$")(1)
    Cancel = True
    Select Case Target.Value
        Case "": Target.Value = "〇"
        Case "〇": Target.Value = ""
    End Select
End Sub

【補足】
(1)列の挿入、削除は実行しないで下さい。自動転記の対象列がズレます。
どうしても必要な場合は、
その場合は、次のような手順が間違いがないでしょう。
  ・ブックのバックアップを取っておきます。
  ・別の新しいシートに、記入済みのものをいったんコピー
  ・列の挿入、削除を実行。
  ・シートモジュールを、再作成したシートのシートモジュールにコピーペイスト
  ・再度、対象列の指定部分を修正する。
 
(2)また、ヘルパー関数として、下記のプロシージャが役に立つ時もあるかもしれません。
<<シートモジュール>>
Sub 自動転記処理を再開() 
    Set dic = Nothing
    Set unionR = Nothing
    Application.EnableEvents = True
End Sub

<<標準モジュール>>に
Sub 自動転記処理を中止する()
    Application.EnableEvents = False
End Sub

'対象列を変更し、かつ同じシートを使い続ける場合は、これを実行します。
’これを実行しないと変更前のdic,対象セル範囲が継続して使われてしまいます。
Sub 自動転記処理を再開()  
    Call Sheet1.自動転記処理を再開  'sheet1での処理を再開する
End Sub

===========
総じて、ある程度マクロの取り扱いに慣れていないと、運用が難しいかもしれません。
前にも記載しましたが、
・入力列はどちから一方に限定し、
・関連する別の列ではそれを式で参照させ、その計算セルはロックを掛けて保護する
  (その列には薄い灰色でも塗りつぶしておけばよいかもしれません。)
という方法が安全確実だと思います。
そう言う意味で上記マクロは参考情報です。

回答
投稿日時: 26/04/21 13:11:25
投稿者: 半平太

仕様の確認をした方がいい気がするのですが、
 
「3行目以下にある「x行目、?列」のセル値に変化があったら、
 その2行目にある薬品名と同じ薬品が他の列にないかチェックし、
 有れば該当列のx行目のセルも同じ値に変える」 で合っていますか?

回答
投稿日時: 26/04/21 17:37:06
投稿者: simple

ありがとうございます。コメントはそのとおりかと思います。
 
私はかなり前の段階で、そのときの前提でコードは作成していたもので、
それに見出し行の個数を急遽追加しただけのものです。
できれば私の発言は凍結扱いにしてもらって、
それとは別に建設的な議論を進めていただければと思います。
よろしくお願いします。
# 正直疲れました。

投稿日時: 26/04/21 19:37:43
投稿者: ZU-

半平太さま、simpleさま
 
この度は、いろいろとお力をいただき、心より感謝申し上げます。
 
また、simpleさまにおかれましては、先日は気分を悪くさせてしまい、大変申し訳ございませんでした。
さらに、いただいたコードを活用させていただき、プロジェクトを進める予定です。
心が痛みますが、引き続きよろしくお願い申し上げます。
 
simpleさま・改半平太さま、あらためてありがとうございました。