t-hom’s diary

主にVBAネタを扱っているブログです。

VBA Win32APIを使って、文字列の実描画幅を取得する。

PCのフォントには固定幅のものと可変幅のものがある。

固定幅のフォントは単純に同じ文字数で改行すれば綺麗な矩形になるが、可変幅のフォントでは単純に同じ文字数で改行してもガタガタになる。

f:id:t-hom:20190119014553p:plain

これを概ね揃うようにWin32 APIを使って、文字列の幅を測りながら出力してみようと思う。

きっかけになったのはタイムラインに流れてきたこちらのツイート。


コード

標準モジュールに以下のコードを張り付ける。

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As Long, ByVal hgdiobj As Long) As Long
Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long

Private Declare Function CreateFont Lib "gdi32" Alias "CreateFontA" (ByVal nHeight As Long, _
    ByVal nWidth As Long, _
    ByVal nEscapement As Long, _
    ByVal nOrientation As Long, _
    ByVal fnWeight As Long, _
    ByVal IfdwItalic As Long, _
    ByVal fdwUnderline As Long, _
    ByVal fdwStrikeOut As Long, _
    ByVal fdwCharSet As Long, _
    ByVal fdwOutputPrecision As Long, _
    ByVal fdwClipPrecision As Long, _
    ByVal fdwQuality As Long, _
    ByVal fdwPitchAndFamily As Long, _
    ByVal lpszFace As String) As Long
    
Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, _
    ByVal lpStr As String, _
    ByVal nCount As Long, _
    lpRect As RECT, _
    ByVal wFormat As Long) As Long

Private Const FW_NORMAL = 400
Private Const FW_BOLD = 700
Private Const DEFAULT_CHARSET = 1
Private Const OUT_DEFAULT_PRECIS = 0
Private Const CLIP_DEFAULT_PRECIS = 0
Private Const DEFAULT_QUALITY = 0
Private Const DEFAULT_PITCH = 0
Private Const FF_SCRIPT = 64
Private Const DT_CALCRECT = &H400

Function MeasureTextWidth( _
        target_text As String, _
        FONT_NAME As String, _
        Optional font_height As Long = 10) As Long
    
    Dim hWholeScreenDC As Long: hWholeScreenDC _
        = GetDC(0&)
    
    Dim hVirtualDC As Long: hVirtualDC _
        = CreateCompatibleDC(hWholeScreenDC)

    Dim hFont As Long: hFont _
        = CreateFont(font_height, 0, 0, 0, FW_NORMAL, _
            0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, _
            CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, _
            DEFAULT_PITCH Or FF_SCRIPT, FONT_NAME)
            
    Call SelectObject(hVirtualDC, hFont)
    
    Dim DrawAreaRectangle As RECT
    Call DrawText(hVirtualDC, target_text, -1, DrawAreaRectangle, DT_CALCRECT)
    
    Call DeleteObject(hFont)
    Call DeleteObject(hVirtualDC)
    Call ReleaseDC(0&, hWholeScreenDC)
    MeasureTextWidth = DrawAreaRectangle.Right - DrawAreaRectangle.Left
End Function

Sub 幅を揃えて出力()
    Const 基準テキスト = "固定幅のフォントは"
    Const 対象テキスト = "固定幅のフォントは単純に同じ文字数で改行すれば綺麗な矩形になるが、可変幅のフォントでは単純に同じ文字数で改行してもガタガタになる。"
    Const FONT_NAME = "MS Pゴシック"
    
    Dim 基準テキストの長さ As Long
    基準テキストの長さ = MeasureTextWidth(基準テキスト, FONT_NAME)
    
    Dim tmpText As String
    tmpText = ""
    Dim i As Long
    For i = 1 To Len(対象テキスト)
        If MeasureTextWidth(tmpText + Mid(対象テキスト, i, 1), FONT_NAME) > 基準テキストの長さ Then
            Debug.Print tmpText
            tmpText = Mid(対象テキスト, i, 1)
        Else
            tmpText = tmpText & Mid(対象テキスト, i, 1)
        End If
    Next
    Debug.Print tmpText
End Sub

メインのプロシージャは「幅を揃えて出力」で、それ以外はほぼWin32APIの処理。
ちなみに64bit版Officeには対応させていない。※面倒くさかったので。。

