コルネの進捗や備忘録が記されたなにか

進捗や成果物や備忘録てきななにかを雑に更新していきます。


スポンサードリンク

【Power Apps】処理の開始と完了の監視に関して

はじめに

この記事ではPower Apps の Slider.Onchange の動作に関する検証結果を纏めています。

これらの検証の纏めは、特定の処理の開始、完了を監視したい。
という要望に役立つかと思います。

発生した事象

事象としては以下のようなことが発生しました。

前提条件
Screen.OnVisible

UpdateContext({val:0});
UpdateContext({isChange:false});
UpdateContext({txt:""})

DropDown.OnChange

UpdateContext({isChange:true});
UpdateContext({val:val+1});
UpdateContext({isChange:false});

Slider.default

val

Slider.OnChange

If(!isChange, UpdateContext({txt:"execute slider.OnChange"}))

Label.Text

txt

上記設定を行い、ドロップダウンの値を変更しました。
その結果、 DroDown.OnChange 内の式が動作することになります。
これらの式は、こちらの公式docs にも記載の、

通常、複数の数式は ; 演算子と一緒にチェーンすることにより評価され、各々を順次に順番に評価します。 ともある通り、順に式が評価されるはずです。
よって以下のような動作になると想像されます。

  1. 変数 isChange の値が true に設定される
  2. 変数 val の値に1が加算される
  3. 2の動作によってSlider にも設定されている val の値が変更されたので、 Slider.OnChange が動作する
  4. Slider.OnChange が動作した結果、 If 関数 内の isChange の値が評価される。
    isChange の値は1で true に設定されており、 ! により否定がとられているので、 "False の場合" の式が実行される。
    ただし、今回は "False の場合" の式が設定されていないため、なにも実行されない。
  5. 変数 isChange の値が false に設定される

しかし実際の動作としては、 Slider.OnChange の動作によって、 !isChangetrue と判断されて、変数 txt に"execute slider.OnChange"が設定されてしまった。

また、この問題に関してふらり さんも検証していただけました。
ありがとうございます!!

これらの結果から、ふらりさんも述べている通り、他コントロールでのSlider の値の変更回数分しっかりトリガーされていることがわかります。

ただ、ここで1つきづいたことがあります。
例えば、 "Button1" を押したときの動作ですが、変数 val の変更に対して、すぐに Slide.OnChange が動作したのであれば、変数 PointUp は0のはずなので、変数 Point の結果は0となるはずです。
また、 "Button3" を押したときの動作の Point の最終結果は100ではなく、60が設定されているはずです。

このことから、まず対象コントロールの動作プロパティないの式が評価されてから、その式によって生じた他コントロールの動作が順次動作されていくのではないか?と私は考えました。
* あくまで実際の動作からの私の想定であり、公式のドキュメントなどにて記載されていることではないことにご注意ください。

この予想を "Button3" を押したときの動作の内部の動き(予想)に当てはめると恐らく以下のような動作をしているのではないでしょうか。

  1. 変数 val の値が1に設定される
  2. 1によって、Slider の値が変更されたので Slider.OnChange の動作がスタックされる
  3. 変数 PointUP の値が10に設定される
  4. 変数 val の値が5に設定される
  5. 4によって、Slider の値が変更されたので Slider.OnChange の動作がスタックされる
  6. 変数 PointUP の値が50に設定される
  7. 2(もしくは5)によってスタックされている動作、 Slider.OnChange を実行する。
    Slider.OnChange には変数 PointPointUP の値を加算するようになっている。この時点では PointUP には50が設定されているため、 Point には、 0 + 5050が設定される
  8. 5(もしくは2)によってスタックされている動作、 Slider.OnChange を実行する。
    Point には、 50 + 50100が設定される

対処案

これらの結果より、1つのプロパティ内で、対象プロパティの開始、終了を1つの変数で判断させるのは難しいということがわかりました。
そこで、コントリールを追加して、その中で、対象プロパティの開始、終了の判定を行う変数を処理してあげる法則を対処法として思いつきました。

具体的な設定方法は以下となります。

f:id:koruneko:20210505052956p:plain

ここで肝となってくるのは、トグル(切り替え)コントロールです。
対象プロパティの処理の開始、終了判定用にそれぞれトグルを追加し、それぞれのトグルが true (チェック)となったときに、開始、終了の判定を行う変数 isChange の値を更新しています。

各コントロールの設定値は以下になります。
Screen.OnVisible

UpdateContext({val:0});
UpdateContext({isChange:false});
UpdateContext({txt:""});
UpdateContext({isStart:false});
UpdateContext({isEnd:false});
UpdateContext({count:0})

Button.OnChange

UpdateContext({isStart:true});
UpdateContext({val:val+1});
UpdateContext({isEnd:true});

Slider.Default

val

Slider.OnChange

If(!isChange, UpdateContext({txt:"execute slider.OnChange"}));
UpdateContext({count:count + 1})

CheckStart.Default

isStart

CheckStart.OnCheck

UpdateContext({isChange:true});
UpdateContext({isStart:false})

CheckEnd.Default

isEnd

CheckEnd.OnCheck

UpdateContext({isChange:false});
UpdateContext({isEnd:false})

実際の動作としては以下となります。
(動画を撮影したときは、Endのトグル(右のやつ)の設定値を記載したテキストがStartになっていました。。。正しくはEndです。)

  1. ボタンが押されたことにより、 Button.OnChange が動作
  2. 以下の順で変数が更新
    1. isStarttrue に設定
    2. val に1加算
    3. isEndtrue に設定
  3. 2-1により、トグル(Start)が true になり、startToggle.OnCheck が動作
    1. isChangetrue に設定
    2. isStartfalse に設定
  4. 2-2により、 Slider.OnChange が動作
    1. isChangetrue なので、If 関数内の式は実行されない
    2. count に1加算
  5. 2-3により、トグル(End)が true になり、endToggle.OnCheck が動作
    1. isChangefalse に設定
    2. isEndfalse に設定

ただし、この設定のままでは、ボタンが連打されたときに3以降の動作が平行で行われることになり、 isChange の値が Slider.OnChange 実行時に必ず true であると保障されなくなってしまうので、何らかの方法で処理が完了していないのに、続けてボタンが連打される事態を防ぐなどの予防策を設ける必要があります。

おわりに

ちょっとめんどくさいですが、以上でPower Apps 内で特定の処理が完了したかの監視が行えるようになるかと思います。

もし、私の記載内容で誤っていることや、もっとこうしたほうが良いのでは?や質問などありましたら遠慮なく教えてください。

【Power Apps】レスポンシブ レイアウトを試してみる~その3~

はじめに

この記事はシリーズとしては、
【Power Apps】レスポンシブ レイアウトを試してみる~その1~
【Power Apps】レスポンシブ レイアウトを試してみる~その2~
の続きとなりますが、上記記事をみていなくても問題のない内容となっています。

今回はこれまで作成してきたレスポンシブ レイアウトをテンプレートを用いて簡単に作成していこうと思います。

前提条件

【Power Apps】レスポンシブ レイアウトを試してみる~その1~でも紹介しましたが、改めて解説します。

Power Apps の設定を変更する

