出直し!! ヘルプ

連載中

連載 終了

2024/03/31

Notes - Excel 連携:#34)帳票関連オブジェクトまとめ

第 20 回から 33 回 までノーツのデータから Excel で帳票を作るために必要な機能を紹介してきました。シリーズの最後として、使用した Excel VBA のオブジェクトを整理します。

以前作成したオブジェクト関連図を更新しました。

このシリーズに関連しなかったメソッドやプロパティは薄くしています。また、図が複雑になあるので、グラフ作成のシリーズのオブジェクトは割愛しています。ご了承ください。


ワークシート操作の中心は Range オブジェクト

セルに対する値の入出力、フォントや文字揃え、計算式の設定、罫線や背景色の設定、セルのマージなど、セルにかかわる処理はすべて Range オブジェクトから操作します。「Range を制する者は Excel を制す」といった感じでしょうか...

逆に言うと、プロパティやメソッドが多岐にわたるためつかみどころがないオブジェクトとも言えます。今回、使用した機能を順に確認しましょう。


Range オブジェクトの取得

Range オブジェクトの取得は Worksheet のプロパティ経由に行います。ワークシート全体や特定のセルを取得する Cells、複数のセルを範囲で取得する Range、列を取得する Columns、行を取得する Rows がありました。


セルの操作

取得した Range(セル)に対して、値や式、文字揃えやフォーマットの設定を行うプロパティです。頻繁に使用する機能ですね。


セルの装飾

フォントや背景色、罫線の設定を行うプロパティです。それぞれのオブジェクトが戻り値となっていて、そのオブジェクトの機能で詳細な設定を行います。

Range オブジェクトを活用して複数のセルをまとめて操作すると効率的ですね。


行や列の幅

Range は行や列、シート全体を表すことができます。これを利用して行や列の幅を設定するプロパティがありました。


印刷設定

ここから先は Range オブジェクトの話ではありません。

Worksheet オブジェクトの PageSetup オブジェクトから印刷設定が行えました。

用紙のサイズや縦横、マージンの設定、用紙に合わせて出力する機能など、THE 印刷な設定以外にも、ヘッダやフッタの設定、帳票が複数ページにわたる場合に2ページ目以降にも必ず出力させる PrintTitleRows というプロパティがありました。


Excel の保存

作成した帳票を Excel 形式や PDF 形式で保存する方法についても説明しました。この操作は、Application と Worksheet オブジェクトを使用して行いました。

Excel シートとして保存するなら SaveAs、PDF や XPS で保存するなら ExportFixedFormat メソッドを使用します。

また、DisplayAlerts プロパティと Close メソッドを利用すれば、保存せずに Excel を終了させることもできました。


前回 Notes - Excel 連携 次回


2024/03/28

変数や関数の宣言とスコープ

以前投稿した ビジネスアプリ開発で大切なこと の記事の中で、コーディングルールについて紹介しました。今回は、変数や関数のスコープという視点からプログラムのわかりやすさについて考えたいと思います。

スコープという側面からは変数や関数、定数で区別ありません。記事内では ”変数” や "関数" などと限定しているかのように記載していますが、読みやすくすること、事例に合わせることが目的です。予めご了承ください。


スコープとは?

変数の有効範囲のことをスコープと言い、スコープの範囲内であれば変数に対してアクセスすることができ、値の出し入れが行えます。また、スコープの範囲内では、同じ変数名を宣言できません。逆にスコープの外側であれば同名の変数が定義でき、別の変数として利用できます。

たとえば、次の2つのプログラムはエラーとなります。

◇ スコープ内で同じ変数を宣言

Sub Sample()
   Dim x As Integer
   Dim x As Integer
      ・・・
End Sub

◇ スコープ外で変数にアクセス

Sub SampleA()
   Dim x As Integer
   Call SampleB()
      ・・・
End Sub

Sub SampleB()
   x = x + 1
End Sub


スコープの種類と宣言方法

スコープはプライベートとパブリックに大別されます。

プライベート モジュール内でのみ利用できる変数
パブリック 他のモジュールからもアクセスできる変数

言葉の意味のままなのですが、パブリックは公開されていて、外部から自由にアクセスできるということですね。


変数の宣言は、一般に Dim を使用しますが、Public や Private というキーワードをつけて明示的にスコープを宣言することができます。