MeasureTextWidthはテキストとフォント名を与えるとLong型で幅を返す。
※幅の単位は不明だけど、恐らくポイントだと思われる。

そしてメインの「幅を揃えて出力」では、対象テキストを1文字ずつtmpTextにくっつけて、基準となるテキスト幅を超える手前でPrintする処理となっている。

実行結果はイミディエイトウインドウに出力される。(この時点ではイミディエイトウインドウのフォント設定によるので、揃ってない。)
f:id:t-hom:20190119020411p:plain

テキストボックス等に貼り付けて対象フォントをFONT_NAMEと同じものを選択すると、このようにある程度揃う。
f:id:t-hom:20190119020518p:plain

以上

基本情報技術者の受験に役立つ、過去に書いたVBA記事の一覧をまとめてみた。

f:id:t-hom:20190105220644p:plain
新年の初投稿で書き忘れてたので。

さて、新年と言えば去年はこのような記事を書いた。
thom.hateblo.jp

節目のブースト効果で、今年こそは何か資格を取ろうとか、色々考えている方もいると思う。
私が購読しているブログでも新年の意気込みが。

今さらながら基本情報でもちょっと勉強してみようかしら。
(絶対に合格してやるぜ(炎) thom訳)

自作WindowsAPIクラスを修正した - 素人がExcelVBAによる「一人働き方改革」に挑むブログ

これを見て、そういえば基本情報技術者の学習に役立ちそうなVBA記事を過去にいくつか書いたのを思い出したので、ここに纏めておこうと思う。
プログラマーの登竜門と言われる基本情報だけど、真面目に学習すればコンピューターサイエンスの基礎が身につくのでノンプログラマーがステップアップするのにもオススメの資格である。

基本情報技術者の対策に役に立つかもしれない記事

真理値表

thom.hateblo.jp

メモリについていろいろ

thom.hateblo.jp
thom.hateblo.jp
thom.hateblo.jp

連結リスト

thom.hateblo.jp

木構造の探索

thom.hateblo.jp

指数表記

thom.hateblo.jp

加算器

thom.hateblo.jp

スタック

thom.hateblo.jp

テスト

thom.hateblo.jp

BNF(少し触れてます)

thom.hateblo.jp

逆ポーランド記法(かすってます)

thom.hateblo.jp

以上

VBA Dir関数とFileSystemObjectの比較

※ 冗談の通じない方はご退場願います。

はじめに私の立場を明確にしておくと、私は個人的にFileSystemObject(以降FSOと記載)が好きで、Dir関数はあまり好きではない。従ってDir関数で事足りる処理でも基本的にVBAコードではFSOを利用する。この記事ではその理由を述べ、Dir派の方をFSO派に改宗させることを目的としたいと思う。悪を滅し、正義の光あらんことを。なんつって。

さて、まずはDir関数がいかに貧相であるかをご覧いただきたい。Dirで出来ることは主に以下の三つである。

  1. 指定したファイル・フォルダの存在チェック
  2. 指定したパターンにマッチするファイル名の取得
  3. 指定したフォルダ内のサブフォルダ・ファイルの一覧取得

機能豊富なFSOにとってこれしきの事は朝飯前である。
FSOが如何に機能豊富であるかはFSOが備える以下のメソッド群を見てもらえば一目瞭然。

  1. BuildPath メソッド
  2. CopyFile メソッド
  3. CopyFolder メソッド
  4. CreateFolder メソッド
  5. CreateTextFile メソッド
  6. DeleteFile メソッド
  7. DeleteFolder メソッド
  8. DriveExists メソッド
  9. FileExists メソッド
  10. FolderExists メソッド
  11. GetAbsolutePathName メソッド
  12. GetBaseName メソッド
  13. GetDrive メソッド
  14. GetDriveName メソッド
  15. GetExtensionName メソッド
  16. GetFile メソッド
  17. GetFileName メソッド
  18. GetFolder メソッド
  19. GetParentFolderName メソッド
  20. GetSpecialFolder メソッド
  21. GetTempName メソッド
  22. MoveFile メソッド
  23. MoveFolder メソッド
  24. OpenTextFile メソッド

