• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:vc++ 2005 Pictureboxの透過処理)

VC++ 2005でPictureboxの透過処理はできるのか?

このQ&Aのポイント
  • VC++ 2005で開発しているC++で、PictureboxBの上にPictureboxAを透過率50%で重ねて表示したい場合、一括で指定する方法はあるのか?また、画像を一括で透過処理する方法はあるのかについて教えてください。
  • 現状は、単純にファイル(写真)を読み込んで、PictureboxのImageに格納しているだけです。将来的には、PictureboxAをドラッグで移動させるため、背景画像(PictureboxB)との位相を取る方法以外での解決策をお願いします。
  • ググっても、単色を透過する方法は見つかるが、画像全体を透過する方法が見つかりません。解決策があれば教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

// No.1 の続きです。長くて申し訳ない Bitmap^ back; Graphics^ backGraphics; void UpdateBuffer(){ if(back==nullptr){ back=gcnew Bitmap(Width,Height); backGraphics=Graphics::FromImage(back); }else if(back->Width!=Width||back->Height!=Height){ delete backGraphics; delete back; back=gcnew Bitmap(Width,Height); backGraphics=Graphics::FromImage(back); } } protected: virtual void OnPaintBackground(PaintEventArgs^ e) override{ ContainerControl^ container=dynamic_cast<ContainerControl^>(Parent); if(container!=nullptr){ this->UpdateBuffer(); backGraphics->Clear(BackColor); Rectangle rect=e->ClipRectangle; rect.Intersect(Rectangle(Point::Empty,this->Size)); if(!rect.IsEmpty){ this->DrawBackgroundControl(backGraphics,rect,container,Point(-Location.X,-Location.Y)); int i0=container->Controls->IndexOf(this); if(i0>=0){ for(int i=container->Controls->Count;--i>i0;){ Control^ ctrl=container->Controls[i]; Point offset=Point( ctrl->Location.X-this->Location.X, ctrl->Location.Y-this->Location.Y); Rectangle rect2=rect; rect2.Intersect(Rectangle(offset,ctrl->Size)); if(!rect2.IsEmpty) this->DrawBackgroundControl(backGraphics,rect2,ctrl,offset); } } } e->Graphics->DrawImageUnscaled(back,0,0); }else{ this->PictureBox::OnPaintBackground(e); } } }; //------------------------------------- // 使用例 public ref class Form1:public Form{ public: Form1(){ SetStyle(ControlStyles::SupportsTransparentBackColor,true); SuspendLayout(); Image^ image=Image::FromFile("test1.png"); // 適当な画像 // ★PictureBox の代わりに上で定義したTransparentPictureBox を使う TransparentPictureBox^ pictureBoxA=gcnew TransparentPictureBox; pictureBoxA->Location=System::Drawing::Point(10,10); pictureBoxA->Size=System::Drawing::Size(100,100); pictureBoxA->SizeMode=PictureBoxSizeMode::StretchImage; pictureBoxA->Image=image; pictureBoxA->Opacity=0.3f; // ★プロパティ Opacity に不透明度 (0.0f = 完全に透明、1.0 = 完全に不透明) を指定。 Controls->Add(pictureBoxA); PictureBox^ pictureBoxB=gcnew PictureBox; pictureBoxB->Location=System::Drawing::Point(60,60); pictureBoxB->Size=System::Drawing::Size(100,100); pictureBoxB->SizeMode=PictureBoxSizeMode::StretchImage; pictureBoxB->Image=(Image^)image->Clone(); Controls->Add(pictureBoxB); this->Size=System::Drawing::Size(200,200); BackColor=Color::FromArgb(0xFF,0xDD,0xDD,0xFF); ResumeLayout(); } public: static void Main(){ Application::Run(gcnew Form1()); } }; int main(){ Form1::Main(); return 0; }

usami33
質問者

お礼

ありがとうございます。 サンプルを作成して動作確認までしていただけるなんて、 本当に助かりました。

その他の回答 (1)

回答No.1

