ほっとひといき給湯室

ほっとひといき給湯室の掲示板です。お気軽にどうぞ!
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
Q&A掲示板の議論にひとこと
投稿日時: 18/01/04 20:44:26
投稿者: simple

Q&A掲示板の議論にひとこと
 
・Q&A掲示板の議論で言い残したことを補足したい、
・議論について自分はこう思う、自分ならこうするぞ
・よくわからなかったので詳しく教えて(こっそり)
・ともかく発言したい
という方は、どうぞふるって投稿願います。
 
「雑談スレだよ」だと本当に雑談したいひとの邪魔になるかもと思い、
こちらにスレッドを建てました。

投稿日時: 18/01/04 20:54:49
投稿者: simple

(昨年雑談スレッドに投稿した古い記事です。移動させておきます)
 
[入力規則の設定について ]
http://www.moug.net/faq/viewtopic.php?t=76593
ですけど、
A1形式とR1C1形式の参照設定の使い分けの話だと思ったのですが、
 少し違ったのかな。
  
書き忘れた論点がありました。
  
複数のセル範囲に同一種類の入力規則を設定する場合、
そもそも繰り返しをする必要はなくて、手作業で一括設定可能です。
 (マクロ記録をとればりっぱなマクロになります)
  
 [A1:D10]に対して入力規則を設定する場合を例にとると、
(1)R1C1参照形式にしている場合は
   "=LENB(RC)<=10"
    ですし、
(2)A1参照形式にしている場合も、
   "=LENB(A1)<=10"
    と指定すれば、他のセルも自動的に参照を調節してくれるはずです。
  
ですから、マクロにする必要すらない、
というのが実際のところかもしれません。
  
わざわざスレッドを建ててまで追いかける必要もないかと思っていますが、
 案外、盲点になっているかもしれませんね。
 

投稿日時: 18/01/06 08:51:26
投稿者: simple

シート指定を省略した場合の取扱について、下記に書きました。
http://www.moug.net/faq/viewtopic.php?t=76636
 
混乱してもいけないと思い、こちらに書きます。
下記のコードは、どんな結果をもたらすか予想できますか?

Sub test()
    Dim r As Range
    
    Sheet1.Select
    Set r = Range(Sheet2.Range("A1"), Sheet2.Range("B2"))
End Sub

 
RangeのシートはアクティブなシートであるSheet1 だから
例の論法で、エラーになるんじゃないか?と思いきや、
エラーにはなりません。
 
というのは、このRangeは ApplicationオブジェクトのRangeプロパティであり、
ワークシートの指定を要しません。
 
ですから、上記のような指定もExcelVBAの仕様の範囲内ではあるわけです。
 
しかし、通常こういう書き方は余り見ません。
それは、シート指定の無いRangeは(特に複数シートを相手にする場合は特に)
避けられるという実務的観点からでしょう。
つまり、「Rangeの前のシートは省略するな」という教育的配慮を優先しているものと
理解しています。
 
ご参考まで。
 
# 反応が無いので、質問型をやめて提案型に書き直しました。

回答
投稿日時: 18/01/07 00:17:13
投稿者: LMK

こんばんは
 

Sub test()
    Dim r As Range
    
    Sheet1.Select
    Set r = Range(Sheet2.Range("A1"), Sheet2.Range("B2"))
End Sub

 
ところで、この同じコードを Sheet1 のシートモジュールに書いたらエラーになりますね。
 
シートを省略した場合の解釈が、
 
 標準モジュール⇒ アクティブなシート
 シートモジュール⇒ 当該シート
 
となると同時に、
 
 標準モジュール⇒ 「原則」アクティブなシートと解釈
 シートモジュール⇒ 「必ず」当該シートと解釈
 
とでも言えばいいんでしょうか、解釈の厳密性に差があるように見えます。

投稿日時: 18/01/07 08:37:19
投稿者: simple

なるほど、そういうことかもしれませんね。ありがとうございます。
 
シート指定を二重に求めるとは何事か陣営ww の人たちからすると、
こんな書き方をすると、エラー回避できるかもしれませんね。
 

Sub シートモジュールsample()
    Dim r As Range
    
    Sheet1.Select
    Set r = Excel.Range(Sheet2.Range("A1"), Sheet2.Range("B2"))
End Sub
Applicationでもよいけど長いので。

回答
投稿日時: 18/01/07 12:56:13
投稿者: LMK