Power Apps でアプリを構築した際、初期設定ではアプリをレスポンシブにするための設定がなされておらず、また画面の向きもロックされてしまっています。

f:id:koruneko:20210418033732p:plain

これらの設定をオフにして、アプリをレスポンシブ対応にします。

ファイル > 設定 > 画面のサイズと向き
より、

  • 画面に合わせて倍率を変更
  • 向きをロックする

の設定をオフにします。

f:id:koruneko:20210418034227p:plain

"画面に合わせて倍率を変更"をオフにすると、"縦横比をロックする"も自動でオフになります。("画面に合わせて倍率を変更"をオフにすると、"縦横比をロックする"をオンにすることはできません。)

設定したら忘れずに"適用"を行います。

テンプレートを確認する

ホーム > 新しい画面 から追加可能なスクリーンを確認してみます。
すると、現時点(2021/4/30)では、以下14個の選択肢があることがわかります。
今回紹介するのは、赤枠で囲った

  • 分割画面
  • サイドバー
  • ヘッダー、メインセクション、フッター

の3種です。

f:id:koruneko:20210430035421p:plain

これらは、コンテナーを利用して作成されています。

分割画面

分割画面は以下のように、水平コンテナの中に垂直コンテナが2つ含まれている構成となっています。

f:id:koruneko:20210430042034p:plain

f:id:koruneko:20210430042116p:plain

このデザインを利用することで、例えば以下のように左の項目で選択したアイテムの詳細を右に表示する。といった画面を作成することできます。

f:id:koruneko:20210501004537p:plain

サイドバー

サイドバーは以下のように、水平コンテナの中に垂直コンテナが2つあり、2つめの垂直コンテナ(右側)のコンテナには水平コンテナと垂直コンテナが存在するとい構成となっています。

f:id:koruneko:20210501004644p:plain

f:id:koruneko:20210501004658p:plain

それぞれのコンテナに設定されている比率( FillPortions )は以下のように設定されています。

SidebarContainer : RightSideContainer = 3: 7
HeaderContainer : MainSelectionContainer = 0 : 1

HeaderContainer には FillPortions が設定されておりませんので注意が必要です。

このデザインを利用することで以下のようなデザインの画面が作成可能です。

f:id:koruneko:20210501011901p:plain

MainSelectionContainer には以下のように"スクロール可能"画面より、 Convas をコピペしてきて貼り付けてあげるといい感じの画面が作成できそうです。

f:id:koruneko:20210501012030p:plain

ヘッダー、メインセクション、フッター

ヘッダー、メインセクション、フッターは以下のように垂直コンテナ内に水平コンテナ、垂直コンテナ、水平コンテナの順で構成されています。

f:id:koruneko:20210501012230p:plain

f:id:koruneko:20210501012306p:plain

こちらのコンテナにはMainSelectionContainer のみ FillPortions が 1 に設定されており、他は0(設定なし)となっています。
高さ( Height )はHeaderContainer と FooterContainer それぞれ 75 に設定されています。

こちらのデザインは小林 竜也 さんの「Power Appsのレスポンシブレイアウトをやってみた」シリーズ
Power Appsのレスポンシブレイアウトをやってみた ~準備編~
Power Appsのレスポンシブレイアウトをやってみた ~コンテナ解説編~
Power Appsのレスポンシブレイアウトをやってみた ~ヘッダー解説編~
(最終回)Power Appsのレスポンシブレイアウトをやってみた ~入力フォーム解説編~
で作成されていたような画面が作成できますね。

おわり

以上でPower Apps でのレスポンシブ レイアウトの作成方法紹介のシリーズは終了です。
自分でコンテナ設置した、色々やる作成方法もいいですが、開発時間の短縮や、一般的に利用されているようなレイアウトのサンプルを用いることによってユーザービリティを上げるという観点から今回紹介したテンプレートを用いることも選択肢の1つとしてありなのではないでしょうか。

【Power Apps】レスポンシブ レイアウトを試してみる~その2~

はじめに

この記事は、【Power Apps】レスポンシブ レイアウトを試してみる~その1~の続きになります。
まだ、確認されていない方は先に上記を確認していただければと思います。

前回までは、Power Apps でのレスポンシブ アプリの作成方法に関する簡単な解説と、実際にアプリを作成してみよう!ということでヘッダまで作成しました。

今回はボディ部分の作成を行っていこうと思います。

コンテナを作成する

ボディを作成する

完成イメージはこんな感じです。

早速作成していきます。
まずは、Body 表示領域となるコンテナを配置します。

垂直コンテナを画面内に配置します。

BodyContainer.LayoutDirection

LayoutDirection.Vertical

位置はヘッダー下にくるように設定します。
サイズは横幅は画面いっぱい表示するようにし、高さは、ヘッダーの高さを除いて表示可能な領域だけとるようにします。

BodyContainer.X

0

BodyContainer.Y

HeaderContainer.Y + HeaderContainer.Height

BodyContainer.Width

Parent.Width

BodyContainer.Height

Parent.Height - Self.Y

今後の説明はすべてこのコンテナの配下に設定していきます。

メニューを作成する

まずは、メニューを作成していきます。

この箇所です。

  • PC で表示した場合のデザイン f:id:koruneko:20210421235059p:plain

  • スマホで表示した場合のデザイン
    f:id:koruneko:20210421235241p:plain f:id:koruneko:20210421235306p:plain

PC で表示した場合は、領域が十分あるので、横に一覧で表示させます。
スマホで表示した場合は表示領域が足りないので、非表示にしています。
かといって、縦に一覧で並べるためにわざわざ領域をとるようなものでもないため、ユーザーが表示したい場合のみ任意で表示できるようにしています。

BodyContainer の配下に垂直コンテナを配置してLinkParentContainer という名前にします。

さらにLinkParentContainer 配下に水平コンテナ(LinkContainer) と垂直コンテナ(SmallLinkContainer) を配置します。

f:id:koruneko:20210422002539p:plain

LinkContainer は薄いピンクのところです。
SmallLinkContainer は薄い肌色の箇所です。

LinkParentContainer は以下のように設定します。

LinkParentContainer.Width

Parent.Width

LinkParentContainer.Height

Parent.Height * If(!SmallLinkContainer.Visible, 0.08, 0.5)

LinkContainer は以下のように設定します。

f:id:koruneko:20210422003000p:plain

LinkContainer.LayoutAlignItems

LayoutAlignItems.Center

LinkContainer.Width

Parent.Width

LinkContainer.FillPortions

1

LinkContainer の配下には以下を設定します。

f:id:koruneko:20210422003510p:plain

それぞれ以下のように設定します。
* PowerAppsLink ~ PowerVirtualAgentLinkまでの4つのラベルは設定してあるテキストのリンクと FillPortions が異なるだけなので、 FillPortions 以外は、代表としてPowerAppsLink だけを取り上げています。

HamburgerIcon.Icon

Icon.Hamburger

HamburgerIcon.Height

Parent.Height

HamburgerIcon.Width

Self.Height

HamburgerIcon.Visible

!(BreakPointsLabel.Text in ["Large", "Extra Large"])

LinkLabel.Text

"Link" & If(BreakPointsLabel.Text in ["Large", "Extra Large"], " > ")

