Como criar botões customizados para o Kinect for Windows

A criação de botões customizados para o Kinect for Windows é bastante simples de ser feita. Para tanto faremos uso de recursos nativos do WPF, orientação a objetos e o Kinect for Windows Developer Toolkit.

Por padrão, o Windows Developer Toolkit contém dois modelos de botões: o KinectTileButton e o KinectCircleButton. O KinectTileButton geralmente é utilizado para navegação entre páginas, enquanto que o KinectCircleButton é utilizado para execução de ações e barras de ferramentas.

TV com Kinect

Para ampliar as opções existentes é preciso criar controles customizados que herdem as características básicas de um botão. O Kinect for Windows Developer Toolkit contém uma classe chamada KinectButtonBase que funciona como base para criação de todo e qualquer botão que se comunica com o Kinect for Windows (por meio do WPF).

Observação: neste exemplo foi utilizada a versão 1.8 do Kinect for Windows Developer Toolkit, mas este exemplo é totalmente compatível com a versão 1.7 do mesmo developer toolkit.

Neste exemplo criaremos um botão com uma imagem de fundo. Este botão irá disparar dois eventos não nativos: um evento quando a mão passar por cima do controle (hand enter) e outro quando a mão deixar o controle (hand leave).

Para fazer o download desse exemplo utilize este link: Criando botões para o Kinect for Windows

Criando a classe do botão

Neste primeiro ponto será preciso criar a classe do botão customizado. Neste exemplo criarei um botão chamado “MyCustomKinectButton”.

Tela de adição de novos itens do Visual Studio

 

O código do botão é apresentado abaixo:

    using Microsoft.Kinect.Toolkit.Controls;
    using System;
    using System.IO;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media.Imaging;
    public class MyCustomKinectButton : KinectButtonBase {

        public event EventHandler OnHandPointerEnter;
        public event EventHandler OnHandPointerLeave;

        public MyCustomKinectButton() {

            InitializeControl();
        }

        private void InitializeControl() {

            KinectRegion.AddHandPointerEnterHandler(this, OnHandPointerEnterHandler);
            KinectRegion.AddHandPointerLeaveHandler(this, OnHandPointerLeaveHandler);

            this.MouseEnter += OnMouseEnter;
            this.MouseLeave += OnMouseLeave;

            this.Style = (Style)Application.Current.FindResource(typeof(MyCustomKinectButton));
        }

        private void OnHandPointerLeaveHandler(object sender, HandPointerEventArgs e) {

            ExecuteHandPointerLeave(this, e);
        }

        private void OnMouseLeave(object sender, System.Windows.Input.MouseEventArgs e) {

            ExecuteHandPointerLeave(this, null);
        }

        private void OnHandPointerEnterHandler(object sender, HandPointerEventArgs e) {

            ExecuteHandPointerEnter(this, e);
        }

        private void OnMouseEnter(object sender, System.Windows.Input.MouseEventArgs e) {

            ExecuteHandPointerEnter(this, null);
        }

        private void ExecuteHandPointerEnter(object sender, HandPointerEventArgs e) {

            if (this.OnHandPointerEnter != null) {

                this.OnHandPointerEnter(this, e);
            }
        }

        private void ExecuteHandPointerLeave(object sender, HandPointerEventArgs e) {

            if (this.OnHandPointerLeave != null) {

                this.OnHandPointerLeave(this, e);
            }
        }

        public override void OnApplyTemplate() {

            ConfigImage();

            base.OnApplyTemplate();
        }

        private void ConfigImage() {

            StackPanel mainPanel = this.GetTemplateChild("MainPanel") as StackPanel;
            Image mainImage = this.GetTemplateChild("MainImage") as Image;

            if (mainPanel != null && mainImage != null) {

                SetImageSize(mainImage);

                SetImage(mainImage);
            }
        }

        private void SetImageSize(Image mainImage) {

            if (this.ActualWidth > 0 && this.ActualHeight > 0) {

                mainImage.Width = this.ActualWidth;
                mainImage.Height = this.ActualHeight;
            }
            else if (this.Width > 0 && this.Height > 0) {

                mainImage.Width = this.Width;
                mainImage.Height = this.Height;
            }
        }

        private static void SetImage(Image mainImage) {

            Assembly currentAssembly = Assembly.GetAssembly(typeof(MyCustomKinectButton));

            using (Stream s = currentAssembly.GetManifestResourceStream("WpfKinect.Images.visualstudio.png")) {

                BitmapImage img = new BitmapImage();

                img.BeginInit();
                img.StreamSource = s;
                img.EndInit();

                mainImage.Source = img;
            }
        }
    }

Pontos a serem destacados:

– MyCustomKinectButton herda da classe KinectButtonBase.