もちろん実務的には、
 1.それなりの理由がなければわざわざシートモジュールに書かない
 2.With で参照をまとめることもできる
わけですが。
 
 

Sub test()
    Dim r As Range
    Set r = Sheet2.Range("範囲")
End Sub

似たような「シートモジュールの寛容度が低い」問題ですが、上は Sheet1 のシートモジュールに書かれたコードです。
他シートのセル範囲を名前で参照する場合も、シート指定がないとエラーになりますね。
名前のスコープが「ブック」なんだからそこは適宜解釈してほしい、と言いたくなるところです。

回答
投稿日時: 18/01/07 14:36:45
投稿者: LMK

なるほど、Excel.Range または Application.Range と書けば、あたかも標準モジュールに書いたかのようにエラー回避できるわけですね。
 

Sub testExcel()
    Dim r As Range
    Set r = Excel.Range("範囲")
End Sub

 
次は Sheet2 のモジュールに書く例です。
最初の例はあたかも標準モジュールに書いたかのようにアクティブなシートの範囲が取得されますが、
2番目の例ではモジュールの既定値が優先され、Sheet2 の範囲が取得されますね。
勉強になります。
 
Sub Sheet2モジュールに書くサンプル1()
    Dim r As Range
    
    Sheet1.Select
    With Application
        Set r = .Range(.Range("A1"), .Range("B2"))
    End With
    MsgBox r.Address(External:=True) '⇒ Sheet1(アクティブなシート)の範囲が返る
End Sub

 
Sub Sheet2モジュールに書くサンプル2()
    Dim r As Range
    
    Sheet1.Select
    With Application
        Set r = .Range(Range("A1"), Range("B2"))
    End With
    MsgBox r.Address(External:=True) '⇒ Sheet2(モジュールの既定値)の範囲が返る
End Sub

投稿日時: 18/01/07 23:12:29
投稿者: simple

貴重な材料の提供、ご指摘、ありがとうございます。
 
余談です:
Excel.Rangeや Application.Rangeなどの使い方は、
将棋の格言にある「敵の打ちたいところに打て」というのを想起させますねえ。

回答
投稿日時: 18/01/12 15:38:32
投稿者: mattuwan44

Sub Sheet2モジュールに書くサンプル3()
    Dim r As Range
    
    Sheet1.Select
    With Me
        Set r = Application.Range(.Range("A1"), .Range("B2"))
    End With
    MsgBox r.Address(External:=True)
End Sub

 
Meでちゃんとどのシートの話か明示したいかな。。。

回答
投稿日時: 18/01/15 02:47:10
投稿者: baoo

う〜ん。
私の場合、自分のコードではブックも省略しないですね。
サンプル提示では省略したりしますけど。
それでWithを使うかSet sht=Workbooks("hoge").Worksheets("fuga")を
よく使います。

投稿日時: 18/01/16 23:05:57
投稿者: simple

baooさんの疑念はもっともで、こうした書法を推奨しているのではないんですね。
 