とはいえVBAの組み込み関数であるDirは特に設定なしで使えるのでこの点FSOは分が悪い。FSOを使用するには原則、参照設定という準備が必要なのだ。参照設定なしで使うとインテリセンスが効かずコーディング効率が著しく低下する。

まぁそもそもDirは単体ですべてのファイル操作を担っているわけではなく、同じFileSystemモジュールに以下の兄弟関数がいる。機能数という意味で比較対象にするなら以下も含めてやらないと不公平というものだろう。

  1. ChDrive 関数
  2. CurDir 関数
  3. CurDir$ 関数
  4. Dir 関数
  5. EOF 関数
  6. FileAttr 関数
  7. FileCopy 関数
  8. FileDateTime 関数
  9. FileLen 関数
  10. FreeFile 関数
  11. GetAttr 関数
  12. Kill 関数
  13. Loc 関数
  14. LOF 関数
  15. MkDir 関数
  16. Reset 関数
  17. RmDir 関数
  18. Seek 関数
  19. SetAttr 関数

しかし、ここで一つ注目していただきたい。FSOのメソッド名は英語としてそのまま意味が通じるのに対し、関数群の方は略記が多く、意味と名前の対応付けを、いちいち覚えておかないといけないのだ。他人がコードを読むときも、関数群の読みやすさは読み手の知識に左右される。対してFSOは簡単な英単語さえ知っていれば、おおよそ何をしているのか想像がつく。処理と名前が綺麗に結びついているからだ。

次にDir関数単体の機能と、FSOでそれに該当する機能を比べてみよう。

指定したファイル・フォルダの存在チェック

Dir関数では

次のように記載する。
Dir([ファイルパス])
Dir([フォルダパス])

ファイルやフォルダが存在した場合はファイル名やフォルダ名を返し、存在しない場合は空文字「""」を返す。このようなルールを、コードを書く人・読む人両方が覚えておかなければならない。

FSOでは

次のように記載する。
fso.FileExists([ファイルパス])
fso.FolderExists([フォルダパス])
ファイルやフォルダが存在した場合はTrueを返し、存在しない場合はFalseを返す。単純明快である。

比較結果

あるか・ないかを調べたいのだから、欲しい返事は「ある/ない」の二択だ。
VBAに置ける二択といえばブーリアン型。「True/False」で返してくれるFSOの方がシンプルで分かりやすい。
そして、プログラムを読む際も「単一パスの存在チェックをしていることが明示的」であるFSOに分がある。

指定したパターンにマッチするファイル名の取得

Dir関数では

次のように記載する。
Dir([パターン])
ここで[パターン]は「*」や「?」などのワイルドカードを含むパス名だ。これもルールを人が覚える必要がある。

また、この記述で返ってくるファイル名は1つだけだ。
2番目にマッチしたファイル名を返すには、もう一度Dirを引数無しで呼び出す必要がある。
そしてDirはすべてのマッチしたファイル名を返し終わると最後に空文字を返す。
このような煩雑なルールを覚えなければならないのだ。

FSOでは

FSOでは一括パターンマッチは出来ない。したがって、まずパス配下のファイルの一覧を取得することになる。
fso.GetFolder([フォルダパス]).Files

GetFolderにより取得したフォルダーオブジェクトのFilesメソッドはFilesというコレクションを返すので、Dirのように何度も呼び出す必要はない。
取得したら、For EachなどでそれぞれIf文による判定を行い、合致するパターンのファイルを個別により分けていく。

比較結果

ここでもDirは知識を要するのに対し、FSOは明示的で分かりやすいコードになる。

指定したフォルダ内のサブフォルダ・ファイルの一覧取得

Dir関数では

次のように記載する。
Dir([フォルダパス\*])
Dir([フォルダパス\*], vbDirectory)

ただし、属性にvbDirectoryを指定しても、ファイルも含めて返してくる。
これはvbNormalの実値が0で、vbDirectory(16) + vbNormal(0)と同じ判定結果になるためだ。
実際にフォルダかどうかを調べるにはGetAttr関数で返ってきたパスがフォルダーかどうか検証しなければならない。

なお、こちらも一度に返せるファイル名・フォルダ名はひとつなのでDirを引数無しで何度も呼び出す必要がある。

FSOでは

FSOでは次のように直感的に意味の分かる書き方ができる。
fso.GetFolder([フォルダパス]).Files
fso.GetFolder([フォルダパス]).SubFolders

