20220109のC#に関する記事は5件です。

仮想空間上でアバターに触れるシステム

こんにちは。ナルキタです。 現在私はVRとタッチケアを合わせた研究に携わっています。 今回はその概要を軽く紹介したいと思います。 まず使用機器一覧です。 Oculus Quest 2 Unityインストール済みのPC Webカメラ マイク マネキン まずは上記の機器を以下の図のように配置します。 上図の様に、ユーザにOculusを装着してもらい、VRアプリを実行します。 この時に、目の前のマネキンと仮想空間上のアバターの座標が合致するように注意します。 座標調整が済んだらVRアプリを実行します。 アプリ実行後、ユーザの目の前のアバターが椅子に座ります。ユーザは仮想空間上でアバターに触れたり撫でることができます。仮想空間上の手は、Oculusのハンドトラッキングによって表示されています。 またユーザの手の動きを後ろからwebカメラで撮影し、ハンドトラッキング及び手の座表を取得します。 上の画像では手の座標を緑の点で示しています このように、仮想空間上のアバターをユーザが触れたり撫でることができるVRアプリを制作致しました。 手の速度を検出するシステムは少々複雑ですが、それ以外は簡単なアセットで構成されているUnityシーンですので、皆さんもぜひお試しくださいませ。 それでは~
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】Win32APIで取得した仮想キーコードをKeys列挙型に変換する方法

本文 Win32APIで取得した仮想キーコードを、Formアプリで使用するKeys列挙型に変換する方法。 キーコードをKeysにキャストしたものと、ControlクラスのModifierKeysをORすると変換がおこなる。 C# Keys keys = (Keys)キーコード | Control.ModifierKeys; 一例 キーフックのコールバック関数内で変換する場合。 C# [StructLayout(LayoutKind.Sequential)] internal class KBDLLHOOKSTRUCT { public uint vkCode; public uint scanCode; public uint flags; public uint time; public UIntPtr dwExtraInfo; } private IntPtr HookProcedure(int nCode, IntPtr wParam, KBDLLHOOKSTRUCT lParam) { if (nCode == 0) { Keys keys = (Keys)lParam.vkCode | Control.ModifierKeys; } return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam); } 参考 Windows FormsのControlクラス https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pulsar C#クライアントライブラリ(DotPulsar)を使ってみた

はじめに こんにちは。 本稿では、PulsarのC#クライアントライブラリ(DotPulsar)(以下、DotPulsar)を使って、簡単なメッセージの送受信をしていきます。 今回は、Windows10上に以下のサーバとクライアントを構築します。 サーバ Pulsar in Docker (standaloneモード) v2.9.1 クライアント .NET SDK 6.0.101(x64) DotPulsar 2.0.1 サーバの準備 PowerShellを開き、以下のコマンドを実行して、 Docker上に、Pulsarのstandaloneモードを構築します。 PS> docker run -it -p 6650:6650 -p 8080:8080 ` --mount source=pulsardata,target=/pulsar/data ` --mount source=pulsarconf,target=/pulsar/conf ` apachepulsar/pulsar:2.9.1 bin/pulsar standalone -nss -nfw クライアントの準備 Consumer PS> dotnet new console -o Consumer PS> cd Consumer PS> dotnet add package DotPulsar Program.csを開いて、以下のコードに修正する。 using DotPulsar; using DotPulsar.Extensions; using System.Text; using System.Buffers; await using var client = PulsarClient.Builder() .ServiceUrl(new Uri("pulsar://localhost:6650")).Build(); await using var consumer = client.NewConsumer() .SubscriptionName("MySubscription") .Topic("persistent://public/default/mytopic") .Create(); await foreach (var message in consumer.Messages()) { Console.WriteLine("Received: " + Encoding.UTF8.GetString(message.Data.ToArray())); await consumer.Acknowledge(message); } Producer PS> dotnet new console -o Producer PS> cd Producer PS> dotnet add package DotPulsar Program.csを開いて、以下のコードに修正する。 using DotPulsar; using DotPulsar.Extensions; using System.Text; using System.Buffers; await using var client = PulsarClient.Builder() .ServiceUrl(new Uri("pulsar://localhost:6650")).Build(); await using var producer = client.NewProducer() .Topic("persistent://public/default/mytopic") .Create(); var text = "Hello World"; _ = await producer.Send(Encoding.UTF8.GetBytes(text)); Console.WriteLine("Sent: " + text); メッセージの送受信 Consumer側の画面 PS> dotnet run Producer側の画面 PS> dotnet run と実行すると、ProducerからConsumerにメッセージが流れ、 Consumer側の画面にReceived: Hello Worldと表示されます。 おわりに 本稿では、DotPulsarを使ったメッセージの送受信を行いました。 今回、シンプルなProducer、Consumerを作成して試しましたが、他にも様々な機能が実装されています。 公式ドキュメントが参考になるかと思います。 参考URL Apache Pulsar DotPulsar
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C# Blazorで作ったサイトをVue.jsで作り直してみた