18/01/06 08:51:26 で私が持ち出した議論は、
Range(Cells(1,1),Cells(2,3))
で普通はRangeにもCellsにもシート指定をつけることが推奨されています。
Rangeのシートだけ特定しても、Cellsは(標準モジュールだからアクティブシートが前提となるので、
アクティブシートとRangeで指定したシートが異なる時はエラーになります。
というよく知られた、間違い易いポイントに関する前提があって、
では、標準モジュールで、

    Sheet1.Select
    Set r = Range(Sheet2.Range("A1"), Sheet2.Range("B2"))
などとしたとき、必ずRangeにもアクティブシートが補足されて、
エラーになると思うでしょう?上の理屈からすると。
でもそうでもないんですね、という注意喚起をしたかっただけなんですね。
昔こちらの掲示板であった議論を想い出して、知ったかぶりをしたということです。
(ですから、本体の議論ではたぶん閲覧者が混乱するだろうと考えて遠慮しておりました。)
 
そこでも書きましたように、どちらのシート指定もすることが可読性にもすぐれているので、
それを推奨します。(しかし、仕様として上記のような考え方も許容されているようですね、
ということを申し上げたかったのです)
 
混乱を招いたですかね。

回答
投稿日時: 18/01/20 20:48:13
投稿者: baoo

いえ、少し誤解させたのは私の方ですね。
私は間違いやすい記法が駄目だと思って言ったわけじゃないんです。
 
私がブックから省略しないのは機械的にそうなっているということです。
あるプログラマーの人が書いた本の中にファーストフードで
ハンバーガーとポテトとコーラを注文したときに店員から
ポテトはいかがでしょうかと聞かれた話がありましたが、
この種の単純な部分で考えたくない。
もっとも、Setの多用かWithのネストの方で考えることになるわけですけど。
私の場合、Withのネストも基本しないので(これもほぼ機械的にです。)
Setを使うことになります。
 
かつてよくあるエラーの元、
Worksheets("hoge").Range(Cells(1,1), Cells(3,3)).Value
のような記述で懲りたときからブックから省略しないようにするのが
身に付いて習慣化してしまっています。
で、このようなものってたぶん皆さんあると思うんです。
 
例えば、私の場合、
sht.Range("B3", sht.Cells(5, 5)).Value
sht.Rnage("B3", "E5").Value
等という書き方もしません。
自然と
sht.Range(sht.Cells(3, 2), sht.Cells(5, 5)).Value
という書き方になります。
他にも最下端を取得する場合、End(xlUp)よりはUsedRangeを使う傾向にあります。
(見栄えの為にブックは省略しています。)
 
一時期、遊びでWithもSetも使わずにブックから省略しないで書いていたことがあります。
ThisWorkbook.Worksheets("hoge").Range(ThisWorkbook.Worksheets("hoge").Cells(ThisWorkbook.Worksheets("hoge").UsedRange.Row, 1), ThisWorkbook.Worksheets("hoge").Cells(ThisWorkbook.Worksheets("hoge").Cells(ThisWorkbook.Worksheets("hoge").Rows.Count, 1).End(xlUp).Row, 5)).Select
なんて書いて試しに動かしてみて、動くとちょっと嬉しいみたいな。
もちろん、後で治すんですが書いてる最中に中断してSetやWithを書くために上の行に行くことで
発生するエラーを回避できるし、今書いている内容についての考えを中断されることもありません。
今書いているのがRange内部のセルの行の値なのかセルそのものなのか分からなくなって
1つの頭の体操ということです。
で、ブックから省略しないのが癖のように習慣化したということです。
 

回答
投稿日時: 18/02/01 23:25:40
投稿者: K.Hiwasa
投稿者のウェブサイトに移動

統合セルの高さ一括自動調整について
http://www.moug.net/faq/viewtopic.php?t=76732
 
ちょっと遅れて一通り読みました。
元コードが、自作ツールの印刷チェック機能のコードの一部分と似ていて驚きました。
私も結合セルの罫線分の幅として0.66を使っています。
実は有名なのかもしれませんが、作成時にいろいろ値を変えて試して結局0.66に落ち着きました。
 
折り返し表示セルや数値セルがあるとAutoFitは当てにならないこともあり、
現在は実際にXPSに印刷してできたファイルを解析して、
文字切れが起きてないかの判定も行っています。
 
しかし、そこまでやってもチェック漏れはあったり、実行条件に制約もあったりで
完全な印刷対策はできていません。

投稿日時: 18/02/02 23:12:12
投稿者: simple

(1)
私も、その昔、このテーマに関して、ほぼ同様のアイデアによるコードを
投稿したことがあります。
手元の記録では、 09/01/05 21:52:15 の発言とあります。
もう9年前ですか.....(遠いところを見る目)
 
ご指摘のとおり、画面上の表示もさることながら、印刷結果なども考えると、
完全な解はなく、どうしても遊び(余裕)をとることが必要となります。
つまり、ある程度"アート"の部分が残ると思います。
 
ですから、海外の投稿家がブログで公開しているのであれば、
それは、その方の経験に基づく調整が施されていると見て良いでしょう。
それを使ってみてOKならそれでよし、とすべきものです。
唯一の正解があるように思うのが間違いですし、
さらに、もっと短いものをと所望するのもいかがなものかと思います。
それによって、対応不能なことが起きる可能性もあるわけです。
 
(2)
ちなみに、回答者さんから、
>やたらIF文がネストしてるなぁって感じですね。(Andでつなげば良さそうにおもいますが・・・)
と指摘がありますが、これはこれで理由があるのです。
 
つまり、
If A AND B Then とした場合、AがFalseであっても、Bの評価をしてしまう
という特性があります。
 
このため、スピードを重視する場合は、これを避けて、
If A Then
   If B Then
      ・・・
と書く方が有効なわけです。(あくまで速度重視という観点ですが)
 
ですから、Andでつなげない点については、それなりの理由があるのです。

投稿日時: 18/02/02 23:29:21
投稿者: simple

「他のブックの値の参照 」(By FILETUBE さん)
http://www.moug.net/faq/viewtopic.php?t=76711
ですが、ちょっと中途半端な終わり方でしたね。
 
手元のサンプル
>ブックAは2000行、チェックする番号列は20列、ブックBは1000行
で、出力も合わせたうえで、速度を測ったところ、
・dictionaryを使用した私のコードでは、 0.35秒程度でした。
・mattuwan44 さんのCountIfを使ったコードでは、0.70秒程度でした。
(ix変数がインクリメントされていないところも修正したうえで実行)
 
いずれも1秒以内ですから、速度的には十分ではないかと思います。
 
dictionaryは、配列と並ぶ重要なデータ構造ですので、
その有用性も説明できたらよかったのですが。

回答
投稿日時: 18/02/07 21:38:31
投稿者: ちゃこ

1シートに複数ページの請求書で特定のページのみ印刷したい
http://www.moug.net/faq/viewtopic.php?t=76739
ですが
>これまでは、毎月400枚全部印刷して
とあるので、改ページは既に設定されていて「○」印の判定だけで
済みそうですが……
 
Sub マルのあるページのみ印刷()
    Dim i As Long
    '40行×10列の請求書400ページの印刷
    '水平改ページ設定済み
    '各ページの4行3列目のセルに"○"があればそのページを印刷する
    With ActiveSheet
        '先頭のページのみ判定
        If .Cells(4, 3) = "○" Then
            .Cells(1, 1).Resize(40, 10).PrintOut From:=1, To:=1
        End If
        '2ページから400ページまでの判定
        For i = 1 To 399
            If .Cells(.HPageBreaks(i).Location _
                    .Offset(3).Row, 3).Value = "○" Then
                .PrintOut From:=i + 1, To:=i + 1
            End If
        Next
    End With
End Sub
 
勘違いしてますか?

回答
投稿日時: 18/02/08 09:08:25
投稿者: mattuwan44

>勘違いしてますか?
いや、合ってると思います。
そかー。印刷時にページを指定してやればいいんですね^^
 
Sub マルのあるページのみ印刷2()
    Dim rng As Range
    Dim hp As HPageBreak
    Dim i As Long
     
    With ActiveSheet
        Set rng = .Range("A1")
        i = 1
        For Each hp In .HPageBreaks
            If rng(4, 3).Value = "○" Then .PrintOut From:=i, To:=i
            Set rng = hp.Location
            i = i + 1
        Next
    End With
End Sub
 
でも、いつも400とも限らない方が多いと思うので、、、、
水平の改行の集まりを巡回してやるといいとおもいます。
 
For Each hp In .HPageBreaks
水平の改行の集まり(HPageBreaks)(名前が複数形になっていることに注目)の中(In)の
個別の改行(HPageBreak)の各各(Each)に対して繰り返します。
 
コレクション(集合体)というものについて少し勉強するといいかも^^
Cells
Worksheets
Workbooks
みんな複数形で表記されてます^^

回答
投稿日時: 18/02/08 10:11:35
投稿者: ちゃこ

mattuwan44 さんの引用:

Sub マルのあるページのみ印刷2()
    Dim rng As Range
    Dim hp As HPageBreak
    Dim i As Long
     
    With ActiveSheet
        Set rng = .Range("A1")
        i = 1
        For Each hp In .HPageBreaks
            If rng(4, 3).Value = "○" Then .PrintOut From:=i, To:=i
            Set rng = hp.Location
            i = i + 1
        Next
    End With
End Sub
 
でも、いつも400とも限らない方が多いと思うので、、、、
水平の改行の集まりを巡回してやるといいとおもいます。
 
For Each hp In .HPageBreaks
水平の改行の集まり(HPageBreaks)(名前が複数形になっていることに注目)の中(In)の
個別の改行(HPageBreak)の各各(Each)に対して繰り返します。
 
コレクション(集合体)というものについて少し勉強するといいかも^^
Cells
Worksheets
Workbooks
みんな複数形で表記されてます^^

 
勉強になります♪
質問された方が、難しく考えているようなので分かりやすい考え方をと思って ^^
 
提示されたコードの場合、最終ページに○がついていても印刷されないような気が……
違っていたらごめんね <(_ _)>

回答
投稿日時: 18/02/09 08:26:51
投稿者: mattuwan44

>提示されたコードの場合、最終ページに○がついていても印刷されないような気が……
 
あぁああああ、、、、、ページの終りは改ページと数えられないのですね。。。。。^^;;
 
 
Sub test()
    With ActiveSheet.HPageBreaks
        Application.Goto .Item(.Count).Location
    End With
End Sub
 
Sub マルのあるページのみ印刷2改()
    Dim rng As Range
    Dim hp As HPageBreak
    Dim i As Long
      
    With ActiveSheet
        Set rng = .Range("A1")
        i = 1
        判断して印刷 rng, i
        For Each hp In .HPageBreaks
            i = i + 1
            判断して印刷 hp.Location, i
        Next
    End With
End Sub
 
Sub 判断して印刷(ByVal rngTarget As Range, ByVal ix As Long)
    If rngTarget(4, 3).Value = "○" Then rngTarget.Worksheet.PrintOut From:=ix, To:=ix
End Sub

投稿日時: 18/02/10 21:08:16
投稿者: simple

10年以上前からのベテラン回答者さんにcollectionの勉強の薦めですか。
勉強になります、ですか。中々言えませんよ。すごい。
私も勉強になりました。

回答
投稿日時: 18/02/16 12:33:19
投稿者: もこな2

反応がかなりおそくなっちゃいましたが、

simple さんの引用:
(2)
ちなみに、回答者さんから、
>やたらIF文がネストしてるなぁって感じですね。(Andでつなげば良さそうにおもいますが・・・)
と指摘がありますが、これはこれで理由があるのです。
 
つまり、
If A AND B Then とした場合、AがFalseであっても、Bの評価をしてしまう
という特性があります。
 
このため、スピードを重視する場合は、これを避けて、
If A Then
   If B Then
      ・・・
と書く方が有効なわけです。(あくまで速度重視という観点ですが)
 
ですから、Andでつなげない点については、それなりの理由があるのです。
なるほど。あれはあれで、まったく無意味ではないんですね。勉強になりました。

回答
投稿日時: 18/02/20 17:16:06
投稿者: もこな2

非表示シートを再表示する方法
http://www.moug.net/faq/viewtopic.php?t=76787
  
メモ帳で追加コメント書いてる間に閉じられちゃいましたけど、たとえばこんなコードを書いた場合。

Sub test()
'==変数の宣言
    Dim WS As Worksheet
    Dim コレクション As Sheets

'==処理
    '(1)For Each 〜 Nextステートメント による処理
    For Each WS In Worksheets(Array("sheet1", "sheet2", "sheet3"))
        WS.Visible = True
    Next WS

    '(2)コレクションに対して一気に処理【表示→非表示】
    Set コレクション = Worksheets(Array("sheet1", "sheet2", "sheet3"))
    コレクション.Visible = False

    '(3))For Each 〜 Nextステートメント と コレクションの組み合わせ【非表示→表示】
    For Each WS In コレクション
        WS.Visible = True
    Next WS
End Sub
私は、「Worksheets(Array("sheet1", "sheet2", "sheet3"))」の部分で少なくとも「配列を”使ってる”」ってことになるとおもうんですよね。さらに、コレクションへのセットは「配列に代入」と言えなくも無いとおもいます。
 
それを踏まえると、いずれもすっきりと記述できますし、非表示のシートに対して、「コレクション.Visible = True」ではエラーになるっていうのは事実かもしれませんが、やりようあるので、個人的には、「配列に代入」という言葉のとらえ方次第ではありますけど、必ずしも配列による処理は出来ないとは言い切れないなぁとおもうんですよね。
 
 
この点、質問者さんは、うまくいかないの一言で済ませて、どのようにしたらどううまくいかないのか聞いても答えないし、どのようなコードを書いているのかも提示しないし、かといってFor〜を使ってると仰るので、先にコメントしたように、シートのINDEX番号使って、For〜Nextステートメントでループさせてるのかなぁ・・と推測するくらいしか出来ないんですよね。
  
まぁ、追っかけて説明する義理もないですし、説明したところで方向固めてて、聞く耳もってなさそうですし、もやもやしますがほっとくしかないんでしょうかね。。。

投稿日時: 18/02/22 00:12:28
投稿者: simple

かなり自己中心なかたのようにお見受けしました。
残念なかたと思うしかないですかね。

トピックに返信