GetOwner() cause unreal editor crash - c++

I'm new in using c++ and UE.
I tried some simple programming but the editor crash.
#include "NewActorComponent.h"
#include "Runtime/Engine/Classes/GameFramework/Actor.h"
UNewActorComponent::UNewActorComponent()
{
PrimaryComponentTick.bCanEverTick = true;
GetOwner()->GetName();
}
I knew maybe the output is null so it is crashed,but idk how to expect the error without any crash.

It's possible the actor component is created but not initialized or attached to an object. You should gate these kind of checks behind IF statements, or use the assert/check macros.
Also, you may want to use the BeginPlay() function instead of the constructor. BeginPlay requires the component to be registered and initialized so it should have an owner.

GetName();
To find the owner of the component.
Ex: When inserting a component in the chair, a reference to the chair will be returned.
From Unreal Engine API Reference:
UObjectBaseUtility::GetName
Syntax: FString GetName()
Remarks
Returns the name of this object (with no path information)
OK, Follow this steps:
1) File -> New Project -> C++ -> Basic Code -> With Starter Content
2) Inside MinimalDefault Map select one chair and pick Add Component Button.
3) Choose New C++ Component
4) Choose Actor Component Class and click em Next Button
5) In Visual Studio inside NewActorComponent.cpp insert code below in BeginPlay() function
UNewActorComponent::UNewActorComponent()
{
PrimaryComponentTick.bCanEverTick = true;
FString ObjectName = GetOwner()->GetName();
UE_LOG(LogTemp, Warning, TEXT("ObjetctName: %s"), *Objectname);
}
6) Show Log Window in Unreal Engine 4
Log Windows
7) Compile!
8) See Results in Log Window
logwindowresults
Below Complete Code. It Works! Enjoy!
#include "NewActorComponent.h"
#include "Runtime/Engine/Classes/GameFramework/Actor.h"
UNewActorComponent::UNewActorComponent()
{
PrimaryComponentTick.bCanEverTick = true;
}
void UNewActorComponent::BeginPlay()
{
Super::BeginPlay();
FString NameOfObject = GetOwner()->GetName();
UE_LOG(LogTemp, Warning, TEXT("Name is: %s"), *NameOfObject)
}
void UNewActorComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}

Related

Unreal Engine 4: C++ Delegate not being called