また、明示的に宣言する以外に Option Public と (Options) で指定しておくと、デフォルトで Public となります。Option Public を記述しないとデフォルトが Private となります。Option Private という記述はできないので注意してください。

暗黙の宣言 を禁止する Option Declare を含め (Options) の指定と変数宣言スコープとの関係をまとめると次のようになります。

宣言方法
暗黙 Dim Public Private
Option (なし) Private Private Public Private
Public Private Public Public Private
Declare (不可) Private Public Private
Public
Declare
(不可) Public Public Private


スコープの動作

以下の画像は連載 Notes - Excel 連携 で使用したプログラムです。サンプルとして提示しているだけなので、プログラムの中身(機能)は本題ではありません...

スクリプトライブラリ lsXls で宣言された定数をそのライブラリを使用しているエージェント内で利用(アクセス)しています。

ライブラリ内で Public 宣言している場合にはこのように利用できますが、Private の場合はエラーとなります。

同じエージェントで Private の定数の宣言がありました。この定数のスコープはそのエージェント内だけとなります。

Public や Private の宣言は、スクリプトライブラリやエージェントなどさまざまな場所で行えます。そのため、最初の説明で『モジュール』というあいまいな言葉を使用しています。


なお、上記事例では定数を使用しました。スコープという側面では、変数や関数も同様です。例えば関数の場合には次のようになります。

なお、関数 x9ToA は Private と明示されていませんが、Option Public の指定がないので、Private な関数となります(上表参照)。


スコープの宣言ができる場所

上記のとおり Public や Private による宣言は『モジュール』間のアクセスをコントロールする機能です。記述は各モジュール内の (Declarations) セクションとなります。

ただ、すべての (Declarations) で記述できるわけではありません。例えば、フォームのアクションボタンの中に記述するとエラーとなります。

アクションボタン自身がフォーム内のサブモジュールと言え、そんな奥まったところで Public 宣言されたらおかしいからなのだと思います。


また、関数内の変数宣言にも Public や Private を使用できず、Dim を使用します。関数内で宣言された変数はその関数内だけがスコープとなります。


チーム開発とスコープ

上記でも登場したライブラリ lsXls を事例に、今度はスコープの価値について考えてみましょう。

このライブラリの内部に Private の関数 x9ToA があります。例えば、仕様の変更によりこの関数の修正が必要となったとします。

修正するには、既存プログラムに対する影響を測定する必要がありますよね。

事例のように、この関数が Private なら、この関数にアクセスするのはこのライブラリの中だけということが明確にわかります。よって、調査範囲はこのライブラリ lsXls 内だけで済みます。

もし、Public 宣言されていた(あるいは、Option Public で Public 扱いとなっていた)と仮定すれば、調査範囲は lsXls を利用しているすべてのプログラムとなってしまいます。アプリケーション(nsf)全体が調査範囲になるということですね。

このような背景から、チーム開発を意識したプログラミングではスコープはできる限り絞った方が良いことになります。

開発した本人であれば、その関数の前提としたスコープはわかっているはずです。その時点で適切なスコープを与えていれば、後任者の無用な調査時間を削減でき、チームの生産性は向上します。

『動けばいいのではなく後任者にも配慮する』開発者のビジネスマナーと言ってもいいですね。


2024/03/26

つないでみよう:#10)Google マップ - Place API で一番近隣の場所を取得

いよいよ、Place API を使用したサンプルプログラムを作成します。今回は座標とキーワードをもとに一番近隣の場所を取得します。


メインルーチン

新しいエージェントを作成、メインルーチンを記述します。検索地点を準備して、一番近隣の場所名を取得する関数 xGetNearestPlaceName をコールして結果を表示します。関数の最後の引数で検索キーワードを指定しています。

Option Declare
Private xns As NotesSession

Sub Initialize
   Dim dLat As Double '緯度
   Dim dLng As Double '経度
   Dim sName As String

   Set xns = New NotesSession
   
   '検索地点の準備
   dLat = 34.683742526906634
   dLng = 135.49698067096077
   
   '検索の実行と表示
   sName = xGetNearestPlaceName(dLat, dLng, "鳥貴族")
   MsgBox sName, 64
End Sub


一番近隣の場所の取得

Place API の Nearby Search を使用して、一番近隣の場所の取得する関数がこちらです。

