您的位置:首页 > 编程语言 > C语言/C++

C++实现UMG中自定义不规则形状按钮

2017-01-14 16:50 543 查看
因为要在项目中使用UMG功能,所以找到项目中名称为 "项目名称.Build.cs" 文件,加入如下代码



创建一个Button的子类







生成的初始代码:

//CustomButton.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Components/Button.h"
#include "CustomButton.generated.h"

/**
*
*/
UCLASS()
class LEARNUE4CPP_API UCustomButton : public UButton
{
GENERATED_BODY()
};


// CustomButton.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "LearnUE4Cpp.h"
#include "CustomButton.h"

在上面代码的基础上修改后的代码:

//CustomButton.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Engine.h"
#include "Runtime/UMG/Public/UMG.h"
#include "Runtime/UMG/Public/UMGStyle.h"
#include "Components/Button.h"
#include "CustomButton.generated.h"

/**
* Classic Slate Button with Advanced Hit implementation.
* Use SetAdvancedHitTexture to set unique button's geometry, determined by it's alpha channel.
* Use SetAdvancedHitAlpha to set an integer in range 0-255. If pixel's alpha is lower than this value, it will be treated as an empty space.
*/
class LEARNUE4CPP_API SCumstomButton : public SButton
{
public:
UTexture2D* AdvancedHitTexture;
int AdvancedHitAlpha;

SCumstomButton() : AdvancedHitTexture(NULL), AdvancedHitAlpha(0) {}

void SetAdvancedHitTexture(UTexture2D* InTexture)
{
AdvancedHitTexture = InTexture;
}

void SetAdvancedHitAlpha(int InAlpha)
{
AdvancedHitAlpha = InAlpha;
}

virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
{
if (!bIsHovered) return FReply::Unhandled();
return SButton::OnMouseButtonDown(MyGeometry, MouseEvent);
}

virtual FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) override
{
if (!bIsHovered) return FReply::Unhandled();
return SButton::OnMouseButtonDoubleClick(InMyGeometry, InMouseEvent);
}

virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
{
if (!bIsHovered) return FReply::Unhandled();
return SButton::OnMouseButtonUp(MyGeometry, MouseEvent);
}
virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;

virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
{
if (AdvancedHitTexture) return;
return SButton::OnMouseEnter(MyGeometry, MouseEvent);
}

virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override
{
return SButton::OnMouseLeave(MouseEvent);
}

virtual FCursorReply OnCursorQuery(const FGeometry& MyGeometry, const FPointerEvent& CursorEvent) const override;

virtual TSharedPtr<IToolTip> GetToolTip() override { return (bIsHovered ? SWidget::GetToolTip() : NULL); }
};

/**
*
*/
UCLASS()
class LEARNUE4CPP_API UCustomButton : public UButton
{
GENERATED_BODY()

public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "AdvancedHitTest") UTexture2D* AdvancedHitTexture;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "AdvancedHitTest", meta = (ClampMin = "0.0", ClampMax = "255.0", UIMin = "0.0", UIMax = "255.0")) int AdvancedHitAlpha;

UFUNCTION(BlueprintCallable, Category = "AdvancedHitTest") void SetAdvancedHitTexture(UTexture2D* InTexture)
{
AdvancedHitTexture = InTexture;
if (MyButton.IsValid()) (static_cast<SCumstomButton*>(MyButton.Get()))->SetAdvancedHitTexture(AdvancedHitTexture);
}

UFUNCTION(BlueprintCallable, Category = "AdvancedHitTest") void SetAdvancedHitAlpha(int InAlpha)
{
AdvancedHitAlpha = InAlpha;
if (MyButton.IsValid()) (static_cast<SCumstomButton*>(MyButton.Get()))->SetAdvancedHitAlpha(AdvancedHitAlpha);
}

UCustomButton(const FObjectInitializer& ObjectInitializer) : AdvancedHitTexture(NULL), AdvancedHitAlpha(NULL), Super(ObjectInitializer) {}

virtual void SynchronizeProperties() override;

virtual TSharedRef<SWidget> RebuildWidget() override;

};

