반응형

이번에는 Webview 라이브러리를 사용하면서 HTML 파일을 별도로 분리하는 방법을 알아보겠습니다. 그리고, 좀더 보기좋은 GUI 구성을 위해 부트스트랩도 함께 적용하도록 하겠습니다. 사실 이부분은...CSS 파일을 별도로 인식시켰으면 좋겠지만, 아직까지 별도의 CSS파일을 적용시키는 것은 안되는 것 같습니다. 

 

1. 라이브러리 설치

라이브러리 설치는 이전 강좌를 참고하세요.

 

2. main.go 파일 작성

main.go 파일에 전체 프로그램 구동을 구현합니다. 아울러, 버튼을 클릭했을 때 동작할 함수(go_hello)를 작성하고, 바인딩해줍니다. Webview라이브러리를 활용하면, go에서 javascript를 실행할 수도 있고, html파일(javascript 포함)에서 go언어를 실행할 수도 있습니다. 그러나 프로그램 가독성을 위해, Bind 한줄이 더 들어가더라도, 함수구현은 go에서 하도록 하겠습니다.

package main

import (
	"fmt"
	"os"

	"github.com/webview/webview"
)

var w webview.WebView

func main() {
	w = webview.New(true)
	defer w.Destroy()
	w.SetSize(600, 600, webview.HintNone) // Create a GoLang function callable from JS
	w.Bind("go_hello", go_hello)	// Go_hello 함수 구현과 html에서 호출하는 go_hello를 Bind해줍니다. 

	// Create UI with data URI
	dir, _ := os.Getwd()
	fmt.Println(dir)
	w.Navigate("file:" + dir + "/hi.html")

	w.Run()
}

// 함수 실행 시, javascript로 팝업 알람을 실행해서 데이터를 보여줍니다.
// HTML문서에서 보여주는 부분만큼은...javascript로..ㅠㅠ
func go_hello() {
	name := "You"
	w.Eval(`alert("Hello` + name + `");`)
}

데이터를 처리하는 것은 go 함수구현에서 할 수 있지만, 마지막으로 데이터를 HTML로 보내서 보여주는 부분은 Javascript로 할 수밖에 없겠네요..^^;;

 

3. hi.html

HTML로 뷰를 구현합니다. 서두에서 말했듯이 CSS 적용이 힘든 관계로 Bootstrap을 CDN으로 불러와 적용시키겠습니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

    <title>My App</title>
</head>
<body>
    <!--Header Section-->
    <div class="box-padding-big">
      <nav class="navbar navbar-expand-sm navbar-dark bg-dark">
        <div class="collapse navbar-collapse">
          <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
              <a class="nav-link" href="#" id=navbardrop" data-toggle="dropdown">File</a>
              <div class="dropdown-menu">
              <a class="dropdown-item" href="#" onclick="go_hello()">Sub1</a>
              <a class="dropdown-item" href="#">Sub2</a>
              <a class="dropdown-item" href="#">Sub3</a>
              </div>
            </li>
            <li class="hav-item">
            	<a class="nav-link" href="#">Edit</a>
            </li>
            <li class="hav-item">
            	<a class="nav-link" href="#">View</a>
            </li>
            <li class="hav-item">
            	<a class="nav-link" href="#">Info</a>
            </li>
          </ul>
        </div>
      </nav>
    </div>

  <!--Main Section-->
  <div style="margin: 20px;">
  	<div style="font-size: 36px; color:chartreuse;font-weight:700">
      <div>GO-Webview HTML View Test <br/>
      with Bootstrap
      </div>
    </div>
    <p class="text-primary" style="margin-top:20px;">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget magna eros. Cras sit amet nulla dignissim, pretium justo sit amet, vulputate orci. Curabitur in aliquam lorem. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi quis pulvinar nunc, sed posuere enim. In hac habitasse platea dictumst. Ut sodales augue eu elit bibendum, ut malesuada felis auctor. Sed mattis ipsum malesuada sem feugiat ultricies. Fusce ultrices vel est id pretium. Sed vel congue augue, non tincidunt tellus. Vivamus facilisis mollis tellus ac vulputate. 
    </p>
  </div>
</body>
</html>

 

4. 결과

아래 명령으로 결과를 확인합니다.

go run main.go

File - Sub1을 클릭하면...

알람 팝업이 잘 나옵니다.

 

이상으로 webview를 이용하여 html 파일과 bootstrap을 적용하는 방법을 알아봤습니다. 너무 쉽게 구현이 가능한데, 성능은 어느정도일지, 어떤 점이 부족할지 계속 알아봐야겠습니다.

 

~~~끝~~~

반응형
반응형

Go언어 GUI 라이브러리 중 Webview를 사용해서 데스크탑 앱을 만들어보도록 하겠습니다. Webview는 HTML로 레이아웃을 구성할 수 있어서 간단한 앱은 쉽게 만들 수 있습니다.

 

1. 라이브러리 설치

이번엔 리눅스환경에서(우분투 20.04) 라이브러리를 설치하겠습니다. 

sudo apt-get install libgtk-3-dev
sudo apt-get install libwebkit2gtk-4.0-dev

go get github.com/webview/webview

2. Sample Project

다음으로 간단히 main.go 파일을 생성하고, 아래와 같이 작성해줍니다.

package main

import "github.com/webview/webview"

func main() {
	w := webview.New(true)
	defer w.Destroy()
	w.SetSize(600, 200, webview.HintNone) // Create a GoLang function callable from JS
	w.Bind("hello", func() string { return "World!" })

	// Create UI with data URI
	w.Navigate(`data:text/html,
	 <!doctype html>
	 <html>
	  <head><title>Hello</title></head>
	  <body><h1>Hello, world!</h1></body>
	  <script> hello().then((x) => { console.log(x) }) </script>
	 </html>`)

	w.Run()
}

 

