アプリ版:「スタンプのみでお礼する」機能のリリースについて

お世話になります。

VC 2005で開発しているC++で教えていただきたい事が有ります。

PictureboxBの上にPictureboxAを透過率50%位で重ねて表示したいのですが、
Pictureboxのプロパティ等で一括で指定できないでしょうか?
出来ない場合、画像を一括で透過処理する方法が有りましたら教えていただけないでしょうか
※ ググって、単色を透過するのは、色々見つけたのですが、画像全体を透過する方法を見つけることが出来ませんでした。

現状は単純にファイル(写真)を読み込んで、PictureboxのImageに格納しているだけです。
※将来的には、PictureboxAをドラッグで移動させたいので、背景画像(PictureboxB)との位相を取る方法以外でお願いいたします。

Bitmap^ PhotBMP = gcnew Bitmap(filename);
// この間にサイズ変更&位置合わせの処理が有りますが、記載を省略させていただいております。
PictureboxA->Image = PhotBMP;

A 回答 (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;
}
    • good
    • 0
この回答へのお礼

ありがとうございます。

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

お礼日時:2014/07/07 10:29

簡単にはできないみたいですね…。



(1) 画像を透過して半透明にするだけなら http://dobon.net/vb/dotnet/graphics/hadeinimage. … にあります。
しかし、これを PictureboxA->Image に指定しても pictureBoxA の背景色 (~灰色) が透けるだけです。
更に、コントロールの背景色を「透明」にする方法として http://msdn.microsoft.com/ja-jp/library/wk5b13s4 … がありますが、これの実態は親コントロール (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. …
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!