LinkLabel.Size

Switch(
    BreakPointsLabel.Text,
    "Small", 6,
    "Medium", 9,
    "Large", 12,
    15
)

LinkLabel.Align

If(HamburgerIcon.Visible, Align.Left ,Align.Right)

LinkLabel.Height

Parent.Height

LinkLabel.FillPortions

If(BreakPointsLabel.Text in ["Large", "Extra Large"], 1, 0)

PowerAppsLink.Text

"Power Apps"

PowerAppsLink.Size

Switch(
    BreakPointsLabel.Text,
    "Small", 6,
    "Medium", 9,
    "Large", 12,
    15
)

PowerAppsLink.Underline

true

PowerAppsLink.Align

Align.Center

PowerAppsLink.Height

Parent.Height

PowerAppsLink.FillPortions

2

PowerAppsLink.Visible

BreakPointsLabel.Text in ["Large", "Extra Large"]

PowerAutomateLink.FillPortions

3

PowerBILink.FillPortions

2

PowerVirtualAgentLink.FillPortions

4

ちょくちょく登場しているin 演算子ですが、対象のデータ内に検索対象の文字が含まれているか?を確認したいときに利用できます。

A in B としたならば、A のデータ内にB のデータが含まれていれば true 含まれていなければ false を返します。
データ内の値全てに対して、if で比較するなどしなくともよくなるので楽でいいですね。

最後にSmallLinkContainer は以下のように設定します。

f:id:koruneko:20210422011648p:plain

SmallLinkContainer.Width

Parent.Width

SmallLinkContainer.FillPortions

If(Self.Visible, 4, 0)

SmallLinkContainer.Visible

isVisibleSmallLink && !(BreakPointsLabel.Text in ["Large", "Extra Large"])

SmallLinkContainer の配下に設定するラベルたちは、先ほど作成したラベルたちをコピーしてきただけなので、説明は割愛します。

FillPortions だけはそれぞれ 1 に設定しておいてください。

f:id:koruneko:20210422011733p:plain

以上でメニュー部の作成は完了です!

メイン部を作成する

メイン部ではPower Platform の各アイコンと簡単な説明(公式サイトより引用)を載せています。
それぞれ以下から引用しています。

Power Apps とは
Power Automate とは
Power BI とは
Power Virtual Agent とは

また、それぞれ OnSelect にて Launch 関数 を設定して、クリック or タップすると、対象のサイトにジャンプするようにしています。

垂直コンテナを配置し、MainContainer にリネームします。
MainContainer の中身は以下のようにしています。

f:id:koruneko:20210423000832p:plain

各Platform 毎に設定はほとんど同じなので、Power Apps のコンテナだけの説明を行います。

MainContainer の配下に垂直 or 水平コンテナを配置します。
今回は画面サイズによってコンテナのレイアウトを可変にしてみようと思うのでどちらを追加しても大丈夫です。(やってみたかった)

PowerAppsContainer.LayoutDirection

If(BreakPointsLabel.Text in ["Large", "Extra Large"], LayoutDirection.Horizontal, LayoutDirection.Vertical)

PowerAppsContainer.LayoutAlignItems

LayoutAlignItems.Center

PowerAppsContainer.Width

Parent.Width

PowerAppsContainer.FillPortions

1

LayoutDirection にて画面サイズによってレイアウトを可変にしています。
LayoutWraptrue にすることで、折り返しが行われるようになるので似たようなことを実装できるかと思います。
気になった方は是非試してみてください。

Platform のコンテナの配下には、イメージとラベルを配置します。

それぞれ以下のように設定します。

Image_PowerApps.Height

Self.Width

Image_PowerApps.FillPortions

1

DescribeLabel_PowerApps.Text

"・Power Apps" & Char(10) &
If(BreakPointsLabel.Text in ["Large", "Extra Large"], "Power Apps は、ビジネス ニーズに合ったカスタム アプリを構築するために短時間でアプリケーションを開発できる環境を提供する、アプリ、サービス、コネクタ、およびデータ プラットフォームのスイートです。 Power Apps を使用すると、基盤となるデータ プラットフォーム (Microsoft Dataverse) または さまざまなオンラインおよびオンプレミスのデータ ソース (SharePoint、Microsoft 365、Dynamics 365、SQL サーバーなど) の いずれか に接続するカスタムのビジネス アプリをすばやく構築できます。")

DescribeLabel_PowerApps.Size

Switch(
    BreakPointsLabel.Text,
    "Small", 6,
    "Medium", 9,
    "Large", 12,
    15
)

DescribeLabel_PowerApps.Height

Parent.Height

DescribeLabel_PowerApps.FillPortions

15

説明のテキストは画面サイズがPC / タブレットの場合のみ表示するようにしています。

同じような設定を他のPlatform にも設定します。

以上でレスポンシブ アプリの作成は完了です!

Power Platform のロゴ・アイコンに関して

今回利用している、Power Platform のアイコンは以下からお借りしました。

Microsoft Power Platform のロゴが変わりました

吉田 大貴 さんありがとうございます!!!

さいごに

コンテナを利用することで、比較的簡単にレスポンシブ アプリが作成できることがわかりました。
記事のなかでも記載していましたが、レスポンシブ アプリを作成するうえで、技術的に気を付けなくてはいけない点は以下2点かと思います。

  • サイズ / 座標には絶対値ではなく、相対値を利用する
  • サイズが変更になったとき文字などがはみ出ていないか

もし、一般的に公開されているようなPC / スマホ対応のWeb サイトのようなものを作成したい!
という場合は、PC 用の画面とスマホ用の画面とでそれぞれ分けて作成し、アクセス時にユーザーの画面サイズによって 、それぞれの画面へ振り分ける(リダイレクト)。
といった作りにしたほうが良いと思います。

ただ、その場合画面数も単純に2倍になるので、

  • 開発工数が増える
  • アプリが重くなる可能性がある

ことに留意ください。
アプリを作成するうえでユーザビリティを向上させるのは利用者目線でいうととても大事なことですが、それによりローコード開発によるメリットが失われると元も子もないですからね。

と、ここまで長々と説明してきましたが、実はPower Apps には初めからコンテナが配置されたレイアウトがテンプレートとして用意されています。

次回はこのテンプレートについて簡単に紹介したいと思いますー。

【Power Apps】レスポンシブ レイアウトを試してみる~その1~

はじめに

Power Apps で、キャンバスアプリを構築する際、最初にアプリをスマホ用のサイズにするか、PC / タブレット用のサイズに調整するかを指定するかと思います。
この選択によってアプリのサイズが決定されます。

しかし、よくあるWEB サイトのようにPC / タブレットで利用する場合は、PC / タブレットのサイズ、レイアウトで利用でき、スマホで確認する場合はスマホのサイズ、レイアウトで利用できるようにしたいという要望もあるかと思います。

これを実現するのが、レスポンシブ レイアウトの設定です。

参考文献

機能を理解するにあたり、参考となった文献は以下です。

Power Apps の設定を変更する

Power Apps でアプリを構築した際、初期設定ではアプリをレスポンシブにするための設定がなされておらず、また画面の向きもロックされてしまっています。