URL を準備して、GET の HTTP リクエストを実行し、レスポンスを NotesJSONNavigator オブジェクトで取得させています。

検索結果は、まず Results エレメントを取得、そこから 1 件目(一番近隣の場所)のエレメントを取得しています。

Function xGetNearestPlaceName(ByVal vdLat As Double, vdLng As Double, ByVal vsKeyword As String) As String
   Dim sURL As String
   Dim sPram As String
   Dim http As NotesHTTPRequest
   Dim jnav As NotesJSONNavigator
   Dim jeResults As NotesJSONElement
   Dim jePlace As NotesJSONElement

   'URL の準備
   sURL = "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
   sPram = xGetPram(vdLat, vdLng, vsKeyword)
   sURL = sURL & "?" & sPram

   'API に接続しレスポンスを JSON で取得
   Set http = xns.CreateHttpRequest()
   http.PreferJSONNavigator = True
   Set jnav = http.Get(sURL)

   '一番近隣の地点情報を取得
   Set jeResults = jnav.GetElementByName("results")
   Set jePlace = xGetPlace_Nth(jeResults, 1)

   '地点情報から名称の取得
   xGetNearestPlaceName = xGetPlaceName(jePlace)
End Function


レスポンスの JSON は以下のようなイメージでした。コードと比較してもらうとわかりやすいかと思います。


パラメータ文字列の作成

xGetPram 関数は URL に付加するパラメータを生成する関数です。引数で指定した検索条件のほかに、API キーや言語設定、ソートの設定を追加して返しています。

なお、検索キーワードには2バイト文字が入ることを前提に @URLEncode 関数を使用して変換しています。

Function xGetPram(ByVal vdLat As Double, ByVal vdLng As Double, ByVal vsKeyword As String) As String
   Dim s As String
   Dim v As Variant

   s = "key=xxxxxxxxxxx"   ' ← ここに API Key をセット
   s = s & "&" & "location=" & CStr(vdLat) & "," & CStr(vdLng)
   'キーワードは設定がある場合のみ 
   If vsKeyword <> "" Then
      '全角文字に対応するためエンコード
      v = Evaluate(|@URLEncode("UTF-8"; "| & vsKeyword & |")|)
      s = s & "&" & "keyword=" & v(0)

   End If
   s = s & "&" & "language=ja"
   s = s & "&" & "rankby=distance"

   xGetPram = s
End Function


n 件目の取得

xGetPlace_Nth 関数は Results エレメントの中らから引数で指定した地点情報を返します。

今回のサンプルでは1件目しか使用しませんが汎用的に使えるよう要素数の確認などエラーチェックを行っています。

Function xGetPlace_Nth(vjeResults As NotesJSONElement, ByVal viIndex As Integer) As NotesJSONElement
   Dim ja As NotesJSONArray

   If vjeResults Is Nothing Then Exit Function
   If viIndex < 1 Then Exit Function
   If vjeResults.Type = Jsonelem_type_array Then
      Set ja = vjeResults.Value
      If ja.Size < viIndex Then Exit Function

      Set xGetPlace_Nth = ja.GetNthElement(viIndex)
   End If
End Function


地点名の取得

最後は、地点情報から場所の名称である name エレメントの値を取得する関数です。処理自体は簡単なのですが、こちらもエラー処理を追加してあります。

Function xGetPlaceName(vjePlace As NotesJSONElement) As String
   Dim je As NotesJSONElement
   Dim jobj As NotesJSONObject

   On Error GoTo Err_Proc

   Set jobj = vjePlace.Value
   Set je = jobj.GetElementByName("name")
   xGetPlaceName = CStr(je.Value)

Exit_Proc:
   Exit Function

Err_Proc:
   Resume Exit_Proc
End Function


前回 連載:つないでみよう 次回


2024/03/24

つないでみよう:#9)Google マップ - Place API の仕様

前回は Place API の利用に必要な準備を行い、API キーを取得しました。今回はこのキーを利用して API を実際にコールしてみます。


API のドキュメント

まずは、API の仕様について確認します。Place API の Documentation のリンクをクリックします。

すると『Google Maps Platform のドキュメント』ページが開きます。Places-Places API と SDK の[API]をクリックすると Place API のドキュメントが確認できます。


検索の種類

ドキュメントによると Place API では次の 3 種類の検索方法が提供されています。

