[[20161014204949]] 『入力内容によって、セルを結合させる方法』(ひろ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『入力内容によって、セルを結合させる方法』(ひろ)

いつもお世話になっております。
先日は、ありがとうございました。
もう少し、詳しく書きますのでよろしくお願いします。
先日、お答えいただいた方ありがとうございました。
下記のような可能でしょうか?
ご指導のほど、お願い致します。

有給休暇取得日一覧表を作成しています。

 有給は半日ごとに取得でき、半日(0.5)か終日(1)のみです。 
 一覧表と入力シートを用意しました。 

有給管理表の有給日数セルの右の数字が取得日です。
この所得日は、有給日数を表し、有給は半日単位で取得できるため、
半日ごとに1列になってます。
1〜20まであります。下のイメージでは3までです。

(例1)入力シート たろうさんに 4/1 と入力すると、

     有給管理表のシート C と D が結合され 4/1 と入力さる。 

(例2)入力シート じろうさんに 4/8(0.5) と入力すると、 

     有給管理表のシート C に 4/8 と入力される。 

【入力シート】
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

       |   A  |   B  |   C    |  D    |  E  |  F  |
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
   1   |  名前 | 有給日数 |  1     |   2    |  3   |   4   |
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 
   2   | たろう|   20    |   4/1   |4/5(0.5)| 4/10 |
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
   3   |じろう|  20   |4/8(0.5)|4/15    |

【有給管理表】
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

       |   A  |   B  | C  | D |  E |  F |  G | H  |
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
   1   |  名前 | 有給日数 |   1    |     2   |   3   |
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 
   2   | たろう|   20    |  4/1   |4/5 |  4/10   |
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
   3   |じろう|  20   |4/8|  4/15 |
   

< 使用 Excel:Excel2013、使用 OS:Windows8 >


ども^^

セルを結合する意味はなんでしょう?
何を表現したいかが解りません。

もしかして、消化分をセルの塗りつぶしでグラフっぽく視覚化するとかですかね。。。?
何日に半日、何日は一日とかは入力した表を見れば解りますよねー・・・
一日は2つ塗潰せばいいような・・・

出来なくはないけど、出来たところで、、、て感じですよね。

やるなら、

0)始め
1)セルを巡回して、
2)もし、値に「0.5」が含まれるなら
3)その時は「(0.5)」を文字列から消去して転記
4)そうでない時は、右隣りも結合して転記
5)次の転記先用意
6)繰り返し(1に戻る)
7)終わり

みたいな感じかなぁと思いますが、
どこまで書けますかね?
(まっつわん) 2016/10/15(土) 09:56


暇があったからコード書いてみました。

Option Explicit

Sub test()

    Dim rngOld As Range
    Dim rngNew As Range
    Dim c As Range
    Dim s As String
    Dim n As Long
    Const cHalf As String = "(0.5)"

    Set rngOld = Sheets(1).Range("A1").CurrentRegion
    Set rngNew = Sheets(2).Range("A1")
    rngOld.Resize(, 2).Copy rngNew
    With rngOld
        Set rngOld = Intersect(.Cells, .Offset(1, 2))
    End With
    Set rngNew = Sheets(2).Range(rngOld(1).Address)
    With rngNew.Offset(-1).Resize(, 40)
        .Cells(2).Value = 1
        .Cells(4).Value = 2
        .Resize(, 4).AutoFill .Cells
    End With

    For Each c In rngOld
        s = c.Value
        If Len(s) > 0 Then
            n = InStr(1, s, cHalf)
            If rngNew.Row <> c.Row Then
                Set rngNew = rngNew.Worksheet.Range(c.Address)
            End If
            If n > 0 Then
                rngNew.Value = Left(s, n - 1)
            Else
                rngNew.Value = s
                rngNew.Resize(, 2).Merge
            End If
            Set rngNew = rngNew.Offset(, 1)
        End If
    Next