f:id:koruneko:20210418033732p:plain

これらの設定をオフにして、アプリをレスポンシブ対応にします。

ファイル > 設定 > 画面のサイズと向き
より、

  • 画面に合わせて倍率を変更
  • 向きをロックする

の設定をオフにします。

f:id:koruneko:20210418034227p:plain

"画面に合わせて倍率を変更"をオフにすると、"縦横比をロックする"も自動でオフになります。("画面に合わせて倍率を変更"をオフにすると、"縦横比をロックする"をオンにすることはできません。)

設定したら忘れずに"適用"を行います。

画面の幅 / 高さについて

Power Apps で画面の幅 / 高さを取得するための式は大きく分けて以下の3つがあります。

  • ユーザの現在の画面のサイズ
  • アプリ構築自に設定された画面サイズ
  • アプリに設定されている最小画面サイズ

それぞれ実際の数式で表すと以下のようになります。

種類 数式
ユーザの現在の画面の幅 App.Width
ユーザの現在の画面の高さ App.Height
アプリ構築時に設定された画面の幅 App.DesignWidth
アプリ構築時に設定された画面の高さ App.DesignHeight
アプリに設定されている最小画面幅 App.MinScreenWidth
アプリに設定されている最小画面高さ App.MinScreenHeight

これらの特性を理解したうえでコントロールのサイズや座標を動的に設定しましょう。

動的にレイアウトを設定する。がいまいちピンとこない方は、公式docs のキャンバス アプリのレスポンシブ レイアウトの作成 - 動的なレイアウトに数式を使用するセクションを参照してください。

余談ですが、この動的レイアウトの設定はレスポンシブなアプリを作成しないときでも常に意識して設定しておくと、見た目もきっちり揃って綺麗にみえるだけでなく、メンテナンスも行いやすくなるのでおすすめです。
* きちんと意味を持たせた式にすること

カスタムブレークポイント

画面のサイズは、画面の幅をアプリの SizeBreakpoints プロパティの値と比較することにより計算することが可能です 。

このプロパティはPC 用に作成されたアプリの場合、 SizeBreakpoints プロパティの既定値は [600, 900, 1200] になります。
スマホ用に作成されたアプリの場合、規定値は [1200, 1800, 2400] になります。

詳しくは以下公式docs をご覧ください。
キャンバス アプリのレスポンシブ レイアウトの作成 - カスタム ブレークポイント

SizeBreakpoints プロパティと画面幅を比較することで、現在のアプリがどのサイズであるか判定する式を設定します。
ラベルを配置して、 Text に以下式を設定します。

BreakPointsLabel.Text

If(
    App.Width <= First(App.SizeBreakpoints).Value, "Small",
    App.Width <= Last(FirstN(App.SizeBreakpoints, 2)).Value, "Medium",
    App.Width <= Last(FirstN(App.SizeBreakpoints, 3)).Value, "Large",
    "Extra Large"
)

この値を参照することで、文字サイズなどを決定することが可能です。

コンテナを利用する

Power Apps には一連のコントロールを保持するための"コンテナー"というプロパティが存在します。
このコンテナーには大きく分けて3つのタイプが存在します。

  • 水平コンテナー
    このコンテナ内に配置された子要素は、水平方向に配置されます。
  • 垂直コンテナー
    このコンテナ内に配置された子要素は、垂直方向に配置されます。
  • コンテナー
    このコンテナ内に配置された子要素は、自由に要素を配置することができます。

今回は画面サイズに合わせてコンテナのサイズも可変としますので、水平コンテナーと垂直コンテナーを利用します。

コンテナに似た機能として、グループというものがあります。
しかし、こちらのグループではアプリのレイアウトに影響を与えませんので注意が必要です。

コンテナーを配置する

それでは早速コンテナーを画面内に配置していきますが、"挿入"リボンの"入力"からでは、"コンテナー"だけで、"水平コンテナー"と"垂直コンテナー"が見当たりません。

f:id:koruneko:20210418150401p:plain

現時点では、"水平コンテナー"と"垂直コンテナー"を利用したい場合は、画面左の挿入(+マーク)の"レイアウト"より選択する必要があるようですので注意が必要です。

f:id:koruneko:20210418150514p:plain

ヘッダを作成する

水平コンテナーを配置して、以下プロパティを変更します。

コンテナーの範囲が分かりやすいようにコンテナーの塗りつぶしを以下に設定します。

headContainer.Fill

CornflowerBlue

コンテナーのサイズや座標の設定です。
画面サイズが変わったときにレイアウトがおかしくなったりしないように数値を直接指定するような設定は避けましょう。

HeaderContainer.X

0

HeaderContainer.Y

0

HeaderContainer.Width

Parent.Width

HeaderContainer.Height

Parent.Height * 0.15

水平方向の両端揃えの定義です。
以下ですと、”間のスペース”となり、コンテナー内のコントロールが順番に左端、右端、左端...と配置されます。

HeaderContainer.LayoutJustifyContent

LayoutJustifyContent.SpaceBetween

垂直方向の配置設定です。
以下ですと中央揃えとなります。

HeaderContainer.LayoutAlignItems

LayoutAlignItems.Center

コンテナー内に、以下のようにコントロールを配置します。

完成イメージは以下のようにしたいので、

f:id:koruneko:20210418233855p:plain

コントロールの配置の順番は以下と同様にしてください。

f:id:koruneko:20210418232937p:plain

それぞれのコントロールの高さ( Height )は、親コントロールと揃えて

Height

Parent.Height

に設定します。

ラベルのフォントサイズ( Size )は、画面サイズに合わせて可変としたいので、

Size

Switch(
    BreakPointsLabel.Text,
    "Small", 8,
    "Medium", 12,
    "Large", 16,
    20
)

に設定します。

次に、それぞれのコントロールの幅の設定です。

ProfileImage は高さと同値としたいため、

ProfileImage.Width

Self.Height

とします。

NameLabelTitleLabel を中心にもってくるために、
PageNameLabel の幅 = NameLabel の幅 + ProfileImage の幅
となるように設定します。

NameLabel.Width

PageNameLabel.Width - ProfileImage.Width

残る、 PageNameLabelTitleLabel の設定ですが、これらは、残りのコンポーネントの余白分だけのスペースを割り当てるように設定します。
上記の設定は FillPortions で実現できます。

docs.microsoft.com

PageNameLabel.FillPortions

1

TitleLabel.FillPortions

3

上記のように設定することで、以下のようになります。

PageNameLabel
f:id:koruneko:20210419000302p:plain

TitleLabel
f:id:koruneko:20210419000316p:plain

次回は

長くなりそうなので一旦ここまで。
次回はBody 部分の作成を行っていこうと思いますー。

【Power Apps】基数の変換を行うカスタム関数を作成しました!

はじめに

Power Apps のカスタム関数を利用して、基数の変換を行う関数を作成しましたので、その紹介になります。

f:id:koruneko:20210315020449p:plain

なお、式の詳しい解説までは今回行いません。

もし気になる方は、コメントやTwitter などで私に質問していただければと思います。

twitter.com

作成したカスタム関数

HexToDecimal