3. 실행

터미널에서 아래와 같이 명령하면..

go run main.go

이쁜 앱이 나타났습니다. 라이브러리만 설치하면 프로그램 작성은 정말 쉽게 할 수 있네요.

 

이상으로  Golang에서 Webview 라이브러리를 이용한 GUI개발을 알아봤습니다. 

다음번엔 HTML 파일을 분리하여 작성하는 방법을 알아보겠습니다.

 

~~~끝~~~

반응형
반응형

오늘은 아래 유튜브 영상의 데스크탑 어플리케이션을 구현해보겠습니다.

https://www.youtube.com/watch?v=qSP8v8Gi3XU

 

1. 라이브러리 설치

이번 영상에서는 Material Design과 LiveCharts를 사용합니다. 아래의 명령으로 Package를 설치해줍니다.

dotnet add package MaterialDesignThemes --version 4.2.1 // material Design 설치
dotnet add package LiveCharts.Wpf --version 0.9.7 // live chart 설치

또는 Nuget GUI Manager 를 설치 후

 

Shift + Ctrl + P 로 명령창에서 Nuget 입력 시 나타나는 명령을 수행합니다.

그리고 Nuget Package Manager에서 아래와 같이 설치해줍니다. Material Design Themes와 Livecharts.wpf로 검색되는 패키지를 설치해줍니다.

귀차니즘....끄적끄적..

 

2. 라이브러리 적용

Material Design을 적용해야합니다. 적용하는 방법은 구글에서 < material design xaml >이라고 검색하면 나오는데, 여기 사이트를 참조하시면 되겠습니다. 그리고, 나중에 livechart에서 사용할 스타일도 정의해놓겠습니다.

<App.xaml>

<Application x:Class="wpf_test04UT2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:wpf_test04UT2"
             xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <Style TargetType="lvc:LineSeries">
                <Setter Property="StrokeThickness" Value="3"></Setter>                
                <Setter Property="Fill" Value="#4EFFFFFF"></Setter>                
                <Setter Property="PointGeometrySize" Value="0"></Setter>
                <Setter Property="LineSmoothness" Value="0"></Setter>
            </Style>
            <Style TargetType="lvc:Axis">
                <Setter Property="ShowLabels" Value="False"></Setter>                
                <Setter Property="IsEnabled" Value="False"></Setter>                                
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

 

3. 메인프레임 구성

메인 프레임에서는 전체적인 틀을 Grid 레이아웃으로 잡아주고, 좌측 그리드에 메뉴를 Material Design Icon으로 구성합니다.

<MainWindow.xaml>

<Window x:Class="wpf_test04UT2.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_test04UT2"
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        mc:Ignorable="d"
        Title="MainWindow" Height="850" Width="1200"
        WindowStartupLocation="CenterScreen"        
        WindowStyle="None"
        Background="{x:Null}"
        AllowsTransparency="True" Loaded="Window_Loaded">
    <Grid>
        <materialDesign:Card Margin="10" UniformCornerRadius="15">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="15*" />
                </Grid.ColumnDefinitions>
                <Grid.Resources>
                    <Style TargetType="materialDesign:PackIcon">
                        <Setter Property="Width" Value="30"></Setter>
                        <Setter Property="Height" Value="30"></Setter>
                    </Style>
                </Grid.Resources>
                <Grid Grid.Column="0">
                    <ListView Margin="0 15">
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="Resistor" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="CircleSlice6" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="CalendarBlankOutline" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="EqualiserVertical" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="ChatOutline" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 60 0 0">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black" x:Name="btnExit" Click="btnExit_click">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="ExitToApp" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                    </ListView>
                </Grid>
                <Grid Grid.Column="1" Background="#f6f5f8" Name="RenderPages">
                
                </Grid>
            </Grid>
        </materialDesign:Card>
    </Grid>
</Window>

이번 과제는 UI에 집중되어 있어서, cs파일에서는 별로 할일이 없습니다.

<MainWindow.xaml.cs>

using System.Windows;

namespace wpf_test04UT2
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            RenderPages.Children.Clear();
            RenderPages.Children.Add(new Dashboard());
        }
        private void btnExit_click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }
    }
}

 

4. 내부 Dashboard 작성

메인프레임에 뿌려줄 '내부'를 별도파일(UserControl)로 구현합니다. Material Design 사용하니까 이쁘고 좋긴 한데, 코드가 길어지고....익숙해지는데 시간이 좀 필요하겠네요..

<Dashboard.xaml>

