2018年2月4日日曜日

Angular5 TODO リスト作成

Angular5 で簡易な TODO リストを作成する実装例を紹介します。

環境準備

node.js 及び npm のインストール

Angular によるアプリケーション開発を行うにあたり、これら機能を利用しますので、それぞれインストールします。インストール後、バージョンを確認します。

バージョン確認
node -v
npm -v

Angular インストール

次のコマンドで Angular CLI をインストールします。
npm install @angular/cli -g


Angular バージョ確認
ng -v


Angular CLI プロジェクトの作成、及びアプリケーションの起動

次のコマンドで Angular CLI プロジェクトを作成します。
ng new todoApp

作成したアプリケーションフォルダに移動
cd todoApp

アプリケーション起動
ng serve -o

→ ブラウザが起動してアプリケーションを表示


ここまでで開発の準備になります。ここから Angular CLI プロジェクトに実装を加えていきます。

機能実装

機能の実装は 1 ~ 15 のステップになります。

タスク数の表示

1.変数 taskText, taskCount を宣言する。

app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  //1
  taskText:string;
  taskCount: number;
}


2.インターポレーションでテンプレートに taskCount を表示する。

app.component.html
<div style="text-align:center">
  <h1>
      タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>
</div>


3.FormsModule をインポートする。

app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';//3

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule//3
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
}


タスクの追加機能

コンポーネントが初期化されるタイミングで発生するライフサイクルイベントをハンドルし、コンポーネントで利用する変数の初期化を行います。

4. OnInit をインポートする。
5. AppComponent に OnInit を実装する。
6. 変数 tasks を宣言する。
7. ngOnInit イベント内で taskText を空文字で、taskCount の値を tasks の要素数で初期化する。
8. addTask メソッドを追加する。

app.component.ts
import { Component, OnInit/*4*/ } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit/*5*/ {
  title = 'app';

  //1
  taskCount: number;
  tasks = [];//6
  
  ngOnInit(){
    //7
    this.taskText = "";
    this.taskCount = this.tasks.length;
  }

  //8
  addTask(taskNameValue: string){
    this.tasks.push(taskNameValue);
    this.taskCount = this.tasks.length;
  }
}

続いてテンプレート(HTML)側にも、データのバインドなどを実装していきます。


9. input(text) を実装し、taskName という名前をつける。
10. input(text) の value に ngModel を利用して taskText の値を双方向バインドする。
11. input(button) に click イベントを実装する。

app.component.html
<div style="text-align:center">
  <h1>
    タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>

  <input #taskName type="text" [(ngModel)]="taskText"><!-- 9, 10 -->

  <input type="button" value="タスク追加" (click)="addTask(taskName.value)"><!-- 11 -->
</div>

ここまでで、input(button) をクリックすると、コンポーネント側で tasks 配列の要素が追加され、テンプレート側でバインドしている taskCount の値も増えていくことを確認することができます。

タスクのリスト表示

続けて、追加したタスクをリスト形式で表示するための実装を加えていきます。


12. tasks 配列の各要素をリスト表示する。

app.component.html
<div style="text-align:center">
  <h1>
    タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>

  <input #taskName type="text" [(ngModel)]="taskText"><!-- 9, 10 -->

  <input type="button" value="タスク追加" (click)="addTask(taskName.value)"><!-- 11 -->
</div>

<ul>
  <!-- 12 -->
  <li *ngFor="let task of tasks">
    {{ task }}
  </li>
</ul>


13. タスクリストの位置調整

app.component.css
ul {
    position: relative;
    left: 40%;
}

ここまでで、ボタンクリックでタスクが追加していくようになります。

タスクの削除

タスクの追加ができたら、タスクの削除もできるようにします。タスクの削除は、タスク(li 要素)をクリックした時に行います。

14. input(button) に click イベントを登録する。