こちらは16進数から10進数に変換を行うための関数です。
この関数は、Hiro さんのPower Apps の カスタム関数を作ってみよう #Example 2: 16進数から10進数に変換する関数を参考(ほぼ流用)に作成させていただきました。

プロパティ

  • 表示名 - HexToDecimal
  • 説明 - Hex → Decimal
  • プロパティの型 - 出力
  • データ型 - 数値

構文

HexToDecimal(Hex)
  • Hex - 必須。テキスト型。10進数に変換したい16進数。

// https://mofumofupower.hatenablog.com/entry/custom_function_apps
With(
    {
        tblDecimals: AddColumns(
            Sequence(Len(Hex), 0),
            "Decimals",
            With(
                {
                    HexVal: Mid(Hex, Len(Hex) - ThisRecord.Value, 1)
                },
                If(
                    HexVal in Sequence(10, 0), HexVal,
                    LookUp(
                        Table({key:"a", val:10}, {key:"b", val:11}, {key:"c", val:12}, {key:"d", val:13}, {key:"e", val:14}, {key:"f", val:15}),
                        key = Lower(HexVal)
                    ).val
                )
            )
        )
    },
    Sum(tblDecimals, Decimals  * 16 ^ Value)
)

DecimalToHex

こちらは10進数から16進数に変換を行うための関数です。

プロパティ

  • 表示名 - DecimalToHex
  • 説明 - Decimal → Hex
  • プロパティの型 - 出力
  • データ型 - テキスト

構文

DecimalToHex(Decimal)
  • Decimal - 必須。数値型。16進数に変換したい10進数。

With(
    {
        tblHexs: AddColumns(
            Sequence(RoundDown(Ln(Decimal) / Ln(16) + 1, 0), 0),
            "Hexs",
            If(
                ThisRecord.Value = 0, Mod(Decimal, 16),
                Mod(RoundDown((Decimal - Mod(Decimal, 16)) / Power(16, ThisRecord.Value), 0), 16)
            )
        )
    },
    Concat(Sort(tblHexs, Value, Descending),
        Switch(
            Hexs,
            10,"a", 11,"b", 12,"c", 13,"d", 14,"e", 15,"f",
            Hexs
        )
    )
)

BinaryToDecimal

こちらは2進数から10進数に変換を行うための関数です。

プロパティ

  • 表示名 - BinaryToDecimal
  • 説明 - Binary → Decimal
  • プロパティの型 - 出力
  • データ型 - 数値

構文

BinaryToDecimal(Binary)
  • Binary - 必須。数値型。10進数に変換したい2進数。

With(
    {
        tblDecimals: AddColumns(
            Sequence(Len(Text(Binary)), 0),
            "Decimals",
            Power(2, ThisRecord.Value) * Mid(Text(Binary), Len(Text(Binary)) - ThisRecord.Value, 1)
        )
    },
    Sum(tblDecimals, Decimals)
)

DecimalToBinary

こちらは2進数から10進数に変換を行うための関数です。

プロパティ

  • 表示名 - DecimalToBinary
  • 説明 - Decimal → Binary
  • プロパティの型 - 出力
  • データ型 - 数値

構文

DecimalToBinary(Decimal)
  • Decimal - 必須。数値型。2進数に変換したい10進数。

With(
    {
        tblBinaries: AddColumns(
            Sequence(RoundDown(Ln(Decimal) / Ln(2) + 1, 0), 0),
            "Binaries",
            If(
                ThisRecord.Value = 0, Mod(Decimal, 2),
                Mod(RoundDown(Decimal / Power(2, ThisRecord.Value), 0), 2)
            )
        )
    },
    Concat(Sort(tblBinaries, Value, Descending), Binaries & "")
)

現在確認しているバグ

現在以下バグを確認しています。
もし、修正案などある方は教えていただけますと助かります。

10進数から16進数の変換に関して

10進数から16進数の変換に

 \frac{\ln{(Decimal)}}{\ln{(16)}}

としていますが、こちら Decimal にて、  16^{12} - 1 以上の値を設定すると正確な結果が得られなくなります。
これは桁落ちが発生しているためです。

 \frac{\ln{(Decimal)}}{\ln{(16)}} = 11.999999999999998718629398474031
ですが、Power Apps でこちらを計算すると
Ln(281,474,976,710,655) / Ln(16) = 12 となります。(気になる人は試してみてください。)

10進数から2進数の変換に関して

10進数から2進数への変換の際に結果に 2 が出力される場合があります。

f:id:koruneko:20210315020402p:plain

ロジックのミスも疑いましたが、こちらの関数の式をアプリ内にべた書きした結果想定通りの結果が返ってきました。

f:id:koruneko:20210315020940p:plain

カスタム関数はまだプレビュー機能ですので、不具合の可能性もありますが引き続き調査を行います。

この事象の共通点は現在まだ発見できておりません。

もしなにかわかる方がいたら教えていただけますと助かります。

おわりに

今回紹介したカスタム関数は私の以下Github にて公開しておきました。

github.com

使用に関しては自己責任でお願いします。

不具合、ご要望があれば教えてください。

Github のReadMe でTeX の表示上手くいってないですね。
今度直さないと。。。

【Power Apps】カスタム関数で当たり判定を作成する

はじめに

この記事ではPower Apps のカスタム関数を利用して、当たり判定関数の作成方法について解説します。

今回取り扱う当たり判定は、

  • 四角 × 四角
  • 円 × 円
  • 四角 × 円

の3パターンです。

当たり判定を作成する

Power Apps のカスタム関数ってなに?という方は、【Power Apps】カスタム関数が作成できるようになりました! を先にご覧ください。

四角 × 四角

まずは一番単純な四角 × 四角の当たり判定を作成します。

この当たり判定の式は、【GPPB Virtual Bootcamp 2021 Sapporo】30分で作成!?解説しながら作る横スクアクションゲームで解説した式を利用します。

今回は上記ブログの流用で、再度の解説は省きます。

当たり判定は以下のようにPlayer とStage を定義したとき

f:id:koruneko:20210214163618p:plain

以下のような式であらわすことができます。

((PlayerX > StageX && PlayerX < StageX + StageWidth) || (StageX > PlayerX && StageX < PlayerX + PlayerWidth)) && ((PlayerY > StageY && PlayerY < StageY + StageHeight) || (StageY > PlayerY && StageY < PlayerY + PlayerHeight))

まず2つの図形が"重なっている"というのは、下図のようにX成分でみたときもY成分でみたときも重なっている。
というのが条件になります。

f:id:koruneko:20210214164617p:plain

上の式でいいますと、
この式がX成分の重なり判定で

((PlayerX > StageX && PlayerX < StageX + StageWidth) || (StageX > PlayerX && StageX < PlayerX + PlayerWidth))

この式がY成分の重なり判定です。

((PlayerY > StageY && PlayerY < StageY + StageHeight) || (StageY > PlayerY && StageY < PlayerY + PlayerHeight))

これら2つの条件を満たしているとき、重なっていると判断できるので && でそれぞれの式を繋げているわけです。

プロパティは以下のように設定します。

表示名

SquareSquare

プロパティの型

出力

データ型

ブール値

パラメーターには以下のようなものを作成します。