Find Place 名称や住所、電話番号などのテキスト情報から検索
Nearby Search 指定した位置の周辺を検索
Text Search キーワードによるあいまいな検索

今回は一番わかりやすい Nearby Search を検証します。


なお、ドキュメントを見て発見したのですが、Place API の新バージョンがリリースされていました。今回の記事は、検証済みの旧来の Place API を使用します。新バージョンについては機会があればまとめたいと思います。



リクエスト方法

結果を JSON 形式で取得する場合の URL は次の通りです。

https://maps.googleapis.com/maps/api/place/nearbysearch/json?parameters

? 以降には、検索条件を指定します(後述)。使用する HTTP のメソッドは GET で、検索条件をすべて URL に記述するパターンとなります。


パラメータ

Nearby Search で利用できるパラメータをまとめます。必要なものを抜粋すると次の通りです(○ は必須)。

key API キー
location 検索地点の座標(latitude,longitude)
radius 検索範囲(メートルで指定)
keyword 検索キーワード
language ja を指定すると日本語で返す
rankby 近い順に取得したい場合 distance を指定
この場合 radius は指定できない
type レストランやカフェなどの プレイスタイプ


API のテスト

リクエスト方法がわかったので API をテストしてみます。今回は Postman というツールを使用して検証してみました。


HTTP のメソッドと URL を入力し、パラメータをセットしました。御堂筋線の本町駅から 1000m の範囲にある ”鳥貴族” を検索しています。

[送信]ボタンをクリックするとリクエストを API に送信します。この時の URL は次のようになります(改行して整形済み)。

https://maps.googleapis.com/maps/api/place/nearbysearch/json?
                key=xxxxxxxxxxxxxxxxxxxxxxxxxxxx&
                location=34.683742526906634,135.49698067096077&
                radius=1000&
                keyword=鳥貴族&
                language=ja

実行結果は次のようになります。

検索結果は results オブジェクト内に配列で列挙されています。その要素1つが1件の場所を表します。重要項目には注釈をつけていますが、座標や名称、プレースタイプが含まれています。なお、プレース ID は Google Place データベースで一意に表す ID です。

ちなみに、実行結果には計 7 件記録されており、その順は次の通りでした。1番近い店舗が 4 番目になっていました。

近い順に並べる場合には、rankby=distance をパラメータに追加します。前述した通り rankby は radius と同時に指定できません。間違って指定すると次のようなエラーが返ります。

{
    "html_attributions": [],
    "results": [],
    "status": "INVALID_REQUEST"
}


next_page_token

rankby=distance をパラメータを指定したり、検索範囲を大きくすると多くの地点情報が返されます。Place API では 1 回のレスポンスで最大 20 件までに制限されています。それ以降の結果がある場合 next_page_token がレスポンスに含まれます。

このトークンを pagetoken パラメータとして送信すると続きの 20 件が取得できます。なお、この時に指定するパラメータは key と pagetoken だけでかまいません。

続きの 20 件にまだ続きがある場合、また next_page_token がレスポンスに含まれます。これを繰り返すことにより、大量の検索結果を得る仕組みになっています。


前回 連載:つないでみよう 次回


2024/03/22

つないでみよう:#8)Google マップ - 連携準備

WebAPI 連携日記の第 8 回です。今回からは Google が提供する API に挑戦します。Google には数えきれないぐらいの API がありますが、今回は Google マップの Place API を試します。この API は Google マップの地点情報(ドキュメントには ”プレイス” と表記)データベースにアクセスできます。


Google Cloud Platform(GCP)

API 利用設定の前に Google Cloud の利用登録が必要となります。

まず、Google Cloud を開き、[無料で利用開始]ボタンをクリックします。

Google Cloud Platform や API の利用規約を確認して[同意して続行]をクリックします。

続いて支払い情報を登録します。プロファイルに住所などの個人情報、支払方法にクレジットカードの情報を入力します。

簡単なアンケートが表示されますので回答して[完了]をクリックします。


プロジェクトの作成

プロジェクトは、 GCP で動くシステムの管理単位で、API の利用設定や課金の単位となります。複数のプロジェクトを作成し、プロジェクトごとに課金額を算出したりできるようです。

Google Cloud のメニューから [IAM と管理]-[プロジェクトを作成]を選択して、プロジェクトを作成します。