app.component.html
<div style="text-align:center">
  <h1>
    タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>

  <input #taskName type="text" [(ngModel)]="taskText"><!-- 9, 10 -->

  <input type="button" value="タスク追加" (click)="addTask(taskName.value)"><!-- 11 -->
</div>

<ul>
  <!-- 12 -->
  <li *ngFor="let task of tasks; let idx = index;" (click)="removeTask(idx)"><!-- 14 -->
    {{ task }}
  </li>
</ul>

コンポーネント側で、タスクを削除するための removeTask イベントハンドラを実装します。

15. app.component.ts
//15
removeTask(idx:number){
  this.tasks.splice(idx, 1);
}

以上で、簡単ではありますが、Angular を利用した TO DO リストの作成ができました。


全ソースコード

各ファイルのソースコードは次のようになっています。

app.component.ts
import { Component, OnInit/*4*/ } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit/*5*/ {
  title = 'app';

  //1
  taskText:string;
  taskCount: number;

  tasks = [];//6
  
  ngOnInit(){
    //7
    this.taskText = "";
    this.taskCount = this.tasks.length;
  }

  //8
  addTask(taskNameValue: string){
    this.tasks.push(taskNameValue);
    this.taskCount = this.tasks.length;
    this.taskText = "";
  }
  //15
  removeTask(idx:number){
    this.tasks.splice(idx, 1);
  }
}

app.component.html
<div style="text-align:center">
  <h1>
    タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>

  <input #taskName type="text" [(ngModel)]="taskText"><!-- 9, 10 -->

  <input type="button" value="タスク追加" (click)="addTask(taskName.value)"><!-- 11 -->
</div>

<ul>
  <!-- 12 -->
  <li *ngFor="let task of tasks; let idx = index;" (click)="removeTask(idx)"><!-- 14 -->
    {{ task }}
  </li>
</ul>

app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';//3

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule//3
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.css
ul {
    position: relative;
    left: 40%;
}
以上になります。


Angular に関連するトピックは次のページにまとめてあります。

Angular 機能紹介一覧
https://kainobi2.blogspot.com/2019/02/angular.html

超簡易 Python サーバー作成方法

Python3 で簡易ウェブサーバーを作成する手順をメモしておきます。

1.フォルダレイアウト
C:\py
  - cgi-bin
    - index.py
    - index.tpl

2.実装
index.py
print('Content-type: text/html; charset=UTF-8\r\n')
fopen = open("cgi-bin/index.tpl", encoding="utf-8")
lines = fopen.read()
fopen.close()
print(lines)

index.tpl
<html>
    <head>
        <title>aaa</title>
    </head>
    <body>
        aaabbbccc
    </body>
</html>

3.コマンド
C:\py> python -m http.server --cgi 8000


4.ブラウザでアクセス
http://localhost:8000/cgi-bin/index.py

2017年12月26日火曜日

等差数列、等比数列の求め方

等差数列の求め方


一般項は

an = a + (n - 1)d



等比数列の求め方


一般項は

an = ar ^ n - 1

2017年12月23日土曜日

Visual Studio Code ソースコード 拡大/縮小機能の有効化


Visual Studio Code にはエディタの拡大率を Ctrl キー + マウスホイールで拡大/縮小する機能があります。デフォルトでは無効化されているので、下記のように有効化します。

ファイル > 基本設定 > 設定

デフォルト:
"editor.mouseWheelZoom": false

変更後:
"editor.mouseWheelZoom": true



Visual Studio Code では意図的に無効化しているようです。TrackPad や TouchPad を利用する際に、この機能により意図せずソースコードが拡大/縮小されてしまうためだそうです。
Feature request: Allow zooming with ctrl+mousewheel combination #6978
https://github.com/Microsoft/vscode/issues/6978

2017年11月30日木曜日

flutter 開発メモ

flutter 開発に関するメモです。基本的な内容がほとんどです。

アプリケーションテンプレートの生成
flutter create watashi_app