パラメータ名 データ型 役割
x_1 数値 オブジェクトAのX座標
y_1 数値 オブジェクトAのY座標
width_1 数値 オブジェクトAの幅
height_1 数値 オブジェクトAの高さ
x_2 数値 オブジェクトBのX座標
y_2 数値 オブジェクトBのY座標
width_2 数値 オブジェクトBの幅
height_2 数値 オブジェクトBの高さ

最後に四角 × 四角の当たり判定の式を設定します。

SquareSquare

((x_1 > x_2 && x_1 < x_2 + width_2) ||
(x_2 > x_1 && x_2 < x_1 + width_1)) &&
((y_1 > y_2 && y_1 < y_2 + height_2) ||
(y_2 > y_1 && y_2 < y_1 + height_1))

これで四角形のオブジェクトA, B の情報を渡すことで、当たり判定を行うことができます。

当たっている場合は、 true 当たっていない場合は false ですね。

円 × 円

プロパティは以下のように設定します。

表示名

CircleCircle

プロパティの型

出力

データ型

ブール値

パラメーターには以下のようなものを作成します。

パラメータ名 データ型 役割
x_1 数値 オブジェクトAの中心のX座標
y_1 数値 オブジェクトAの中心のY座標
r_1 数値 オブジェクトAの半径
x_2 数値 オブジェクトBの中心のX座標
y_2 数値 オブジェクトBの中心のY座標
r_2 数値 オブジェクトBの変形

円と円の当たり判定にはピタゴラスの定理を活用します。

パラメータの値を図にして表すと以下のようになります。

f:id:koruneko:20210306200901p:plain

このとき、2つの円の距離は三平方の定理によって求めることが可能ですね。

f:id:koruneko:20210306201529p:plain

 c^{2} = a^{2} + b^{2}

このとき、
 a = x_1 - x_2
 b = y_1 - y_2
 x_1 などは x_1 に読み替えてください。
であるので2つの円の距離は、
 \sqrt{(x_1 - x_2)^{2} + (y_1 - y_2)^{2}}
となります。

この2つの円の距離と、2つの円の半径の和を比較して、この2つの円の距離が2つの円の半径の和以下であれば2つの円が接していると判断することができます。
 \sqrt{(x_1 - x_2)^{2} + (y_1 - y_2)^{2}}  \leqq r_1 + r_2

このとき、より式の記載を簡単にするために左辺の平方根を右辺を乗算することで簡略化させましょう。
 (x_1 - x_2)^{2} + (y_1 - y_2)^{2}  \leqq (r_1 + r_2)^{2}

上記をPower Apps で式にすると以下になります。

CircleCircle

Power(x_1 - x_2, 2) + Power(y_1 - y_2, 2) < Power(r_1 + r_2, 2)

これで円形のオブジェクトどうしの当たり判定を実装することができました!

四角 × 円

最後に四角形と円の当たり判定です。
これはちょっと複雑になってきます。

まずはカスタムプロパティの作成です。
以下のように設定します。

表示名

SquareCircle

プロパティの型

出力

データ型

ブール値

パラメーターには以下のようなものを作成します。

パラメータ名 データ型 役割
x_1 数値 四角形オブジェクトのX座標
y_1 数値 四角形オブジェクトのY座標
width 数値 四角形オブジェクトの幅
height 数値 四角形オブジェクトの高さ
x_2 数値 円形オブジェクトの中心のX座標
y_2 数値 円形オブジェクトの中心のY座標
r 数値 円形オブジェクトの変形

四角形と円の当たり判定の理論については以下サイトが大変わかりやすく解説をしてくれていました。
円と長方形の当たり判定

こちらのサイトに記載の式をPower Apps で記載すると以下のようになります。

SquareCircle

// 矩形上下領域
(x_2 > x_1) && (x_2 < x_1 + width) && (y_2 > y_1 - r) && (y_2 < y_1 + height + r) ||
// 矩形左右領域
(x_2 > x_1 - r) && (x_2 < x_1 + width + r) && (y_2 > y_1) && (y_2 < y_1 + height) ||
// 左上の円
Power(x_1 - x_2, 2) + Power(y_1 - y_2, 2) < Power(r, 2) ||
// 右上の円
Power((x_1 + width) - x_2, 2) + Power(y_1 - y_2, 2) < Power(r, 2) ||
// 右下の円
Power((x_1 + width) - x_2, 2) + Power((y_1 + height) - y_2, 2) < Power(r, 2) ||
// 左下の円
Power(x_1 - x_2, 2) + Power((y_1 + height) - y_2, 2) < Power(r, 2)

なおこのとき、
 A = 矩形上下領域
 B = 矩形左右領域
 C = 左上の円
 D = 右上の円
 E = 左下の円
 F = 右下の円
です。

実際に利用してみる

では、作成したカスタム関数を実際に利用してみましょう!

まずは、先ほど作成したカスタム関数を画面内に追加します。

続いて以下のようなコレクションを作成して、ステージの情報を作成します。

ClearCollect(
    stage,
    {x:0, y:0, width:0, height:0, Type:"Square"},
    {x:0, y:Self.Height / 2, width:150, height:150, Type:"Square"},
    {x:200, y:100, width:150, height:150, Type:"Square"},
    {x:500, y:300, width:300, height:150, Type:"Square"},
    {x:1000, y:70, width:150, height:400, Type:"Square"},
    {x:50, y:100, r:50, Type:"Circle"},
    {x:300, y:400, r:100, Type:"Circle"},
    {x:600, y:650, r:70, Type:"Circle"},
    {x:650, y:90, r:90, Type:"Circle"},
    {x:1200, y:550, r:40, Type:"Circle"},
    {x:0, y:0, r:0, Type:"Circle"}
)

今回はこの情報をもとに、SVG でステージを描画したいと思います。

イメージを追加して以下のように設定します。

Image.Image

"data:image/svg+xml,"& 
EncodeUrl(
    "<svg viewBox='0 0 "& Self.Width & " " & Self.Height & "' xmlns='http://www.w3.org/2000/svg'>" &
        Concat(
            ForAll(
                stage,
                Switch(
                    Type,
                    "Square",
                    "<rect 
                        x='" & x &"' 
                        y='" & y &"' 
                        width='" & width &"' 
                        height='" & height &"' 
                    />",
                    "Circle",
                    "<circle 
                        cx='" & x &"' 
                        cy='" & y &"'
                        r='" & r &"'   
                    />"
                )
            ),
            Value
        ) & "
    </svg>"
)

次にこのステージのオブジェクトとの当たり判定を行うオブジェクトを設置します。
今回

  • 四角 × 四角
  • 円 × 円
  • 四角 × 円

の3パターンの当たり判定を作成しており、オブジェクトの種類は四角形と円の2種なので、"アイコン"より"四角形"と"円"の2つを追加してください。
これらは現在選択している値によって切り替えたいと思います。
"ラジオ"を追加して以下のように設定します。

Radio1.Items

["Square", "Circle"]

文字通り、このラジオにて選択されているオブジェクトを表示したいため、それぞれのオブジェクトの Visible で以下のように設定します。

Rectangle1.Visible

Radio1.Selected.Value = "Square"

Circle1.Visible