それぞれの戻り値もFilesコレクション・Foldersコレクションで、For Eachループでスマートに処理できる。

まとめ

リーダブルコードを心がけるうえで、Dirはもはや害悪でしかない。今こそDir関数に正義の鉄槌を!FSO万歳。

注意)個人の感想です。随所に偏見が見られますので鵜呑みにしないようにお気をつけください。

VBA 標準モジュールの分割基準

VBAではマクロを記述する場所として複数の標準モジュールを利用できるが、何を基準に分けたら良いか分からないというツイートを見かけたので、私の考えを記しておこうと思い久々にブログ更新。

モジュール分割の大前提として、私はまずプロシージャが適切に分割されているかどうかが重要だと考える。

例えば以下のようにそれぞれのマクロが単一のプロシージャで構成されているとき、モジュール分割の動機は薄い。
f:id:t-hom:20181208134636p:plain

しかしプロシージャの分割を覚えると、単一の機能を果たすマクロが複数のプロシージャで構成されることが発生する。
f:id:t-hom:20181208134922p:plain

紙面の都合で2つのマクロを図示しているが、実際にはどんどんマクロが増え、どのマクロがどのプロシージャを呼び出すのが、ごちゃごちゃして訳が分からない状態になってくる。

すると、モジュールを分割して整理したいという要求が生まれる。
f:id:t-hom:20181208135134p:plain

【注意】図ではマクロ1つに1モジュールになっているがこれはあくまで紙面の都合である。そんなことをしてるとマクロが増えるたびにモジュールが増え、モジュールだらけになってしまう。あくまで管理しやすい単位に分割するということ。

モジュールをGoogle検索すると、『装置・機械・システムを構成する、機能的にまとまった部分。』という表記がある。

例えば過去にAutoScrapBookというマクロブックを作った際は、自動スクリーンショット機能(スクラップ)の他に、編集機能、エクスポート機能、シートクリア機能、設定機能などのリボンメニューを作った。
f:id:t-hom:20181208140717p:plain

この機能グループをそれぞれVBAの標準モジュールと対応付けている。
私はモジュール分割を『マクロのカテゴライズ』だと考えている。普通、部屋を整理整頓するときも、文房具・食器・薬・掃除道具なんかを一緒くたに入れたりしない。マクロの整理もそれと似たようなもので、モジュール名≒カテゴリ名と考えるとうまく整理できるんじゃないかと思う。

参考としてソフトウェア工学で使用される凝集度という言葉についてリンクを掲載する。
凝集度 - Wikipedia

もちろん、機能的凝集が最善とされている。

あと、共通部分を切り出して別モジュールにするという意見が割と沢山見られたけれど、一概にそれが良いとも言えないので、デメリットも把握したうえで対応されると良いと思う。
thom.hateblo.jp

そもそもプロシージャがうまく分割できないという方は以下ご参考までに。
thom.hateblo.jp

以上

VBA 正円同士の当たり判定用クラス

ゲームでは正確性よりもスピードが求められる場面がある。
当たり判定もその一つで、キャラ同士がぶつかったかどうかの判定は矩形や正円などに単純化して表現される。

今回Twitterで羽毛田氏がたい焼きのキャラの当たり判定の方法を模索してるようなので以下の画像を提案してみた。
f:id:t-hom:20180909081504p:plain

キャラを正円の組み合わせで表現できれば、3×3で9通りの正円の当たり判定を行えば良いことになる。

今回はキャラ同士ではなく、正円同士がぶつかっているかどうかの判定用にクラスを書いてみた。

クラス名はCollisionSenser。
コードはこちら。

Public Name As String
Public X As Double
Public Y As Double
Public Radius As Double

Function DoesHit(c As CollisionSenser)
    DoesHit = Radius + c.Radius > CalcDiagonalDistance(Abs(X - c.X), Abs(Y - c.Y))
End Function

Private Function CalcDiagonalDistance(a, b)
    CalcDiagonalDistance = VBA.Math.Sqr(a ^ 2 + b ^ 2)
End Function

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

パブリックフィールドとして名前とX座標とY座標と半径を持たせており、当たり判定用のDoesHit関数はCollisionSenserオブジェクトを受け取って自分と当たっているかどうかを返す。