End Sub

コツとしては、
rngNew.Resize(, 2).Merge
と結合してから、
Set rngNew = rngNew.Offset(, 1)
とOffsetプロパティで次の書き込み先を取得するとこですかね。。。

あと、別のシートの同じセル位置は、
アドレスを取得してRangeプロパティの引数に入れちゃうとかかなぁ。。。

この程度の説明で伝わればいいけど。。。。

(まっつわん) 2016/10/15(土) 10:53


質問者様におたずねします。
前のスレッド、
[[20161013131822]] 『有給休暇取得日一覧表 自動的にセルを結合する方』(ひろ) 
において、回答が寄せられているのに貴方のコメントがありません。
そのことはどのように受け止めておられるのでしょうか?
単にありがとうだけですか?

(γ) 2016/10/15(土) 13:50


 γさんから指摘がありますが、他にも、たとえば、

[[20151227224152]] 『small関数のエラー』(ひろ)
[[20150207160417]] 『色付きセルを数値化し、それを合計する方法につい』(ひろ) 

 いささか、古いトピですが、(ひろ)さんの質問スタンスとして、質問したテーマの回答が、妥当だったか
 適切ではなかったかによらず、それらに対するレスがないものが目立ちます。

 やはり、Q/Aは双方のコミュニケーションが本筋だと思いますが?

(β) 2016/10/15(土) 14:23


まっつわんさん、コメントありがとうございます。

セルを結合する意味は、ご承知の通り、管理表として印刷し掲示する為です。

コードまで書いて頂きありがとうございます。

詳しくない為、よくわかりません・・・。
勉強してみます。

分からない時は、また質問させて頂きますので、よろしくお願いします。

(ひろ) 2016/10/15(土) 16:30


まっつわんさん、たびたび申し訳ありません。

調べながら、取り組んでますが、全然わかりません・・・。

よろしければ、詳しく教えていただけませんか?

よろしくお願いします。
(ひろ) 2016/10/15(土) 18:16


>調べながら、取り組んでますが、全然わかりません・・・。
>よろしければ、詳しく教えていただけませんか?

どうやって調べてますか?
どこがわかりませんか?

入門書とかWebの入門サイトとかは一通り読まれてますか?

>0)始め
>1)セルを巡回して、
>2)もし、値に「0.5」が含まれるなら
>3)その時は「(0.5)」を文字列から消去して転記
>4)そうでない時は、右隣りも結合して転記
>5)次の転記先用意
>6)繰り返し(1に戻る)
>7)終わり
この辺の日本語の手順をVBAに翻訳することは難しいですか?

どこまで理解が出来ているのかわかりませんので、
どんな説明していいかわかりませんが、
時間ができれば詳しく解説してもいいですが、
時間がいつ取れるかは確約できませんので、
ご了承願います。

(まっつわん) 2016/10/16(日) 07:44


こんにちは。

ひろさん
せっかく、QA掲示板というやりとりのできる場所で質問されているのに
詳しく教えるという名目の 講義を読むだけじゃつまらなくないですか。