Radio1.Selected.Value = "Circle"

また、円に関しては楕円ではなく、真円での当たり判定なので、高さと幅は同じ値となるようにしておきましょう。

Circle1.Height

Self.Width

※ 楕円の当たり判定の式は大分複雑な計算式となるので省いています。
  実装が大変なのはもちろんですが、Power Apps で当たり判定のような頻繁に呼ばれるようなものでそのような複雑な計算式は処理性能の観点から避けるべきではないかなぁ。。。と個人的には考えています。
  式に関しては興味のある方は是非調べてみてください。

次にこのオブジェクトたちを動かすためのスライダーを設定します。
今回は簡単のために、X座標用のスライダーとY座標用のスライダーの2つを作成しましょう。

X座標用のスライダーの最大値は Parent.Width に、Y座標用のスライダーのスライダーの最大値は Parent.Height に設定しておきます。

設定ができたら、スライダーの値がオブジェクトの XY に設定されるようにしましょう。

X

X

Y

Parent.Height - Y

※ スライダーの名前をそれぞれXとYにしています。
これでスライダーの値を変えることでオブジェクトの座標も変わるようになったかと思います。

これでオブジェクトたちの用意はできたので、最後に当たり判定です。

当たり判定は、これまでの私のブログでも紹介してきたように、トグル(切り替え)を利用します。

トグルの Defaule に以下のように設定します。

Toggle1

CountIf(
    ForAll(
        stage,
        If(
            Type = "Square" && Radio1.Selected.Value = "Square",
            CollisionUtils_1.SquareSquare(
                Rectangle1.X, Rectangle1.Y, Rectangle1.Width, Rectangle1.Height,
                x, y, width, height
            ),
            Type = "Circle" && Radio1.Selected.Value = "Square",
            CollisionUtils_1.SquareCircle(
                Rectangle1.X, Rectangle1.Y, Rectangle1.Width, Rectangle1.Height,
                x, y, r
            ),
            Type = "Circle" && Radio1.Selected.Value = "Circle",
            CollisionUtils_1.CircleCircle(
                Circle1.X + Circle1.Width / 2, Circle1.Y + Circle1.Height / 2, Circle1.Width / 2,
                x, y, r
            ),
            Type = "Square" && Radio1.Selected.Value = "Circle",
            CollisionUtils_1.SquareCircle(
                x, y, width, height,
                Circle1.X + Circle1.Width / 2, Circle1.Y + Circle1.Height / 2, Circle1.Width / 2
            )
        )
    ),
    Value = true
) > 0

簡単に解説します。
オブジェクト間の当たり判定を行うのは、"コレクションに設定された値" と "オブジェクトの値" です。
コレクションの情報を取得するために ForAll 関数を利用しています。
このとき1レコードでも接している、つまり True のものが1レコードでもあれば接していると判断できるため、CoutIf 関数の結果が0より多きければ、オブジェクトどうしが接していると判断することができます。

また、オブジェクトどうしの組み合わせで呼び出す関数が異なるので、If 関数でそれぞれ呼び出す関数をわけています。

この関数の呼び出し時1点注意すべき事項があります。
作成した関数では、円の中心座標を受け取ることを想定しています。

SVG で円を描画する際の、 circle では円の中心座標と半径を指定して描画するのに対し、Power Apps のオブジェクトである Circle は円の左上上端の座標と直径の座標を指定して描画します。

これらの違いを認識する必要があります。

よって、Power Apps で描画されている円の中心のX座標を取得するには Circle1.X + Circle1.Width / 2 とし、円の中心のY座標を取得するには Circle1.Y + Circle1.Height / 2 とし、円の半径を取得するには Circle1.Width / 2 とする必要があります。

最後に当たったとされた場合に視認しやすいようにしましょう。
今回はこれをオブジェクトの色を変更することでわかるようにしたいと思います。

Fill

If(
    Toggle1.Value,
    Red,
    RGBA(56, 96, 178, 1)
)

以上で完了です!
お疲れさまでした!!

おわりに

こういったよく使うような汎用的な式を関数化することによって、今後の開発を高速化することが可能になります。

次はダメージ計算とかを関数化してみて、"~ゲームを作りながら覚える~ Power Apps のカスタム関数"とかやりたいですね。

Power Apps のカスタム関数で入力パラメータにレコード / テーブルを利用する際の覚書

はじめに

この記事では、Power Apps のカスタム関数でパラメータにレコード、及びテーブルを利用する際の覚書になります。
もし誤っている内容や、私の理解が足りないような記載がありましたら指摘してもらえると助かります。

また、現時点(2021/02/28)ではカスタム関数はPreview 機能なため、この記事をご覧になっている際には機能などが大幅に変更になっている可能性がありますので、 ご注意ください。

カスタム関数とは

カスタム関数ってなに?という方は、以前私が簡単にまとめた記事があるので、まずはそちらをご覧になってください。

koruneko.hatenablog.com

パラメータを利用してみる

レコード

入力、及び出力のデータ型にレコードを設定した場合の動作についてです。

以下のように設定します。

f:id:koruneko:20210228181307p:plain

左上のプロパティを選択すると先ほど作成した、関数とパラメータが存在します。

f:id:koruneko:20210228181551p:plain

Record_record の式をみてみると以下のように設定されています。

Record_record

{SampleStringField: "SampleText", SampleNumberField: 10, SampleBooleanField: true}

この式がなにを表しているのか?というと、関数を呼び出す際のパラメータに渡すレコードのフィールドを定義しています。

ここで定義したようなレコード以外を渡すとエラーになってしまうので、注意が必要です。

アウトプットは、 Record で定義します。

Record

{SampleStringField: "[" & record.SampleStringField & "]", SampleNumberField: record.SampleNumberField * 2, SampleBooleanField: true}

今回はテストのため、与えられたレコードを少し加工して返すだけにしています。

画面に戻り、この関数を呼び出してみましょう。

Gallery.Items

Component1_1.Record({SampleStringField: "Text", SampleNumberField: 100, SampleBooleanField: true})

f:id:koruneko:20210228185947p:plain

先ほど作成した関数に予め定義されたようなレコードを渡すと、 SampleStringField の値は前後に"[]"を付けて、 SampleNumberField の値は2を乗算した値が返ってきていることが確認できます。

また、下記の画像のように異なるフィールドのレコードを渡すとエラーになってしまうということも確認できました。

f:id:koruneko:20210228190428p:plain

テーブル

続いてパラメータの型にテーブルを設定した場合です。

基本的にレコードの時と考え方は同じです。

以下のように設定します。

f:id:koruneko:20210228191246p:plain

テーブルのときもレコードのときと同様にフィールドの定義が必要です。

Tabele_table

Table({SampleStringField: "SampleText", SampleNumberField: 10, SampleBooleanField: true})

出力には以下のように加工したテーブルを返します。

Table

ForAll(
    table,
    {
        SampleStringField: "{" & SampleStringField & "}",
        SampleNumberField: SampleNumberField / 2,
        SampleBooleanField: SampleBooleanField
    }
)

SampleStringField では、渡された文字列を"{}"で囲って返し、 SampleNumberField では渡された値を2で割った値を返すようにしています。