アプリケーションの実行
アプリケーションのトップフォルダ(pubspec.yaml のあるフォルダ)で、次を実行
flutter run


2017年11月23日木曜日

WPF 添付イベント(Attached Event)実装例

添付イベントの実装例を紹介します。

MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp3
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        
        private void InputChangedHandler(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("InputChangedHanlder is called.");
        }
    }

    public static class EventHelper
    {
        public static readonly DependencyProperty IsEventRaisingProperty =
            DependencyProperty.RegisterAttached("IsEventRaising",
            typeof(bool),
            typeof(EventHelper),
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsEventRaisingChanged)));

        public static bool GetIsEventRaising(DependencyObject sender)
        {
            return (bool)sender.GetValue(IsEventRaisingProperty);
        }

        public static void SetIsEventRaising(DependencyObject sender, bool ier)
        {
            sender.SetValue(IsEventRaisingProperty, ier);
        }

        public static readonly RoutedEvent InputChangedEvent = EventManager.RegisterRoutedEvent(
            "InputChanged",
            RoutingStrategy.Bubble,
            typeof(RoutedEventHandler),
            typeof(EventHelper)
        );

        public static void AddInputChangedHandler(DependencyObject sender, RoutedEventHandler handler)
        {
            UIElement element = sender as UIElement;
            if (element != null)
            {
                element.AddHandler(InputChangedEvent, handler);
            }
        }

        public static void RemoveInputChangedHandler(DependencyObject sender, RoutedEventHandler handler)
        {
            UIElement element = sender as UIElement;
            if (element != null)
            {
                element.RemoveHandler(InputChangedEvent, handler);
            }
        }

        private static void OnIsEventRaisingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as TextBox).TextChanged += (_s, _e) =>
            {
                (sender as TextBox).RaiseEvent(new RoutedEventArgs(InputChangedEvent));
            };
        }
    }
}

MainWindow.xaml
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp3"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:Custom="http://infragistics.com/DockManager" x:Class="WpfApp3.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow X" Height="350" Width="525">
    <Grid>
        <TextBox local:EventHelper.IsEventRaising="True"
                 local:EventHelper.InputChanged="InputChangedHandler"
                             />
    </Grid>
</Window>

2017年11月20日月曜日

WPF ユーザーコントロールのプロパティにデータをバインド

ユーザーコントロールのプロパティに、他のユーザーコントロールのプロパティをバインドしてみます。

ターゲットプロパティ・・・値を設定するプロパティ
ソースプロパティ・・・値を取得してくるプロパティ

ターゲットプロパティは、依存関係プロパティ(Dependency Property)である必要があります。


実装例:
この例では、Slider コントロールの Value プロパティを、TextBox の Text プロパティにバインドしています。なお、TextBox の Text プロパティは依存関係プロパティ(Dependency Property)です。

<Slider x:Name="slider1"
        HorizontalAlignment="Left" 
        Margin="49,36,0,0" 
        VerticalAlignment="Top" 
        Width="257"
        />
<TextBox HorizontalAlignment="Left"
         Height="24" Margin="49,85,0,0" 
         TextWrapping="Wrap"
         VerticalAlignment="Top"
         Width="257"
         Text="{Binding ElementName=slider1, Path=Value}"/>

2017年11月19日日曜日

WPF Trigger 実装例

WPF Trigger の実装例です。

Button の Content の値に応じて Button の背景色を赤色に変更します。また、Button にマウスがホバーしている間、Button の文字色を白色に変更します。


<Window x:Class="TriggerDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TriggerDemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button
            Content="button1"
            Height="30"
            Width="200">
            <Button.Resources>
                <Style TargetType="Button">
                    <Style.Triggers>
                        <!--Content が "button1" ならば-->
                        <Trigger Property="Content" Value="button1">
                            <!--背景色を赤色に変更-->
                            <Setter Property="Background" Value="Red"/>
                        </Trigger>
                        <!--Button 上にマウスがホバーしていたら-->
                        <Trigger Property="IsMouseOver" Value="True">
                            <!--前景色を白色に変更-->
                            <Setter Property="Foreground" Value="White"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Button.Resources>
        </Button>
    </Grid>