<UserControl x:Class="wpf_test04UT2.Dashboard"
        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_test04UT2"
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.wpf"
        mc:Ignorable="d"
        Height="850" Width="1100">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="8*" />
        <ColumnDefinition Width="4*" />
      </Grid.ColumnDefinitions>
      <Grid.Resources>
        <Style TargetType="materialDesign:PackIcon">
          <Setter Property="Width" Value="30"></Setter>
          <Setter Property="Height" Value="30"></Setter>
        </Style>
      </Grid.Resources>
      <Grid Grid.Column="0" Background="#f6f6f8">
        <StackPanel Margin="10">
            <Grid Height="60">
              <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left"
              BorderBrush="{x:Null}" Background="{x:Null}">
                <StackPanel Margin="5">
                  <materialDesign:PackIcon Kind="ReorderHorizontal" Foreground="Gray" />
                </StackPanel>
              </Button>
              <ComboBox HorizontalAlignment="Right" Width="100" materialDesign:HintAssist.Hint="Last 15 Days">
                <ComboBoxItem>
                  <TextBlock Text="Last 15 Days" />
                </ComboBoxItem>
                <ComboBoxItem>
                  <TextBlock Text="Last 30 Days" />
                </ComboBoxItem>
              </ComboBox>
            </Grid>
            <WrapPanel HorizontalAlignment="Center">
              <Border BorderBrush="White" BorderThickness="5" Margin="20 0" CornerRadius="15">
                <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth0" UniformCornerRadius="15" BorderThickness="5"
                BorderBrush="White" Width="110" Height="130" Background="#F6F6F8">
                  <StackPanel Margin="10">
                    <materialDesign:PackIcon Kind="Twitter" Foreground="#29A3EC" />
                    <TextBlock FontWeight="SemiBold" FontSize="25" Text="280K" Margin="0 10 0 0" />
                    <TextBlock FontSize="12" Text="Follwers" />
                    <materialDesign:PackIcon Kind="EllipsisHorizontal" HorizontalAlignment="Right" />
                  </StackPanel>
                </materialDesign:Card>
              </Border>
              <Border BorderBrush="White" BorderThickness="5" Margin="20 0" CornerRadius="15">
                <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth0" UniformCornerRadius="15" BorderThickness="5"
                BorderBrush="White" Width="110" Height="130" Background="#F6F6F8">
                  <StackPanel Margin="10">
                    <materialDesign:PackIcon Kind="Instagram">
                      <materialDesign:PackIcon.Foreground>
                        <LinearGradientBrush StartPoint="1,0" EndPoint="0.5,1">
                          <GradientStop Color="#912A73" Offset="0" />
                          <GradientStop Color="#FA8E22" Offset="1" />
                        </LinearGradientBrush>
                      </materialDesign:PackIcon.Foreground>
                    </materialDesign:PackIcon>
                    <TextBlock FontWeight="SemiBold" FontSize="25" Text="690K" Margin="0 10 0 0" />
                    <TextBlock FontSize="12" Text="Followers" />
                    <materialDesign:PackIcon Kind="EllipsisHorizontal" HorizontalAlignment="Right" />
                  </StackPanel>
                </materialDesign:Card>
              </Border>
              <Border BorderBrush="White" BorderThickness="5" Margin="20 0" CornerRadius="15">
                <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth0" UniformCornerRadius="15" BorderThickness="5"
                BorderBrush="White" Width="110" Height="130" Background="#F6F6F8">
                  <StackPanel Margin="10">
                    <materialDesign:PackIcon Kind="Youtube" Foreground="#29A3EC" />
                    <TextBlock FontWeight="SemiBold" FontSize="25" Text="2.3M" Margin="0 10 0 0" />
                    <TextBlock FontSize="12" Text="Follwers" />
                    <materialDesign:PackIcon Kind="EllipsisHorizontal" HorizontalAlignment="Right" />
                  </StackPanel>
                </materialDesign:Card>
              </Border>
              <Border BorderBrush="White" BorderThickness="5" Margin="20 0" CornerRadius="15">
                <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth0" UniformCornerRadius="15" BorderThickness="5"
                BorderBrush="White" Width="110" Height="130" Background="#F6F6F8">
                  <StackPanel Margin="10">
                    <materialDesign:PackIcon Kind="Facebook" Foreground="#29A3EC" />
                    <TextBlock FontWeight="SemiBold" FontSize="25" Text="60K" Margin="0 10 0 0" />
                    <TextBlock FontSize="12" Text="Follwers" />
                    <materialDesign:PackIcon Kind="EllipsisHorizontal" HorizontalAlignment="Right" />
                  </StackPanel>
                </materialDesign:Card>
              </Border>
            </WrapPanel>
            <materialDesign:Card Margin="30 20" UniformCornerRadius="20">
              <StackPanel>
                <Grid>
                  <TextBlock Margin="20" HorizontalAlignment="Left" FontWeight="SemiBold" Text="Instagram Subscribers" FontSize="18"/>
                  <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                    <TextBlock FontWeight="ExtraBold" FontSize="14" Text="&#xF06C;" FontFamily="wingdings" VerticalAlignment="Center" Foreground="#42A5F4" />
                    <TextBlock Text="Gained" HorizontalAlignment="Right" VerticalAlignment="Center" FontWeight="SemiBold" FontSize="14" Margin="5 0 10 0"/>
                    <TextBlock FontWeight="ExtraBold" FontSize="14" Text="&#xF06C;" FontFamily="wingdings" VerticalAlignment="Center" Foreground="#F55F54" />
                    <TextBlock Text="Lost" HorizontalAlignment="Right" VerticalAlignment="Center" FontWeight="SemiBold" FontSize="14" Margin="5 0 20 0" />
                  </StackPanel>
                </Grid>
                <lvc:CartesianChart Series="{Binding SeriesCollection}" Foreground="Black" Margin="10 0" Height="200">
                  <lvc:CartesianChart.AxisX>
                    <lvc:Axis Labels="{Binding Labels}" Separator="{x:Static lvc:DefaultAxes.CleanSeparator}" />
                  </lvc:CartesianChart.AxisX>
                  <lvc:CartesianChart.AxisY>  
                    <lvc:Axis LabelFormatter="{Binding Formatter}" />
                  </lvc:CartesianChart.AxisY>
                </lvc:CartesianChart>
              </StackPanel>              
            </materialDesign:Card>
            <WrapPanel HorizontalAlignment="Center">
              <materialDesign:Card Margin="10" UniformCornerRadius="20" Padding="10">
                <StackPanel>
                  <TextBlock Text="Key Matrics" Margin="10 20" FontWeight="SemiBold"/>
                  <Grid Height="150">
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition />
                      <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                      <RowDefinition />
                      <RowDefinition />
                      <RowDefinition />
                      <RowDefinition />
                    </Grid.RowDefinitions>
                    <TextBlock Text="Clicks" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="13" FontWeight="SemiBold" />
                    <TextBlock Text="Links" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="13" FontWeight="SemiBold" />
                    <TextBlock Text="Followers" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="13" FontWeight="SemiBold" />
                    <TextBlock Text="Impressions" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="13" FontWeight="SemiBold" />
                    <StackPanel Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                      <TextBlock Text="10K" FontWeight="SemiBold" Margin="5 0" />
                      <ProgressBar Margin="5 0" Width="100" Height="8" Foreground="#FFFFFF13" Background="#FFE8E8E8" BorderBrush="#FFF3F349" Value="78" />
                      <TextBlock Text="12K" FontWeight="SemiBold" />
                    </StackPanel>
                    <StackPanel Grid.Column="1" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                      <TextBlock Text="10K" FontWeight="SemiBold" Margin="5 0" />
                      <ProgressBar Margin="5 0" Width="100" Height="8" Foreground="#FFFFFF13" Background="#FFE8E8E8" BorderBrush="#FFF3F349" Value="78" />
                      <TextBlock Text="12K" FontWeight="SemiBold" />
                    </StackPanel>
                    <StackPanel Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                      <TextBlock Text="10K" FontWeight="SemiBold" Margin="5 0" />
                      <ProgressBar Margin="5 0" Width="100" Height="8" Foreground="SeaGreen" Background="#FFE8E8E8" BorderBrush="SeaGreen" Value="78" />
                      <TextBlock Text="12K" FontWeight="SemiBold" />
                    </StackPanel>
                    <StackPanel Grid.Column="1" Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                      <TextBlock Text="10K" FontWeight="SemiBold" Margin="5 0" />
                      <ProgressBar Margin="5 0" Width="100" Height="8" Foreground="SeaGreen" Background="#FFE8E8E8" BorderBrush="SeaGreen" Value="78" />
                      <TextBlock Text="12K" FontWeight="SemiBold" />
                    </StackPanel>                    
                  </Grid>
                </StackPanel>
              </materialDesign:Card>
              <materialDesign:Card Margin="10" UniformCornerRadius="20" Background="#633648">
                <StackPanel Margin="10">
                  <TextBlock Text="Engagged Users" FontSize="14" Foreground="White" TextAlignment="Center" />
                  <TextBlock Text="12.5K" TextAlignment="Center" Margin="0 5" Foreground="White" FontSize="18" />
                  <lvc:CartesianChart Margin="0 5" Series="{Binding LastHourSeries}" Hoverable="False" DataTooltip="{x:Null}" Height="160" Width="160">
                    <lvc:CartesianChart.AxisX>
                      <lvc:Axis MinValue="0" />
                    </lvc:CartesianChart.AxisX>
                  </lvc:CartesianChart>
                  <materialDesign:PackIcon Kind="ArrowUp" HorizontalAlignment="Center" Margin="0 5" Width="20" Height="20" Foreground="#62A78B" />
                </StackPanel>
              </materialDesign:Card>
              <materialDesign:Card Margin="10" UniformCornerRadius="20" Background="#633648">
                <StackPanel Margin="10">
                  <TextBlock Text="Page Impression" FontSize="14" Foreground="White" TextAlignment="Center" />
                  <TextBlock Text="12.5K" TextAlignment="Center" Margin="0 5" Foreground="White" FontSize="18" />
                  <lvc:CartesianChart Margin="0 5" Series="{Binding LastHourSeries1}" Hoverable="False" DataTooltip="{x:Null}" Height="160" Width="160">
                    <lvc:CartesianChart.AxisX>
                      <lvc:Axis MinValue="0" />
                    </lvc:CartesianChart.AxisX>
                  </lvc:CartesianChart>
                  <materialDesign:PackIcon Kind="ArrowUp" HorizontalAlignment="Center" Margin="0 5" Width="20" Height="20" Foreground="#62A78B" />
                </StackPanel>
              </materialDesign:Card>
            </WrapPanel>
        </StackPanel>
      </Grid>
      <StackPanel Grid.Column="1" Background="White">
        <WrapPanel VerticalAlignment="Top" Margin="20 20 20 10">
          <Button Style="{StaticResource MaterialDesignFloatingActionButton}" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="Black">
            <StackPanel Margin="-5">
              <materialDesign:PackIcon Kind="BellOutline" />
            </StackPanel>
          </Button>
          <Button Background="#FFFFEEFA" BorderBrush="#FFFFEEFA" Foreground="#FFF0689E" Margin="10 0" Height="40">
            <WrapPanel HorizontalAlignment="Center" >
              <materialDesign:PackIcon Kind="GiftOutline" Width="25" Height="25" />
              <TextBlock Text="2 NEW UPDATES" VerticalAlignment="Center" FontWeight="SemiBold" Margin="10 0" />
            </WrapPanel>
          </Button>
          <Button Style="{StaticResource MaterialDesignFloatingActionButton}" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="Black">
            <StackPanel Margin="-5">
              <materialDesign:PackIcon Kind="BellOutline" />
            </StackPanel>
          </Button>
        </WrapPanel>
        <Border Margin="40 10" CornerRadius="20" Background="#FFFFFEFA">
          <Image Source="Images/aaa.jpg" Stretch="Uniform" x:Name="ImgCartoon" Height="150" />
        </Border>
        <Calendar Margin="45 10" />
        <materialDesign:Card Margin="20 10" Padding="5" UniformCornerRadius="20" HorizontalAlignment="Center">
          <WrapPanel Margin="10">
            <materialDesign:PackIcon Kind="HandPeace" Foreground="#FFC83D" VerticalAlignment="Center" Margin="10 0" />
            <TextBlock Margin="10 0" VerticalAlignment="Center">
              <TextBlock.Inlines>
                <Run Text="Say Hi To" />
                <Run Text="Laith Hart" FontWeight="SemiBold" FontSize="14" />
              </TextBlock.Inlines>
            </TextBlock>
            <Image Source="Images/bbb.jpg" Width="40" Height="40" x:Name="avatar1" Margin="10 0" />
          </WrapPanel>
        </materialDesign:Card>
        <materialDesign:Card Margin="20 10" Padding="5" UniformCornerRadius="20" HorizontalAlignment="Center">
          <WrapPanel Margin="10">
            <materialDesign:PackIcon Kind="HandPeace" Foreground="#FFC83D" VerticalAlignment="Center" Margin="10 0" />
            <TextBlock Margin="10 0" VerticalAlignment="Center">
              <TextBlock.Inlines>
                <Run Text="Say Hi To" />
                <Run Text="Laith Hart" FontWeight="SemiBold" FontSize="14" />
              </TextBlock.Inlines>
            </TextBlock>
            <Image Source="Images/bbb.jpg" Width="40" Height="40" x:Name="avatar2" Margin="10 0" />
          </WrapPanel>
        </materialDesign:Card>
      </StackPanel>
    </Grid>