I've been working on converting some blueprint logic over to C++. One of the things I have is a button. The button can be pressed in VR and has a delegate that is called to notify any registered functions that the button press occurred. Here is how the delegate is declared in the AButtonItem.h class.
#pragma once
#include "BaseItem.h"
#include "ButtonItem.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FButtonItemPressedSignatrue);
UCLASS()
class AButtonItem : public ABaseItem
{
GENERATED_BODY()
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Touch)
float myMaxButtonPress;
public:
UPROPERTY(EditAnywhere, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
};
The delegate's broadcast function is then being called when the button is pressed like so:
ButtonItem_OnPressed.Broadcast();
(This function should defiantly be called because I have a debug statement that prints right before the call. Its also important to note this was all working when it was blueprint logic.)
Here is where I try to register with the delegate and how I declared the function that will be called:
WeaponMaker.h:
UFUNCTION()
void OnNextBladeButtonPressed();
WeaponMaker.cpp:
void AWeaponMaker::BeginPlay()
{
Super::BeginPlay();
TArray<USceneComponent*> weaponMakerComponents;
this->GetRootComponent()->GetChildrenComponents(true, weaponMakerComponents);
for (int componentIndex = 0; componentIndex < weaponMakerComponents.Num(); componentIndex++)
{
if (weaponMakerComponents[componentIndex]->GetName().Equals("NextBladeButton") == true)
{
myNextBladeButton = (AButtonItem*)weaponMakerComponents[componentIndex];
break;
}
}
if (myNextBladeButton != NULL)
{
myNextBladeButton->ButtonItem_OnPressed.AddDynamic(this, &AWeaponMaker::OnNextBladeButtonPressed);
}
}
I put a breakpoint and a print statement in the function OnNextBladeButtonPressed so I should immediately know when it works but its never happening. I also re-created the blueprint itself from scratch but still no luck. Sometimes on compile I get a crash due to the InvocationList being invalid but I haven't found much info on that issue either. Bottom line is, OnNextBladeButtonPressed is not getting called when it should be.
Edit: Here is where I call the broadcast function in my AButtonItem code. It seems to be getting called since i see the UE_LOG output in the console:
void AButtonItem::Tick(float deltaTime)
{
FTransform buttonWorldTransform;
FVector buttonLocalSpacePos;
FVector ownerLocalSpacePos;
FVector localDiff;
float buttonPressAmount;
if (myHasStarted == true)
{
Super::Tick(deltaTime);
if (myButtonComponent != NULL)
{
if (myPrimaryHand != NULL)
{
//Get the world space location of the button.
buttonWorldTransform = myButtonComponent->GetComponentTransform();
//Convert the location of the button and the location of the hand to local space.
buttonLocalSpacePos = buttonWorldTransform.InverseTransformPosition(myInitialOverlapPosition);
ownerLocalSpacePos = buttonWorldTransform.InverseTransformPosition(myPrimaryHand->GetControllerLocation() + (myPrimaryHand->GetControllerRotation().Vector() * myPrimaryHand->GetReachDistance()));
//Vector distance between button and hand in local space.
localDiff = ownerLocalSpacePos - buttonLocalSpacePos;
//Only interested in the z value difference.
buttonPressAmount = FMath::Clamp(FMath::Abs(localDiff.Z), 0.0f, myMaxButtonPress);
localDiff.Set(0.0f, 0.0f, buttonPressAmount);
//Set the new relative position of button based on the hand and the start button position.
myButtonComponent->SetRelativeLocation(myButtonInitialPosition - localDiff);
//UE_LOG(LogTemp, Error, TEXT("buttonPressAmount:%f"), buttonPressAmount);
if (buttonPressAmount >= myMaxButtonPress)
{
if (myHasBeenTouchedOnce == false)
{
//Fire button pressed delegate
if (ButtonItem_OnPressed.IsBound() == true)
{
ButtonItem_OnPressed.Broadcast();
AsyncTask(ENamedThreads::GameThread, [=]()
{
ButtonItem_OnPressed.Broadcast();
});
}
myHasBeenTouchedOnce = true;
myButtonComponent->SetScalarParameterValueOnMaterials("State", 1.0f);
Super::VibrateTouchingHands(EVibrationType::VE_TOUCH);
}
}
}
else
{
//Slowly reset the button position back to the initial position when not being touched.
FVector newPosition = FMath::VInterpTo(myButtonComponent->GetRelativeTransform().GetLocation(), myButtonInitialPosition, deltaTime, 10.0f);
myButtonComponent->SetRelativeLocation(newPosition);
}
}
}
}
First of all:
UPROPERTY(EditAnywhere, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
This should be:
UPROPERTY(BlueprintAssignable, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
For convenience.
Secondly the tick function may be called before begin play is executed for a number of reasons. Your even't won't be broadcasted if the game hasn't begin play yet. So to avoid just add a check in your tick function.
if(bHasBegunPlay)
{
// .. your logics ...
}
Sometimes on compile I get a crash due to the InvocationList being invalid but I haven't found much info on that issue either. Bottom line is, OnNextBladeButtonPressed is not getting called when it should be.
I don't see any issue in the code from the question. At my glance, the issue could be in different location. I would suspect that AWeaponMaker had been deleted at moment of broadcasting.

handle drop event of drag and drop from ListView to ListView with UWP and C++/WinRT app

I am working on a simple UWP application written in C++/WinRT under Windows 10 that contains two ListView controls. The goal of this application is to learn how to select an item from one ListView control, drag it to the other ListView control, and drop the item so that it is copied from the source ListView control to the destination ListView control.
All of the examples I have found thus far use C# with a few using C++/CX rather than C++/WinRT and native C++ however I have managed to slog through to the point where the basic mechanics of selecting an item from the source ListView works as does the drag and the drop onto the destination ListView. However when trying to fetch the information from the drop event in order to update the destination ListView I am getting an exception.
Question: What changes do I need to make so that the selected text in the source ListView control can be dragged and dropped on the destination ListView control and the text then be added to the destination ListView control?
The Output window of Visual Studio 2017 shows the following text which I interpret to be a bad address exception:
Unhandled exception at 0x0259DC3C (Windows.UI.Xaml.dll) in TouchExperiment_01.exe: 0xC000027B: An application-internal exception has occurred (parameters: 0x05F5E3D8, 0x00000005).
Unhandled exception at 0x74ECE61D (combase.dll) in TouchExperiment_01.exe: 0xC0000602: A fail fast exception occurred. Exception handlers will not be invoked and the process will be terminated immediately.
Unhandled exception at 0x74F9D7D9 (combase.dll) in TouchExperiment_01.exe: Stack cookie instrumentation code detected a stack-based buffer overrun.
Unhandled exception at 0x74F9D7D9 (combase.dll) in TouchExperiment_01.exe: Stack cookie instrumentation code detected a stack-based buffer overrun.
The exception is raised when the following line of source code in the function void MainPage::OnListViewDrop(), which is the last function in the MainPage.cpp source file, is executed:
auto x = e.DataView().GetTextAsync();
Additional Information A: Using the debugger I found that the error message associated with the exception which implies an error in the data provided by the method OnListViewDragItemsStarting(). The text of the exception error message is:
{m_handle={m_value=0x05550330 L"DataPackage does not contain the specified format. Verify its presence using DataPackageView.Contains or DataPackageView.AvailableFormats." } }
I also found at the site where the exception is first thrown and caught by Visual Studio, stopping the application in base.h (source from C++/WinRT templates), an error text of 0x8004006a : Invalid clipboard format indicating that I have lack of agreement on the format of the data that the start of drag creates and the drop of drag is trying to consume.
An overview of the source code
I modified a standard C++/WinRT app template in the area of the MainPage.xml, MainPage.cpp, MainPage.h, and pch.h. I also added the class files for a new class, DataSource, which uses a std::vector<> to contain some test data. This memory resident data is initialized with some dummy data in the App constructor:
App::App()
{
InitializeComponent();
DataSource::InitializeDataBase();
Suspending({ this, &App::OnSuspending });
// … other code
First of all I had to add a line to the pch.h file to provide the templates for drag and drop:
#include "winrt/Windows.ApplicationModel.DataTransfer.h" // ADD_TO: need to add to allow use of drag and drop in MainPage.cpp
The XAML source file contains the source for the two ListView controls as well as a TextBlock control which displays a full description of the item selected in the source ListView:
<Page
x:Class="TouchExperiment_01.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TouchExperiment_01"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Width="1130" Margin="0,0,0,0">
<ListView x:Name="myList" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="300" SelectionChanged="OnSelectionChanged"
CanDragItems="True" DragItemsStarting="OnListViewDragItemsStarting" BorderBrush="AliceBlue" BorderThickness="3">
</ListView>
<TextBlock x:Name="myTextBlock" Height="200" Width="200" Text="this is temp text to replace." TextWrapping="WrapWholeWords" Margin="5"/>
<ListView x:Name="myList2" HorizontalAlignment="Right" Height="100" VerticalAlignment="Top" Width="300" SelectionChanged="OnSelectionChanged" AllowDrop="True"
DragOver="OnListViewDragOver" Drop="OnListViewDrop" BorderBrush="DarkGreen" BorderThickness="5">
</ListView>
</StackPanel>
</Page>
The class declaration for DataSource is simple. The class definition is as follows:
#pragma once
class DataSource
{
public:
DataSource();
~DataSource();
static int InitializeDataBase();
struct DataSourceType
{
std::wstring name;
std::wstring description;
};
static std::vector<DataSourceType> myDataBase;
}
;
and the initialization of the vector, which is done when the App constructs when the application starts up is:
int DataSource::InitializeDataBase()
{
myDataBase.clear();
for (int i = 0; i < 50; i++) {
DataSourceType x;
wchar_t buffer[256] = { 0 };
swprintf_s(buffer, 255, L"Name for %d Item", i);
x.name = buffer;
swprintf_s(buffer, 255, L"Description %d. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.", i);
x.description = buffer;
myDataBase.push_back(x);
}
return 0;
}
The MainPage.cpp source code behind the XAML page is:
#include "pch.h"
#include "MainPage.h"
#include "DataSource.h"
using namespace winrt;
using namespace Windows::UI::Xaml;
namespace winrt::TouchExperiment_01::implementation
{
MainPage::MainPage()
{
InitializeComponent();
// load up the source ListView with the name field from out
// in memory database.
auto p = myList().Items();
for (auto a : DataSource::myDataBase) {
p.Append(box_value(a.name));
}
// add a single ListViewItem to the destination ListView so that we
// know where it is.
p = myList2().Items();
p.Append(box_value(L"list"));
}
int32_t MainPage::MyProperty()
{
throw hresult_not_implemented();
}
void MainPage::MyProperty(int32_t /* value */)
{
throw hresult_not_implemented();
}
void MainPage::OnSelectionChanged(Windows::Foundation::IInspectable const & target, Windows::UI::Xaml::RoutedEventArgs const & )
{
// the user has selected a different item in the source ListView so we want to display
// the associated description information for the selected ListViewItem.
winrt::Windows::UI::Xaml::Controls::ListView p = target.try_as<winrt::Windows::UI::Xaml::Controls::ListView>();
if (p) {
int iIndex = p.SelectedIndex();
myTextBlock().Text(DataSource::myDataBase[iIndex].description);
}
}
void MainPage::OnListViewDragItemsStarting(Windows::Foundation::IInspectable const & target, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs const & e)
{
// provide the data that we have in the ListView which the user has selected
// to drag to the other ListView. this is the data that will be copied from
// the source ListView to the destination ListView.
auto p = target.try_as<winrt::Windows::UI::Xaml::Controls::ListView>();
if (p) {
int iIndex = p.SelectedIndex();
e.Items().SetAt(0, box_value(iIndex));
}
}
void MainPage::OnListViewDragOver(Windows::Foundation::IInspectable const & target, Windows::UI::Xaml::DragEventArgs const & e)
{
// indicate that we are Copy of data from one ListView to another rather than one of the other
// operations such as Move. This provides the operation type informative user indicator when the
// user is doing the drag operation.
e.AcceptedOperation(Windows::ApplicationModel::DataTransfer::DataPackageOperation::Copy);
}
void MainPage::OnListViewDrop(Windows::Foundation::IInspectable const & target, Windows::UI::Xaml::DragEventArgs const & e)
{
// update the destination ListView with the data that was dragged from the
// source ListView.
auto p = target.try_as<winrt::Windows::UI::Xaml::Controls::ListView>();
auto x = e.DataView().GetTextAsync(); // ** this line triggers exception on drop.
}
}
A screen shot of the application with an item selected in the source ListView before a drag is started looks is as follows. The source ListView control is on the left and the destination ListView control is on the right.
Addendum: References and documentation
Microsoft Docs - Windows.ApplicationModel.DataTransfer Namespace
Microsoft Docs - DragItemsStartingEventArgs Class which contains a link to this example project that looks to be using C++/CX Drag and drop sample on GitHub which contains Windows-universal-samples/Samples/XamlDragAndDrop/cpp/Scenario1_ListView.xaml.cpp that has a useful example.
The reason for the exception was due to a misuse of the GetTextAsync() method which is an asynchronous method that requires using threads, tasks, coroutines, or some other concurrency functionality.
I found the example source code Windows-universal-samples/Samples/XamlDragAndDrop/cpp/Scenario1_ListView.xaml.cpp which provided the hint as to what I was doing wrong. See also the article at https://github.com/Microsoft/cppwinrt/blob/master/Docs/Using%20Standard%20C%2B%2B%20types%20with%20C%2B%2B%20WinRT.md
// We need to take a Deferral as we won't be able to confirm the end
// of the operation synchronously
auto def = e->GetDeferral();
create_task(e->DataView->GetTextAsync()).then([def, this, e](String^ s)
{
// Parse the string to add items corresponding to each line
auto wsText = s->Data();
while (wsText) {
auto wsNext = wcschr(wsText, L'\n');
if (wsNext == nullptr)
{
// No more separator
_selection->Append(ref new String(wsText));
wsText = wsNext;
}
else
{
_selection->Append(ref new String(wsText, wsNext - wsText));
wsText = wsNext + 1;
}
}
e->AcceptedOperation = DataPackageOperation::Copy;
def->Complete();
});
Overview of Changes Made to Correct the Problem
I decided to use coroutines with GetTextAsync() since I was using the latest build of Visual Studio 2017 Community Edition. To do so required some changes to the method return type from void to winrt::Windows::Foundation::IAsyncAction along with a couple of changes to the solution properties and the addition of a couple of include files to allow for the coroutines changes to compile and run properly.
See the answer and notes about several different approaches to concurrency along with the Visual Studio 2017 solution properties changes to use coroutines and the co_await operator at C++11 threads to update MFC application windows. SendMessage(), PostMessage() required?
At the top of MainPage.cpp I added the following two include directives:
#include <experimental\resumable>
#include <pplawait.h>
I modified the OnListViewDragItemsStarting() method to look like:
void MainPage::OnListViewDragItemsStarting(Windows::Foundation::IInspectable const & target, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs const & e)
{
// provide the data that we have in the ListView which the user has selected
// to drag to the other ListView. this is the data that will be copied from
// the source ListView to the destination ListView.
auto p = target.try_as<winrt::Windows::UI::Xaml::Controls::ListView>();
unsigned int n = e.Items().Size();
if (p) {
int iIndex = p.SelectedIndex();
e.Data().Properties().Title(hstring (L"my Title"));
e.Data().SetText(DataSource::myDataBase[iIndex].name.c_str());
e.Data().RequestedOperation(winrt::Windows::ApplicationModel::DataTransfer::DataPackageOperation::Copy);
}
}
Finally I rewrote the method OnListViewDrop() to use coroutines as follows (also required the return type of the declaration in the class declaration to be changed to agree with the new return type):
winrt::Windows::Foundation::IAsyncAction MainPage::OnListViewDrop(Windows::Foundation::IInspectable const & target, Windows::UI::Xaml::DragEventArgs const & e)
{
// update the destination ListView with the data that was dragged from the
// source ListView. the method GetTextAsync() is an asynch method so
// we are using coroutines to get the result of the operation.
// we need to capture the target ListView before doing the co_await
// in a local variable so that we will know which ListView we are to update.
auto p = target.try_as<winrt::Windows::UI::Xaml::Controls::ListView>();
// do the GetTextAsync() and get the result by using coroutines.
auto ss = co_await e.DataView().GetTextAsync();
// update the ListView control that originally triggered this handler.
p.Items().Append(box_value(ss));
}

UE4 iTween C++ throws "this was nullptr"

I'm trying to use iTween (via C++, not BP) to rotate an actor to face another, but it throwing an exception in Actor.h that says:
I'm using the following code to start the tween:
AActor* actorToRotate = Cast<AActor>(this);
if (actorToRotate != nullptr && CharacterToAttack != nullptr)
{
FRotator rotationFrom = actorToRotate->GetActorRotation();
FRotator rotationTo = CharacterToAttack->GetActorRotation();
FName tweenName = TEXT("turret");
AiTweenEvent* TurretTween = UiTween::ActorRotateFromToSimple(tweenName, actorToRotate, rotationFrom, rotationTo, CoordinateSpace::world, false, 2.0f, easeInAndOutQuartic);
}
Rather than using the actorToRotate variable I've tried using this in ActorRotateFromToSimple() but I get the same error.
if (CharacterToAttack != nullptr)
{
FRotator rotationFrom = GetActorRotation();
FRotator rotationTo = CharacterToAttack->GetActorRotation();
FName tweenName = TEXT("turret");
AiTweenEvent* TurretTween = UiTween::ActorRotateFromToSimple(tweenName, this, rotationFrom, rotationTo, CoordinateSpace::world, false, 2.0f, easeInAndOutQuartic);
}
If anyone smarter than me shed some light onto this issue it would be greatly appreciated.
Additional information I think might be important:
actorToRotate is custom type of ATDWeapon that extends from AActor
CharacterToAttack is custom type of ATDAICharacter that extends from ATDCharacter
The function that executes this code is called by GetWorldTimerManager().SetTimer()
I've added #include "iTween/iTween.h" to the top of my TDWeapon.cpp file
Ah, the problem wasn't in the code. I was using "simulate in editor" in the UE4 Editor rather than "play in editor".
It appears that AiTweenEvent* UiTween::SpawnEvent(AiTAux* aux) needs a player controller and uses GetWorldLocal()->GetFirstPlayerController()->GetPawn()->GetTransform() to get it's transform. In my instance, "simulate in editor" doesn't spawn a player so GetPawn() returns nullptr which GetTransform() doesn't like.
Awesome.

VS 2005 C++ edit content of the CRichEditCtrl instance

I've installed a Windows XP Professional SP3 on a VMWare image and the Visual Studio 2005 on it. I've created a new dialog based C++ MFC project with /clr support. I've put a RichEdit 2.0 control onto the auto-generated dialog and I'm trying to read up a text file and put its content into this RichEdit 2.0 control by button click without formatting. I've added a variable to the RichEdit 2.0 called pCRichEditCtrl and here is my code which doesn't work.
CWinApp inheritance:
BOOL CTextFormatterApp::InitInstance()
{
...
AfxInitRichEdit2();
CWinApp::InitInstance();
...
}
CDialog inheritance:
void CTextFormatterDlg::OnBnClickedButton1()
{
StreamReader^ objReader = gcnew StreamReader("c:\\text.txt");
String ^sLine = "";
sLine = objReader->ReadLine();
while (sLine != nullptr)
{
pCRichEditCtrl.SetSel(pCRichEditCtrl.GetTextLength(), -1);
pCRichEditCtrl.ReplaceSel(CString(sLine));
sLine = objReader->ReadLine();
}
objReader->Close();
}
I don't know whether it counts but I get the following warnings at linking:
TextFormatterDlg.obj : warning LNK4248: unresolved typeref token (01000016) for 'AFX_CMDHANDLERINFO'; image may not run
TextFormatter.obj : warning LNK4248: unresolved typeref token (01000012) for 'AFX_CMDHANDLERINFO'; image may not run
TextFormatterDlg.obj : warning LNK4248: unresolved typeref token (01000015) for 'IAccessibleProxy'; image may not run
I'm not sure what I'm doing because I'm familiar only with newer frameworks and I don't know either Windows.
Input file exists, I can see the read text if I debug the application but I can't see any changes in the edit box. I've tried to call pCRichEditCtrl.UpdateData(true); but nothing has changed.
Is it enough to add a variable for getting the controller of the box (pCRichEditCtrl)? It seems to the pointer doesn't point to the proper control item.
Do you have any idea what is missing?
There's no need to use CLI to just read text files, try something like:
void CTextFormatterDlg::OnBnClickedButton1()
{ CStdioFile f1;
CString sLine;
if (!f1.Open(_T("c:\\text.txt"), CFile::modeRead | CFile::typeText))
return;
while (f1.ReadString(sLine))
{ pCRichEditCtrl.SetSel(pCRichEditCtrl.GetTextLength(), -1);
pCRichEditCtrl.ReplaceSel(sLine);
}
f1.Close();
}
EDIT: control variable pCRichEditCtrl
a) should be declared in the dialog class as CRichEditCtrl pCRichEditCtrl;
b) should be connected to the ID of the control (e.g.: IDC_RICHEDIT21), like
void CTextFormatterDlg::DoDataExchange(CDataExchange* pDX)
{ CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_RICHEDIT21, pCRichEditCtrl);
}
c) I have tested the following code and it works for me (adds "aa" to the control window on each button click)
pCRichEditCtrl.SetSel(pCRichEditCtrl.GetTextLength(), -1);
pCRichEditCtrl.ReplaceSel(TEXT("aa"));
I share the final solution with the community to be available for those who faces with the same issue. I don't know why do I have to use Update(FALSE); on the CWinApp inheritance two times but it solves everything. If someone has an idea or a better (nicer) solution don't hesitate to share it with us, I'll move the accepted flag to that version (if it is possible, I haven't tried it before).
void CTextFormatterDlg::OnBnClickedButton1()
{
StreamReader^ objReader = gcnew StreamReader("c:\\text.txt");
String ^sLine = objReader->ReadLine();
UpdateData(FALSE); //this is the first unexpected first aid
while (sLine != nullptr)
{
pCRichEditCtrl.SetSel(pCRichEditCtrl.GetTextLength(), -1);
pCRichEditCtrl.ReplaceSel(CString(sLine + "\r\n"));
UpdateData(FALSE); //this is the second unexpected first aid
sLine = objReader->ReadLine();
}
objReader->Close();
}

