インストールレスプログラミング( ´ー`)

VBA , JavaScript , HTAなど 365アプリはインストール必要ですが、仕事に無いケースはほぼないから(・_・;)

教材作成にどっぷり

ちょっとVBAについてまったくできていません。

いろいろな絵を描いたり教材づくりをせっせとやってます。

いろんなことをやってるんですが,その中でもあまりにも魅力的な絵につかまって,時間を浪費中。

1472年に掲載されたエンペドクレスの4元素の絵。これがあまりにも私の心にヒットして,どうにか描きたいなと思っているところ。

没後かなり経つので,著作権の面ではまず問題なさそう。

必死にこの絵を探しました。

こちらに色が塗られた絵があります。これがほしい。でも高い。デジタルで配布する教材にはちょっと無理。
pixels.com

元絵の著作権が切れてても,こちらはこの著作権者の所有物なので,オリジナルから自分で描かないといけません(;´▽`A``

さて,オリジナルはどこだ・・と必死に探していたら,日本語ではヒットしないけど英語ではいくつかヒット

File:Four elements at de responsione mundi et de astrorum ordinatione.jpg - Wikimedia Commons

残念ながらぼけぼけです。 なぜこんな画像をパブリックドメインで貼った(;´▽`A``

でも,あきらめきれず中身を読んでると,

f:id:chemiphys:20170322000125p:plain

どうも原書を読ませてくれそうなリンクが張ってあります。

Harvard Mirador Viewer

時代の進歩ってすごいですね。

seq.17に目的の図があります。
f:id:chemiphys:20170322000334p:plain

さて,なぞってみようとしたら,これは難関だなぁとまずそれはさくっとあきらめ。

PhotoshopCC と IllustratorCCのライセンスを買っているので,ここはトレースだ!と思い,Photoshopでいらないところを落とした後,Illustratorでトレース・・

f:id:chemiphys:20170322000552p:plain

トレースしたものを図としてうまく貼り付けて,グループ解除やらしていくと,パワーポイントで色がぬれる感じにしてくれます。
目的の部分に色が塗れるように,各パーツ大きめに取って,組み合わせて 完成させようとしているところ。

無駄なことをしているとは思うんですが,

カッコイイと思った以上,他にもカッコイイと思う子もいるかもしれない。

心を動かされるのが一番の動機になるので,自分の心が動いたところはやるべきと思うんです。

なので,多大な時間を費やしていますが,この絵はなんとか恰好がつくレベルまで再現してみようとしています。

(;´▽`A``VBAドコイッタ

わたしにとってのクラスモジュール感

shokuren.hateblo.jp
上記の記事でクラスモジュールに関して触れてあるので,わたしも乗っかってみようと思いました。

いろんな人がいていいと思うので,正直なところを。

クラスモジュール=効率がいいというのはわたしも無いと思います。

クラスモジュール化の私なりの基準は,

① 要素数が多いデータの構造をクラスで書き,コレクションに収める場合
 1レコードが1つのインスタンスで,それをたくさん作れる。
 データ構造が変わっても,クラス部分をすこしいじれば対応できています。

② インスタンスをたくさん作り,それぞれ個別に何かしないといけない場合
 熱運動の時たくさんの粒に自由に運動させる。一粒一粒がクラスモジュールにより独立して運動させたりできる。
 標準モジュールのみで書くなら,各粒子の座標等の属性を全部同時に制御する必要があり,大変でした。

③ あまりにも部品数が多く,部品部品を切り分けないとわけがわからなくなりそうな場合
 変数の把握も大変なくらい全体が膨れ上がる場合は,部品部品に分け,変数をカプセル化で隠すことで他の部品の変数を気にせず使える。カプセル化せずにPublicで宣言してた時はクラスにしてもメリットがわかりませんでした。


標準モジュール等でもそうですが,モジュールを分けると変数の宣言が増え,コードの行数は確実に増えますよね。引数に使うことでいくらか減らせますが,それでもまぁ増える。

標準モジュールのみでそれをやると,変数の数がどんどん,どんどん膨れ上がりますが,クラスモジュールを使い,なおかつ内部の変数を隠すところまでやれば,変数の把握がとてもすっきりします。

各部品ごとにほぼ独立させられるというのはとても魅力で,外から見える情報を必要なもののみに限定していかないと,個人的にはクラスのメリットは無いと考えています。

部品をきちんと独立させられているクラスモジュール利用のプロジェクトでは,何か不具合が起こったときや,仕様変更をする際も,基本は外部と影響はないので部品のみメンテで対応でき,容易に解決できていると感じています。

いつもOption Explicitをして,コードを書いていますが,これなくしてもVBAなら勝手に変数判断してくれるし,

宣言すら無くしてしまいたいなーと思うことが多々あるんですが,素人ですので,想定外に変数の型が変化したりしていて,VBAがコンパイル時に止まって

「ここ,君が思っているようにウゴイテイナイミタイダヨ?」

と教えてくれて助かっています。

部品化,インスタンス化,そのコードのみに限らず何度も繰り返し使うときはやっぱりクラスはいいなぁと 個人的には思いますね。。

配列のみで大量のデータを扱うのは正直具合悪くなりますので,クラス+コレクションでデータを扱うことの便利さには非常に感謝しています。(ΦωΦ)

覚えたてで,あまり良いコーディングができているわけでないのでおこがましいところも多々あるかもしれませんが,素人ならではの意見として書いてみました。

Powerpoint VBA 三択問題を作る ② 問題準備・選択肢部分

三択問題作りその2 です。
chemiphys.hateblo.jp

これの続き

問題データの取り扱い部分に集中してお届けします。

以前,大量データの扱いでお世話になったものをPowerpointに適用してみました。
thom.hateblo.jp

こちらのコードは,実務でもとても扱いやすく使ってますし,抽出その他のメンテナンスもし易くて,本当に重宝しています。

パワーポイントの表のデータはとても小さいんですが,この考え方は使いたいと思い,パワーポイント用に自分なりに適用しなおしてみました。

プロ版やめたので,ダウンロードリンクは消去

目次

モジュールがかなり増えてきていますので,全部は載せません。上記のファイルをダウンロードして試されてください。
大丈夫なはずですが,テストするのも自己責任でお願いします。

表の変更点は,前回は 選択肢1,2,3 と正答を表に書いていましたが,どうせランダムに並べるなら 正答を最初に書いて,誤答2つを並べるというふうに変わっています。

さて,元のデータ構造が変わってもコードの書き換えが最小限で済むように,Enumを利用します。Excelの時ほどではありませんが,宣言用に1つ標準モジュールを使用しています。

標準モジュール

m00宣言

Public Const 問題表列数 = 6
Enum M
    番号 = 1
    問題
    正答
    誤答1
    誤答2
    備考
End Enum

今のところはこれだけですが,回答を収めるほうもコレクションで作っていきたいので,後々その分も宣言に増えていきます。

Module1

ここで実際の処理をします。
まだ,表示部分等には手を加えていないので,前回から変わった部分だけ。

Public 問題集 As Collection

宣言部分に問題集のコレクションが追加されています。

Function RandArray(argMax As Long) As Variant
    Dim Col As Collection: Set Col = New Collection
    Dim Arr(): ReDim Arr(1 To argMax)
    Randomize
    
    Dim i As Long
    For i = 1 To argMax
        Col.Add Rnd
    Next
    
    Dim tmp As Long, c
    For i = 1 To argMax
        tmp = 0
        For Each c In Col
            If c < Col(i) Then tmp = tmp + 1
        Next
        Arr(i) = tmp + 1
    Next
    
    RandArray = Arr
End Function

Function GetDataAsCollection() As Collection
    Dim SourceTable As PowerPoint.Table
    Set SourceTable = ActivePresentation.Slides(2).Shapes("問題表").Table
    Set 問題集 = New Collection
    Dim Arr: ReDim Arr(0 To SourceTable.Rows.Count, 1 To 問題表列数)
    Dim i, j, r As Row, c As Cell
    i = 0
    For Each r In SourceTable.Rows
        j = 1
        With New 問題
            For Each c In r.Cells
                .LetParameter j, c.Shape.TextFrame.TextRange.Text
                j = j + 1
            Next
            問題集.Add .Self
        End With
        i = i + 1
    Next
    問題集.Remove 1
    
    'Test
    DimAs 問題
    
    Dim 問題順 As Variant
    問題順 = RandArray(10)
    
    Dim 選択肢順 As Variant
    'Test
    For i = 1 To 10
        Set= 問題集(問題順(i))
        
        選択肢順 = RandArray(3)
        
        Debug.Print "問題番号" &.番号 & " : " &.問題, _
            "選択肢1:" &.選択肢(CLng(選択肢順(1))), " ,選択肢2:" & _.選択肢(CLng(選択肢順(2))), " ,選択肢3:" &.選択肢(CLng(選択肢順(3))), _
            "  ,正答:" &.正答
    Next
            
    
    Stop
End Function

前回のRandArray関数と コレクションを使って表のデータを扱う部分が追加されています。

問題.cls

データ構造を規定しているクラスです。

Option Explicit
Private Parameter(1 To 問題表列数)

Property Get 番号() As Long
    番号 = GetParameter(M.番号)
End Property

Property Get 正答() As String
    正答 = GetParameter(M.正答)
End Property

Property Get 問題() As String
    問題 = GetParameter(M.問題)
End Property
Property Get 選択肢(argNo As Long) As String
    If argNo > 3 Or argNo < 1 Then Exit Property
    選択肢 = GetParameter(M.正答 + argNo - 1)
End Property
Sub LetParameter(argParameterNo, argValue)
    Parameter(argParameterNo) = argValue
End Sub

Function GetParameter(argParameterNo) As Variant
    GetParameter = Parameter(argParameterNo)
End Function

Property Get Self() As Object
    Set Self = Me
End Property

GetParameter,LetParameterを使わせてもらっています。引数にはargを使うという自分ルールを今はやっているので,そのあたりはオリジナルコードから変わっています。
選択肢を数値で扱えないとRandArrayが活きないので,引数を取れる形で用意。

とりあえずこのあたりが変更点です。

GetDataCollectionの実施結果

実際に問題には今は活きていないのですが,

GetDataCollectionでやれていることについて触れます。

実行すると,現在はイミディエイトウィンドウにわーっと出力します。

問題番号2 : Baは何の元素か。 選択肢1:バッテリー ,選択肢2:バリウム ,選択肢3:バウム   ,正答:バリウム
問題番号5 : Znは何の元素か。 選択肢1:亜鉛 ,選択肢2:フェライト ,選択肢3:鉄   ,正答:亜鉛
問題番号1 : Naは何の元素か。 選択肢1:カリウム ,選択肢2:カルシウム ,選択肢3:ナトリウム   ,正答:ナトリウム
問題番号7 : Mgは何の元素か。 選択肢1:マグネット ,選択肢2:マグネシウム ,選択肢3:マンガン   ,正答:マグネシウム
問題番号8 : Heは何の元素か。 選択肢1:フロン ,選択肢2:ヘロン ,選択肢3:ヘリウム   ,正答:ヘリウム
問題番号9 : Liは何の元素か。 選択肢1:リプライ ,選択肢2:リプトン ,選択肢3:リチウム   ,正答:リチウム
問題番号3 : Caは何の元素か。 選択肢1:ホネセイブン ,選択肢2:カルシウム ,選択肢3:カリウム   ,正答:カルシウム
問題番号10 : Beは何の元素か。 選択肢1:ベリリリウム ,選択肢2:ベリウム ,選択肢3:ベリリウム   ,正答:ベリリウム
問題番号6 : H は何の元素か。 選択肢1:ヒ素 ,選択肢2:ヒドラ ,選択肢3:水素   ,正答:水素
問題番号4 : Feは何の元素か。 選択肢1:鉄 ,選択肢2:亜鉛 ,選択肢3:フェライト   ,正答:鉄

実行のたびにかわるので一例です。

このように,問題の実施順と,選択肢を入れ替えることに成功していることは,確認ができます。

GetDataCollectionの補足

コードの説明をします。

    Dim SourceTable As PowerPoint.Table
    Set SourceTable = ActivePresentation.Slides(2).Shapes("問題表").Table
    Set 問題集 = New Collection
    Dim Arr: ReDim Arr(0 To SourceTable.Rows.Count, 1 To 問題表列数)
    Dim i, j, r As Row, c As Cell

パワーポイントのテーブルは階層が深いのでTableをオブジェクト変数に入れます。
Arr配列は使ってないや(;´▽`A``もう面倒なので残ったまま。すみません。ツカッテマセン。
For Eachをどうしても使ってみたかったので,rをRowオブジェクトとして,cをCellオブジェクトとして宣言。

たしかにFor Eachを使うメリットはないかもしれませんが,ローカルウィンドウを見たところ,
Rowsコレクション→Rowオブジェクト→Cellsコレクション→Cellオブジェクト という階層で存在していたので,使ってみました。

    i = 0
    For Each r In SourceTable.Rows
        j = 1
        With New 問題
            For Each c In r.Cells
                .LetParameter j, c.Shape.TextFrame.TextRange.Text
                j = j + 1
            Next
            問題集.Add .Self
        End With
        i = i + 1
    Next
    問題集.Remove 1

最初は一度Arrに放り込んで・・と思っていたんですが,直接LetParameterを使えたのでなかなか簡単に書けている気がしています。

    DimAs 問題
    
    Dim 問題順 As Variant
    問題順 = RandArray(10)
    
    Dim 選択肢順 As Variant
    'Test
    For i = 1 To 10
        Set= 問題集(問題順(i))
        
        選択肢順 = RandArray(3)
        
        Debug.Print "問題番号" &.番号 & " : " &.問題, _
            "選択肢1:" &.選択肢(CLng(選択肢順(1))), " ,選択肢2:" & _.選択肢(CLng(選択肢順(2))), " ,選択肢3:" &.選択肢(CLng(選択肢順(3))), _
            "  ,正答:" &.正答
    Next
            
    
    Stop

RandArrayは一気にVariantに放り込まないと意味がないのでそういうフレーズが2ヶ所。

問題順をランダムにするために,iは1→10の順で変わりますが,それを問題順(i)に入れることで問題順をランダムにしています。
選択肢もそんな感じでランダムにしています。

今はメイン部分とまだ連携させていないので,その結果をDebug.Printで出力している感じです。

だいたいこんなところ・・ですね。あんまり解説していない・・。

最後に

このつくり方の優れた点は,データを取り出す際にEnumによる連想配列的な使い方,コードのメンテナンスのしやすさと数字でも制御できるハイブリッドな点です。
使いたいプロパティもGetProperty関数でいくらでも追加できますし,追加しなくても直接GetProperty関数&Enumで楽に利用できます。

f:id:chemiphys:20170320004557p:plain

PowerpointのTableオブジェクトでFor Each ステートメントが十分に使えたとは言えませんが,

全ての行について,すべてのセルの値をコレクションに放り込んだんだよ,という意思がFor Eachで書くと込めれます。

だからでしょうね,私がFor Each好きなのは。。コードに意思を感じるステートメントです。(個人の見解です)

形としては好きな雰囲気で組めました。

次回書くときはちゃんと動くように,そして回答をコレクションに保持させるように作ります。

Powerpoint VBA 重複しないランダムな整数値を作る

クイズの選択肢をランダムに並び替える。

この方法はいくらでもあると思うんですが,他でも応用が効くように,ランダムな整数値を作り,その順に並べなおすという方法を取ってみる。

その前段階として,例えば 5 という数値を与えたら 1~5の値をランダムに並べたものを配列で返す,という関数を作ってみることにしました。

Excelでなら,WorksheetfunctionにRankやCountifがあるから比較的楽に作れますが,

Powerpoint等になると,少し手間がかかりました。

手間がかかる方法を取っただけかもしれませんけど。。

最初に整数値を並べてそれをシャッフルする方法などもよく書いてありますが,今回はそれではないです。。

コードはこちら

Function RandArray(argMax As Long) As Variant
    Dim col As Collection: Set col = New Collection
    Dim Arr(): ReDim Arr(1 To argMax)
    Randomize
    
    Dim i As Long
    For i = 1 To argMax
        col.Add Rnd
    Next
    
    Dim tmp As Long, c
    For i = 1 To argMax
        tmp = 0
        For Each c In col
            If c < col(i) Then tmp = tmp + 1
        Next
        Arr(i) = tmp + 1
    Next
    
    RandArray = Arr
End Function

要素数が決まっているので,コレクションは使わなくてもいけます。ただ使いたかっただけ。。使い続けないと忘れる。。

方針としては,次のように考えました。
① RandomizeとRnd関数のコンビで 重複しない乱数を発生させます。
② まずその乱数をargMaxで指定された数だけコレクションに収める。
③ 重複していない(はず)なので,順位を取ればランダムに並んだ整数値を取れるはずです。
  ExcelならWorksheetfunctionのrankでさくっとこれが実現できますが,Powerpointではそれはできません。
  rank関数はCountifで代用できます。でも,これもExcelならWorksheetfunctionでいけますが,PowerpointにはCountifもありませんでした・・(;´▽`A``
  はい。For EachループでごりごりCountifの代わりをすることにしています。。

    Dim tmp As Long, c
    For i = 1 To argMax
        tmp = 0
        For Each c In col
            If c < col(i) Then tmp = tmp + 1
        Next
        Arr(i) = tmp + 1
    Next

For eachで ぐるぐる回す変数はバリアント型またはオブジェクト型である必要があります。
なので,cは型を与えずバリアント型で宣言しています。

Rankの代わりがCountifでできる,または,単純にループでできる,というのは盲点でした。当たり前といえば当たり前ですが,考えたり調べたりするものですね。。

目から鱗です。パズルのようで面白い。考えてみると楽しかったです。

PowerpointでRank使えないけどどうしたらいいの!?という場合の解決法になるかも,という意味でも今回の試みは面白かったです。


えっと,RandArray関数はVariant型配列なので,

RandArray(5) としたら1~5をランダムにならべたものを収納していますので,
まず何か違う変数に一回その配列ごといれてください。
実行するたびRandomizeで値が変わるので,直接 RandArray(5)(1)みたいな取得をして使うことは,正しい使用法とはならないことになります。

    Dim arr
    arr = RandArray(5)

こんな感じでバリアント型に一気につっこむ。一気にやらないといけないというのは大事な注意点です。。

次回は具体的に選択肢を入れ替えるあたりを書きます。

Powerpoint VBA 三択問題を作る

だいぶパワーポイントから離れていたので,久々に連休ですし,ちょっと続き物を書いてみます。

クイズみたいなものをパワーポイントでやるポイントを載せていきます。

概要

さて,次のようなものを作りました。まだ最低限の実装ですが,基本的な考え方は入れています。

ダウンロードは消去しました。

ファイル名の右についているちっちゃいダウンロードボタンでダウンロードすると,私の環境ではファイル名は文字化けしませんでした。

二つのスライドのみから構成されます。

f:id:chemiphys:20170317231258p:plain

選択肢1~3 と 問題 これら全部にボタンというマクロを動作設定します。

f:id:chemiphys:20170317231311p:plain
スライドは2枚しかありません。しかもそのうち表示用は1枚のみですが,選択肢のボタンを押すと,正誤の判定を行い,問題文を表示したりする図形をクリックすると,次の問題に進む。
10問終わったら 正答数を返すという動きをしています。

VBAコード

標準モジュール

Option Explicit
Public 問題番号 As Long
Public 正解数 As Long

Sub ボタン(oShp As Shape)
    Select Case oShp.Name
        Case "問題"
            Call 次の問題
        Case "選択肢1"
            Call 正誤判定(1)
        Case "選択肢2"
            Call 正誤判定(2)
        Case "選択肢3"
            Call 正誤判定(3)
    End Select
End Sub

Sub 次の問題()
    Dim Sld1 As Slide: Set Sld1 = ActivePresentation.Slides(1)
    Dim Sld2 As Slide: Set Sld2 = ActivePresentation.Slides(2)
    Dim 問題表 As Table: Set 問題表 = Sld2.Shapes("問題表").Table
    
    If 問題番号 = 0 Then
        正解数 = 0
    End If
    問題番号 = 問題番号 + 1
Stop
    Sld1.Shapes("問題").TextFrame.TextRange.Text = 問題表.Cell(問題番号 + 1, 2).Shape.TextFrame.TextRange.Text
    Sld1.Shapes("選択肢1").TextFrame.TextRange.Text = 問題表.Cell(問題番号 + 1, 3).Shape.TextFrame.TextRange.Text
    Sld1.Shapes("選択肢2").TextFrame.TextRange.Text = 問題表.Cell(問題番号 + 1, 4).Shape.TextFrame.TextRange.Text
    Sld1.Shapes("選択肢3").TextFrame.TextRange.Text = 問題表.Cell(問題番号 + 1, 5).Shape.TextFrame.TextRange.Text
     
End Sub

Sub 正誤判定(argNo As Long)
    Dim Sld1 As Slide: Set Sld1 = ActivePresentation.Slides(1)
    Dim Sld2 As Slide: Set Sld2 = ActivePresentation.Slides(2)
    Dim 問題表 As Table: Set 問題表 = Sld2.Shapes("問題表").Table
    
    Dim Ret As String
    If argNo = CLng(問題表.Cell(問題番号 + 1, 6).Shape.TextFrame.TextRange.Text) Then
        Ret = "正解です おめでとう! 次の問題へ行くにはここをクリック"
        正解数 = 正解数 + 1
    Else
        Ret = "間違いです。正解は" & 問題表.Cell(問題番号 + 1, 6).Shape.TextFrame.TextRange.Text & "番です。" & _
        vbCrLf & " 次の問題へ行くにはここをクリック"
    End If
    Sld1.Shapes("問題").TextFrame.TextRange.Text = Ret
    If 問題番号 = 10 Then
        Ret = Ret & vbCrLf & "10問終わりました。 正答数は " & 正解数 & "です。おつかれさまでした。" & _
        vbCrLf & "再度挑戦するなら,問題をクリックしてください。"
        Sld1.Shapes("問題").TextFrame.TextRange.Text = Ret
        問題番号 = 0
    End If
End Sub

コードの説明

必要な部分の説明を加えます。

Sub ボタン(oShp As Shape)

こう書いたマクロを図形の動作に設定すると,oShpという変数にトリガーの図形を取得できます。

Public 問題番号 As Long
Public 正解数 As Long

常にループ待機等をしているわけではありません。ボタンを押したら,という動きになります。
そのため,プロシージャは必要な時しか動かないので,値が消えないようPublic宣言をしています。

Dim 問題表 As Table: Set 問題表 = Sld2.Shapes("問題表").Table

表のセルを多数扱う場合は,Tableオブジェクトをオブジェクト変数に入れておいて,使うと楽です。

Sld1.Shapes("選択肢1").TextFrame.TextRange.Text = 問題表.Cell(問題番号 + 1, 3).Shape.TextFrame.TextRange.Text

Powerpointの表はアクセスが深いです。
Cell(行,列).Shape.TextFrame.TextRange ・・・とたどっていかないといけないのが難点ですね。

必要な説明はこのくらいでしょうか。とても短いマクロと少ない部品ですが,多数の問題を同じレイアウトで取り扱えます。

内容は極めて雑に作っていますが,発展させればなかなかのものが作れるんじゃないかなーと思われます。

次回は,選択肢をランダムにすることを考えてみます。(ΦωΦ)

フラグのことをよく忘れます。

以前 If文のお化け,と表現した時にthomさんにいろいろと教わったのに,すっかり忘れて実際の仕事で使っているものでIf文だらけになっています。

Do Loop を多用するんですが,そうそうExit Doで抜けるわけにもいかないことが多い。

実務はやはりいろいろ条件が多く,モデル化したものより複雑で,しかも時間制限が激しい。

会議と並行して会議進行にかかわるデータ処理をしつつ,必要な資料のためにコーディングもしているという,けっこうひどい状況です。

まともに時間をかけれない場合はもうコードをコピペして,必要な部分だけ変えたりすることもあります。

まず,きちんと結果を出すことが最優先。中身の最適化の優先度はけっこう低い。

でも,次年度に向けて改善はしないといけません。

他人にバトンタッチするためでもありますし,自分がデバッグするときのためでもあります。

人は忘れるというのが大前提なので,問題だと感じたものは問題だと感じているときに修正して,修正したものを次年度に持ち越さないとイケナイデス。


さて,If文だらけになるケースっていうのは,複数の条件を同時に満たしたらこの処理,みたいな話をするときです。

ほとんどの業務ってそれなんですよね。Select Case文やSwitch関数ではどうにもならない時。

加えて,とにかく解決を急ぎつつ確認して確からしいと判断して,やっとデータを出力して会議のメンバーに確認,検証を頼む,という流れになるので,

その時作っているものは条件もめちゃめちゃ。とにかく望む結果がでればいいというやつです。

でも,知らない人や1年後の自分にはなんでこんな書き方してるんだ??となります。。

やはりシンプルに,できるだけ肯定的に条件を書きたい。裏を使うような条件はできれば避けたい。


そういうときに役に立つのは フラグ です。でも,私定期的にフラグを使うという考え方が抜け落ちます。困ったものです。

今日もお風呂に入ってのんびり仕事で使ったコードのことを考えてたらなんでフラグで処理しなかったんだと がっかりしました。

11月くらいから予想しつつ,助言をもらいつつ取り組んできたので,今のところやれてますがまだ終わってません。。(;´▽`A``

内容のイメージとしては,

人を対象として,評価していく。

検査方式が A,B,C あって,
さらにAには8種類の評価基準があり,Bには2種類の評価基準があります。CはBと近い評価基準を使いますが1種類。

A,B,Cそれぞれ似通ったレポート,審議資料,集計を行う必要があります。
書式は与えられたものを使うので,基本的にはセルの位置等は与えられた書式に依存します。でも書式を提供する側には,処理する側の気持ちは入っていないため,微妙にセルの座標等はずれています。Wordの書式だったりExcelの書式だったりいろいろです。
それぞれの審査基準を通ったものは,1~4組,しかも男女で分けていかないといけません。

わたしがここしばらく取り組んでいる仕事ってのはこんな感じのものです。そして,データの項目はそれぞれに対し100はいかない感じです。だいたい80くらいのことが多い。

3つの方式を合わせると数百行のデータです。

こんな話なので,つい

If 方式=A And 評価基準=① then
・・・・
    If 組=1 then
  どうのこうの
Elseif 方式=A And 評価基準=② then
   ・・・・


みたいな感じで書いていきます。相手が文字列だけなら連結してまとめて評価という方法も考えますが,値と不等号で処理したりとかもしますしね,ほんと いろいろ いろいろあるんです。

で,条件の間間にその時すべき処理を書くので大パニックです。

でも,大事な視点は 最終的な処理はほんの4種類くらいしかなかったりします。

それなのに途中の条件が複雑なのに負けて,上のような表記をして,自分からどんどん罠にはまっていきます。

コマッタモノデス。

まぁIf文は使ってはいいとは思うけど処理が4つくらいしか無いなら long型のフラグとか用意して1~4のどれに該当するかを記述していって,

最後にフラグの値で処理を分ければ終わる話ですよね。

条件分岐と処理をきちんと分けれますし,ずいぶんシンプルに見やすく書けるはず。

うんきっとできそうだ。。



もう寝ないといけないので,書きたい放題 とりとめのない話で終わりますが,

明日はきちんとコードの整理をして,頭の中をまとめたいと思います。

thomさんに教えてもらった記事。

thom.hateblo.jp

この時期にいろいろデータ処理を習っててよかったなぁとしみじみ思います。

ですが,多重ネストを回避するということは・・実務と同時並行はできませんでしたが,後から振り返ってきちんとやることでまた学ぼう。

毎年ある仕事内容に関することなので,終わった後に整理したことは,きっと次年度に生きる(ΦωΦ)

For each delete next 調べてみた

さて,前回の記事で結局Excelではどうなっているのか気になったので,調べてみようと思いました。

図形のIDを追っていけば,内部仕様が少しはわかるかな,という感じ。

さて,コレクションの仕組みから考えて妥当であろうというPowerpoint,Wordではこのような感じ。

f:id:chemiphys:20170314225357p:plain
このようにいくつか図形を置いておいて,

Sub test()

Dim s As Shape
Dim sht As Document: Set sht = ActiveDocument
Dim i As Long: i = 1
Dim j As Long
ActiveDocument.Paragraphs.Add
For Each s In sht.Shapes
    For j = 1 To sht.Shapes.Count
       sht.Paragraphs(i + 1).Range.Text = sht.Paragraphs(i + 1).Range.Text & j & ":" & sht.Shapes(j).ID & "_"
    Next
    sht.Paragraphs.Add
    s.Delete
    i = i + 1
Next
End Sub

ワードでなにも目印が無いところに書きこませるのとっても苦手です。

f:id:chemiphys:20170314225452p:plain

奇数の図形IDを持つ図形が消されずに取り残されていくさまがわかります。

さて,Excel。こっちはセルがあるから書くの楽。

f:id:chemiphys:20170314225725p:plain

Sub test()

Dim s As Shape
Dim sht As Worksheet: Set sht = ActiveSheet
Dim i As Long: i = 1
Dim j As Long
For Each s In sht.Shapes
    For j = 1 To sht.Shapes.Count
       sht.Cells(i, j) = "'" & j & ":" & sht.Shapes(j).ID
    Next
    s.Delete
    i = i + 1
Next
End Sub

f:id:chemiphys:20170314225800p:plain

削除する部分に関しては,全く同じように書いているのにも関わらず,Excel側はきれいに小さいIDのものから消しています。

パワーポイントやワードでこのように消していくためには,Shapes(1)をずっと消していくという書き方に対する挙動をしているようですね。

そりゃあちゃんと消えるわ。

うん。

でも,

なんでExcelだけそうなの?

どういう仕組みなんでしょうね。。

コレクションに慣れたらむしろこっちのほうが気持ち悪い(;´▽`A``