</UserControl>

 

차트에 뿌려줄 데이터 및 동작을 cs파일에 구현합니다.

<Dashboard.xaml.cs>

using LiveCharts;
using LiveCharts.Wpf;
using System;
using System.IO;
using LiveCharts.Defaults;
using System.Windows.Controls;
using System.Windows.Media.Imaging;

namespace wpf_test04UT2
{

  public partial class Dashboard : UserControl
  {
    public SeriesCollection SeriesCollection { get; set; }
    public SeriesCollection LastHourSeries { get; set;  }
    public SeriesCollection LastHourSeries1 { get; set;  }
    public string[] Labels { get; set; }
    public Func<double,string> Formatter { get; set; }    
    public Dashboard()
    {
      InitializeComponent();
      SeriesCollection = new SeriesCollection{
        new StackedColumnSeries
        {
          Values = new ChartValues<double> {25, 52, 61, 89},
          StackMode = StackMode.Values,
          DataLabels = true
        },
        new StackedColumnSeries
        {
          Values = new ChartValues<double> {-15, -75, -16, -49},
          StackMode = StackMode.Values,
          DataLabels = true
        }
      };
      LastHourSeries = new SeriesCollection
      {
        new LineSeries
        {
          AreaLimit = -10,
          Values = new ChartValues<ObservableValue>
          {
            new ObservableValue(3),
            new ObservableValue(1),
            new ObservableValue(9),
            new ObservableValue(4),
            new ObservableValue(5),
            new ObservableValue(3),
            new ObservableValue(1),
            new ObservableValue(2),
            new ObservableValue(3),
            new ObservableValue(7),
          }
        }
      };
      LastHourSeries1 = new SeriesCollection
      {
        new LineSeries
        {
          AreaLimit = -10,
          Values = new ChartValues<ObservableValue>
          {
            new ObservableValue(13),
            new ObservableValue(11),
            new ObservableValue(9),
            new ObservableValue(14),
            new ObservableValue(5),
            new ObservableValue(3),
            new ObservableValue(1),
            new ObservableValue(2),
            new ObservableValue(3),
            new ObservableValue(7),
          }
        }
      };
      Labels = new[] { "Feb 7", "Feb8", "Feb 9", "Feb 10" };
      Formatter = GetValue => GetValue.ToString();
      DataContext = this;
      string imgCartoon = Directory.GetCurrentDirectory().ToString()+"\\Images\\aaa.jpg";      
      string imgavatar  = Directory.GetCurrentDirectory().ToString()+"\\Images\\bbb.jpg";   
      ImgCartoon.Source = new BitmapImage(new Uri(imgCartoon));
      avatar1.Source = new BitmapImage(new Uri(imgavatar));
      avatar2.Source = new BitmapImage(new Uri(imgavatar));
    }    
  }  
}

 

