- 投稿日:2020-04-21T23:11:23+09:00
View を支えるトリガーアクション
はじめに
オレオレ解釈の覚え書き その5
トリガーアクションについてです。
※今回も Expression Blend に付属する Trigger, Action について触れていきます。本文
トリガーは動作のきっかけを通知する機構で、トリガーが何かを感知したときに行われる処理がアクションです。これらはセットで使用されるため、まとめてトリガーアクションと呼ばれています。
トリガーにはいくつか種類があります。ここではコントロールのイベント発生を感知する EventTrigger を使ってみます。以下の例では、メッセージボックスを表示するアクションを用意し、ウィンドウがロードされたときに起動するように紐づけています。TriggerActionnamespace TestApp.Views.Behaviors { public class MessageAction : TriggerAction<DependencyObject> { protected override void Invoke(object parameter) { var owner = this.AssociatedObject as Window ?? Window.GetWindow(this.AssociatedObject); MessageBox.Show(owner, "メッセージ", "タイトル", MessageBoxButton.OK, MessageBoxImage.Information); } } }View<Window x:Class="TestApp.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:behaviors="clr-namespace:TestApp.Views.Behaviors"> <!-- トリガーとアクションを設定できる --> <i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <behaviors:MessageAction/> </i:EventTrigger> </i:Interaction.Triggers> </Window>この例のような動作はビヘイビアでも実現できるでしょう。両者の違いは、同じ処理をさせるか、同じふるまいをさせるかにあります。アクションは処理だけが切り出されており、特定のイベントに依存しません。イベントの感知はトリガーに任せています。一方でビヘイビアは処理のきっかけとなるイベントまで丸ごと部品化されています。
おわりに
今回はトリガーアクションについてでした。
数回に分けてまとめてきた View を支える要素ですが、少し掘り下げただけでも、この構成の奥深さが垣間見えてきます。これらの仕組みを活用することで、処理どうしの癒着が減り、再利用しやすいプログラムの構築に近づくはずです。View は一区切りにして、次回は ViewModel の相互作用処理についてまとめてみます。今回のテーマであるトリガーアクションにも関係がある仕組みになります。
- 投稿日:2020-04-21T22:48:58+09:00
今更ながらWPFに置き換えてみる(14)
クリック透過ON/OFFの機能追加
アイコンモードで表示する際、秒とかアナログ時計とかののイメージだけをWindow化して画面に出します。そもそも地味機能ツールなんで、透過させて目立たない表示にできるという意図なんですが、どうせなら設定でクリックイベントを透過させてみようということで方法を検索するとQiita内のページにありがたい記述がありました「→WPF で オーバーレイ表示をする」
クリック透過にすると当然対象Window上のコントロール操作ができなくなるので、そこはNotifyIcon上のコンテキストメニューでON/OFF可能にしてみました。また同じメニュー内でWindowのTOPMOSTも同様に切り替えできる設定なので、クリック透過のON/OFFの判定時にはその分の計算をやってます。
public class G { //・・・略 public static int catch_extendStyle; //拡張WINDOW イベント受け public static int through_extendStyle; // イベント透過 } //・・・中略・・・ //Icon mode Ignore click event protected const int GWL_EXSTYLE = (-20); protected const int WS_EX_TRANSPARENT = 0x00000020; protected const int WS_EX_TOPMOST = 0x00000008; //・・・中略・・・ protected override void OnSourceInitialized(EventArgs e) { //Icon Mode時のクリックEventの受け・スルー切り替え base.OnSourceInitialized(e); //WindowHandle(Win32) を取得 var handle = new WindowInteropHelper(this).Handle; //クリックをキャッチ int extendStyle = GetWindowLong(handle, GWL_EXSTYLE); G.catch_extendStyle = extendStyle; //クリックをスルー extendStyle |= WS_EX_TRANSPARENT; //フラグの追加 G.through_extendStyle = extendStyle; //初期はキャッチで設定 SetWindowLong(handle, GWL_EXSTYLE, G.catch_extendStyle); } //・・・中略・・・ private void NotifyIcon_MenuItem_Click(object sender, RoutedEventArgs e) { //ノティファイアイコン上でのコンテキストメニュー全般の処理 MenuItem selectedItem = (MenuItem)sender; switch (selectedItem.Tag.ToString()) { case "0": //show/hide //・・・中略・・・ case "8": //Icon Mode click ignore on/off if (G.MODE == 2) //ICONモードの場合のみ許可 { var handle = new WindowInteropHelper(this).Handle; int extendStyle = GetWindowLong(handle, GWL_EXSTYLE); if (this.Topmost == false) { extendStyle ^= WS_EX_TOPMOST; //TopMostの場合はその分の値を減算 } if (extendStyle == G.catch_extendStyle) { SetWindowLong(handle, GWL_EXSTYLE, G.through_extendStyle); this.IgnoreEvent.IsChecked = true; } else { SetWindowLong(handle, GWL_EXSTYLE, G.catch_extendStyle); this.IgnoreEvent.IsChecked = false; } } else this.IgnoreEvent.IsChecked = false; break; //・・・中略・・・ } }こんな感じになります。
(クリック受け→クリック無視→TOPMOST→クリック受けで変化させています)時報お知らせ表示
- 投稿日:2020-04-21T22:48:58+09:00
今更ながらWPFに置き換えてみる(13)
クリック透過ON/OFFの機能追加
アイコンモードで表示する際、秒とかアナログ時計とかののイメージだけをWindow化して画面に出します。そもそも地味機能ツールなんで、透過させて目立たない表示にできるという意図なんですが、どうせなら設定でクリックイベントを透過させてみようということで方法を検索するとQiita内のページにありがたい記述がありました「→WPF で オーバーレイ表示をする」
クリック透過にすると当然対象Window上のコントロール操作ができなくなるので、そこはNotifyIcon上のコンテキストメニューでON/OFF可能にしてみました。また同じメニュー内でWindowのTOPMOSTも同様に切り替えできる設定なので、クリック透過のON/OFFの判定時にはその分の計算をやってます。
public class G { //・・・略 public static int catch_extendStyle; //拡張WINDOW イベント受け public static int through_extendStyle; // イベント透過 } //・・・中略・・・ //Icon mode Ignore click event protected const int GWL_EXSTYLE = (-20); protected const int WS_EX_TRANSPARENT = 0x00000020; protected const int WS_EX_TOPMOST = 0x00000008; //・・・中略・・・ protected override void OnSourceInitialized(EventArgs e) { //Icon Mode時のクリックEventの受け・スルー切り替え base.OnSourceInitialized(e); //WindowHandle(Win32) を取得 var handle = new WindowInteropHelper(this).Handle; //クリックをキャッチ int extendStyle = GetWindowLong(handle, GWL_EXSTYLE); G.catch_extendStyle = extendStyle; //クリックをスルー extendStyle |= WS_EX_TRANSPARENT; //フラグの追加 G.through_extendStyle = extendStyle; //初期はキャッチで設定 SetWindowLong(handle, GWL_EXSTYLE, G.catch_extendStyle); } //・・・中略・・・ private void NotifyIcon_MenuItem_Click(object sender, RoutedEventArgs e) { //ノティファイアイコン上でのコンテキストメニュー全般の処理 MenuItem selectedItem = (MenuItem)sender; switch (selectedItem.Tag.ToString()) { case "0": //show/hide //・・・中略・・・ case "8": //Icon Mode click ignore on/off if (G.MODE == 2) //ICONモードの場合のみ許可 { var handle = new WindowInteropHelper(this).Handle; int extendStyle = GetWindowLong(handle, GWL_EXSTYLE); if (this.Topmost == false) { extendStyle ^= WS_EX_TOPMOST; //TopMostの場合はその分の値を減算 } if (extendStyle == G.catch_extendStyle) { SetWindowLong(handle, GWL_EXSTYLE, G.through_extendStyle); this.IgnoreEvent.IsChecked = true; } else { SetWindowLong(handle, GWL_EXSTYLE, G.catch_extendStyle); this.IgnoreEvent.IsChecked = false; } } else this.IgnoreEvent.IsChecked = false; break; //・・・中略・・・ } }こんな感じになります。
(クリック受け→クリック無視→TOPMOST→クリック受けで変化させています)時報お知らせ表示
- 投稿日:2020-04-21T22:48:58+09:00
今更ながらWPFに置き換えてみる(13)
クリック透過ON/OFFの機能追加
アイコンモードで表示する際、秒とかアナログ時計とかののイメージだけをWindow化して画面に出します。アプリにはWindow透過設定を持ってます(Window Opacity利用)。そもそも地味機能ツールなんで、透過させて目立たない表示にできるという意図なんですが、どうせなら設定でクリックイベントを透過させたほうがいいんではと思い、んで方法を検索するとQiita内のページにありがたい記述がありました「→WPF で オーバーレイ表示をする」
クリック透過にすると当然対象Window上のコントロール操作ができなくなるので、NotifyIcon上のコンテキストメニューでON/OFF切り替え可能に。メインウインドウひらっきっぱなし→ずっとWinハンドラ値は変わらないので、最初にグローバルにクリック受けと無視のそれぞれの値を保存しておきます。
WindowのTOPMOSTも変更可能にしてるので、コンテキストメニューでのクリック透過のON/OFFの判定時にはTOPMOST値も考慮してスイッチしてます。public class G { //・・・略 public static int catch_extendStyle; //拡張WINDOW イベント受け用の保存変数 public static int through_extendStyle; // イベント透過用の保存変数 } //・・・中略・・・ //Icon mode Ignore click event protected const int GWL_EXSTYLE = (-20); protected const int WS_EX_TRANSPARENT = 0x00000020; //透過時の値 protected const int WS_EX_TOPMOST = 0x00000008; //topmost時の値 [DllImport("user32")] protected static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32")] protected static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwLong); //・・・中略・・・ protected override void OnSourceInitialized(EventArgs e) { //Icon Mode時のクリックEventの受け・スルー切り替え base.OnSourceInitialized(e); //WindowHandle(Win32) を取得 var handle = new WindowInteropHelper(this).Handle; //クリックをキャッチする場合の値を算出して保存 int extendStyle = GetWindowLong(handle, GWL_EXSTYLE); G.catch_extendStyle = extendStyle; //クリックをスルーする場合の値を算出して保存 extendStyle |= WS_EX_TRANSPARENT; //フラグの追加 G.through_extendStyle = extendStyle; //初期はキャッチで設定 SetWindowLong(handle, GWL_EXSTYLE, G.catch_extendStyle); } //・・・中略・・・ private void NotifyIcon_MenuItem_Click(object sender, RoutedEventArgs e) { //ノティファイアイコン上でのコンテキストメニュー全般の処理 MenuItem selectedItem = (MenuItem)sender; switch (selectedItem.Tag.ToString()) { case "0": //show/hide //・・・中略・・・ case "8": //Icon Mode click ignore on/off if (G.MODE == 2) //ICONモードの場合のみ許可 { var handle = new WindowInteropHelper(this).Handle; int extendStyle = GetWindowLong(handle, GWL_EXSTYLE); if (this.Topmost == false) { extendStyle ^= WS_EX_TOPMOST; //TopMostでない場合はその分の値を減算 } if (extendStyle == G.catch_extendStyle) { SetWindowLong(handle, GWL_EXSTYLE, G.through_extendStyle); this.IgnoreEvent.IsChecked = true; } else { SetWindowLong(handle, GWL_EXSTYLE, G.catch_extendStyle); this.IgnoreEvent.IsChecked = false; } } else this.IgnoreEvent.IsChecked = false; break; //・・・中略・・・ } }こんな感じになります。
(クリック受け→クリック無視→TOPMOST→クリック受けで変化させています)時報お知らせ表示
- 投稿日:2020-04-21T21:39:11+09:00
[C#] プロパティを文字列で指定して値をsetし、forループ中で使用する
もくじ
→https://qiita.com/tera1707/items/4fda73d86eded283ec4fやりたいこと
あるクラスで、同じようなデータを複数個、プロパティとして持っているものがあった。そいつが、
public List<double> DataCollection = List<double>();と持てばいいのに、
public double Data1 = 0.0; public double Data2 = 0.0; ・ ・ ・ public double Data20 = 0.0;みたいな形で持っていたために、そこに値を入れるときにいちいち
Data1 = 10.0;
を20回書かないといけない、みたいなことになりものすごく冗長となった。元のプロパティを色々な事情で直せない場合でも、せめてforでくるくる回して、値を全部のプロパティに代入できるようにしたい。
今回の解
System.Reflection.PropertyInfo
クラスのメソッドを使用した。やりたいことができた.csclass Program { static void Main(string[] args) { var MyData = new MyData(); for (int i = 0; i < 3; i++) { MyData.GetType().GetProperty("Data" + (i + 1)).SetValue(MyData, i); } Console.WriteLine($"OriginalProperty : {MyData.Data1}, {MyData.Data2}, {MyData.Data3}"); } } public class MyData { public double Data1 { get; set; } = 0.0; public double Data2 { get; set; } = 0.0; public double Data3 { get; set; } = 0.0; }失敗例
C言語のポインタの配列のイメージで、下記のようにしたが、うまくいかなかった。
(暫くC言語書いてない&想像で書いて実際にコンパイルしてないので正しく動くか不明)C言語のイメージ、こういうことがC#でしたい.cdouble data1 = 0; double data2 = 0; double data3 = 0; double* DataCollection[3] = { &data1, &data2, &data3 }; void main() { int i = 0; for (i = 0; i < 3; i++) { *DataCollection[i] = 10; } }そのイメージで書いた.csclass Program { static void Main(string[] args) { var MyData = new MyData(); double[] DataCollection = { MyData.Data1, MyData.Data2, MyData.Data3 }; for (int i = 0; i < 3; i++) { DataCollection[i] = i; } Console.WriteLine($"Array : {DataCollection[0]}, {DataCollection[1]}, {DataCollection[2]}"); Console.WriteLine($"OriginalProperty : {MyData.Data1}, {MyData.Data2}, {MyData.Data3}"); } } class MyData { public double Data1 = 0.0; public double Data2 = 0.0; public double Data3 = 0.0; }実行結果
元のプロパティの値を一気にforで変えたいのに、変わってない。しらべたいこと
今回は、
Data1
、Data2
みたいに末尾に連続した数字がついていたので今回のやり方でループで処理できたが、そうでない場合でもループさせたいときは、やっぱりC言語の時みたいに書きたい。
なんかやり方ないか??参考
https://docs.microsoft.com/ja-jp/dotnet/api/system.reflection.propertyinfo?view=netframework-4.8
[C#] 文字列でプロパティ名を指定してアクセス(参照・更新)する方法
https://webbibouroku.com/Blog/Article/access-property【C#】プロパティ名でプロパティにアクセスする
https://qiita.com/tokishirazu/items/66a25331d4c78980366e
- 投稿日:2020-04-21T20:53:23+09:00
ASP.NET Core アプリの Cookie に secure フラグを立てる
ASP.NET Core アプリの Cookie に secure フラグを立てる
セキュリティ監査とかで secure フラグを立てないといけない人向け.
Startup.cs を開き、先頭に
using Microsoft.AspNetCore.Http;
を追加. 次にConfigureServices
メソッドにservices.Configure<CookiePolicyOptions>(options => { options.Secure = CookieSecurePolicy.Always; });を追加する. 最後に
Configure
メソッドにapp.UseCookiePolicy();を追加する. どの行に設定するのがベストなのかはわからないが、
app.UseStaticFiles();
の次の行において動作することだけは確認した.
- 投稿日:2020-04-21T19:09:28+09:00
[Unity] 画面をキャプチャしてバイナリで保存する
0. 概要
Unityで大量のシミュレーション画像を生成してBMPで保存していたが、非常に取り回しが悪いので複数画像をバイナリ化して1つのファイルにしたい。そこで、
PostRender
を使って描画される画面の左上ピクセルから順にRGBで並んだ配列をバイナリ化して1つのファイルに保存したので、その備忘録を以下に記す。1. バイナリ画像化
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Capture : MonoBehaviour { Texture2D capture_display; string fileName = "screenshot\\image.bin"; System.IO.BinaryWriter writer; byte[] yxrgb; int ary_size; // Use this for initialization void Start () { capture_display = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); writer = new System.IO.BinaryWriter(new System.IO.FileStream(fileName, System.IO.FileMode.Append)); ary_size = Screen.width * Screen.height * 3; yxrgb = new byte[ary_size]; } private void OnDestroy() { writer.Close(); } private IEnumerator OnPostRender() { yield return new WaitForEndOfFrame(); // capture the frame RenderTexture.active = Camera.main.targetTexture; capture_display.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0); capture_display.Apply(); for (int i = 0; i < Screen.width; i++) { for (int j = 0; j < Screen.height; j++) { int offset = ( (i * Screen.width) + (j) ) * 3; yxrgb[offset + 0] = (byte)((int)(capture_display.GetPixel(i, j).r * 255)); yxrgb[offset + 1] = (byte)((int)(capture_display.GetPixel(i, j).g * 255)); yxrgb[offset + 2] = (byte)((int)(capture_display.GetPixel(i, j).b * 255)); } } writer.Write(yxrgb); } }
yield return new WaitForEndOfFrame();
を入れておかないと1フレーム遅れた画像が書き出されてしまうので気を付けること。
- 投稿日:2020-04-21T14:39:32+09:00
ReactiveCommand の Subscribe で悩んでいた時の解決法
- 投稿日:2020-04-21T14:35:49+09:00
RaspberryのDocker上でGPIOをWiringPiで使う
はじめに
RaspberryもGPIO(というかハードウェア全般)も初心者がDockerのコンテナでタクトスイッチのオンオフをConsoleに出力するだけのお話
環境
・Raspberry
・.NetCore 3.1(開発側)
・WiringPi
・実行はDocker(インストールしておいてください)ソースはこちら
ハマりどころ
その1
現象
.NetCoreのruntimeコンテナでGPIOのアプリを起動したいので、マイクロソフトのイメージmcr.microsoft.com/dotnet/core/runtime:3.1-bionic-arm32v7を使ったところapt-getでWiringPiがインストールできませんでした(知っている方教えてください)
対処法
DockerfileにてラインタイムイメージにコンパイラをインストールしWiringPiをビルドすることで解決
その2
現象
RaspberryでGPIOを扱う場合に登場する/dev/gpioがコンテナ上ではアクセスができなくて困った。
対処法
Docerのコマンドに--deviceといパラメータがこれを使えばいいことが判明
だけど、今度はパーミッションエラーが発生
--privilegedコマンドを使えば回避できることが判明(特権モードで実行なので慎重に)手順
開発側
- TackInvokerというフォルダを作成
- TackInvokerフォルダに移動
- dotnet new console
- Program.csを下記のファイルで置き換える
- TackInvokerフォルダの上に下記のDockerfileを配置
- docker build -t {自身のDockerHubID}/Tackinvoker:latest .
- docker push {自身のDockerHubID}/Tackinvoker:latest
Raspberry側
- docker run -it --rm --device /dev/gpiomem --privileged {自身のDockerHubID}/Tackinvoker:latest
素材達
Program.cs
using System; using System.Runtime.InteropServices; using System.Threading; namespace TackInvoker { class Program { public const int INPUT = 0; public const int OUTPUT = 1; public const int INT_EDGE_FALLING = 1; public const int INT_EDGE_RISING = 2; public const int Tack_PIN = 17; [DllImport("wiringPi")] extern static int wiringPiSetupGpio(); [DllImport("wiringPi")] extern static void pinMode(int pin, int mode); [DllImport("wiringPi")] extern static void digitalWrite(int pin, int mode); [DllImport("wiringPi")] extern static int wiringPiISR(int pin, int edgeType, CallbackFunc func); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void CallbackFunc(); static void Main(string[] args) { int ret = 0; // wiringPiのセットアップ wiringPiSetupGpio(); // GPIO をINPUTに設定する. pinMode(Tack_PIN, INPUT); CallbackFunc callBackFunc = delegate () { Console.WriteLine("CallbackFunc is called !"); }; // GPIO がONになったらコールバック関数を呼ぶ. ret = wiringPiISR(Tack_PIN, INT_EDGE_RISING, callBackFunc); // 無限に待機する. Thread.Sleep(Int32.MaxValue); } } }Dockerfile
# ビルドイメージ FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build WORKDIR /app # copy csproj and restore as distinct layers COPY *.sln . COPY TackInvoker/*.csproj ./ TackInvoker/ # copy everything else and build app COPY TackInvoker ./TackInvoker/ RUN dotnet restore TackInvoker WORKDIR /app/TackInvoker RUN dotnet publish -c Release -o out # ランタイムイメージ FROM mcr.microsoft.com/dotnet/core/runtime:3.1-bionic-arm32v7 # WiringPiをインストールする RUN apt-get update RUN apt-get install -y libi2c-dev RUN apt-get install -y git-core RUN apt-get install -y sudo RUN apt-get install -y make RUN apt-get install -y gcc RUN git clone https://github.com/WiringPi/WiringPi.git WORKDIR /WiringPi RUN ./build WORKDIR /app COPY --from=build /app/TackInvoker/out ./ ENTRYPOINT ["dotnet", "TackInvoker.dll"]
- 投稿日:2020-04-21T12:38:58+09:00
MacのVisual Studio CodeでC#を実行する
Visual Studio CodeでC#を実行できるようにしようとするといろいろ嵌まったので,記録しておきたいと思います.
Visual Studio Codeをインストール
https://code.visualstudio.com
dmgをダウンロードして,appをコピーすることでインストール
ターミナル作業
以下はターミナルでの作業になります.
Homebrewをインストール
本家サイトに掲載されているとおり,以下のコードを入力して実行します.
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"途中でパスワードを求められる(恐らく要管理者権限).
ScriptCSをインストール
$ brew install scriptcsmonoのパッケージなどもここで読み込まれている.
Visual Studio Codeの拡張機能を登録
検索メニューからCode Runnerを検索して,選ぶ.
「install」ボタンをクリックしてインストールする.
その他,日本語メニューの方がいい人は「Japanese Language Pack」も入れておく.
Code Runnerの設定
拡張機能の右下のギヤアイコンを右クリックして「拡張機能の設定」を開く
clearPreviousOutputやrunInTerminal,saveFileBeforeRunなどはチェックしておいた方がいいかもしれません.
「settings.jsonで編集」と書かれているリンクを開いて以下のコードを追加
"code-runner.executorMap": { "csharp": "scriptcs -script" },この設定がないと"Unexpected named argument:"となって,嵌まります.
StackOverflowの記事settings.jsonは,私の場合には上記でチェックしたものを含めて,こんな風になっていました.
ファイルを保存して,設定完了.
テスト実行
C#コード
helloworld.csusing System; class test { public static void Main(){ Console.WriteLine( "Hello,World" ); } } test.Main();(base) Mac:~ user$ scriptcs -script "/Users/user/Desktop/helloworld.cs" Hello,World (base) Mac:~ user$echoback.csusing System; class test { public static void Main(){ string a = Console.ReadLine(); Console.WriteLine( a ); } } test.Main();(base) Mac:~ user$ scriptcs -script "/Users/user/Desktop/echoback.cs" こんにちは こんにちは (base) Mac:~ user$末尾の
test.Main()
はCodeRunner.appのC#環境などでは不要ですが,この環境では書かないと動かないので注意しないといけません.
- 投稿日:2020-04-21T07:19:53+09:00
【Unity】引数を使ったボタンで好きな数字をテキストに表示する
環境
Unity 2019.3.7f1
はじめに
同じような処理のボタンが複数ある場合、
引数を使ったボタンでコードを簡略化できます。こちらは一つの関数で処理しています。
— Maru@個人アプリ開発者 (@Maru60014236) April 20, 2020方法
1.ボタンに割り当てる関数で引数を宣言する。
2.ボタン側で引数の入力値を設定具体例
1~9の引数をそれぞれ設定したボタンを作成し、
ボタンを押すとテキストに
設定した数値が表示されるようにしてみましょう。1.前準備
・ボタンを9つ作成
【Unity】オブジェクトを等間隔で配置する方法 Grid Layout Group
https://qiita.com/Maru60014236/items/56d2d53e0a80f1e65e94
で作ったボタン群を使います。
(内容:ボタン並べただけ)
・空のオブジェクトを作成
・新規スクリプト作成
・空のオブジェクトに作成したスクリプトを割り当てる・テキストを作成
テキストは、見やすくするためこのように設定
・フォントサイズ50
・水平オーバーフロー Overflor
・垂直オーバーフロー Overflor
2.ボタンのテキスト変更
ボタンのテキストを1~9に変更。
テキストフォントサイズを50にする。
3.ボタンに割り当てる関数を作成
このようにコードを書きます。using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;//UIを使うため追加 public class test : MonoBehaviour { [SerializeField] private Text suuji_text;//Text型の変数suuji_textを宣言 void Start() { } //ボタンを押したら実行する関数 実行するためにはボタンへ関数登録が必要 //int型の引数numberを宣言 public void Push_Button(int number) { suuji_text.text =""+ number;//suuji_textに引数の数値を代入 } }4.ボタンに関数割り当て
ボタンのクリック時のところに空のオブジェクトを割り当て
数値入力欄が出現するので、
ここにボタンテキストに対応した数値を入力
それぞれのボタンで関数割り当て&数値入力を行ってください。
5.空のオブジェクトのスクリプトに前準備で作成したテキストをアタッチ
実行
— Maru@個人アプリ開発者 (@Maru60014236) April 20, 2020おわりに
引数を使った関数でコードスッキリ!!
- 投稿日:2020-04-21T06:14:15+09:00
【Unity】オブジェクトを等間隔で配置する方法 Grid Layout Group
環境
Unity 2019.3.7f1
はじめに
方法
1.整列させたいオブジェクト群をPanelオブジェクトに入れる
2.そのPanelオブジェクトにGrid Layout Group(グリッドレイアウトグループ)コンポーネントを追加
3.各種設定行う具体例
実際にやってみましょう。
1.整列させたいオブジェクト群をPanelオブジェクトに入れる
パネルオブジェクト作成
今回Panelに色は不要なので透過を0にして透明にしておきます。
パネルの配下にボタンを入れる
2.PanelオブジェクトにGrid Layout Group(グリッドレイアウトグループ)コンポーネントを追加
Panelを選択
コンポーネントを追加
3.各種設定行う
ボタンのサイズやセルの間隔などが調整できます。
今回はこのように設定しました。
おわりに
これで手作業での等間隔調整とはおさらばです!
- 投稿日:2020-04-21T01:54:09+09:00
EntityFramework外部キー含めた複合インデックスの張り方
メモ程度に残しておきます。
以下のようなvirtualを使って外部キーとして定義されているCustomerモデルを持つRecordモデルがある。
/// <summary> /// 記録 /// </summary> [Description("記録")] [Table("Records")] public class Record { /// <summary> /// コンストラクタ /// </summary> public Record() { } // <summary> /// ID /// </summary> [Description("ID")] public long Id { get; set; } /// <summary> /// 記録日時 /// </summary> [Description("記録日時")] public DateTime RecordAt { get; set; } /// <summary> /// 顧客 /// </summary> [Required] public virtual Customer Customer { get; set; } } /// <summary> /// 顧客 /// </summary> [Description("顧客")] [Table("Customers")] public class Customer { /// <summary> /// コンストラクタ /// </summary> public Customer() { } // <summary> /// ID /// </summary> [Description("ID")] public long Id { get; set; } /// <summary> /// 名前(姓) /// </summary> [Description("名前(姓)")] [Required] [StringLength(20)] public string LastName { get; set; } /// <summary> /// 名前(名) /// </summary> [Description("名前(名)")] [Required] [StringLength(20)] public string FirstName { get; set; } }このモデルにRecordAtとCustomer.Idの2つで複合indexを張りたいパターン。
/// <summary> /// 記録 /// </summary> [Description("記録")] [Table("Records")] public class Record { /// <summary> /// コンストラクタ /// </summary> public Record() { } // <summary> /// ID /// </summary> [Description("ID")] public long Id { get; set; } /// <summary> /// 記録日時 /// </summary> [Description("記録日時")] [Index("IX_Customer_Id_RecordAt", 2)] public DateTime RecordAt { get; set; } /// <summary> /// CustomerプロパティのIdの値が入る /// </summary> [ForeignKey("Customer")] [Index("IX_Customer_Id_RecordAt", 1)] public long Customer_Id { get; set; } /// <summary> /// 顧客 /// </summary> [Required] public virtual Customer Customer { get; set; } } /// <summary> /// 顧客 /// </summary> [Description("顧客")] [Table("Customers")] public partial class Customer { /// <summary> /// コンストラクタ /// </summary> public Customer() { } // <summary> /// ID /// </summary> [Description("ID")] public long Id { get; set; } /// <summary> /// 名前(姓) /// </summary> [Description("名前(姓)")] [Required] [StringLength(20)] public string LastName { get; set; } /// <summary> /// 名前(名) /// </summary> [Description("名前(名)")] [Required] [StringLength(20)] public string FirstName { get; set; } }ForeignKey属性を付けると「外部キー制約のモデル名_プロパティ名」でCustomer.Idの値がセットされるプロパティを定義できる。
Index属性は(キー名, Order)で複合インデックスを張ることができる。