Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9529

[WPF/xaml] xaml+C#で当番決めのためのルーレットを作る

$
0
0

もくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f

やりたいこと

週一回のミーティングの司会役を決めるためにルーレットを使っているが、なんとなくxamlでもできそうな気がしたので試しに作ってみたい。

イメージはシンプルにこんな感じ。
image.png

やり方

下記のようにしてやる。
キーワードは「StoryBoard」。

  • [xaml]ルーレットの円を作成。
  • [C#]人数分の名前を、stringのListで持つ(以降、人数はListの件数で判断)
  • [C#]人数分の名前を、円の中に書く。
  • [C#]人数分の区切りの線を引く。
  • [C#]名前と区切り線を、一人分の角度*List番号分回転させて表示する。
  • [xaml]に、ルーレット(円の中身全体)を永遠に回し続けるStoryBoardを作成する。
  • [C#]ボタンをおしたら、ルーレットを回すStoryBoardをスタートする。

※一人分の角度は360/人数

コード

xaml

MainWindow.xaml
<Window x:Class="WpfApp38.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:WpfApp38"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="600"
        Loaded="Window_Loaded"
        Name="Root">

    <Window.Resources>
        <!-- ルーレットのアニメーション定義 -->
        <Storyboard  x:Key="StartRoulettea">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"  Storyboard.TargetName="RouletteMain" Storyboard.TargetProperty="(Grid.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"
                                           RepeatBehavior="Forever" >
                <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0" />
                <LinearDoubleKeyFrame KeyTime="00:00:00.5" Value="360" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>

    <Grid>
        <Viewbox Margin="20">
            <Grid Name="RouletteMain" RenderTransformOrigin="0.5,0.5">
                <Grid.RenderTransform>
                    <TransformGroup>
                        <!-- 回転の角度 -->
                        <RotateTransform Angle="0"/>
                    </TransformGroup>
                </Grid.RenderTransform>

                <!-- ルーレットの外側の円 -->
                <Ellipse Name="RouletteEllipse" Stroke="Black" StrokeThickness="5" Width="500" Height="500" >
                    <Ellipse.Fill>    
                        <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">    
                            <GradientStop Color="Red" Offset="0.0" />    
                            <GradientStop Color="Orange" Offset="0.2" />    
                            <GradientStop Color="Yellow" Offset="0.4" />    
                            <GradientStop Color="LimeGreen" Offset="0.6" />    
                            <GradientStop Color="Blue" Offset="0.8" />    
                            <GradientStop Color="Violet" Offset="1.0" />    
                        </LinearGradientBrush>    
                    </Ellipse.Fill>
                </Ellipse>
            </Grid>

        </Viewbox>

        <!-- 上の線 -->
        <Rectangle Stroke="Black" StrokeThickness="10" Height="50" Width="5" VerticalAlignment="Top"/>

        <!-- スタートボタン -->
        <Button Name="StartButton" Width="100" Height="50" Content="スタート" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="10" Click="Button_Click"/>
    </Grid>
</Window>

コードビハインド(cs)

MainWindow.xaml.cs
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace WpfApp38
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// ルーレット回転中かどうか
        /// </summary>
        bool IsRounding = false;

        /// <summary>
        /// メンバー一覧
        /// ここにメンバー名をAddしたら、
        /// Window_Loaded()の中で枠を自動でつくる
        /// </summary>
        List<string> Members = new List<string>();

        /// <summary>
        /// コンストラクタ
        /// ここでメンバー登録をする
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            Members.Add("Aさん");
            Members.Add("Bさん");
            Members.Add("Cさん");
            Members.Add("Dさん");
            Members.Add("Eさん");
            Members.Add("Fさん");
            Members.Add("Gさん");
            Members.Add("Hさん");
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // 一人あたりの使用する角度を決める
            int anglePerOne = 360 / Members.Count;

            // 人数分の線を引き、名前のテキストを作成する
            for (int i = 0; i < Members.Count; i++)
            {
                ////////////////////////
                // 人数分の区切り線を引く
                ////////////////////////
                var tfgLine = new TransformGroup();
                tfgLine.Children.Add(new RotateTransform(i * anglePerOne));

                var line = new Line()
                {
                    X1 = 0,
                    Y1 = 0,
                    X2 = 0,
                    Y2 = RouletteEllipse.Width / 2,
                    StrokeThickness = 5,
                    Stroke = Brushes.Red,
                    Fill = Brushes.Transparent,
                    VerticalAlignment = VerticalAlignment.Top,
                    HorizontalAlignment = HorizontalAlignment.Center,
                    RenderTransformOrigin = new Point(0, 1.0),
                    RenderTransform = tfgLine
                };

                RouletteMain.Children.Add(line);

                ////////////////////////
                // 人数分の名前を書く
                ////////////////////////
                int textHeight = 30;
                var tfgText = new TransformGroup();
                tfgText.Children.Add(new RotateTransform(-90 + (anglePerOne / 2) + (i * anglePerOne)));

                var text = new TextBlock()
                {
                    Text = Members[i],
                    Width = RouletteEllipse.Width / 2,                  // ルーレットの円の半分
                    VerticalAlignment = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Right,
                    TextAlignment = TextAlignment.Center,
                    FontSize = textHeight,
                    RenderTransformOrigin = new Point(0, 0.5),
                    RenderTransform = tfgText
                };

                RouletteMain.Children.Add(text);
            }
        }

        /// <summary>
        /// ルーレットのスタート/ストップ
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // ルーレットを回すためのStoryBoardを検索
            var sb = FindResource("StartRoulettea") as Storyboard;

            if (IsRounding == false)
            {
                // 回転開始(スタート)
                sb.Begin();

                StartButton.Content = "ストップ";
            }
            else
            {
                // 回転停止(ストップ)
                sb.Pause();

                StartButton.Content = "スタート";
            }

            IsRounding = !IsRounding;
        }
    }
}

できあがり

image.png

備考

背景のグラデーションあると見た目がさみしくないが、超目押し可能となるので問題。

コード

https://github.com/tera1707/WPF-/tree/master/031_XamlRoulette

参考

++C++
https://ufcpp.net/study/dotnet/wpf_xamlani.html

自分のページ
[WPF/xaml]Storyboardでアニメーションをつくる
https://qiita.com/tera1707/items/a7fcdd95fc3120ae3c8b


Viewing all articles
Browse latest Browse all 9529

Trending Articles