5. 결과

좀 있어보이나요? 좌측 메뉴가 동영상 강좌랑 달리 스타일이 안들어간 것 같습니다만, 수정하기 귀찮네요..필요할 때 하다보면 되겠죠..??ㅠㅠ

 

~~~끝~~~

반응형
반응형

오늘은 아래 유튜브 영상의 데스크탑 어플리케이션을 구현해보겠습니다.

https://www.youtube.com/watch?v=sgEhK3mbDYo

 

 

1. 라이브러리 설치

이번 영상에서는 Material Design과 LiveCharts를 사용합니다. 아래의 명령으로 Package를 설치해줍니다.

dotnet add package MaterialDesignThemes --version 4.2.1 // material Design 설치
dotnet add package LiveCharts.Wpf --version 0.9.7 // live chart 설치

또는 Nuget GUI Manager 를 설치 후

 

Shift + Ctrl + P 로 명령창에서 Nuget 입력 시 나타나는 명령을 수행합니다.

그리고 Nuget Package Manager에서 아래와 같이 설치해줍니다. Material Design Themes와 Livecharts.wpf로 검색되는 패키지를 설치해줍니다.


2. 라이브러리 적용

Material Design을 적용해야합니다. 적용하는 방법은 구글에서 < material design xaml >이라고 검색하면 나오는데, 여기 사이트를 참조하시면 되겠습니다. 그리고, 나중에 livechart에서 사용할 스타일도 정의해놓겠습니다.

<App.xaml>

<Application x:Class="wpf_test04UT1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:wpf_test04UT1"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

 

추가로, WS Simple Gallifreyan 폰트가 강좌 중간에 필요합니다. 적당히 다운받아 사용 가능한데, 이번엔 패스하겠습니다.

 

3. 구현

<MainWindow.xaml>

