質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

UI

UIはUser Interfaceの略であり、人間がコンピュータとやりとりをするためのシステムです。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

Q&A

解決済

1回答

4636閲覧

ElementHost上にPictureBoxを重ねて透過させたい

g_uo

総合スコア212

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

UI

UIはUser Interfaceの略であり、人間がコンピュータとやりとりをするためのシステムです。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

0グッド

0クリップ

投稿2017/03/28 06:26

###ElementHost上にPictureBoxを重ねてPictureBoxを透過させる
Windows Form Applicationにおいて、ElementHostにPictureBoxを重ねます。そのうえで、PictureBoxを透過させElementHostの描画が見えるようにしたいです。

これを実現する方法はありますでしょうか?また、そもそも実現可能なものでしょうか?

###透過しない
PictureBoxのParentにElementHostを設定しても、PictureBoxの背景はFormの背景色が表示されます。
このときPictureBoxのBackColorはTransparentを設定しています。

###実現したいこと
画像の描画速度向上のため、ElementHostを用いてWPF Imageコントロールに画像を描画します。
これに合わせて、画像上に十字のラインを表示し、そのライン上の輝度値を別のChartコントロールにプロットします。

画像描画 -> ElementHost
十字描画 -> PictureBox

これを実現するため、ElemetHostにPictureBoxを重ねたいと考えた次第です。

###補足
本件に関して、個人的に様々な情報を調べましたが的確な回答がありませんでした。何か情報をお持ちでしたらご教示いただきたく存じます。
また、情報源をなくしてしまいましたが、海外のサイトでは今回のような使用方法は実現不可であるといった趣旨の投稿も見受けられました。英文であったこともあり、その信ぴょう性を疑い諦め悪くこちらで質問を投稿しました。
どうぞよろしくお願いします。

なお、Windows Formsは仕様上の制限ですので、WPFですべて作り変えるという方法はとれません。現在は、PictureBoxを2枚重ねて実現しております。

###開発環境
OS:Windows 8.1 Pro(64bit)
Framework:.Net Framework 4.5.2
IDE:Visual Studio 2013 Professional

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

以前、同じ問題にあたったことがあります。
その時は結局解決せず、2つの画像を動的に合成する処理で逃げました。
今回の問題だと動くコントロールの透過だと思うので、合成して~は適用できないかと思います。
そのため、私なりに考えた案としましては
「画像表示と十字カーソルを一つのユーザーコントロール(以降:UC)をWPFで作る」
です。

要は、WPFで作ったUCをElementHostのChildに与えてあげればよいということです。
多少XAMLの知識は必要ですが、WPF上でなら十字カーソルのようなコントロールを重ねても
今回のような問題は起きません。

実際に書いてみたので、ご参考になればと思います。

■ ユーザーコントロールの画面(UserControl1.xaml)

XML

1<UserControl x:Class="WindowsFormsApplication1.UserControl1" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 d:DesignHeight="300" 7 d:DesignWidth="300" 8 mc:Ignorable="d"> 9 <Canvas Name="PreviewSpace"> 10 11 <!--色を抽出する画像--> 12 <Image x:Name="bgImage" 13 Canvas.Left="0" 14 Canvas.Top="0" 15 Stretch="None"/> 16 17 <!--十字カーソル オブジェクト--> 18 <!--Thumbはドラッグ操作用--> 19 <Thumb x:Name="CloseCursor" 20 Canvas.Left="0" 21 Canvas.Top="0" 22 Width="50" 23 Height="50" 24 DragCompleted="CloseCursor_DragCompleted" 25 DragDelta="CloseCursor_DragDelta"> 26 <Thumb.Template> 27 <ControlTemplate> 28 29 <!--十字カーソルは画像でもいいですが、透過画像を用意するのがめんどうだったのでラインで書きました--> 30 <Grid Background="Transparent"> 31 <Line Stroke="Red" 32 StrokeThickness="2" 33 X1="25" X2="25" Y1="0" Y2="50"/> 34 <Line Stroke="Red" 35 StrokeThickness="2" 36 X1="0" X2="50" Y1="25" Y2="25"/> 37 </Grid> 38 39 </ControlTemplate> 40 </Thumb.Template> 41 </Thumb> 42 </Canvas> 43</UserControl>

