フローチャートはプログラミングでよく用いられていたが、最近は専ら業務の流れを説明する図として利用されている。
特に部門をまたがる業務の全体像を把握するには便利である。
しかし、図なのでとにかく作成が面倒くさい。
どうしてもボックスのサイズをそろえたり、位置を揃えたり、コネクターをつなげたりといった細かい作業に時間を取られてしまう。
今回はマクロを使ってフローチャートを簡単に作成する方法について紹介する。
目次
作成するマクロの概要
まずはGIFアニメで楽々とフローを作成している様子を紹介。
プロセスボタンをクリックするとプロセス入力モードになり、あらかじめ用意された枠をクリックすることでプロセス名が入力できる。
コネクターボタンをクリックするとコネクター接続モードになり、プロセスを次々クリックしていくだけで矢印で接続される。
最後にチャートの完成ボタンをクリックすると、不要な枠が消え、まっすぐな鉤型コネクターは直線コネクターに変換されることでコネクターのズレも綺麗になる。
作り方
新しいブックに標準モジュール「Module1」を挿入し、以下のコードを張り付ける。
Option Explicit Public Enum Mode デフォルト = 0 消去 = 2 プロセス入力 = 3 コネクタ接続 = 5 判断入力 = 4 End Enum Public Enum Direction North = 1 West = 2 South = 3 East = 4 End Enum Public 前にクリックしたシェイプ As Shape Public Function 反対方向(D As Direction) As Direction Dim ret As Direction If D < 3 Then ret = D + 2 Else ret = D - 2 End If 反対方向 = ret End Function Sub Click() Dim 今クリックしたシェイプ As Shape: Set 今クリックしたシェイプ _ = Sheet1.Shapes(Application.Caller) If Sheet1.現在のモード <> コネクタ接続 Then Set 前にクリックしたシェイプ = Nothing Dim シェイプ文字列 As String Select Case Sheet1.現在のモード Case Mode.消去 Call シェイプ無効化(今クリックしたシェイプ) Case Mode.プロセス入力 シェイプ文字列 = InputBox("入力してください") If シェイプ文字列 = "" Then Exit Sub Call シェイプ有効化(今クリックしたシェイプ) Call シェイプ変更(今クリックしたシェイプ, msoShapeFlowchartProcess) 今クリックしたシェイプ.TextFrame2.TextRange.Text = シェイプ文字列 Case Mode.判断入力 シェイプ文字列 = InputBox("入力してください") If シェイプ文字列 = "" Then Exit Sub Call シェイプ有効化(今クリックしたシェイプ) Call シェイプ変更(今クリックしたシェイプ, msoShapeFlowchartDecision) 今クリックしたシェイプ.TextFrame2.TextRange.Text = シェイプ文字列 Case Mode.コネクタ接続 If Not 前にクリックしたシェイプ Is Nothing Then Dim コネクタ As Shape Set コネクタ = Sheet1.Shapes.AddConnector(msoConnectorElbow, 624, 154, 816, 272) コネクタ.Line.EndArrowheadStyle = msoArrowheadOpen コネクタ.Line.Weight = 1.5 コネクタ.Line.ForeColor.RGB = vbBlack Dim 接続方向 As Direction 接続方向 = 方位判定(前にクリックしたシェイプ, 今クリックしたシェイプ) コネクタ.ConnectorFormat.BeginConnect _ ConnectedShape:=前にクリックしたシェイプ, _ ConnectionSite:=接続方向 コネクタ.ConnectorFormat.EndConnect _ ConnectedShape:=今クリックしたシェイプ, _ ConnectionSite:=反対方向(接続方向) End If Set 前にクリックしたシェイプ = 今クリックしたシェイプ Case Else MsgBox "モードを選択してください。" End Select End Sub Sub シェイプ有効化(sh As Shape) With sh .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = vbBlack .Line.ForeColor.RGB = vbBlack .Line.Weight = 2 .Fill.Transparency = 0 .Line.DashStyle = msoLineSolid .Fill.ForeColor.RGB = vbWhite End With End Sub Sub シェイプ無効化(sh As Shape) With sh .AutoShapeType = msoShapeFlowchartProcess .Line.Weight = 0.25 .TextFrame2.TextRange.Delete .Line.ForeColor.RGB = RGB(150, 150, 150) .Fill.Transparency = 1 .Line.DashStyle = msoLineDash End With End Sub Sub ひな形作成() Set 前にクリックしたシェイプ = Nothing Call 全シェイプ削除 Dim 幅 As Double: 幅 = 100 Dim 高さ As Double: 高さ = 40 Dim 開始X As Double: 開始X = 100 Dim 開始Y As Double: 開始Y = 120 Dim 横間隔: 横間隔 = 50 Dim 縦間隔: 縦間隔 = 30 Dim 横数: 横数 = 5 Dim 縦数: 縦数 = 10 Dim x, y For x = 0 To 横数 - 1 For y = 0 To 縦数 - 1 Dim sh As Shape Set sh = Sheet1.Shapes.AddShape( _ Type:=msoShapeFlowchartProcess, _ Left:=開始X + (x * (幅 + 横間隔)), _ Top:=開始Y + (y * (高さ + 縦間隔)), _ Width:=幅, _ Height:=高さ) Call シェイプ無効化(sh) sh.OnAction = "Click" Next Next Call Sheet1.ボタン状態クリア Sheet1.現在のモード = デフォルト End Sub Sub 全シェイプ削除() Dim s As Shape For Each s In ActiveSheet.Shapes If s.Type <> msoFormControl Then '←ボタンを削除しないため s.Delete End If Next End Sub Function 方位判定(s1 As Shape, s2 As Shape) As Direction Dim s1横中央: s1横中央 = s1.Left + (s1.Width / 2) Dim s2横中央: s2横中央 = s2.Left + (s2.Width / 2) Dim 横の距離: 横の距離 = s1横中央 - s2横中央 Dim s1縦中央: s1縦中央 = s1.Top + (s1.Height / 2) Dim s2縦中央: s2縦中央 = s2.Top + (s2.Height / 2) Dim 縦の距離: 縦の距離 = s1縦中央 - s2縦中央 If Abs(横の距離) - Abs(縦の距離) > 0 Then If 横の距離 > 0 Then 方位判定 = West Else 方位判定 = East End If Else If 縦の距離 > 0 Then 方位判定 = North Else 方位判定 = South End If End If End Function Sub シェイプ変更(TargetShape As Shape, T As MsoAutoShapeType) Dim 接続されたコネクタ一覧 As New Collection Dim s As Shape '現在TargetShapeに接続されたコネクタを一覧化しておく For Each s In TargetShape.Parent.Shapes If s.Connector Then If s.ConnectorFormat.BeginConnected Then If s.ConnectorFormat.BeginConnectedShape Is TargetShape Then 接続されたコネクタ一覧.Add _ Array(s, s.ConnectorFormat.BeginConnectionSite, True) 'True=Begin End If End If If s.ConnectorFormat.EndConnected Then If s.ConnectorFormat.EndConnectedShape Is TargetShape Then 接続されたコネクタ一覧.Add _ Array(s, s.ConnectorFormat.EndConnectionSite, False) 'False=End End If End If End If Next 'シェイプタイプを切り替えたタイミングでコネクタの接続が外れる TargetShape.AutoShapeType = T '一覧に登録されたコネクタをTargetShapeに再接続する Dim c As Variant For Each c In 接続されたコネクタ一覧 Dim コネクタ As Shape: Set コネクタ = c(0) If c(2) Then 'True=Begin, False=End コネクタ.ConnectorFormat.BeginConnect TargetShape, c(1) Else コネクタ.ConnectorFormat.EndConnect TargetShape, c(1) End If Next End Sub Sub チャート完成() Dim s As Shape Dim Arr() As String ReDim Arr(0) For Each s In Sheet1.Shapes If s.Type <> msoFormControl Then s.OnAction = "" If s.Connector Then If s.Height < 2 Or s.Width < 2 Then s.ConnectorFormat.Type = msoConnectorStraight End If End If If s.Fill.Transparency = 1 And s.AutoShapeType = msoShapeFlowchartProcess Then s.Delete End If End If Next Call Sheet1.ボタン状態クリア End Sub
次に、Sheet1モジュールに以下のコードを張り付ける。
Private cm As Mode Public Property Get 現在のモード() As Mode 現在のモード = cm End Property Public Property Let 現在のモード(m As Mode) cm = m End Property Sub ボタン状態クリア() With Sheet1.Buttons(Array("Mode3", "Mode4", "Mode5", "Mode2")).Font .FontStyle = "標準" .ColorIndex = 0 End With End Sub Sub ModeButton() Set Module1.前にクリックしたシェイプ = Nothing Dim 押されたボタン As Button Set 押されたボタン = Sheet1.Buttons(Application.Caller) Call ボタン状態クリア If 現在のモード = CInt(Right(押されたボタン.Name, 1)) Then 現在のモード = Mode.デフォルト Else With 押されたボタン.Font .FontStyle = "太字" .ColorIndex = 5 End With 現在のモード = CInt(Right(押されたボタン.Name, 1)) End If End Sub
次にSheet1にボタンを配置する。
このボタンはフォームコントロールのものを使用すること。
割り当てるマクロは、次のとおり。
「ひな形作成」ボタン→「ひな型作成」マクロ
「プロセス入力」ボタン→「Sheet1.ModeButton」マクロ
「判断入力」ボタン→「Sheet1.ModeButton」マクロ
「コネクター」ボタン→「Sheet1.ModeButton」マクロ
「消去」ボタン→「Sheet1.ModeButton」マクロ
「チャートの完成」ボタン→「チャート完成」マクロ
ボタンを右クリックで選択すると、左上の名前ボックスで名前を付けることができる。
今回は押されたボタンの判定にこの名前を使用するので、
以下のボタンにはそれぞれ名前をつけておく。
「プロセス入力」ボタン→Mode3
「判断入力」ボタン→Mode4
「コネクター」ボタン→Mode5
「消去」ボタン→Mode2
以上でマクロは完成である。
使ってみる
ひな形作成ボタンを押すと、このように薄い枠が表示される。
私の環境では、シートのズームは70%くらいにしておくと収まりが良い。
(設計したときにシートが70%ズームになっているのに気づかず、その状態でフィットするようにコーディングしてしまった。将来的にはサイズ調整するUIも付けたいけど、今のところ作りっぱなしの手抜き)
プロセス入力ボタンを押すとボタンが青字になり、この状態で枠をクリックすることでプロセスが入力できる。
判断入力では「ひし形」の図形が配置される。
コネクターボタンをクリックすると、最初のプロセスクリックでは何も起きないが、その時にクリックしたシェイプを記憶し、次にクリックしたシェイプと矢印で接続される。連続でプロセスをクリックすることで次々つなげることができる。
一旦コネクターを切って新しいシェイプから始めたいときは、一度別のモードに切り替えるか、もう一度コネクターボタンを押して一度デフォルトモードにもどしてから、再度コネクターボタンでコネクタ接続モードに切り替える。
プロセスを修正するときは、プロセスモードで既存のプロセスをクリックすればよい。
プロセスを判断に切り替えたいときも、判断モードで既存プロセスをクリックする。
また、不要なプロセスを削除したい場合はシェイプごと消すのではなく、消去モードにしてクリックする。
コネクターの削除は今のところ手動だ。
最後にチャートの完成ボタンを押すと、不要な枠が消える。
また、作成途中はコネクターの種類がすべて鉤型コネクターなので、真横や真下につないでもズレて見える。
チャートの完成ボタンを押すことでこれらの本来まっすぐになるべきコネクタは直線コネクタに自動変換され、綺麗になる。
完成ボタンを押した後はプロセス入力はできなくなるので注意。
なお、再度ひな形作成ボタンを押すと、ボタン以外の全シェイプが消去されて新しい枠が配置される。
課題
斜めに配置されたプロセスを接続した場合はこのようになる。
これは、シェイプ同士の中心距離を縦、横ではかり、より短い方のルートを通るように設計したためだ。
ただ、フローの流れを考えると、この設計は失敗だった。
今のところ、このように混線してしまうので、これは手で付け替える必要がある。
デザイン
冒頭のアニメーションで紹介したマクロはセル幅をフローが収まる幅に合わせてある。
また、背景色やヘッダや罫線もあらかじめ作成してある。
フローの位置に合わせて手動でセル幅を変更する際は、ひな形の枠を全選択して書式設定からセルと連動して動かないように設定しておくとよい。
完成したフローを別のシートへ移動
完成したフローがこちら。
完成したフローを別のシートに移すには、オブジェクトの選択モードにして、
全シェイプ選択し、
この状態でコピーして別のシートに張り付ければ良い。
背景をデザインしている場合はこのように背景のセルを必要範囲選択してコピーすると、その範囲に存在するシェイプも一緒に付いてくる。
ただ、普通に張り付けるとセル幅に合わせてつぶれてしまう。
この場合は張り付け直後に表示される「Ctrl」と書かれた小さなポップアップをクリックし、元の列幅を保持するように変更すると直る。
マクロの解説
さて、マクロの動作についてざっくり簡単に概要を説明する。
まずひな形作成であるが、これは単に設定値に合わせてシェイプをAddしているだけ。
ポイントは「sh.OnAction = "Click"」でシェイプにマクロを登録している点である。
これは最終的にはチャート完成時に、「s.OnAction = ""」でマクロ登録を外している。
Clickマクロはシェイプで共通であるが、「Application.Caller」で呼び出し元のシェイプ名がわかるので、そのシェイプ名をもとに該当するシェイプオブジェクトを「今クリックしたシェイプ」変数に格納して操作している。
Clickマクロは現在のモードによって処理が分かれている。
モードはModule1の冒頭で列挙型「Mode」として定義しており、現在のモードはSheet1にプロパティとして保持させている。
モードは4つのモードボタンで切り替える。
これも共通のModeButtonマクロが呼び出されるが、呼び出したボタンはApplication.Callerで判定している。
「Dim 押されたボタン As Button」の部分で、Button型というのは見たことが無いかもしれない。
これはオブジェクトブラウザで非表示のメンバーを表示させると見ることができる。
ボタンもシェイプの一種ではあるが、Shape型で処理すると、「押されたボタン.Font」でメンバーが見つからないというエラーになる。
Object型で対応しても良かったのだが、インテリセンスを使わないと扱い方がわからなかったので固有型で宣言した。
プロセスや判断の入力、消去などはシェイプの変更で対応している。
コネクタの接続部分は苦労したが、今クリックしたシェイプと前にクリックしたシェイプの位置関係を「方位判定」関数で処理して適切な位置でつないでいる。
この関数の戻り値はModule1で定義している列挙型「Direction」である。
東西南北あるいは英語でNEWSを考えると、並び順が以下のようになっているのは不自然に思われるかもしれない。
Public Enum Direction North = 1 West = 2 South = 3 East = 4 End Enum
これはシェイプのConnectionSiteが次の順になっているので合わせた結果である。
最後にシェイプの完成時には高さまたは幅が2未満のコネクタを直線コネクタに変換している。
(1未満ではうまくいかなかったので2未満とした)
マクロの解説は以上
おわりに
私はこのマクロを「BreadChart(ブレッドチャート)」と名付けた。
最近たまたま電子工作で利用するBreadboardを見て閃いたためだ。
ブレッドボード - Wikipedia
- 出版社/メーカー: サンハヤト
- メディア: Tools & Hardware
- この商品を含むブログを見る
もともと5年ほど前からフローチャートを楽に作るマクロを考えていたのだが、当時は今一つ「これだっ」と思えるアイデアが出ずに悩んでいた。
また実装スキルも低かったので、「こんな風にやればできるかも」と思ってもなかなか作れなかった。
いろいろと試行錯誤しながらガラクタを作り続けているうちに徐々に実装スキルが付き、今では自分が「できるかも」と思ったものは大体作れるようになった。
今はできないことでも、トライ&エラーを繰り返して悩むというプロセスを踏んでおけばスキルがついていつかできるようになる。そういうもんだと実感した。
みなさんも作りたいけどなかなかうまくいかないマクロがあったら、すぐに諦めずにあーだこーだ試行錯誤を続けると良い。たとえ今はガラクタであっても、いつかそれが宝の山になる日が来るかもしれない。
追記
8/13 ブラッシュアップしてGitHubに公開した。詳細は以下参照。
thom.hateblo.jp