</Window>


関連情報:

WPF DataTrigger 実装例
http://kainobi2.blogspot.jp/2017/05/wpf-datatrigger.html

2017年11月18日土曜日

WPF 添付プロパティ(Attached Property)の実装方法

WPF でクラスインスタンスを利用する際に、クラスに対して直接プロパティを追加できないが、任意のプロパティを追加して利用したい状況があるかと思います。そのような場合、添付プロパティ(Attached Property)を利用することができます。


MainWindow.xaml.cs

コードビハインドで「propa」と入力してスニペットを挿入します。その後、適宜名前やメタデータを変更していきます。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public static double GetRecord(DependencyObject obj)
    {
        return (double)obj.GetValue(RecordProperty);
    }

    public static void SetRecord(DependencyObject obj, double value)
    {
        obj.SetValue(RecordProperty, value);
    }

    // Using a DependencyProperty as the backing store for Record.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RecordProperty =
        DependencyProperty.RegisterAttached("Record",
            typeof(double),
            typeof(MainWindow), 
            new FrameworkPropertyMetadata(0.0)
            );

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var btn = sender as Button;
        Debug.WriteLine(btn.GetValue(RecordProperty));
    }
}



MainWindow.xaml

追加した Record 添付プロパティに、double 値を設定します。

<Window x:Class="AttachedPropertyDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AttachedPropertyDemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button 
            Content="abc"
            Height="30"
            Width="200"
            local:MainWindow.Record="3.0"
            Click="Button_Click"/>
    </Grid>
</Window>

関連情報:
WPF 依存関係プロパティ
http://kainobi2.blogspot.jp/2016/11/wpf.html

2017年11月17日金曜日

WPF バインディング:Source の使い方

Binding オブジェクトの持つ、Source プロパティの利用方法の紹介です。Source プロパティを利用することで、Resources に登録されている任意のオブジェクトを参照することができます。

例えば、Resources に用意されている Int 型の値を、TextBox の Tooltip プロパティにバインドしてみます。

※ Int 型の値を利用するためには、mscorlib アセンブリの参照を追加しています。

<Window x:Class="WpfApp3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp3"
        mc:Ignorable="d"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow X" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <sys:Int32 x:Key="num1">123</sys:Int32>
        </Grid.Resources>

        <TextBox x:Name="textBox1"
                 Height="30"
                 Width="250"
                 Text="abc"
                 ToolTip="{Binding Source={StaticResource num1}}"/>
    </Grid>
</Window>

2017年11月11日土曜日

WPF バインディング:RelativeSource の使い方

Binding オブジェクトの持つ、RelativeSource プロパティの利用方法の紹介です。

バインディングを利用して、バインドするソースとして、バインドターゲットの UI 要素から相対位置に存在する UI 要素のプロパティを指定する時には、RelativeSource プロパティを利用することができます。

例えば、TextBox の Tooltip プロパティにバインドするバインドソースとして、TextBox の親(Grid)の親である Window の Title プロパティを利用することを考えてみます。

デザインタイムでは、UI 要素は下記の構造になっています。TextBox から、2 つ上位にある Window のプロパティを参照します。

Window
    - Grid
        - TextBox


TextBox.Tooltip プロパティには、RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window} として、RelativeSoure を利用し、Mode に FindAncestor、AncestorType に Window をそれぞれ指定しています。これで、TextBox のツールチップには「MainWindow X」という値が表示されるようになります。

<Window x:Class="WpfApp3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp3"
        mc:Ignorable="d"
        Title="MainWindow X" Height="350" Width="525">
    <Grid>

        <TextBox x:Name="textBox1"
                 Height="30"
                 Width="250"
                 Text="abc"
                 ToolTip="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=Title}"/>
    </Grid>
</Window>