// CustomButton.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "LearnUE4Cpp.h"
#include "CustomButton.h"

#pragma region >>> SCustomButton <<<
FReply SCumstomButton::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (!AdvancedHitTexture) return SButton::OnMouseMove(MyGeometry, MouseEvent);
bool WhatToReturn = true;
FVector2D LocalPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
LocalPosition.X = floor(LocalPosition.X);
LocalPosition.Y = floor(LocalPosition.Y);
LocalPosition /= MyGeometry.GetLocalSize();
int ImageWidth = AdvancedHitTexture->PlatformData->SizeX;
LocalPosition.X *= ImageWidth;
LocalPosition.Y *= AdvancedHitTexture->PlatformData->SizeY;
int BufferPosition = (LocalPosition.Y * ImageWidth) + LocalPosition.X;
FColor* ImageData = static_cast<FColor*>((AdvancedHitTexture->PlatformData->Mips[0]).BulkData.Lock(LOCK_READ_ONLY));
if (!ImageData)
{
WhatToReturn = false;
}
else
{
if (ImageData[BufferPosition].A <= AdvancedHitAlpha) WhatToReturn = false;
}

AdvancedHitTexture->PlatformData->Mips[0].BulkData.Unlock();
if (WhatToReturn != bIsHovered)
{
bIsHovered = WhatToReturn;
if (bIsHovered) SButton::OnMouseEnter(MyGeometry, MouseEvent);
else SButton::OnMouseLeave(MouseEvent);
}
return SButton::OnMouseMove(MyGeometry, MouseEvent);
}
FCursorReply SCumstomButton::OnCursorQuery(const FGeometry& MyGeometry, const FPointerEvent& CursorEvent) const {
if (!bIsHovered) return FCursorReply::Unhandled();
TOptional<EMouseCursor::Type> TheCursor = Cursor.Get();
return (TheCursor.IsSet()) ? FCursorReply::Cursor(TheCursor.GetValue()) : FCursorReply::Unhandled();
}
#pragma endregion

#pragma region >>> UCustomButton <<<
void UCustomButton::SynchronizeProperties()
{
Super::SynchronizeProperties();
(static_cast<SCumstomButton*>(MyButton.Get()))->SetAdvancedHitTexture(AdvancedHitTexture);
(static_cast<SCumstomButton*>(MyButton.Get()))->SetAdvancedHitAlpha(AdvancedHitAlpha);
}

TSharedRef<SWidget> UCustomButton::RebuildWidget()
{
TSharedPtr<SCumstomButton> CustomButton = SNew(SCumstomButton)
.OnClicked(BIND_UOBJECT_DELEGATE(FOnClicked, SlateHandleClicked))
.OnPressed(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandlePressed))
.OnReleased(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandleReleased))
.OnHovered_UObject(this, &ThisClass::SlateHandleHovered)
.OnUnhovered_UObject(this, &ThisClass::SlateHandleUnhovered)
.ButtonStyle(&WidgetStyle)
.ClickMethod(ClickMethod)
.TouchMethod(TouchMethod)
.IsFocusable(IsFocusable)
;

CustomButton->SetAdvancedHitTexture(AdvancedHitTexture);
CustomButton->SetAdvancedHitAlpha(AdvancedHitAlpha);

MyButton = CustomButton;

if (GetChildrenCount() > 0) Cast<UButtonSlot>(GetContentSlot())->BuildSlot(MyButton.ToSharedRef());

return MyButton.ToSharedRef();
}
#pragma endregion

把上面的代码复制到你的项目中,  根据自己的实际项目名称和类名称进行修改。编译成功后打开UE4创建UMG, 这时就会在UMG的Palette面板 Common分类中看到通过C++定义的按钮。把按钮拖拽到Canvas上,在Details面板中的AdvancedHitTest分类下边的Advanced Hit Texture 设置为你按钮想显示的图片。图片的主显示内容以外的区域必须是全透明的,否则无效。 Appearenace->Style:
Normal, Hovered, Pressed 都设置为相同的图片,并且DrawAs属性设置为Image



运行,最终效果如下,鼠标只有在图形上边点击才会响应点击事件

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unreal engine