ボタン長押しプログレスバー(サークル)

### <font  color="6495ed">1.概要</F>
重要な決定ボタンは長押しして進捗表示が進み進捗100%でボタン押しを決定とする仕組みを見かけますが同様なものが必要となり作りました。

<iframe width="560" height="315" src="https://www.youtube.com/embed/RJ-BtJ5tpbw?si=k-xZ5NGHkNsBxvK-" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

- 通常の四角ボタンでは良くないのでXAMLで丸ボタンにしてます。
- ボタンを押しながらマウスがボタンから離れた場合、「押し」をキャンセルした方が良いのでボタンの位置を取得してマウスがボタンから離れたか判定してます。
.
- 進捗表示は一進捗につき、2回分計算します。まず初めに円中心X0,Y0から進捗表示の内側のX2,Y2を出して次はその位置を円中心として外郭のY1,X1を求めています。そうしないと円外郭に合せて進捗表示ができません。(X0,Y0からX2,Y2まで線が引かれてしまう)

![DAT.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/ba9878c4-e443-91df-8ad9-87142673eba6.jpeg)

```
sは進捗度。
X2,Y2はX0,Y0を円中心として、
X2=X0+30*math.Sin(s*3.14/100);
Y2=Y0+30*Math.Cos(s*3.14/100);
30はX0,Y0からX2,Y2の長さ。この場合は半径。

X1,Y1は上で求めたX2,Y2を円中心として同様に、
X1=X2+6*Math.Sin(s*3.14/100);
Y1=Y2+6*Math.Cos(s*3.14/100);
6はX2,Y2からX1,Y1までの長さ

X1,Y1,X2,Y2が求められるので後はこれを元に線を引けば外郭にそってプログレスバーが進みます。

```


### <font  color="6495ed">2.WPF (C#)</F>
```c#
////////////////////////////////////////////////////////////////////
// ﾎﾞﾀﾝ長押し / inf102 2023 WPF(C#) 
// 丸ボタン化は https://www.yone-it-note.site/wpf-circlebutton/
////////////////////////////////////////////////////////////////////

using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Shapes;

namespace WPF_CIRCLE_BTN {

    public partial class MainWindow : Window {

        static int s=-100;
        static int g=0;
        static bool flg=false;

        public void m(string m){
            MessageBox.Show(m);
        }

        public MainWindow() {
            InitializeComponent();

        }

        private async void B1_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
            
            g=0;
 
            //////////////////////////////////////////////////
            // コントロール用 B1== x:name(btn)
            Point cont = B1.PointToScreen(new Point(0, 0));

            // デスクトップ用
            Point desk=this.PointToScreen(new Point(0, 0));

            // デスクトップからみたコントロールのX位置
            int cont_x=(int)cont.X;

            // デスクトップからみたアプリのX位置
            int desk_x=(int)desk.X;
            
            // アプリ内でのコントロールのXY位置
            int XC=cont_x-desk_x;
            int YC=(int)cont.Y - (int)desk.Y;

            //m (YC.ToString() + " X=" + XC.ToString());
            //return;
                                    
            /////////////////////////////////////////////////

            await Task.Run( async ()=>{

                while(true){

                    if ( g==1 ) return;
                    
                    if (B1.IsMouseOver == true && flg == false){
                        
                        this.Dispatcher.Invoke((Action)(() =>{

                            // ローカルマウス位置
                            System.Windows.Point point = e.GetPosition(this);
                            int MY=(int)point.Y;
                            int MX=(int)point.X;

                            if ( (MX >= (cont.X-desk.X) && MX <= XC+B1.Width ) && (MY >= (cont.Y-desk.Y) && MY <= YC+B1.Height)  )    { 
                                s-=2;
                                if (s<=-302) {
                                    B1.Content="承認済";
                                    s=-100;
                                    return;
                                }
                                
                                var Line1 = new Line();
                                Line1.StrokeThickness = 2;
                                Line1.Stroke = System.Windows.Media.Brushes.Red;

                                /////////////////////////////////////////////////
                                // 進捗バー表示
                                // 内側のFrom位置
                                Line1.X1 =(cont.X-desk.X)+(B1.Width/2);
                                Line1.Y1 =(cont.Y-desk.Y)+(B1.Height/2);

                                // 内側のTo位置計算
                                double XX=Line1.X1+30*Math.Sin(s*3.14/100);
                                double YY=Line1.Y1+30*Math.Cos(s*3.14/100);
                                
                                // 内側のTo位置、及び外側のFrom位置
                                Line1.X1=XX;
                                Line1.Y1=YY;
                                         
                                // 外側のTo位置計算
                                Line1.X2=XX+6*Math.Sin(s*3.14/100);
                                Line1.Y2=YY+6*Math.Cos(s*3.14/100);

                                canvas.Children.Add(Line1);
                                /////////////////////////////////////////////////
                            }
                            else {
                                s=-100;
                                canvas.Children.Clear();
                                Title=s.ToString();
                                flg=true;
                            }                       
                       }));
    
                    }else {
                        this.Dispatcher.Invoke((Action)(() =>{
                            canvas.Children.Clear();
                        }));
                        
                        flg=false;
                        s=-100;
                        return;
                    }
                    await Task.Delay(5);
                }
            });
        }

        private void B1_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
            g=1;
            s=-100;
            canvas.Children.Clear();
        }
    }
}
```

<font  color="6495ed">

#### 3.XAML

</FONT>

丸ボタン化は https://www.yone-it-note.site/wpf-circlebutton/

```xml

<Window x:Class="WPF_CIRCLE_BTN.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:WPF_CIRCLE_BTN"
        mc:Ignorable="d"
        Title="MainWindow" Height="267" Width="279">
    <Grid>
        <Canvas Name="canvas"/>
        <Button x:Name="B1" Content="承 認" HorizontalAlignment="Left" Width="60" Height="60" VerticalAlignment="Top" PreviewMouseLeftButtonDown="B1_PreviewMouseLeftButtonDown" PreviewMouseLeftButtonUp="B1_PreviewMouseLeftButtonUp" RenderTransformOrigin="-0.789,-0.423" Margin="64,43,0,0"  >
            <Button.Resources>
                <Style TargetType="{x:Type Border}">
                    <Setter Property="CornerRadius" Value="{Binding ActualWidth, RelativeSource={RelativeSource Self}}" />
                </Style>
            </Button.Resources>
        </Button>

    </Grid>
</Window>

```