作成しない場合、自動で1つ生成されます。


API キーの発行

Google Cloud のメニューから [API とサービス]-[ライブラリ]を選択します。さまざまなカテゴリの API ライブラリが表示されますが、今回は ”マップ” の右にある ”すべて表示” をクリックします。マップに関連する API だけが表示されますので、Place API をクリックします。

Place API に関するさまざまな情報が表示されます。まずは、[有効にする]ボタンをクリックして、API の利用を宣言します。

すると、API 利用時に必要となる API キーが表示されます。


次回の予定

これで Googole マップ Place API の利用に必要な材料がそろいました。次回はこの API の仕様についてまとめます。


前回 連載:つないでみよう 次回


2024/03/20

変数宣言 と 暗黙の宣言

以前投稿した ビジネスアプリ開発で大切なこと の記事の中で、コーディングルールについて紹介しました。今回は、変数宣言の必要性についてまとめます。


変数宣言と型

変数とは、プログラムで使用するデータ(値)を保存する器のようなものです。その値を使って集計などの計算をしたり、値を判定して分岐させたり、さまざまな用途で利用します。

通常、この変数を利用するには、”変数宣言” を行って器を準備します。

   Dim i As Integer    ' 整数型
   Dim s As String     ' 文字列型

Dim が変数宣言を行う命令で、i や s が変数名で器の名前ですね。As 以降が型宣言といって、その変数に入る値の種類を宣言します。これをデータ型と言います。

変数に値を代入するには ”=” を使用して値をセットします。

   i = 0
   s = "これは文字列型の変数です"

このように 1 つの変数に特定の 1 つの値を保持する変数をスカラー型変数と総称します。


スカラー型以外としては、オブジェクトを保存する変数があります。

   Dim nd As NotesDocument

さらに、複数のスカラー型変数をまとめて取り扱える配列や List、ユーザ定義のデータ型、ユーザ定義型のクラス(オブジェクト)などさまざまな種類があります。


そして、LotusScript には、どんな型の値でも保持できる Variant 型という特殊なデータ型があります。次のように 1 つの変数の中に違う型のデータを代入することができます。

   Dim v As Variant

   v = 0    ' 数値を代入
   v = "文字列"    ' 値を文字列に変更
   set v = New NotesSession()    ' オブジェクトも入ります



暗黙の宣言

LotusScript のプログラムを見ていると変数宣言がないのに変数を使用しているケースがあります。サンプルとして次のようなエージェントを作成してみました。

変数 s に文字列を代入してメッセージボックスで表示するだけのエージェントです。実行すると『出直し!! ドミノ塾』と正しく表示されます。

デバッグモードで実行すると変数 s が生成され値がセットされていることが確認できます。

これは、暗黙の宣言という機能によるもので、宣言していない変数名を使用すると自動的に変数が生成される機能となります。


暗黙の宣言のデメリット

変数宣言意をいちいちしなくても変数が利用できるなんて、暗黙の宣言て機能は便利だと思いましたか?

でも、この機能がきっかけでバグが出ることもあります。例えば、次のプログラムは実行はできますがメッセージは正しく表示されません。

Sub Initialize
   sText = "出直し!! ドミノ塾"
   MsgBox sTest
End Sub

原因は、変数のタイプミスですね。値をセットした変数と違う名前がメッセージボックスに指定されています。デバッガで実行を確認すると 2 つの変数が生成されていることがわかります。

このようにタイプミスでも設計保存(コンパイル時)にエラーが出ず、気が付かないことがデメリットになります。


暗黙の宣言の禁止

このような問題を排除するために、以下のステートメントを (Options) に記述すると暗黙の宣言を禁止するとができます。

Option Declare

これを記述すると変数宣言が必須となりますので、変数 sText の宣言も追加します。するとタイプミスがエラーとなって表示されます。

なお、Option Declare の代わりに Option Explicit と記述しても同じ効果が得られます。


チーム開発のためには

後任の方がプログラムを確認したとき、コード上に突然登場した変数が、意図したものかタイプミスか判別するすべがありません。このような問題を避けるためにも、暗黙の宣言は一律禁止しておくべきです。

こうしておくことで、そのプログラムは、少なくとも文法的には正しいことが保証されます。問題があるとすれば論理的なバグということで、調査する範囲が限定できますね。