■ ユーザーコントロールのビジネスロジック(UserControl1.xaml.cs)

C#

1using System; 2using System.ComponentModel; 3using System.Runtime.CompilerServices; 4using System.Windows; 5using System.Windows.Controls; 6using System.Windows.Controls.Primitives; 7using System.Windows.Media; 8using System.Windows.Media.Imaging; 9 10namespace WindowsFormsApplication1 11{ 12 /// <summary> 13 /// UserControl1.xaml の相互作用ロジック 14 /// </summary> 15 public partial class UserControl1 : UserControl 16 { 17 /// <summary> 18 /// 色情報クラス(変更通知あり) 19 /// </summary> 20 public class RGB : INotifyPropertyChanged 21 { 22 public int R { get { return _R; } set { _R = value; Raise(); } } private int _R; 23 public int G { get { return _G; } set { _G = value; Raise(); } } private int _G; 24 public int B { get { return _B; } set { _B = value; Raise(); } } private int _B; 25 26 /// <summary> 27 /// ディープコピー 28 /// </summary> 29 /// <param name="rgb"></param> 30 public void Copy( RGB rgb ) 31 { 32 this.R = rgb.R; 33 this.G = rgb.G; 34 this.B = rgb.B; 35 } 36 37 #region INotifyPropertyChanged の実装 38 39 public event PropertyChangedEventHandler PropertyChanged = ( _, __ ) => { }; 40 private void Raise( [CallerMemberName]string propertyName = "" ) 41 { 42 this.PropertyChanged( this, new System.ComponentModel.PropertyChangedEventArgs( propertyName ) ); 43 } 44 45 #endregion 46 } 47 48 /// <summary> 49 /// 色情報 50 /// </summary> 51 public RGB RGBValue { get; private set; } 52 53 /// <summary> 54 /// デフォルト 55 /// </summary> 56 public UserControl1() 57 { 58 InitializeComponent(); 59 60 // 初期化 61 this.RGBValue = new RGB(); 62 } 63 64 /// <summary> 65 /// ターゲットの画像を設定 66 /// </summary> 67 /// <param name="path">画像URI</param> 68 public void SetBGImage( string path ) 69 { 70 BitmapImage image = new BitmapImage(); 71 72 image.BeginInit(); 73 image.UriSource = new Uri( path ); 74 image.EndInit(); 75 76 this.bgImage.Source = image; // 表示 77 } 78 79 /// <summary> 80 /// ライン上の色を取得する 81 /// </summary> 82 /// <returns>色</returns> 83 public RGB GetRGBValue() 84 { 85 Point location = GetCursorLocation(); 86 87 // 画像の範囲外の色は取得しない(できない) 88 if ( location.X < 0 || location.X >= this.bgImage.Source.Width 89 || location.Y < 0 || location.Y >= this.bgImage.Source.Height) return this.RGBValue; 90 91 // 指定した位置の色情報を取得して返す処理 92 var cd = new CroppedBitmap( (BitmapImage) this.bgImage.Source, new Int32Rect( (int) location.X, (int) location.Y, 1, 1 ) ); 93 var pixels = new byte[4]; 94 new FormatConvertedBitmap( cd, PixelFormats.Bgra32, null, 0 ).CopyPixels( pixels, 4, 0 ); 95 96 return new RGB() { R = pixels[2], G = pixels[1], B = pixels[0] }; 97 } 98 99 #region 十字カーソルのドラッグイベント 100 101 /// <summary> 102 /// 十字カーソルのドラッグ中 イベント 103 /// </summary> 104 /// <param name="sender"></param> 105 /// <param name="e"></param> 106 private void CloseCursor_DragDelta( object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e ) 107 { 108 var thumb = sender as Thumb; 109 Canvas.SetLeft( thumb, Canvas.GetLeft( thumb ) + e.HorizontalChange ); 110 Canvas.SetTop( thumb, Canvas.GetTop( thumb ) + e.VerticalChange ); 111 112 // 色値を設定する 113 this.RGBValue.Copy( this.GetRGBValue() ); 114 } 115 116 /// <summary> 117 /// 十字カーソルのドラッグ完了 イベント 118 /// </summary> 119 /// <param name="sender"></param> 120 /// <param name="e"></param> 121 private void CloseCursor_DragCompleted( object sender, DragCompletedEventArgs e ) 122 { 123 /// 十字カーソイルが画面からはみ出た時に画面内に戻す制御を行っている 124 125 var thumb = sender as Thumb; 126 127 Point location = this.GetCursorLocation(); 128 Point move = new Point( Canvas.GetLeft( thumb ), Canvas.GetTop( thumb ) ); 129 130 // 横位置の補正 131 if (location.X < 0) move.X = ( thumb.Width / 2 * -1 ); 132 else if (location.X > this.bgImage.Source.Width) move.X = this.bgImage.Source.Width - ( thumb.Width / 2 ); 133 134 // 縦位置の補正 135 if (location.Y < 0) move.Y = ( thumb.Height / 2 * -1 ); 136 else if (location.Y > this.bgImage.Source.Height) move.Y = this.bgImage.Source.Height - ( thumb.Height / 2 ); 137 138 Canvas.SetLeft( thumb, move.X ); 139 Canvas.SetTop( thumb, move.Y ); 140 } 141 142 #endregion 143 144 /// <summary> 145 /// 画像を主体とした十字カーソルの位置を取得 146 /// </summary> 147 /// <returns></returns> 148 private Point GetCursorLocation() 149 { 150 Vector vec = this.CloseCursor.PointToScreen( new Point( 0.0d, 0.0d ) ) - this.bgImage.PointToScreen( new Point( 0.0d, 0.0d ) ); 151 152 // 十字コントロールの中心点を計算して返す 153 return new Point( vec.X + ( this.CloseCursor.Width / 2 ), vec.Y + ( this.CloseCursor.Height / 2 ) ); 154 } 155 } 156}

■ メインフォーム(Form1.cs)

C#

1using System; 2using System.Drawing; 3using System.Windows.Forms; 4using System.Windows.Media; 5 6namespace WindowsFormsApplication1 7{ 8 /// <summary> 9 /// メインフォーム 10 /// </summary> 11 public partial class Form1 : Form 12 { 13 /// <summary> 14 /// バインド用 15 /// </summary> 16 private BindingSource _bindingSource1 = new BindingSource(); 17 18 /// <summary> 19 /// コンストラクタ 20 /// </summary> 21 public Form1() { InitializeComponent(); } 22 23 /// <summary> 24 /// Form1のロードイベント 25 /// </summary> 26 /// <param name="sender"></param> 27 /// <param name="e"></param> 28 private void Form1_Load( object sender, EventArgs e ) 29 { 30 UserControl1 _uc = new UserControl1(); 31 32 // ユーザーコントロール(UC)の設定 33 _uc.SetBGImage( @"C:\TEMP\Sample.JPG" ); 34 35 // あらかじめ配置してある ElementHost コントロールにUCを配置する。 36 this.elementHost1.Child = _uc; 37 38 // UCで変更された値をリアルタイムで反映するためにバインドしている。 39 this._bindingSource1.DataSource = _uc.RGBValue; 40 41 this.lblColor_R.DataBindings.Add( new System.Windows.Forms.Binding( "Text", this._bindingSource1, "R", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged ) ); 42 this.lblColor_G.DataBindings.Add( new System.Windows.Forms.Binding( "Text", this._bindingSource1, "G", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged ) ); 43 this.lblColor_B.DataBindings.Add( new System.Windows.Forms.Binding( "Text", this._bindingSource1, "B", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged ) ); 44 } 45 } 46}

上記の実装では輝度値の取得は行っていません。(取得方法がわからなかったためです。)
また、UC側での変更を動的にForm1と連動したいがためにバインドを行っていますが、不要であればUC側の GetRGBvalue を直接呼び出しても使用できます。

起動画面は以下になります。
起動画面

※静止画では伝わりにくいですが、十字カーソル(判定領域は四角)をドラッグすると下側のRGBの内容が変動します。

投稿2017/03/30 03:06

rtomp

総合スコア44

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

g_uo

2017/03/30 09:02

rtompさん、ご回答ありがとうございます。ご提示いただいた手法で解決できそうです。大変助かります。 >以前、同じ問題にあたったことがあります。 >その時は結局解決せず、2つの画像を動的に合成する処理で逃げました。 やはり、ElementHostとPixtureBoxを重ねて透過することはできないのですね。この情報については、rtompさんの経験と知識に感謝いたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問