簡単にはできないみたいですね…。 (1) 画像を透過して半透明にするだけなら http://dobon.net/vb/dotnet/graphics/hadeinimage.html にあります。 しかし、これを PictureboxA->Image に指定しても pictureBoxA の背景色 (~灰色) が透けるだけです。 更に、コントロールの背景色を「透明」にする方法として http://msdn.microsoft.com/ja-jp/library/wk5b13s4(v=vs.110).aspx がありますが、これの実態は親コントロール (Form) の背景を自コントロールの背景として使用するというだけの物で、兄弟コントロール (PictureboxB) は映り込んでくれません。 (2) 強引に PictureboxA 自体を「透過」させるのを実装してみました (下のコード)。(実は他に綺麗で簡単な方法があるかも知れませんが。) 【説明】 PictureBox から派生クラスを作って PictureBox の振る舞いを一部変更しています。 前半部分は (1) で紹介した URL の方法で、指定した画像の半透明版を作成しています。 後半部分は背景を描き込む関数 PictureBox::OnPaintBackground を overload して、背景として無理矢理他のコントロールを描画しています。 一応動作する事は確かめましたが、適当に書いたので効率面で問題があります。バグも在るかも知れませんので、使うなら注意深く使って下さい…。 -------------------- #using "System.dll" #using "System.Drawing.dll" #using "System.Windows.Forms.dll" using namespace System::Windows::Forms; using namespace System::Drawing; public ref class TransparentPictureBox:public PictureBox{ public: TransparentPictureBox(){ this->InitializeBackground(); this->InitializeForeground(); } protected: ~TransparentPictureBox(){ this->DeleteBackground(); this->DeleteForeground(); } //------------------------------------- // 前景を半透明にする部分 private: void InitializeForeground(){ this->imageAttributes=gcnew System::Drawing::Imaging::ImageAttributes; this->Opacity=1.0f; } void DeleteForeground(){ this->Image=nullptr; } float opacity; System::Drawing::Imaging::ImageAttributes^ imageAttributes; public: property float Opacity{ void set(float value){ if(opacity==value)return; System::Drawing::Imaging::ColorMatrix^ cm=gcnew System::Drawing::Imaging::ColorMatrix; cm->Matrix00 = 1; cm->Matrix11 = 1; cm->Matrix22 = 1; cm->Matrix33 = value; cm->Matrix44 = 1; imageAttributes->SetColorMatrix(cm); opacity=value; this->UpdateAlphaImage(); } float get(){return opacity;} } private: System::Drawing::Image^ original; public: property System::Drawing::Image^ Image{ void set(System::Drawing::Image^ value){ if(this->original==value)return; this->original=value; this->UpdateAlphaImage(); } System::Drawing::Image^ get(){return this->original;} } private: Bitmap^ alphaImage; void UpdateAlphaImage(){ if(this->alphaImage!=nullptr){ delete alphaImage; alphaImage=nullptr; this->PictureBox::Image=nullptr; } if(original!=nullptr){ alphaImage=gcnew Bitmap(original->Width,original->Height); { Graphics^ g=Graphics::FromImage(alphaImage); g->DrawImage( original,Rectangle(Point::Empty,original->Size), 0,0,original->Width,original->Height,GraphicsUnit::Pixel,imageAttributes); delete g; } this->PictureBox::Image=alphaImage; } } //------------------------------------- // 背景に他のコントロールを描き込む部分 System::Reflection::MethodInfo^ methodOnPaint; System::Reflection::MethodInfo^ methodOnPaintBackground; void InitializeBackground(){ System::Reflection::BindingFlags flags =System::Reflection::BindingFlags::Instance |System::Reflection::BindingFlags::Public |System::Reflection::BindingFlags::NonPublic; this->methodOnPaint=Control::typeid->GetMethod("OnPaint",flags); this->methodOnPaintBackground=Control::typeid->GetMethod("OnPaintBackground",flags); } void DeleteBackground(){ delete backGraphics; delete back; } void DrawBackgroundControl(Graphics^ g,Rectangle rect,Control^ control,Point offset){ g->SetClip(rect); g->TranslateTransform(offset.X,offset.Y); rect.Offset(-offset.X,-offset.Y); try{ array<System::Object^>^ args=gcnew array<System::Object^>{gcnew PaintEventArgs(g,rect)}; this->methodOnPaintBackground->Invoke(control,args); this->methodOnPaint->Invoke(control,args); }catch(...){} g->TranslateTransform(-offset.X,-offset.Y); g->ResetClip(); } // 続く…

参考URL:
http://dobon.net/vb/dotnet/graphics/hadeinimage.html

関連するQ&A

専門家に質問してみよう