読者です 読者をやめる 読者になる 読者になる

Powerpoint VBAを使おう!

Powerpoint VBAやExcelのVBAで遊んでいます。Word VBAも始めました。

絵のことを書くと著作権のこと調べないといけないですね。

雑記

まだ時間がとれていませんので,調べれてはいませんが,

今回とても気に入った絵と出会い,原本のデータとも幸いにも出会うことができ,

AdobeStockのためにライセンスを買っていた IllustratorCC,PhotoShopCCを使ったトレースがうまくいって,

自分では満足のいく教材の図が書けました。

元素等の話をする上で,私を助けてくれることは間違いないです。

元々ゲーマーで,ファンタジーな世界が大好きです。

なので,前回の図はがっつりストライクなんです。

再掲

f:id:chemiphys:20170323001056p:plain


元絵 エンペドクレスの4元素の絵
Four elements at de responsione mundi et de astrorum ordinatione


さて,デジタルの場で話をしているわけなので,無視しちゃいけないのは著作権。

紙であれば,授業の場ではある一定条件での使用を認められる職種ではあるわけですが,デジタルではそうはいかない。。

基本はパブリックドメインのものを利用するかCC表示に従い行動,表示するよう努めています。

今回のはWikipediaのほうにこう書かれています。


The author died in 1478, so this work is in the public domain in its country of origin and other countries and areas where the copyright term is the author's life plus 100 years or less.

This work is in the public domain in the United States because it was published (or registered with the U.S. Copyright Office) before January 1, 1923.

死後100年経ってるから,パブリックドメインでいいよ。ということですよね。。


古めかしい素材が好きなので,この条件でいうなら,わたしが利用できる図というのはまだまだたくさん眠っているのでしょうし,

なぞるのは大変でも今回のようにトレース機能を利用すればできることはかなり広がります。

じゃあ画像を見るために通過させていただいているハーバード図書館の権利を侵害していないか。というのも気になり,そちらの著作権のページを見たら・・

www.harvard.edu


よく意味がわかりませんでした(;´▽`A``

原書の著作権を侵害することは許しませんし,そのような例を見つけたら報告してくださいね,

と書いているように私は受け取っています。


原書の著作権に準じますよということであれば,今回私がとった行動はたぶん著作権的には問題ないんだろうなぁというところ。。

パブリックドメインの素材はWikipediaにたくさんあります。

CC表示をきちんとすればいいよ,という素材もたくさんありますし,立場上そのような表示は積極的に使い,他の方の著作物を使う場合は表示をするようにしようね,というふうに自然な流れで授業に加えられます。

イメージの元を他の著作物からもらう場合もありますね。

Adobe Stockのsapunkele という方の絵が大好きです。この方の絵を見ながら人を描く練習をしています。

あまりにもシンプルなヒトの絵なので,頭が丸で手足がある,,というもので 誰が書いてもヒトってこんな感じじゃね?という絵ですが,バランスが絶妙。

画像は多数ライセンス取得もしていますが,そこのヒトたちを見て,自分が望む形のヒトを描く助けになる。



著作権のことは,聞かれたときにきちんと答えられるように,ちゃんと確認しないといけないんだろうなぁ。

(;´▽`A``

VBAちょい組んでないなぁ・・・ ネタを探さないと・・

COUNTIFSを知らなかったことに衝撃

EXCEL

今日も元気にお絵かきしています。

フォトショップとイラストレーターも覚えないとですね。こんなすごいものなんだなぁ。トレーススゴイ。

まともに使おうとは思っていませんが,このトレースには驚きます。

世の中便利なものがたくさん。。

f:id:chemiphys:20170322215626p:plain

フリーフォームなのに頂点編集ができないものなどができちゃうので,ばらばらにしているところです。

この文字の雰囲気,火の雰囲気,,タマラナイモノガアリマス。

さて,朝けっこう塗ってしまってたのを置いてきたので,また家で練習しています。

何度もやると,そのたびに発見があるからスバラシイ。


そうそう,今日こんな便利な関数あったのね,と知らずにいた数年間を後悔している関数があります。

COUNTIFとは長いこと友達なんですが,COUNTIFS とかあったんですね・・(;´▽`A``

なんだこのチート関数は・・というくらいの衝撃が私にはあります。

VBAがあると,なんでもとりあえず自分でだいたいできてしまうので,ワークシート関数に疎いことがあるんですが,今回もまさにそれ。。

COUNTIF単体でも十分高機能ですが,いくつもの検索条件でできるとかシラナカッタヨ。
f:id:chemiphys:20170322221019p:plain
f:id:chemiphys:20170322220939p:plain

すごいなぁとしみじみ。
EXCEL2007からだそうですね・・ 何年間か残念です。。

知らなかったからこそ集計関連のVBAの腕が上がったんだと,自分をなぐさめる位しかありません(;´▽`A``

教材作成にどっぷり

雑記

ちょっと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 三択問題を作る ② 問題準備・選択肢部分

Powerpoint VBA

三択問題作りその2 です。
blog.powerpointvba.club
これの続き

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

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

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

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

3択基本②.pptm 直


目次

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

表の変更点は,前回は 選択肢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 重複しないランダムな整数値を作る

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)

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

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