正円同士の当たりは、円の中心同士の距離が半径の合計を超えているかどうかで判定できる。
f:id:t-hom:20180909082209p:plain

円の中心同士の距離は三平方の定理で求まる。
f:id:t-hom:20180909082451p:plain

■三平方の定理
A^2 + B^2 = C^2

つまりC = sqr(A^2 + B^2)

以下のコードでテストしてみた。

Sub TestCollisionSenser()
    Dim CollisionSensers As Collection
    Set CollisionSensers = New Collection

    Dim sh As Shape
    For Each sh In Selection.ShapeRange
        With New CollisionSenser
            .Name = sh.Name
            .Radius = sh.Width / 2
            .X = sh.Left + .Radius
            .Y = sh.Top + .Radius
            CollisionSensers.Add .Self
        End With
    Next
    
    Dim cs1 As CollisionSenser, cs2 As CollisionSenser
    For Each cs1 In CollisionSensers
        For Each cs2 In CollisionSensers
            If Not cs1 Is cs2 Then
                If cs1.DoesHit(cs2) Then
                    Debug.Print cs1.Name & " does hit to " & cs2.Name
                End If
            End If
        Next
    Next
End Sub

複数の円を選択してコードを実行すると、
f:id:t-hom:20180909082728p:plain

イミディエイトウィンドウに次のように表示される。

Oval 5 does hit to Oval 6
Oval 6 does hit to Oval 5
Oval 6 does hit to Oval 10
Oval 9 does hit to Oval 11
Oval 10 does hit to Oval 6
Oval 11 does hit to Oval 9

あとはキャラ用のクラスがこのCollisionSenserを必要数保持すれば複雑な形のキャラ同士でも簡易当たり判定できるかと思う。

以上

経緯


MicrosoftがOfficeのクリップアートを廃止してから資料の質が向上した件

Microsoftがクリップアート廃止してからもうすぐ4年。
当時ゴリゴリのクリップアートユーザーだった私はとても残念に思っていたけれど、ふと最近資料を作っていて実はクリップアートが無い方が資料の質が上がるのでは?と感じるようになった。

当時はこういうアバター系をよく使っていたんだけど、
f:id:t-hom:20180909025159p:plain

最近はもう、こういうので済ます。
f:id:t-hom:20180909025407p:plain

え、ダサいって?

何を言っているんだ。この方はUML(Universal Modeling Language)に出てくるアクター様だぞ。
システムの設計ドキュメントに出てくる公式キャラ!

まぁ、正直UMLはナイス仕事をしたと思う。
「棒人間で充分じゃね?」という至高の決断。

クリップアートって綺麗なんだけど、具体的すぎて使い勝手が今一つだと感じていた。
性別・肌の色・服装といった具合に、本質と関係ない情報がごちゃごちゃと入っている。
それに比べて棒人間の抽象度は素晴らしい。純粋な概念図である。
そして手書き・デジタルともに書きやすさもピカイチ。

棒人間は一例だけど、イラストを使わない図解も上手くなってる気がする。図解の基本的な書籍で(タイトル忘れたけど)、図解の基本は文字を四角や丸で囲む、矢印で関係を表す等のシンプルなテクニックだと書いてあったのを思い出した。
つまり絵の情報に頼らない分、より本質をとらえた図解が必要になった。結果的に資料の質は上がったと思う。

クリップアートだとイメージ通りのイラストが見つからなかったり、統一感を出したいけど微妙にタッチが違うもので妥協せざるを得ないことが多く、いまいち垢抜けない資料になってしまっていたし、絶妙なイラストを探し回って時間をロスすることも多かった。

クリップアート廃止後の図解は基本的にオートシェイプで済ませている為、統一感を出しやすいし、そこまで複雑な作画はしないのでイラストをあれでもないこれでもないと漁ってた頃よりはるかにスピーディー。

更にWindows 10 以降、フラットデザインが主流になったことでクリップアートをゴテゴテに使った資料はどこか古めかしくダサい印象を受ける。

もうあの頃には戻れないなぁ。

ということで、あくまで個人の見解ではあるが、MicrosoftがOfficeのクリップアートを廃止してから資料の質が向上したと思う。

PowerPoint VBA サンプル ~ フロー図のコネクタだけ選択・複数シェイプに書かれた数字を一括インクリメント