<Window x:Class="wpf_test04UT1.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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        xmlns:MetroChart="clr-namespace:De.TorstenMandelkow.MetroChart;assembly=De.TorstenMandelkow.MetroChart"
        xmlns:local="clr-namespace:wpf_test04UT1"
        mc:Ignorable="d"
        Title="MainWindow" Height="800" Width="1024"
        WindowStyle="None">
        
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid Grid.Column="1" Grid.Row="1" Background="#FFE6E6E6">
            <ScrollViewer>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="200"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                    </Grid.ColumnDefinitions>
                    
                    <Grid Grid.Column="0">
                        <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10">
                            <Rectangle.Effect>
                                <DropShadowEffect BlurRadius="20"/>
                            </Rectangle.Effect>
                        </Rectangle>
                        <Grid Margin="25" Height="120">
                            <Grid Width="35" Height="50" Background="#FFFFAF24" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
                                <Grid.Effect>
                                    <DropShadowEffect BlurRadius="20"/>
                                </Grid.Effect>
                                <materialDesign:PackIcon Kind="ContentCopy" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
                            </Grid>
                            <TextBlock Text="Espaco Usado" HorizontalAlignment="Right" FontFamily="Champagne &amp; Limousines" Margin="5" VerticalAlignment="Top" Foreground="Gray"/>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10 20">
                                <TextBlock Text="49/50" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Center" Foreground="Gray" FontSize="50"/>
                                <TextBlock Text="GB" FontFamily="Champagne &amp; Limousines" Margin="0 5" VerticalAlignment="Bottom" Foreground="Gray" FontSize="20" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20" Cursor="Hand">
                                <materialDesign:PackIcon Kind="AlertOutline" Foreground="Red" Width="10" Height="10" VerticalAlignment="Center" Margin="5 0"/>
                                <TextBlock Text="AAdquirir mais espaco" FontSize="10" Foreground="#FF8522BD"/>
                            </StackPanel>
                        </Grid>
                    </Grid>

                    <Grid Grid.Column="1">
                        <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10">
                            <Rectangle.Effect>
                                <DropShadowEffect BlurRadius="20"/>
                            </Rectangle.Effect>
                        </Rectangle>
                        <Grid Margin="25" Height="120">
                            <Grid Width="35" Height="50" Background="#FF41A43C" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
                                <Grid.Effect>
                                    <DropShadowEffect BlurRadius="20"/>
                                </Grid.Effect>
                                <materialDesign:PackIcon Kind="Store" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
                            </Grid>
                            <TextBlock Text="Receita" HorizontalAlignment="Right" FontFamily="Champagne &amp; Limousines" Margin="5" VerticalAlignment="Top" Foreground="Gray"/>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10 30">
                                <TextBlock Text="R$" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Bottom" Margin="0 2" Foreground="Gray" FontSize="20"/>
                                <TextBlock Text="35.674,00" FontFamily="Champagne &amp; Limousines"  VerticalAlignment="Bottom" Foreground="Gray" FontSize="25" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20" Cursor="Hand">
                                <materialDesign:PackIcon Kind="Calendar" Foreground="Gray" Width="10" Height="10" VerticalAlignment="Center" Margin="5 0"/>
                                <TextBlock Text="Ultimas 24h" FontSize="10" Foreground="Gray"/>
                            </StackPanel>
                        </Grid>
                    </Grid>

                    <Grid Grid.Column="2">
                        <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10">
                            <Rectangle.Effect>
                                <DropShadowEffect BlurRadius="20"/>
                            </Rectangle.Effect>
                        </Rectangle>
                        <Grid Margin="25" Height="120">
                            <Grid Width="35" Height="50" Background="#FFCF1F1F" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
                                <Grid.Effect>
                                    <DropShadowEffect BlurRadius="20"/>
                                </Grid.Effect>
                                <materialDesign:PackIcon Kind="InformationOutline" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
                            </Grid>
                            <TextBlock Text="Erros Corrigidos" HorizontalAlignment="Right" FontFamily="Champagne &amp; Limousines" Margin="5" VerticalAlignment="Top" Foreground="Gray"/>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10 30">                                
                                <TextBlock Text="75" FontFamily="Champagne &amp; Limousines"  VerticalAlignment="Center" Foreground="Gray" FontSize="40" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20" Cursor="Hand">
                                <materialDesign:PackIcon Kind="Github" FontSize="15" Foreground="Gray" Width="10" Height="10" VerticalAlignment="Center" Margin="5 0"/>
                                <TextBlock Text="Monitorado pelo Git Hub" FontSize="11" Foreground="Gray"/>
                            </StackPanel>
                        </Grid>
                    </Grid>     

                    <Grid Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="3" HorizontalAlignment="Center" Width="580" Height="550"> 
                        <Grid Background="White" Margin="20 50 20 20">
                            <Grid.OpacityMask>
                                <VisualBrush Visual="{ Binding ElementName=BorderG1 }"/>
                            </Grid.OpacityMask>
                            <Border x:Name="BorderG1" CornerRadius="5" Background="White" />
                            <StackPanel VerticalAlignment="Bottom">
                                <TextBlock Text="Receita Diaria" FontFamily="Champagne &amp; Limousines" Margin="20 10" VerticalAlignment="Bottom" Foreground="Gray" FontSize="30"/>
                                <StackPanel Orientation="Horizontal" Margin="20 5" >
                                    <materialDesign:PackIcon Kind="ArrowUp" Foreground="Green" VerticalAlignment="Center"/>
                                    <TextBlock Text="55%" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Bottom" Foreground="Green" FontSize="15"/>
                                    <TextBlock Text="Crescimento nas vendas hoje" Margin="20 0" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Bottom" Foreground="Gray" FontSize="20"/>   
                                </StackPanel>
                                <StackPanel Orientation="Horizontal" Margin="10 5" >
                                    <materialDesign:PackIcon Kind="Clock" Foreground="Gray" VerticalAlignment="Center"/>                                    
                                    <TextBlock Text="Atualizado a 4 minutos" Margin="5 0" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Bottom" Foreground="Gray" FontSize="20"/>   
                                </StackPanel>
                            </StackPanel>                            

                        </Grid>
                        <Grid Margin="50 20 50 200">
                            <Grid.OpacityMask>
                                <VisualBrush Visual="{ Binding ElementName=BorderG2 }"/>
                            </Grid.OpacityMask>
                            <Border x:Name="BorderG2" CornerRadius="15" Background="#FF340051" />

                            <MetroChart:RadialGaugeChart Background="{x:Null}" ChartTitle="Consumo" ChartSubTitle="" Foreground="LightGray" HorizontalAlignment="Center">
                                <MetroChart:RadialGaugeChart.Series>
                                    <MetroChart:ChartSeries
                                        DisplayMember="Titulo"
                                        ItemsSource="{Binding Path=Consumo}"
                                        SeriesTitle="Consumo"
                                        ValueMember="Porcentagem" />
                                </MetroChart:RadialGaugeChart.Series>
                            </MetroChart:RadialGaugeChart>
                        </Grid>                    
                    </Grid>               
                </Grid>
            </ScrollViewer>
        </Grid>

        <Grid Grid.Row="1">
            <Grid.Background>
                <LinearGradientBrush EndPoint="0 1" StartPoint="0 0">
                    <GradientStop Offset="0.0" Color="#aeaeae" />
                    <GradientStop Offset="1.0" Color="#888" />
                </LinearGradientBrush>
            </Grid.Background>
            <Grid.RowDefinitions>
                <RowDefinition Height="100"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.Effect>
                <DropShadowEffect BlurRadius="20"/>                
            </Grid.Effect>            

            <Grid Background="#ffa46fe4">
                <TextBlock Text="DASHBOARD" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="WS Simple Gallifreyan" Foreground="#FFBC96EA" FontSize="16"/>
            </Grid>

            <StackPanel Grid.Row="1">
            
                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="ViewDashboard" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="DASHBOARD"/>
                    </Grid>
                </Button>
                
                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="Account" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="PROFILE"/>
                    </Grid>
                </Button>

                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="ContentPaste" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="TABLES"/>
                    </Grid>
                </Button>

                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="TruckDelivery" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="PROVIDERS"/>
                    </Grid>
                </Button>

                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="Settings" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="CONFIGURATIONS"/>
                    </Grid>
                </Button>

            </StackPanel>
        </Grid>

        <Grid x:Name="GridBarraTitulo"  Grid.ColumnSpan="2" Background="#FF8522BD" MouseDown="GridBarraTitulo_MouseDown">
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Background="{x:Null}" Margin="10,0">
                <Button Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}" Width="25" Height="25" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White">
                    <materialDesign:PackIcon Kind="Bell"/>
                </Button>
                <Button Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}" Width="25" Height="25" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White">
                    <materialDesign:PackIcon Kind="Account"/>
                </Button>
                <Button x:Name="ButtonFecher" Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}" Width="25" Height="25" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" Click="ButtonFechar_Click">
                    <materialDesign:PackIcon Kind="Power"/>
                </Button>
            </StackPanel>
        </Grid>
    </Grid>