また、暗黙の宣言で作成された変数は Variant 型となります。Variant 型変数はどんな値でもセットできる反面、どのような値が入るべきか?入っているのか?を確認するためには、デバッグモードで確認するか、値を代入しているコードを探し出すしかありません。非常に手間がかかりますので、担当が変わることを前提としたチーム開発では不向きであるといえます。


ちなみに、現在のバージョンでは Option Declare の宣言はデフォルトでセットされ、あえて削除しないと、暗黙の宣言は有効にできません。しかし、少し前のバージョンでは、デフォルトでセットされていませんでした。ですので、過去のプログラムでは、有効になっていないことがあり得ますので注意が必要です。

また、フォームやビュー、アクションボタンなど一部の設計要素では、現在もデフォルトで Option Declare が宣言されません。このような設計要素では意識的にセットするようにしましょう。


2024/03/18

作ってみよう:#3)お小遣い帳 - 過去の入力から選択肢を取得

アプリケーション作ることを主体にした連載 ”作ってみよう” の第 3 回です。

前回、ベースとなる簡単なアプリを作成しましたので、少しずつ機能を追加しましょう。今回は、過去の入力から選択肢を取得する方法です。


ターゲットとなるのは、購入場所 です。どこで買い物するかは事前にわからないので、マスタなどあらかじめ準備できません。だからと言って、毎回手入力だと面倒ですね。

そこで、一度入力した購入場所を選択肢として表示する機能を作成ます。


利用する機能は、@DbColmun と @DbLookup 関数です。それぞれの関数の仕様や使い方は、別途まとめていますので、以下のリンクからご確認ください。

@DbColmun ビューまたはフォルダから列の値を取得します。
@DbLookup ビューを検索して値を取得します。


ビューの作成

どちらの関数もビューの列を経由して値を取得する仕様です。そこで、@関数から接続する検索用のビューを作成します。

前回作成した 1.日付順 ビューをコピペして編集します。列を移動して、1列目は店舗 Vendor、2列目は支店 Branch フィールドに変更します。3列目以降は使用しないのですが、確認用としてそのままとします。

重要なのは、1列目がソートされていることです。@DbLookup でビューを検索する条件だからですね。


続いて、ビューの名前を変更します。

ビュー名 (x.検索\1.購入場所)
別名 vSchVendor

ビュー名を ( ) で括るとそのビューは非表示となり、ビューの一覧に表示されません。

アウトラインやナビゲータで左にメニューを作成することが一般的なので、非表示って必要なの?と思われるかもしれませんが、[表示]-[移動]メニューに表示されてしまい、ビューに移動できてしまいます。


表示するビューはユーザに提供するもの、プログラムでアクセスするビューは非表示とすると決めておくとよいかと思います。ユーザ向けのビューはユーザからの要望で変更しがちです。「要望に応えたら機能が動かなくなった」なんてトラブルは回避したいですよね。


フォームの修正

作成したビューから購入場所情報を取得して選択肢として表示する設定を行います。

まずは、Vender と Branch フィールドの種類を『ダイアログリスト』に変更し、[制御]タブの「選択」は『式で選択肢を設定』を指定します。設定する式は以下通りです。


◇ Vendor フィールド

xLst := @DbColumn("Notes":"NoCache"; ""; "vSchVendor"; 1);
@Unique(xLst)

ビューの一列目を取得して選択肢とする式ですね。


◇ Branch フィールド

xLst := @DbLookup("Notes":"NoCache"; ""; "vSchVendor"; Vendor; 2);
@Unique(xLst)

Vendor フィールドの値でビューを検索して、ヒットしたエントリの2列目を取得する式です。


どちらの式にも、取得した結果を @Unique しています。この関数は、その名の通り重複した結果を排除してくれます。今回のように履歴から取得するタイプでは、重複は普通にあり得ますから、必ず設定が必要ですね。


続いて選択肢が確実に更新されるように設定します。フィールドのプロパティの[制御]タブで以下をチェックします。

Vendor キーワードの変更時にフィールドを更新
Branch 文書の更新時に選択肢を更新

この設定の必要性については、『ダイアログリストフィールドの設定と挙動』をご確認ください。


最後に新しい購入場所の追加ができるように『リストにない値も可』をチェックします。


動作確認

出来上がったら動作確認しましょう。