せっかく、「調べながら、取り組」まれたのですから
どのように理解されたか、どのように分からないか、説明されてはどうでしょう。
説明なされば、ひろさんにジャストフィットの解説がいただけると思いますよ。
ちゃんと取り組んだひとだけの特権です v(^^
よかったら検討してみてください。

( 佳 ) 2016/10/16(日) 17:01


まっつあんさん、コメントありがとうございます。

入門書やウェブの基礎編みて勉強しています。

もうすこし、勉強してみます。

いまは、分からない部分の説明すらできないです。

もうすこし、勉強してみます。
(ひろ) 2016/10/17(月) 15:03


佳さん、コメントありがとうございます。

もうすこし、勉強してみます。

ありがとうございます。
(ひろ) 2016/10/17(月) 15:05


>いまは、分からない部分の説明すらできないです。

なるほど、じゃ、上から読んで行って、
最初に詰まったところ、あるいは戸惑ったところはどこですか?

一行ずつ意味を理解してみましょう^^

参考URL>>
http://www.ken3.org/vba/excel-help.html
(まっつわん) 2016/10/17(月) 17:43


>いまは、分からない部分の説明すらできないです。
>もうすこし、勉強してみます。

状況は理解しました^^
ちょっと独学では無理そうなので、
活発に掲示板を利用してみてはいかがでしょうか?

時に、きつい意見が書かれることも多々あるでしょうが、
基本的に非難されてるわけではなくて、率直な感想がほとんどです。
書き言葉だときつい印象に取られがちですが、
それぞれ都合があり、時に素っ気ない書き込みもあるとは思いますが、
無視されるよりは全然いいのですし、
当然上手く説明出来なくてなかなか思いが伝わらない場合もあり、
すごくストレスに感じることもあると思います。
ですが、そこは気にせず粘り強くご自分の意図を伝えてください。

特に、誰かに自分の意図を説明して解ってもらえるようになることが、
VBAでエクセル君に自分の意図を伝えられるようになる第一歩と僕は考えます^^

↑日本語の手順とVBAのコードとどこが対応しているか、
コメントを入れてみましたので参考にしてください。

Option Explicit

Sub test()

    Dim rngOld As Range                 '元のデータのセル範囲
    Dim rngNew As Range                 '書き込み先セル(範囲)
    Dim c As Range                      'セル範囲内の各セル
    Dim s As String                     'セルの内容(文字列)
    Dim n As Long                       '文字列の中の(0.5)の位置(何文字目か)
    Const cHalf As String = "(0.5)"     '半日と判定できる文字列

    'セル範囲を変数に取得
    Set rngOld = Sheets(1).Range("A1").CurrentRegion
    Set rngNew = Sheets(2).Range("A1")
    '転記先にタイトル列のコピー
    rngOld.Resize(, 2).Copy rngNew
    '表の中のデータの範囲を取得
    With rngOld
        Set rngOld = Intersect(.Cells, .Offset(1, 2))
    End With
    '左から2番目のシートの同じアドレスのセル範囲を取得
    Set rngNew = Sheets(2).Range(rngOld(1).Address)
    '転記先のタイトル行入力
    With rngNew.Offset(-1).Resize(, 40)
        .Cells(2).Value = 1
        .Cells(4).Value = 2
        .Resize(, 4).AutoFill .Cells
    End With

    'データ範囲内の各セルを巡回
    For Each c In rngOld
        'セルの値を変数に代入
        s = c.Value
        'もし文字数が0以上(=空白でない)なら
        If Len(s) > 0 Then
            '文字列に半日を示す文字が含まれているか検索
            n = InStr(1, s, cHalf)
            'もし転記先と転記元とで行番号が違うなら、
            If rngNew.Row <> c.Row Then
                '転記先を転記元と同じセル番地にする
                Set rngNew = rngNew.Worksheet.Range(c.Address)
            End If
            'もしデータが半日なら("(0.5)"という文字列が見つかったなら)
            If n > 0 Then
                '(0.5)を除いて転記
                rngNew.Value = Left(s, n - 1)
            'そうでないなら
            Else
                '値をそのまま転記
                rngNew.Value = s
                'セルを右隣のセルと結合
                rngNew.Resize(, 2).Merge
            End If
            '次の転記先を取得
            Set rngNew = rngNew.Offset(, 1)
        End If
    Next
End Sub

※先にセル範囲を変数に代入してるとこで戸惑ってるのかなぁ。。。。
(まっつわん) 2016/10/18(火) 09:16


まっつあんさん、コメントありがとうございます。

ご丁寧に説明頂きありがとうございます。

頑張っでみます。

(ひろ) 2016/10/19(水) 12:48


>頑張っでみます。
ひとりで頑張らず、

上から順に読んで行って、

「なんだ!!!この書き方は?!!!!」
とか、
「意味ありげな言葉が出てくるけどこれってなによ?!」

と、引っかかったところを、どんどん聞いて(騒いで)下さい。

それの方が答えやすいです。

全部を詳細に解説しようとすれば、膨大な量の話をしないといけないので^^;

(まっつわん) 2016/10/19(水) 16:05


そもそも論で恐縮です。
 
・入力シートから常に洗いがえで、すべての【入力シート】のデータを
 【有給管理表】シートに反映するのか、
・変更のあった都度、その変更だけを反映するのかすら、
明確な方針は出されていないような気がします。
質問の文面からは後者のようにも読めます。
 
もし、前者の方針であるなら、
有給管理票の更新に先立って初期化する必要があるでしょう。
(例えば、じろう さんが 
・いったん、4/15と入力(それを有給管理票に反映)したたあとで、
・4/15(0.5)と修正した
場合、今のコードだと0.5カウントには変更されませんよ。)
 
一方、後者方式(入力シートの変動の都度反映)を採るなら、
・データの消去
・データの修正
などがきちんと行われるか検証が必要です。
これは前のスレッドからの続きということになります。
 
また、ユーザーが質問者さんだけなら問題ないですが、
もし多数のユーザーが使うのであれば、セキュリティも関係します。
有給管理票(ないしその元データである入力シート)は、
簡単に改竄ができては困る性質のものです。
質問者さんがそのあたり、どの程度意識されているのかわかりませんが。
運営場面も考慮した検討が必要でしょう。
単にコードだけの問題では無いように思います。

(γ) 2016/10/19(水) 23:07


まっつわんさん
お世話になっております。

上記コードを標準モジュールに入れてみました。

セル範囲を変数に代入という部分が分かりません。

よろしくお願いします。

(ひろ) 2016/10/21(金) 02:57


ども^^

昨日から書いてたんですが、地震騒ぎで纏めきれませんでした^^;

>セル範囲を変数に代入という部分が分かりません。
簡単な言葉ですが、説明しようとしたら、一語一語が深いんですよねぇ。

【変数とは】
 変数とは数値や文字などを入れる入れ物のようなものです。
実質的には、「変数を宣言する」ことでメモリーに領域が確保されます。
メモリー上の膨大な領域のとある場所に名前を付けておけば、
扱いが簡単になるというわけです。

【代入とは】
 左辺に示されるメモリー領域(変数)に
右辺のデータを紐付ける(記録する)ことをいいます。

【セル(範囲)とは】
例えば、
「A1セルの値をC1セルに3倍にして書き込みたい」
というときに、

Rnage("C1")=Range("A1") * 3

と書く人が居ますが、「ホントに意味解ってるのかなぁ?」と思います。
Range("A1")は値ではないですよね?
「A1セルの値」が値なわけで、「A1セル(=Range("A1")」はセルそのものなのです。
つまり、値なり字の大きさなり、塗りつぶしの色なり、アドレスのA1なり、
これらすべてで形作られているのが実体としてのセルです。

そしてセルその物が操作の対象であり、
操作の対象のValueプロパティの値を操作するのですから、
Rnage("C3").Value = Range("A1").Value * 3
と書くべきなのです。
(ただし、省略が許されているので、前述のような記述も許されます。)
こういった、データ、属性、命令、関数が共存して構成されるものを、
「オブジェクト」と呼びます。
特にセル範囲(単一セルでもセル範囲)のことは「Rangeオブジェクト」呼びます。

【変数の型】
変数の型には、
整数型(Integer)
長整数型(Long)
倍精度浮動小数点型(Double)
文字列型(String)
等がありますが、
実はオブジェクト型というのもありまして、
オブジェクトも代入すすることが出来ます。
とくにセル範囲はRangeというオブジェクト型になります。

【オブジェクト変数に代入】
オブジェクトを変数に代入するときは
Setステートメントを使います。
逆に値はLetステートメントを使います。

Dim n As Long
Let n = 10

しかし、Letステートメントは省略が許されているので、
わざわざ書く人は稀だと思います。

代入と書きましたが、厳密には、オブジェクトは内部的に、野球選手の背番号のように
「固有の番号」が割り振られており、
この「固有の番号」をオブジェクト変数に代入しています。

【なんで先にセル範囲にセル範囲を代入するのか】
一つ目は、

Dim rngOld as Range

と宣言しておくと、

rng とまで書いてCtrlキー + Spaceキーを押すと、
候補に一覧がでるのでそれから選択できるので便利。
rngo まで書いてCtrlキー + SpaceキーでrngOldが入っちゃいます。

二つ目は、
rngOld. と書くと、メンバーの一覧がでるのでそれから選べばいいので便利。
英語苦手なんでこの機能がないと、ほんと苦労します^^;

三つ目は、
コードは説明文(作業手順書)だと僕は思っているので、
最初に対象のセル範囲を明示したほうが、
読みやすい(=伝わりやすい)と思っているからです。


こんな説明で伝わりますでしょうか?
ここででてきた用語はネットで改めて検索して調べて理解して欲しいと思います。
それで解らなければ続いて聞いて下さい。

(まっつわん) 2016/10/22(土) 12:38


こんにちは。

>セル範囲を変数に代入という部分が分かりません。
変数は値を入れる箱のようなもの、という説明をよく見かけますが
ここでいう値は値段のことではなく、
文字や数値は言うまでもありませんが、セルやセル範囲や、シートやブックも含まれます。
まあ、箱といっても実際に手でさわれる物理的な箱があるわけではありませんで(^^;
箱がある「かのように」、箱にあたいを入れる「かのように」考えるということです。

さて。
セル範囲を変数に代入すると、それ以降は、
その変数がそのセル範囲そのものであるかのように扱うことができます。

変数を使うと具合のいいことはいろいろありますが、たとえば
複数のセル範囲を対象に、順番に同じ処理を繰り返すような場合に
もちろんセル範囲の数だけ同じようなコードを書いてもいけないことはありませんが
同じことを何度も書くのは面倒です。

セル範囲を順番に、変数に入れては変数を対象に処理を行うコードにすれば
繰り返し部分のコードは1回書くだけで済む、そのようなつくりにできます。

> 'セル範囲を変数に取得
> Set rngOld = Sheets(1).Range("A1").CurrentRegion
> Set rngNew = Sheets(2).Range("A1")
要するに、変数をあとの部分でうまいこと使ってやろうと目論んでいるわけです。

こんな説明で伝わるでしょうか。

( 佳 ) 2016/10/22(土) 14:59


 セル範囲の変数代入には、もう2つ、メリットがあります。

 1.たとえば、処理対象が Range("F5:H20") だったとして、このセル範囲に対する処理がコードのあちらこちらに
   出てきているとします。
   あるとき、要件がかわって 対象範囲が F5:J30 になったとしますと、コードのあちらこちらに出てきている
   Range("F5:H20") という記述を【もれなく】Range("F5:J30") に変更しなければいけません。

   面倒ですし、変更漏れもありそうですね。

   でも、たとえば Dim myR As Range という変数(箱)を規定しておいて

   Set myR = Range("F5:H20") と1回だけ記述しておけば、コードのあちこちにある Range("F5:H20") は、すべて MyR と記述することができますし
   対象領域が F5:J30 になれば、その1回だけ記述してあるコードを Set myR = Range("F5:J30") になおすだけで
   あとは、変更不要になります。

 2.わずかですが MyR として参照するほうが Range("F5:H20") として参照するよりも効率が優れています。

(β) 2016/10/22(土) 17:14


>セル範囲を変数に代入という部分が分かりません。

あぁ、読み直して、も少し追記。

佳さんβさん追記してもらったメリットもありますよね^^

もう一つ。
> 'セル範囲を変数に取得
> Set rngOld = Sheets(1).Range("A1").CurrentRegion
> Set rngNew = Sheets(2).Range("A1")
> '転記先にタイトル列のコピー
> rngOld.Resize(, 2).Copy rngNew

上記は、コピーしたらもう変数の内容はほぼ不要(実際には次のセル範囲の取得で参照してます)
なんですが、
なんで変数を使うかというと、
Sheets(1).Range("A1").CurrentRegion.Resize(, 2).Copy Sheets(2).Range("A1")
1行が長くて読みにくくなるから、行を分けて記述しています。
画面を目いっぱい使って書くなら問題ないですが、
実際にはシートも見たいし、ヘルプも見たいし、Webで検索して調べ物もしたいし、
ウィンドウをいっぱい表示してますので、個々のウィンドウを大きく取れないので、
画面に1行が収まってないと作業効率が落ちるので、
僕の場合あんまり長々1行で書かないですかね。
また長くなるときは、_(アンダーバー)+ (半角スペース)で折り返して書けるので、
あまり横に長くならないようにしてます。

先にセル範囲入れるデメリットは、
使うかなぁって思って書いても、後で使わないじゃん。
ってことが時々ある程度ですかね。。。
(まっつわん) 2016/10/22(土) 17:54


まっつわんさん、
コメントありがとうございます。

御礼が遅くなり、申し訳ありません。
地震大丈夫でしたか?

やはり、難しいです・・・。
もう一度、読み返して頑張ります。

分からない時は、また
よろしくお願いします。
(ひろ) 2016/10/27(木) 21:10


佳さん、
コメントありがとうございます。

頑張ってみます。
(ひろ) 2016/10/27(木) 21:13


βさん、コメントありがとうございます。

奥が深いですね。
しっかり勉強します。

お教えいただきありがとうございます。
(ひろ) 2016/10/27(木) 21:16


>まっつわんさん、
>コメントありがとうございます。
>御礼が遅くなり、申し訳ありません。
お礼は特に必要ないですけど、「解った!」と言ってもらえると
こちらもうれしいのですが・・・

>地震大丈夫でしたか?
地震は特に身内で家が壊れたとか怪我したとかは無いので、
大丈夫です。

関連で崖がちょっと崩れたので、今日、治してたんですが、、
「道路が通れない!」と苦情><
「あんたらのために直してるんだぜ?」とは大きな声では言えず・・・^^;
「すみません。どうぞお通りくださいませませ^^」

>やはり、難しいです・・・。
>もう一度、読み返して頑張ります。
難しいですかぁ。。。

【オブジェクトとは】
 例えば、「車」があります。
 これもオブジェクトです。
車体があり、タイヤがありシートがありハンドルがあり、
これらが構成する「物」が車ですよね?

つまり車の色が知りたかったら、
「あなたの車の(車体の)色は?」と聞きますよね?

これを僕が書いたコード風に書いたら、

Sub test()

  dim myCar as car

 set myCar = 「あなたの車」

  Msgbox myCar.Body.Color
End sub

この時の車体や色がプロパティです。

エンジンをかけたかったら、

  myCar.EngineStart

とでもなるでしょうか?
これがメソッドになります。

次に以下を試してほしいと思います。

Sub Test2()
  dim Rng as range

    set rng = Range("A1")
    stop
end sub

これを実行すると、「stop」でプログラムが一時停止します。
その時にローカルウィンドウの「Rng」の左の「+」マークをクリックしてみたください。
これが、Range("A1")の実体の一端です。
この中の文字の色であったり、値であったり、セルのアドレスであったり、
そういうデータが欲しければ、それぞれのプロパティを指定して取り出したら、
いいことになります。

こんな説明で解るといいのですが。。。

(まっつわん) 2016/10/28(金) 19:14


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.