何やらTwitterPowerPoint VBAネタがよく流れてくるので便乗してみる。

と言っても新規ネタは無いので昔Webサイトに掲載した内容の再掲。
パワーポイントVBA - You.Activate
(サイトの方のアクセスは微量なのでなかなか日の目を見ない。)

フローチャート等でコネクタだけor画像だけを選択するマクロ

パワポでフロー図を作ることもよくあると思うけれど、後から図形の枠線だけ色を変えたいとか、コネクターの線だけ太くしたいとかいうことってよくある。

そうするためには例えばCtrl + クリックでコネクタだけをチマチマ選択していく必要があるが、数が多いととても面倒くさい。

次に紹介するマクロを使うとマウスドラッグで範囲選択した後に図形かコネクターかどちらか不要な方を一発で選択解除できる。
f:id:t-hom:20180908081855g:plain

コードはこちら。
※このころの私はマルチバイト識別子がマイブーム

Sub 選択除外_図形のみ選択()
    Call 選択除外(True)
End Sub
 
Sub 選択除外_コネクターのみ選択()
    Call 選択除外(False)
End Sub
 
Private Sub 選択除外(非コネクター As Boolean)
     
    'シェイプが選択されていなければ、処理を中断する。
    If Not ActiveWindow.Selection.Type = ppSelectionShapes Then Exit Sub
     
    '残すシェイプのリストを準備
    Dim 残すリスト() As String
    ReDim 残すリスト(0)
     
    DimAs Shape
 
    For EachIn ActiveWindow.Selection.ShapeRange
        If.Connector Xor 非コネクター Then
         
            '残すシェイプの末尾に図の名前を追記
            残すリスト(UBound(残すリスト)) =.Name
             
            '次の追記用にリストを1つ拡張
            ReDim Preserve 残すリスト(UBound(残すリスト) + 1)
        End If
    Next
     
    'ループで一個作りすぎるので、最後にマイナス1する
    ReDim Preserve 残すリスト(UBound(残すリスト) - 1)
    
    Dim 現在のスライド As Slide
    Set 現在のスライド = ActiveWindow.Selection.SlideRange(1)
     
    '残すリストの図形を選択しなおす。
    現在のスライド.Shapes.Range(残すリスト).Select
     
End Sub

複数シェイプ上の番号を簡単に増減する

フローチャート等でプロセスごとに番号を振っていて、例えば間にプロセスを挿入したり削除した場合、後続の番号が全部ずれ込んでチマチマ修正する羽目になる。
とても面倒なので、選択範囲のシェイプに書かれた番号を一括で増減できるマクロを作った。

f:id:t-hom:20180908083439g:plain

Sub 番号プラス()
    Call 番号増減(1)
End Sub
 
Sub 番号マイナス()
    Call 番号増減(-1)
End Sub
 
Private Sub 番号増減(数値)
 
    'シェイプが選択されていなければ、処理を中断する。
    If Not ActiveWindow.Selection.Type = ppSelectionShapes Then Exit Sub
     
    DimAs Shape
    For EachIn ActiveWindow.Selection.ShapeRange
        If.HasTextFrame Then
            If.TextFrame.HasText Then
                With.TextFrame.TextRange
                    'Asc関数にテキストを入れると1文字目の文字コードを返す。
                    'それに指定された数値を足してChrで文字に戻したあと、
                    '2文字目以降を結合。
                    .Text = Chr(Asc(.Text) + 数値) & Mid(.Text, 2)
                End With
            End If
        End If
    Next
End Sub

PowerPoint VBAでお勧めのページ

いつも隣にITのお仕事

「PowerPoint・VBA」の記事一覧 | いつも隣にITのお仕事
こちらは「ExcelVBAを実務で使い倒す技術」の著者であるタカハシさんのサイトのPowerPointカテゴリーの記事。
初心者向けに分かりやすく書かれている。

ExcelVBAを実務で使い倒す技術

ExcelVBAを実務で使い倒す技術

Powerpoint VBAを使おう!

chemiphys.hateblo.jp
こちらは理科の教員をされているchemiphysさんのサイト。
PowerPointVBAでものすごい高度なことやってる。
特に下の2つは私の中では伝説級。

chemiphys.hateblo.jp

chemiphys.hateblo.jp

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。