</Window>

 

<MainWindow.xaml.cs (데이터 주입부)>

using System.Windows;
using System.Collections.Generic;

namespace wpf_test04UT1
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Consumo consumo = new Consumo();
            DataContext = new ConsumoViewModel(consumo);
        }
        private void ButtonFechar_Click(object sender, RoutedEventArgs e){
            Application.Current.Shutdown();
        }
        private void GridBarraTitulo_MouseDown(object sender, RoutedEventArgs e){
            DragMove();
        }


    }
    internal class ConsumoViewModel{
        public List<Consumo> Consumo { get;  private set; }

        public ConsumoViewModel(Consumo consumo){
            Consumo = new List<Consumo>();
            Consumo.Add(consumo);
    }
    }

    internal class Consumo {
        public string Titulo { get; private set; }
        public int Porcentagem{ get; private set; }
        public Consumo(){
        Titulo = "Consum, Atual";
        Porcentagem = CalcularPorcentagem();

        }
        private int CalcularPorcentagem(){
            return 47; //
        }
  }
}

 

4. 결과

커맨드창에서 

dotnet build
dotnet run

하면 아래와 같이 이쁜 UI가 실행됩니다.

...이거 하느라...3시간 반 동영상보며 따라했네요..ㅠㅠ. 그래도 이쁜 결과물이 나와줘서 뿌듯합니다.

 

~~~끝~~~

반응형
반응형

파일관리 프로그램 예제입니다.

 

<main.py>

## File Chooser

from kivy.app import App
from kivy.uix.gridlayout import GridLayout

class TopGridLayout(GridLayout):
    def selected(self, directory, filename):
        try:
            self.ids.image.source = filename[0]
        except:
            pass

class TreeApp(App):
    def build(self):
        return TopGridLayout()

if __name__ == '__main__':
    TreeApp().run()

 

<tree.kv>

<TopGridLayout>:
    cols:2
    id:my_widget

    #FileChooserIconView:
    FileChooserListView:
        id:filechooser
        path:'D:\\'
        dirselect: True
        on_selection:my_widget.selected(filechooser.path, filechooser.selection)

    Image:
        id:image
        source:""

 

<결과>

 

한글 지원이 아직 부족하네요.

반응형
반응형

행성들이 가운데 태양을 중심으로 공전하는 모습을 구현해보겠습니다.

 

<main.py>

import math

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.clock import Clock
import math

Window.size = (900, 900)
center_w = Window.size[0]/2
center_h = Window.size[1]/2

class Sun(Widget):
    pass

class Mercury(Widget):
    pass

class Vinus(Widget):
    pass

class Earth(Widget):
    pass

class Mars(Widget):
    pass