タイトルの通りのことをやってみました。 結論から言うと、Blazorをやっているとvueの学習コストが下がるので「dotnetしかやったことないよ!」という人にはVueはお勧めできるかと思います。 Blazorで作った話はこちら↓ BlazorでSkclusive-UIを使った話 ページ:https://syamaz.github.io/website/ 今回作ったものはこちら↓ ページ:https://syamaz.github.io/website-vue/ 環境 Vue3 Vue-router@4 Vuetify 3.0.0-alpha Vite gh-pages vueコンポーネントとrazorコンポーネント コンポーネントにはスタイル、テンプレート(UI)、スクリプトが含まれるという点でvueコンポーネントとrazorコンポーネントはほぼ同じ役割を持たせることができます 以下、Materialデザインの「カード」を列挙するページについてのコンポーネントです。 vue コード <template> <v-container> <h1>Works</h1> <v-container v-for="app in apps" v-bind:key="app"> <v-card> <v-card-title>{{app.name}}</v-card-title> <v-card-media> <v-img :src="app.img"></v-img> </v-card-media> <v-card-text>{{ app.text }}</v-card-text> <v-card-subtitle>Platform {{ app.platform.join(", ") }}</v-card-subtitle> <v-card-subtitle>Status {{app.status}}</v-card-subtitle> <v-card-text></v-card-text> <v-divider></v-divider> <v-card-actions> <v-btn v-if="app.url != ''" :to="app.url"><span class="text-info">Read more</span></v-btn> <v-btn v-if="app.outerurl != ''" :href="app.outerurl"><span class="text-info">Read more</span></v-btn> </v-card-actions> </v-card> </v-container> </v-container> </template> <script setup> import routineTreeImg from "../assets/RoutineTree.png" const apps = [ { name: "RoutineTree", img: routineTreeImg, text: "Task management application that helps you accomplish your daily routine tasks.", platform: ["iOS"], status: "In Review", url: "", outerurl: "https://syamaz.github.io/RoutineTree/" }, { name: "My homepage", img: "", text: "This website.", platform: ["web"], status: "Released", url: "/", outerurl: "" } ] </script> <style> </style> Blazor コード @page "/works" @inject NavigationManager navman @using website.Components @using website.Pages.Works.Parts @using website.Pages.Works.Datas <style> .styled-linkbutton { @*縦並び*@ display: block; text-transform:none; } .styled-linkbutton:is(:hover) { text-decoration: underline; } </style> <PageTitle>Works - sYamaz</PageTitle> <Typography Variant="TypographyVariant.H5"> Works </Typography> @foreach (var item in Datas) { <Box Padding="2" Margin="2"> <WorkCardView WorkData="@item" /> </Box> } @code { private IEnumerable<AnyWorkData> Datas { get { yield return new AnyWorkData { Title = "RoutineTree", Description = "Task management application that helps you accomplish your daily routine tasks.", ReadMoreURL = "https://syamaz.github.io/RoutineTree/", ImagePath = "images/RoutineTree.png", Status = WorkStatus.inReview, SupportPlatform = SupportPlatform.iOS }; yield return new AnyWorkData { Title = "Some web app/service", Description = "My practice project using Vue and AWS", ReadMoreURL = "", ImagePath = "images/Noimage.png", Status = WorkStatus.underDevelop, SupportPlatform = SupportPlatform.web }; // --- end --- yield return new AnyWorkData { Title = "My homepage", Description = "This website.", ReadMoreURL = "", ImagePath = "images/Noimage.png", Status = WorkStatus.release, SupportPlatform = SupportPlatform.web }; } } } ルーティング Blazorの場合、デフォルトでルーティング機能が付いてます。 @page "/{url}"をコンポーネント内で宣言することで他ページから遷移することができます。 vueでvue-routerを使う場合はコンポーネントで宣言というよりは一括で宣言することになります。(ドキュメントを十分に読み込めてないだけで、別の方法があるかもしれません) vue コード import { createRouter, createWebHistory } from 'vue-router' // ページのコンポーネントをインポート import AboutVue from '../components/About.vue' import WorksVue from '../components/Works.vue' import PostsVue from '../components/Posts.vue' const routes = [ { path: '/', name: 'About', component: AboutVue }, { path: '/works', name: 'Works', component: WorksVue }, { path: '/posts', name: 'Posts', component: PostsVue }, ] const baseURL = import.meta.env.BASE_URL; console.log("base : " + baseURL) const router = createRouter({ history: createWebHistory(baseURL), routes }) export default router GitHub Pages 基本的に楽をしたいため、gh-pagesnpmパッケージを使用します。 vite.config.jsにデバッグ時と公開時でBaseURLをスイッチする定義を追加 // vite.config.js import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import vuetify from '@vuetify/vite-plugin' import path from 'path' // https://vitejs.dev/config/ export default defineConfig({ // 略 resolve: { alias: { '@': path.resolve(__dirname, 'src'), }, }, // この一行を追加 '/{Githubリポジトリ名}'とか'/'とか base: process.env.NODE_ENV === 'production' ? '{公開時}' : '{デバッグ時}', // 略 }) このbaseプロパティをvue-routerで使用します import.meta.env.BASE_URL: {string} アプリが配信されているベース URL。これは base 設定オプション によって決まります。 //vue-router@4 const baseURL = import.meta.env.BASE_URL; const router = createRouter({ history: createWebHistory(baseURL), routes }) export default router まとめ dotnet開発者が→Webに手を広げていく際の一つの道が、「WinForm/WPF/UWP」→「Blazor」→「vue」なのかもしれません
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WPFで簡単レポート作成(2)複数ページのレポート