画面のほうで、実際に動作確認してみましょう。

Gallery.Items

Component1_1.Tabel(
    Table(
        {SampleStringField: "a", SampleNumberField: 10, SampleBooleanField: false},
        {SampleStringField: "b", SampleNumberField: 50, SampleBooleanField: true}
    )
)

f:id:koruneko:20210228192951p:plain

ちゃんと動いていますね。

テーブルでは、すべてのレコードで定義したフィールドが存在している必要はありません。

f:id:koruneko:20210228193117p:plain

f:id:koruneko:20210228193310p:plain

ただし、どこかのレコードで少なくとも1つは設定されたフィールドが含まれている必要があります。

f:id:koruneko:20210228193510p:plain

これはコレクションを作成したときの動作と同様、対象フィールドが設定されていないレコードはそのフィールドが0や空白、false などとして扱われるからですね。
つまり実際はそのレコードには省略しているフィールドも存在しているというわけです。

動作が不安定?

簡単な使い方は上記でわかりました。

これからは、使用していた中でちょっと動作が怪しいな?と思ったものを纏めました。
なお、冒頭でも述べている通りこれはまだPreview 機能なので修正などの処置が行われる可能性があります。

テーブルの入力フィールドが更新されない

テーブルの入力フィールドを以下のように修正しました。
SampleNumberField を削除しています。

Table_table

Table({SampleStringField: "SampleText", SampleBooleanField: true})

Table

ForAll(
    table,
    {
        SampleStringField: "{" & SampleStringField & "}",
        SampleNumberField: 10,
        SampleBooleanField: SampleBooleanField
    }
)

これに伴い出力も変更しています。

この修正を行ったうえで画面でこのカスタム関数を呼び出している式を修正しましょう。

SampleNumberField が不要になったので削除します。

f:id:koruneko:20210228194247p:plain

すると上記のようにフィールドが異なる旨のエラーが出力されてしまいました。

これは変更が反映されていないのが原因です。
現時点での対策として、カスタム関数を保存し直すという手があります。

説明を適当に修正して保存し直しましょう。

これでも直らなかった場合は、まずはアプリを保存しましょう。

やると不味い行動として、
対象のコンポーネントを削除 -> 再度対象コンポーネントを追加
というのがあります。

これをするとどうなるか?というと以下のようなエラーが表示され、アプリがクラッシュします。(しました)

f:id:koruneko:20210228195057p:plain

WebAuthoring abnormal termination. Client date/time: 2021-02-28T10:47:51.149Z Version: 3.21023.28 (v3.21023.28.179268482) Session ID: ed3cfda3-7c17-44c3-948e-67cf1293852e description: {"exception":{"message":"XMLHttpRequest error(string). {\"traceLevel\":3,\"message\":\"An error occurred in Document API document.createcompletecontrol, activity id 572d8111-aa18-4ba1-8aca-e417fa34a389\",\"status\":500}","name":"UnhandledError","isCritical":true,"detail":{"exception":{}}},"error":"[circular]","promise":{"oncancel":null,"nextState":null,"state":{"name":"error","enter":"[function]","cancel":"[function]","done":null,"then":null,"completed":"[function]","error":"[function]","notify":"[function]","progress":"[function]","setCompleteValue":"[function]","setErrorValue":"[function]"},"listeners":null,"value":"[circular]","isException":false,"errorId":16,"done":"[function]","then":"[function]"},"id":16,"setPromise":"[function]"} stack: UnhandledError: XMLHttpRequest error(string). {"traceLevel":3,"message":"An error occurred in Document API document.createcompletecontrol, activity id 572d8111-aa18-4ba1-8aca-e417fa34a389","status":500} at t [as constructor] (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:205175) at new t (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:245836) at o.translateError (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/AppMagic.WebAuthoring.js?v=3.21023.28.179268482:1:509997) at o.raiseTerminalError (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/AppMagic.WebAuthoring.js?v=3.21023.28.179268482:1:509279) at o.unhandledException (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/AppMagic.WebAuthoring.js?v=3.21023.28.179268482:1:509192) at o. (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/AppMagic.WebAuthoring.js?v=3.21023.28.179268482:1:507788) at https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:307766 at Object.throw (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:307872) at u (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:306691) at Object.q [as notify] (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/openSource/modified/winjs/js/base.js?v=3.21023.28.179268482:2:38070) errorNumber: 0 errorMessage: XMLHttpRequest error(string). {"traceLevel":3,"message":"An error occurred in Document API document.createcompletecontrol, activity id 572d8111-aa18-4ba1-8aca-e417fa34a389","status":500} callStack: UnhandledError: XMLHttpRequest error(string). {"traceLevel":3,"message":"An error occurred in Document API document.createcompletecontrol, activity id 572d8111-aa18-4ba1-8aca-e417fa34a389","status":500} at t [as constructor] (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:205175) at new t (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:245836) at o.translateError (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/AppMagic.WebAuthoring.js?v=3.21023.28.179268482:1:509997) at o.raiseTerminalError (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/AppMagic.WebAuthoring.js?v=3.21023.28.179268482:1:509279) at o.unhandledException (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/AppMagic.WebAuthoring.js?v=3.21023.28.179268482:1:509192) at o. (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/AppMagic.WebAuthoring.js?v=3.21023.28.179268482:1:507788) at https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:307766 at Object.throw (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:307872) at u (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/js/Core.js?v=3.21023.28.179268482:1:306691) at Object.q [as notify] (https://cdn-paaprodejp.azureedge.net/v3.21023.28.179268482/studio/openSource/modified/winjs/js/base.js?v=3.21023.28.179268482:2:38070)

他操作も私が確認できていないだけで、やると不味いことが多々ありそうなので、保存するなりで対策しましょう。
また、修正した入力パラメータを元に戻しておくのもよさそうですね。
恐らく裏で不正なデータ扱いされていて非常に不安定な状態だと思いますので。。。

なおこの問題は型:レコードでは確認できませんでした。

型が勝手にテーブルからレコードに変更される

仕様??わからないですが、事実としての動作を記しておきます。

パラメータをテーブルではなくレコードにしてみます。

Table_tabel

{SampleStringField: "SampleText", SampleBooleanField: true}

このカスタム関数を呼び出している箇所を確認してみると以下エラーが表示されています。

f:id:koruneko:20210228200102p:plain

対象カスタム関数のパラメータをみてみると、以下のようにテーブル -> レコードに型が変わっています。

f:id:koruneko:20210228200259p:plain

仕様??型解決してくれてる??(正直余計な事しないでほしい)

f:id:koruneko:20210228200404p:plain

ただ、逆に入力項目の型:レコードの項目にテーブルを設定しようとすると、上記のようなエラーが出力されるので、恐らく、型:テーブルを設定しているにも関わらずレコード型を設定できることがよくないんでしょうね。

型:テーブルを設定した際の入力パラメータの型チェックに漏れがあるのですかね。
実際のソースみることができないので憶測になりますが、そんな感じがします。

おわりに

冒頭でも述べている通り、カスタム関数の作成はPreview 機能なので今後機能が変更になることがあります。

また、なにか誤っていたりした場合は教えていただけると助かります。


スポンサードリンク