class Solar(Widget):
    sw_seconds = 0
    def update(self, nap):  # nap: 증분, dt delta time
        self.sw_seconds += nap

        ## Earth
        E_dis = 300   # 태양으로부터의 거리
        E_r = self.ids.earth.size[0]      # 지구 직경
        E_rv = 45 # 각도도
        self.ids.earth.pos = self.calc_pos(E_dis, E_r, E_rv)

        ## Mercury
        M_dis = 80  # 태양으로부터의 거리
        M_r = self.ids.mercury.size[0]    # 수성 직경
        M_rv = 60  # 시간에 따른 각도
        self.ids.mercury.pos = self.calc_pos(M_dis, M_r, M_rv)

        ## Vinus
        V_dis = 120  # 태양으로부터의 거리
        V_r = self.ids.vinus.size[0]  # 금성 직경
        V_rv = 50  # 시간에 따른 각도
        self.ids.vinus.pos = self.calc_pos(V_dis, V_r, V_rv)

        ## Mars
        MS_dis = 350  # 태양으로부터의 거리
        MS_r = self.ids.mars.size[0]  # 화성 직경
        MS_rv = 30  # 시간에 따른 각도
        self.ids.mars.pos = self.calc_pos(MS_dis, MS_r, MS_rv)



    def calc_pos(self, dis, radius, radial_v):
        degree = radial_v * self.sw_seconds
        pos_x = dis * math.cos(math.pi * degree / 180) + center_w
        pos_y = dis * math.sin(math.pi * degree / 180) + center_h
        pos = (pos_x, pos_y)
        return pos

class SolarApp(App):
    def build(self):
        SolarSystem = Solar()
        Clock.schedule_interval(SolarSystem.update, 1.0 / 60.0)
        return SolarSystem

if __name__ == '__main__':
    SolarApp().run()

 

<solar.kv>

<Sun>:
    size: 50, 50
    canvas:
        Color:
            rgb: 1,0,0
        Ellipse:
            size: self.size
            pos: self.pos

<Mercury>:
    size: 15, 15
    canvas:
        Color:
            rgb: 0,0,1
        Ellipse:
            size: self.size
            pos: self.pos
<Vinus>:
    size: 20, 20
    canvas:
        Color:
            rgb: 1,1,0
        Ellipse:
            size: self.size
            pos: self.pos

<Earth>:
    size: 20, 20
    canvas:
        Color:
            rgb: 0,1,1
        Ellipse:
            size: self.size
            pos: self.pos
<Mars>:
    size: 18, 18
    canvas:
        Color:
            rgb: 1,0.3,0
        Ellipse:
            size: self.size
            pos: self.pos

<Solar>:
    Sun:
        id:sun
        pos: self.parent.center
    Mercury:
        id:mercury
        pos: self.parent.center
    Vinus:
        id:vinus
        pos: self.parent.center
    Earth:
        id:earth
        pos: self.parent.center
    Mars:
        id:mars
        pos: self.parent.center

<결과>

반응형
반응형

1. hello_world.py

import PySimpleGUI as sg

sg.Window(title="Hello World", layout=[[]], margins=(100,50)).read()

 

2. hello_psg.py

import PySimpleGUI as sg

layout = [
    [sg.Text("Hello from PySimpleGUI")],
    [sg.Button("OK")]
]

window = sg.Window("Demo", layout)

while True:
    event, values = window.read()
    if event =="OK" or event == sg.WIN_CLOSED:
        break

window.close()

3. Image_Viewer.py

import PySimpleGUI as sg
import os.path
file_list_column = [
    [
        sg.Text("Image Folder"),
        sg.In(size=(25,1), enable_events=True, key="-FOLDER-"),
        sg.FolderBrowse(),
    ],
    [
        sg.Listbox(
            values=[], enable_events=True, size=(40, 20),
            key="-FILE LIST-"
        )
    ],
]
image_viewer_column = [
    [sg.Text("Choose an image from the list on the left:")],
    [sg.Text(size=(40,1), key="-TOUT-")],
    [sg.Image(key="-IMAGE-")],
]

layout = [
    [
        sg.Column(file_list_column),
        sg.VSeperator(),
        sg.Column(image_viewer_column),
    ]
]

window = sg.Window("Image Viewer", layout)

while True:
    event, values = window.read()
    if event =="Exit" or event == sg.WINDOW_CLOSED:
        break
    if event == "-FOLDER-":
        folder = values["-FOLDER-"]
        try:
            file_list = os.listdir(folder)
        except:
            file_list = []

        fnames = [
            f
            for f in file_list
            if os.path.isfile(os.path.join(folder, f))
            and f.lower().endswith((".png", ".gif"))
        ]
        window["-FILE LIST-"].update(fnames)
    elif event == "-FILE LIST-":
        try:
            filename = os.path.join(
                values["-FOLDER-"], values["-FILE LIST-"][0]
            )
            window["-TOUT-"].update(filename)
            window["-IMAGE-"].update(filename=filename)
        except:
            pass


window.close()

 

<결과>

반응형
반응형

Fyne tutorial에 있는 timer 예제입니다.

 

1. main.go

package main

import (
	"time"

	"fyne.io/fyne/app"
	"fyne.io/fyne/widget"
)

func showTime(clock *widget.Label) {
	formatted := time.Now().Format("03:04:05")	//현재시각을 포멧에 따라 출력한다.
	clock.SetText(formatted)
}

func main() {
	a := app.New()
	w := a.NewWindow("Clock")

	clock := widget.NewLabel("")
	showTime(clock)

	w.SetContent(clock)
	go func() {
		t := time.NewTicker(time.Second) //매 초마다 메시지(시간)를 전송하는 채널 t생성 

		for range t.C {			//채널 C로 time값을 받아 순서대로 처리한다. 
			showTime(clock)		//매 초마다 시간을 출력한다. 
		}
	}()

	w.ShowAndRun()	//앱을 보여주고 실행한다. 
}
 

 

<결과>

 

 

~~끝~~

 
반응형

+ Recent posts