how to write a function Click() for dynamic created button?

Trying to write a simple VCL program for educating purposes (dynamicly created forms, controls etc). Have such a sample code:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TForm* formQuiz = new TForm(this);
formQuiz->BorderIcons = TBorderIcons() << biSystemMenu >> biMinimize >> biMaximize;
formQuiz->Position = TPosition::poDesktopCenter;
formQuiz->Width = 250;
formQuiz->Height = 250;
formQuiz->Visible = true;
TButton* btnDecToBin = new TButton(formQuiz);
btnDecToBin->Parent = formQuiz;
btnDecToBin->Left = 88;
btnDecToBin->Top = 28;
btnDecToBin->Caption = "Dec to Bin";
btnDecToBin->Visible = true;
}
I wonder how can i write a function for dynamic created button, so it would be called when the button is clicked. In this example i need a 'btnDecToBin->Click();' func but i don't know where should i place it.
Inside 'void __fastcall TForm1::Button1Click(TObject *Sender){}' ?
I will appreciate any input, some keywords for google too.
You could do two things, you could either create an action and associate it with the button, or you could make a function like so:
void __fastcall TForm1::DynButtonClick(TObject *Sender)
{
// Find out which button was pressed:
TButton *btn = dynamic_cast<TButton *>(Sender);
if (btn)
{
// Do action here with button (btn).
}
}
You bind it to the button instance by setting the OnClick property btnDecToBin->OnClick = DynButtonClick please note that the function is inside the form Form1. This will work due to the nature of closures (compiler specific addition). The problem comes if you delete Form1 before formQuiz without removing the reference to the click event. In many ways it might be a more clean solution to use an Action in this case.
Edit: On other way to do this, if you have a standard layout for your quizforms, you could make a custom TQuizForm class inheriting from TForm. In this way you wouldn't have to bind the event each time you create the form.
all buttons have the normal "events" you just need to reference them to the method you will deal with the event.
example:
...
btnDecToBin->OnClick = &Test;
-- and add a additional method to .cpp
void __fastcall TForm1::Test(TObject *Sender)
{
TButton *btn = dynamic_cast<TButton *>(Sender);
if (btn->name == "your_button_name"){
// Do action here with button (btn).
}
}
and on .h
void __fastcall TForm1::Test(TObject *Sender);
reference the button either by the tag or name. I usually use a array of buttons that I create dynamically. ALWAYS sanity check your "sender" by casting it. There are other ways to hack info from the object but they are a path to heartache... LOL.