はじめに この記事は、WPFのFixedDocumentを使ったレポート作成について書いた別記事『WPFで簡単レポート作成』の続きだ。(前回記事も是非見てください) 前回は単一ページの例だったが、今回はページが複数になるレポートの例を書いてみた。 行数が変化するレポート 例えば請求書というものは、売り物や取引内容にもよるが、請求項目の行数が変化することが多い。必ずしも内容が1ページに収まるとは限らない。そんなときは、ページネーションが必要になる。 今回、ページネーションを考慮して作るレポートの見た目は、こんな感じだ。 請求項目が多くなる場合、実際の請求書は表紙があり、そこに収まらないときにアタッチシートが付くといった構造になるだろう。しかし、今回は話を単純化するために画像のようなアタッチのみのレポートとする。 データの準備 以下は、データを格納するクラス。 商品出荷.cs internal class 商品出荷 { public DateTime 出荷日 { get; set; } public string? 品名 { get; set; } public decimal 数量 { get; set; } public decimal 単価 { get; set; } public decimal 金額 { get { return Math.Ceiling(数量 * 単価); } } } 以下で、商品内容やデータ行数をランダムに作成し、起動ごとに表示内容が変化するようにしている。 MainWindowViewModel.cs private List<商品出荷> 商品出荷データ作成() { var shukkas = new List<商品出荷>(); var rand = new Random(); var count = rand.Next(10, 100); for (int i = 1; i < count; i++) { shukkas.Add(new 商品出荷() { 出荷日 = DateTime.Now.AddDays(i - 200), 品名 = "商品" + i, 数量= rand.Next(10, 100) * 100, 単価 = rand.Next(10, 100) * 10, }); } return shukkas; } DataGridで簡単な一覧表を作る WPFで先ほどの画像のような一覧表を作成するにはDataGridが最も適している。しかし、DataGridのデフォルトではタイトル行が立体的になっていて帳票に相応しい見た目では無い。だが、それも設定次第でらしくなる。タイトル行のBackgroundを白く塗ることで以下のような単純な表に変わってくれる。 その他にも細かく設定が必要だが、XAMLを一度書いてしまえば後はコピーして再利用できるので、さほど苦労を感じない。 以下は事務的で飾り気のない、いわゆる帳票を作表する為のちょっとしたエッセンスが含まれている。 AttachUserControl.xaml <UserControl x:Class="MultiPageReport.UserControls.AttachUserControl" -- 省略 -- Height = "1122.52" Width = "793.7"> <UserControl.Resources> <Style x:Key="Header1" TargetType="DataGridColumnHeader"> <Setter Property="Background" Value="White"/> <Setter Property="BorderBrush" Value="Black"/> <Setter Property="BorderThickness" Value="0,0,1,1"/> <Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="Height" Value="0.76cm"/> </Style> <Style x:Key="Text1" TargetType="TextBlock"> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="HorizontalAlignment" Value="Left"/> </Style> <Style x:Key="Text2" TargetType="TextBlock"> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="HorizontalAlignment" Value="Right"/> </Style> </UserControl.Resources> <Canvas Background="White"> <DataGrid ItemsSource="{Binding 商品出荷s}" RowHeight="30" AutoGenerateColumns="False" RowHeaderWidth="0" BorderBrush="Black" BorderThickness="1,1,0,0" CanUserAddRows="False" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontFamily="MS Mincho" IsHitTestVisible="False" Margin="2cm,2cm" Width="17cm" ColumnHeaderStyle="{StaticResource Header1}"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding 出荷日,StringFormat=yyyy/MM/dd}" Header="出荷日" Width="*" ElementStyle="{StaticResource Text1}"/> <DataGridTextColumn Binding="{Binding 品名}" Header="品名" Width="*" ElementStyle="{StaticResource Text1}"/> <DataGridTextColumn Binding="{Binding 数量,StringFormat={}{0:N0}}" Header="数量" Width="*" ElementStyle="{StaticResource Text2}"/> <DataGridTextColumn Binding="{Binding 単価,StringFormat=C,ConverterCulture=ja-JP}" Header="単価" Width="*" ElementStyle="{StaticResource Text2}"/> <DataGridTextColumn Binding="{Binding 金額,StringFormat=C,ConverterCulture=ja-JP}" Header="金額" Width="*" ElementStyle="{StaticResource Text2}"/> </DataGrid.Columns> </DataGrid> </Canvas> </UserControl> これをデザインビューで見ると以下のように映る。 ページヘッダー用のTextBlockを置いてページ番号も表示できるが、今回は手抜き。 yield returnでページを吐き出す ページ作りは、前節のAttachUserControlのDataContextに、値を設定したAttachViewModelを代入して、1ページずつyield returnで吐き出す。AttachViewModelのメンバは商品出荷クラスのリストだけだ。 AttachViewModel.cs internal class AttachViewModel { public List<商品出荷> 商品出荷s { get; set; } } MainWindowViewModel.cs private IEnumerable<UserControl> GenerateUserControls() { var shukkas = 商品出荷データ作成(); int rowSize = 30; int rowCount = shukkas.Count; int pageCount = (int)Math.Ceiling((decimal)(rowCount / rowSize)); int bgnRow=0,endRow = rowSize-1; for (int p = 0; p < pageCount; p++) { if (endRow > rowCount - 1) { endRow = rowCount - 1; } yield return new AttachUserControl() { DataContext = new AttachViewModel() { 商品出荷s = shukkas.Where((v, i) => i >= bgnRow && i <= endRow).ToList(), } }; bgnRow += rowSize; endRow += rowSize; } } 商品出荷sリストを作るために使っているWhereメソッドは、呼び出されるたびにshukkasリスト内の全アイテムを舐めて条件の真偽を判定している。非効率であることがデバッグしてみてわかったが、そこはそっとしておいてくれ 上記のイテレータを使って、FixedDocumentにページを格納していく。イテレータでyield returnされるたびに制御が外側のMainWindowViewModelのコンストラクタに移る。 MainWindowViewModel.cs public FixedDocument ReportViewer { get; } public MainWindowViewModel() { var doc = new FixedDocument(); foreach (UserControl report in GenerateUserControls()) { var page = new FixedPage() { Height = 1122.52, Width = 793.7 }; var pageContent = new PageContent(); page.Children.Add(report); pageContent.Child = page; doc.Pages.Add(pageContent); } ReportViewer = doc; } MainWindow.xamlは前回記事『WPFで簡単レポート作成』と変わらない。 MainWindow.xaml <Window x:Class="MultiPageReport.MainWindow" -- 省略 -- Title="MainWindow" Height="600" Width="600"> <Window.DataContext> <local:MainWindowViewModel/> </Window.DataContext> <Grid> <ContentPresenter Content="{Binding ReportViewer}"/> </Grid> </Window> 表紙があってアタッチがそれに続く構造の場合、表紙用のユーザーコントロールとアタッチ用のユーザーコントロールを別々に用意して、イテレータを以下のようなロジックで書き換える。表示データの開始行と終了行を調整すれば、表紙とアタッチを幾つかのバリエーションで作れるだろう。 MainWindowViewModel.cs private IEnumerable<UserControl> GenerateUserControls() { // // 表紙ViewModelをnewして値設定 // yield return new 表紙UserControl() { DataContext = 表紙ViewModel, }; for (int p = 0; p < pageCount; p++) { // // アタッチViewModelをnewして値設定 // yield return new アタッチUserControl() { DataContext = アタッチViewModel, }; // } } 表紙の請求書自体の作成もループさせれば、複数ページのアタッチを伴った請求書を連続してプレビューすることも可能だろう。 簡単・便利なWPF & XAMLによるレポート作成。複雑な構造のレポートも手軽に作れて、本当に楽しいぜっ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む