あらかじめデータをコピペして、重複した状態にしておきます。

文書を新規作成して、購入場所の選択肢が正しく表示されるか確認します。次のように重複排除されて表示できれば成功です。

また、別の店舗を選択したら、支店の選択肢が正しく変更されるかも確認しましょう。


前回 作ってみよう 次回


2024/03/16

作ってみよう:#2)お小遣い帳 - ベースアプリの作成

まずは、基本的な機能をノーツクライアント用として作成します。データの入力と表示だけができるシンプルなアプリケーションです。

まずは、空のアプリケーション(nsf)を新規で作成します。ここにフォームとフォームとビューを作成します。


フォーム

まずは、フォームを新規作成します。

フォーム名 1.支出
別名 fExpence


フォームに配置するフィールドは次の通りです。

項目 フィールド名 種類 補足
金額 Amount 数値
日付 Date 日付
場所 Vendor テキスト 店舗名
Branch テキスト 支店
分類 Budget ダイアログリスト おサイフ
ItemGroup ダイアログリスト 費用区分
メモ Memoテキスト

費用分類については次の項目を選択しとして用意します。

おサイフ 費用区分
業務
教養・啓発
交際
娯楽
旅行・レジャー
その他


飲食
懇親会・飲み会
交通費・宿泊
会費・利用料
土産・贈答品
書籍・ソフト
ガジェット
その他

選択肢はフィールドのプロパティの[制御]タブに設定します。


表を利用してフィールドとそのラベルを配置すると簡単に整然とした画面が作成できます。

標準の設定だと余白がなく、息苦しい感じがします。表のプロパティにある”間隔”を活用すると一括で設定できます。表全体の余白設定になりますので、行や列を追加しても有効となる便利です。


次にアクションボタンを作成します。

ボタン 非表示設定
閉じる @Command([FileCloseWindow])
編集 @Command([EditDocument]) 編集時
保存 @Command([FileSave]) 読み込み時


最後にウィンドウタイトル式を記述します。文書を開いた際にタブに表示される文言を設定する式ですね。

x := @If(Memo = ""; Vendor; Memo);
@If(@IsNewDoc; "支出"; x = ""; "支出"; x)

この式では、メモを優先して表示し、入力がない場合は購入場所、どちらもない場合や新規文書では ”支出” と表示します。

完成したフォームは次のような感じになります。


ビュー

アプリケーションを空で作成しても(無題)ビューが作成されています。今回はこれを編集します。まず、ビューの名称をセットします。

ビュー名 1.日付順
別名 vExpenceByDate


次に各フィールドを表示する列を作成します。各フィールドを表示する列を順に配置し、列幅を調整します。日付は降順でソートしておきます。

金額は数値ですので右寄せで表示します。ただ、そのままだと次の列と接近しすぎて見づらくなります。そこで空の列を幅 1 で作成しておくと見やすくなりますね。


続いてアクションボタンを作成します。

ボタン 非表示設定
閉じる @Command([FileCloseWindow])
新規作成 @Command([Compose]; "fExpence")


ビューの選択式を設定し、支出フォームの文書だけを表示するように設定します。

SELECT Form = "fExpence"

最後に交互の列の色と間隔を指定し、少し余裕のある見やすい設定に整えます。


ベースアプリの完成

フォームとビューができたのでノーツから開いて動作確認をします。

とりあえずではありますが、たったこれだけの操作で、使えるアプリケーションができました。
ノーツって便利ですね。


次回からはこのアプリをベースに機能を追加して、より使いやすいアプリに拡張していきます。


前回 作ってみよう 次回


2024/03/14

作ってみよう:#1)新連載始めます!

2023 年に始めたブログ『出直し!! ドミノ塾 』は、本日 3 月 14 日で 1 周年になりました!
そしてこの記事がちょうど 200 本目となります !!


それを記念(?)して、新企画をスタートします。


これまでの記事をざっと確認しましたが、機能説明が主体となっているものが多く、実アプリにどのように応用すればいいのかわかりずらい内容ではないかと感じました。

そこで、今回の新企画ではアプリケーション作ることを主体にした連載にしようと考えました。アプリケーション開発の流れや機能の組み込み方などをより具体的にお伝えできればと考えております。


最初のアプリ

記念すべき最初のアプリは『お小遣い帳』です。