– Existem dois eventos neste botão: OnHandPointerEnter e OnHandPointerLeave. Um deles é chamado quando a mão passa por cima do controle e o outro quando a mão deixa o controle. Veja que para a assinatura destes eventos temos de utilizar a classe KinectRegion (http://msdn.microsoft.com/en-us/library/microsoft.kinect.toolkit.controls.kinectregion_members.aspx). Além disso, associei estes mesmos dois eventos com os eventos MouseEnter e o MouseLeave existentes no controle. Desta forma o controle não perde o seu funcionamento quando usado com o mouse.

– O método OnApplyTemplate é sobrescrito: note que no construtor desta classe a propriedade Style é definida, carregando recursos associados com o tipo de dados MyCustomKinectButton. Além disso, no método OnApplyTemplate é definido o tamanho da imagem e a imagem que será carregada.

A imagem que será carregada e associada com o controle está embutida dentro do assembly do controle como um Embedded Resource – veremos como adicionar um Embedded Resource mais a frente – o código que faz acesso ao Embedded Resource pode ser encontrado no método SetImage.

Criando o dicionário de recursos

Um dicionário de recursos (resource dictionary) é um dicionário de objetos que podem ser utilizados via managed code e/ou via XAML. Geralmente, dicionários de recursos são utilizados na definição de templates para controles – e este será o seu uso neste exemplo.

Como padrão, crio um arquivo chamado Generic.xaml dentro de uma pasta chamada Themes, como na imagem abaixo:

Solution Explorer com a hierarquia da pasta Theme com o arquivo Generic.xaml

O conteúdo do arquivo Generic.xaml pode ser encontrado logo abaixo:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ck="clr-namespace:WpfKinect"
    xmlns:local="clr-namespace:WpfKinect">
    
    <Style TargetType="{x:Type local:MyCustomKinectButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MyCustomKinectButton">
                <StackPanel x:Name="MainPanel">
                    <Image x:Name="MainImage" ClipToBounds="True">
                        <Image.Style>
                            <Style TargetType="{x:Type Image}">
                                <Style.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="Effect">
                                            <Setter.Value>
                                                <DropShadowEffect ShadowDepth="0" Color="Black" Opacity="1" BlurRadius="10"/>
                                            </Setter.Value>
                                        </Setter>
                                    </Trigger>
                                </Style.Triggers>
                            </Style>
                        </Image.Style>
                    </Image>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    </Style>

</ResourceDictionary>

Note que o arquivo se baseia no namespace do assembly corrente, e também perceba que o estilo (theme) descrito via XAML é orientado ao objeto que será renderizado, no caso o objeto MyCustomKinectButton.

Detalhe adicional no XAML: veja que existe uma trigger para a propriedade IsMouseOver. Essa trigger quando acionada inicia uma animação que inclui uma sombra ao redor da imagem.

Abaixo as imagens com o efeito de sombra (esquerda) e sem o defeito de sombra (direita).

Comparação dos icones com e sem sombra

Imagem incorporada ao assembly

Outro ponto importante a ser discutido é a origem da imagem. Neste exemplo fizemos uso de uma imagem incorporada ao assembly. Essa característica é vantajosa, pois torna a solução compacta e centralizada, sem exigir a existência de artefatos externos. Por outro lado, a incorporação de imagens, áudios e vídeos (como qualquer outro tipo de artefato) a um assembly pode ser negativa, pois pode tornar o tamanho do assembly maior.

Incorporar uma imagem a um assembly é simples, basta adicionar a imagem ao projeto (como na imagem abaixo), clicar com o botão direito sobre a imagem, acessar as propriedades da imagem e definir a propriedade “Build Action” como “Embedded Resource” (como em uma das imagens abaixo).

Solution Explorer com o detalhe da imagem adicionada

Menu de propriedades da imagem com destaque para a propriedade Build Action

O código necessário para extração dos bytes da imagem do binário pode ser encontrado no método SetImage, e também é apresentado abaixo:

private static void SetImage(Image mainImage) { 
 
    Assembly currentAssembly = Assembly.GetAssembly(typeof(MyCustomKinectButton)); 
 
    using (Stream s = currentAssembly.GetManifestResourceStream("WpfKinect.Images.visualstudio.png")) { 
 
        BitmapImage img = new BitmapImage(); 
 
        img.BeginInit(); 
        img.StreamSource = s; 
        img.EndInit(); 
 
        mainImage.Source = img; 
    } 
}

Por
MSc. Fernando Henrique Inocêncio Borba Ferreira
Microsoft Most Valuable Professional – Visual C#

Referências:
http://msdn.microsoft.com/en-us/library/cc903952(v=vs.95).aspx
http://msdn.microsoft.com/en-us/library/microsoft.kinect.toolkit.controls.kinectbuttonbase.aspx

Publicidade

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.