ビジネスと関係ないアプリで申し訳ないのですが、誰でもイメージのつくアプリですよね。自作アプリの中で一番使用頻度が高いこともあり、工夫した点がいろいろとあります。より、具体的にアプリの作り方をお伝えできるかと思い採用することとしました。

以下の画面は、現在使用中のアプリの画面です。日頃は Nomad Mobile(iOS 版)で使用しています。

日々の出費を入力するだけの単純な機能です。入力項目としては、

  • 金額
  • 日付
  • 購入場所
  • 費用分類
  • メモ(必要に応じて購入した物の情報を入力)

だけです。モバイル機器からの入力だと、少ない項目でないとつらいですよね。そして、入力を極力簡素化するために、次のような機能を設けています。

  • 過去の購入履歴から一番近い購入場所を自動表示
  • 新しい購入場所の場合 GoogleMap から近隣の店舗を検索し選択
  • 分類の選択肢はその購入場所での指定履歴から多い順に表示

購入してすぐに入力するのであれば、金額のみで通常は完了するようになっています。


このような機能を実現するアプリをゼロから作成する作業の過程をネタに連載を進めます。

Nomad Mobile 用画面の作成やノーツクライアントとのハイブリッド利用、GPS や GoogleMap API 連携についても触れる予定です。


作ってみよう 次回


2024/03/10

Notes - Excel 連携:#33)帳票を PDF で保存

前回は、作成した帳票を Excel ファイルとして保存する方法を紹介しました。今回は PDF や XPS 形式で保存する方法を紹介します。


PDF や XPS 形式の保存

Excel の操作では [ファイル] - [エクスポート] メニューを使用して PDF や XPS 形式で出力できます。通常の保存とは別の機能として提供されています。

VBA でも同様で、別のメソッド ExportAsFixedFormat が用意されています。

Workbook.ExportAsFixedFormat メソッド (Excel)

メソッドには引数が多数ありますが、重要なのは初めの 2 つです。

1 つ目は Type です。この引数は出力形式を指定します。設定できる値は XlFixedFormatType 列挙 に定義されていますが、現時点では次の 2 種類だけです。

定数 説明
0 xlTypePDF PDF 形式で出力
1 xlTypeXPS XPS 形式で出力


2 つ目は FileName で、説明するまでもありませんが、保存するファイル名ですね。


LotusScript で記述すると次のようになります。

   Call oXls.Workbooks(1).ExportAsFixedFormat(xlTypePDF, "E:\Notes-Excel#33.pdf")

なお、上記 XlFixedFormatType 列挙 の 2 つは、xlXls ライブラリに事前に定数宣言しています。

'XlFixedFormatType 列挙
Public Const xlTypePDF = 0
Public Const xlTypeXPS = 1


サンプルプログラム

では、前回のエージェントを修正して PDF で保存するように修正すると次のようになります。

  ・・・
   '印刷設定
   Call xPageSetup(oSheet)

   '作成した帳票を PDF で保存
   oXls.DisplayAlerts = False
   Call oXls.Workbooks(1).ExportAsFixedFormat(xlTypePDF, "E:\Notes-Excel#33.pdf")
   Call oXls.Workbooks(1).Close()
End Sub

ただ、前回と違い Excel シート自身は保存していません。通常だと、保存せず終了すると『保存しますか?』と聞いてきます。今回のコードでは DisplayAlerts = False がセットされているため確認なく終了できてはいますが、あまり丁寧なコードではありませんね。

このような場合に使用できるのが Close メソッドの 1つ目の引数 Savechanges です。False をセットすると保存の確認なしに閉じることができます。

Workbook.Close メソッド (Excel)

これを利用すると次のようになります。結果は何も変わりませんが...

   Call oXls.Workbooks(1).Close(False)


このプログラムを実行すると指定したファイル名で PDF ファイルが出力されます。たったこれだけのコードで PDF が作成できます。なかなか便利な機能ですね。


まとめ

今回紹介した方法を使えば、ノーツのデータを PDF に変換できます。

Excel 経由となってしまいますが、逆に言うと Excel の機能を使ってノーツではできないことができるようになります。今回のような帳票やグラフを挿入した文書(PDF)が体裁よく出力できるということですね。

ノーツの可能性を広げる機能ですので、ぜひとも挑戦ください。


前回 Notes - Excel 連携 次回