Click function on Toggle Buttons in Unreal Engine 4 C++ - c++

I have a doubt about CheckBoxes and click events. I have some button which executes a function OnClick, something like this on code:
SomeButton->OnClicked.AddDynamic(this, &ClassName::FunctionToExecute);
For style reasons, I thought that I should use a Toggle Button, implemented with a CheckBox, instead of a regular Button. However, I am having trouble finding the correct method to bind the function to each click. So far, I tried something like this, but it doesn't work. I also tried declaring a delegate, but it won't work either.
SomeCheckBox->OnCheckStateChanged.Add(&ClassName::FunctionToExecute);
What is the correct way to bind the function to the OnCheckStateChanged() event?
Thanks a lot in advance :smile:

If you are using a UMG Check box (which it sounds like you are), than we can look at the delegate declaration:
// In Checkbox.h
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FOnCheckBoxComponentStateChanged, bool, bIsChecked );
and notice that we need a bool input parameter for our callback function.
So that means that our callback function has to look like this:
void UYourWidget::OnCheckboxChanged(bool bIsChecked) {}
You can then bind your widget like this:
if(CheckBox)
{
CheckBox->OnCheckStateChanged.AddDynamic(this, &UTextChatWidget::Test);
}
If you are using a slate check box, then the callback function declaration is a bit different. It uses the ECheckBoxState enum instead of a boolean.
SNew(SCheckBox)
.OnCheckStateChanged(this, &SFoo::OnStateChanged)
void SFoo::OnStateChanged(ECheckBoxState NewState) {}
My typical approach for figuring this stuff out is to simply do a CTRL+SHIFT+F search for the delegate in Visual Studio to find other examples of it.

Related

Should all buttons contain a reference to the controller in MVC code (C++)?

I'm trying to figure out the best (cleanest) way to structure some code in C++ for an application I'm building. I think MVC makes sense as the way to go, but after a fair amount of research I'm not totally clear I'm doing things the right way.
Here's an example to illustrate my question:
Model
I have a class which contains drawing data called Canvas. An example function, used to clear the current contents of the canvas, is ClearCanvas().
Ultimately, I want a button in the interface to be able to call this function and clear the canvas.
Controller
I have a controller class for the canvas: CanvasController
The controller creates and then holds a reference to a canvas object: CurrentCanvas
The controller also creates the view: CanvasView and then sets a reference to itself on the view: CurrentCanvasView->SetControllerRef(this);
View
The view is made up of a series of nested classes that define the UI. For example, the hierarchy leading to the button in question might be something like this:
CanvasView
-VerticalBox
--HorizontalBox
---Button
During the view's constructor, a reference to the controller is passed from the view to all interactive elements, eg. NewButton->SetControllerRef(this->GetControllerRef());
Button Pressed
So now when the button is pressed, it can function like this:
void ClearCanvasButton::OnButtonPressed()
{
Controller->CurrentCanvas->ClearCanvas();
}
So my general question is: (1) does this seem like the right way to be doing things, or badly structured?
Also (2): Should the controller be encapsulating the canvas functions, for example:
void CanvasController::ClearCanvas()
{
CurrentCanvas->ClearCanvas();
}
Such that the function on the button could simply be:
void ClearCanvasButton::OnButtonPressed()
{
Controller->ClearCanvas();
}
I'm just not sure whether it's correct to essentially be passing down a reference to the controller to all elements of the view which ultimately want to change the model, or whether there is a cleaner way.
Apologies if the question has been asked a thousand times in a thousand different ways, I have been searching around trying to understand this.
You don't need a class ClearCanvasButton, if your Button class contains a member like
std::function<void()> onButtonPressed;
or similar, rather than
virtual void onButtonPressed() {};
You then pass a lambda that references the controller
CanvasView::CanvasView()
{
// make the widgets
Button.onButtonPressed = [Controller](){ Controller->ClearCanvas(); };
}

call wxHyperlinkEvent without clicking on link

I am using wxHyperLink. OnHyperlinkClicked(wxHyperlinkEvent&) is called when user clicks on the link. OnHyperlinkClicked() helps to switch between 2 screens. I want to call this function explicitly - without user interaction.
I am using the following code for that:
BEGIN_EVENT_TABLE(UserRegistrationFrame, wxFrame)
EVT_HYPERLINK(wxID_ANY, UserRegistrationFrame::OnAuthCodeOptionLinkClicked)
END_EVENT_TABLE()
void MyClass::MyFunction()
{
wxHyperlinkEvent event;
OnAuthCodeOptionLinkClicked(event);
}
void MyClass::OnAuthCodeOptionLinkClicked(wxHyperlinkEvent& event)
{
// code to switch
}
Is this the correct way to achieve my goal? Or do I have to use something different?
The code is not correct, because with EVENT_TABLE you are setting a handler that doesn't exist.
When the user clicks on the control the event is fired, and the static table will call UserRegistrationFrame::OnAuthCodeOptionLinkClicked, not MyClass::OnAuthCodeOptionLinkClicked
I'd better forget EVENT_TABLES and go with Dynamic Event Handling. Using Bind() gives you more features.
Now, you want to call the event-handler function directly, not coming from a user action. Then you need to create an event just to pass it to the handler. That's what you do in MyClass::MyFunction(), right?
Don't mix jobs. If both your direct-call and the event-handler use a common feature, put it in a different function and call it directly or from the event-handler.
But the question is Why do you use a wxHyperlinkCtrl for a task like screen switching? Do you want also the default browser to be launched?

How to get the text value of a control through its parent window

I have the following wxDialog parent window:
I have created that parent window by the following code:
settingsFrm settingsWindow(this, "Settings");
settingsWindow.ShowModal();
I have tried to use FindWindowByName to get the value of the first text ctrl as follow:
wxLogMessage(dynamic_cast<wxTextCtrl*>(settingsWindow->FindWindowByName("keywords_txt"))->GetValue());
But unfortunately, it doesn't work and gives me a runtime error.
I don't know if that method suitable to do what I want.
How to get the value/other of a control through its parent window?
From your comments, it seems like you expect the function to find the control from the name of the variable in your code which is not how it works and would be pretty much impossible.
FindWindowByName() uses the window name (and, as a fallback, label, but this is irrelevant here because text controls don't have labels anyhow), so for it to work you need to set the window name when creating the control, using the corresponding parameter of its ctor. This is very rarely useful in C++ code, however, as it's simpler to just store a pointer to the control in some variable and use this instead.
FindWindowByName() can often be useful when creating controls from XRC, however. If you do this, then you should specify names for your controls in XRC and pass the same name to this function.
How did you create the TextCtrl instance? You should have something like wxTextCtrl m_textCtrl1 = new wxTextCtrl(/// arguments); Accessing the value should be very easy, as wxString text = m_textCtrl1->GetValue(); You definitely don't need FindWindowByName just for what you are trying to do here.

MFC's CTabCtrl::HitTest function returns "1" for any tab clicked

Hi (although greeting usually gets deleted),
I'm using the MFC's CTabCtrl control and try to determine which tab was clicked (to drag & drop it later). Should be quite easy I thought - anyway got stuck with the HitTest function which returns "1" for whichever tab is clicked.
As I started the project very recently, it's literaly just a handful of lines. The mentioned HitTest function is used in Tdi.cpp file in CHlavniOkno::CTdi::OnLButtonDown function (full source code at http://nestorovic.hyperlink.cz/cpp_mfc.zip ):
afx_msg void CHlavniOkno::CTdi::OnLButtonDown(UINT flagy,CPoint bod){
if (::DragDetect(m_hWnd,bod)){
TCHITTESTINFO hti={bod};
if (int idZalozky=HitTest(&hti)>=0)
parametryTazeneZalozky=new TParametryTazeneZalozky(this,idZalozky);
}
CTabCtrl::OnLButtonDown(flagy,bod);
}
I definitely must have omitted something tiny, as is almost always the case...
Thanks for your time by having a look at the problem.
Tomas
The statement int idZalozky=HitTest(&hti)>=0 is setting idZalozky to the result of the test HitTest(&hti)>=0. As a boolean test this will always return either 0 or 1.
You probably want:
int idZalozky=HitTest(&hti);
if (idZalozky>=0)
{
...
}

Weird bug in Qt application

In my application, I have my re-implemented QGraphicsView checking for a mouseReleaseEvent(), and then telling the item at the position the mouse is at to handle the event.
The QGraphicsItem for my view is made up of two other QGraphicsItems, and I check which one of the two is being clicked on (or rather having the button released on), and handle the respective events.
In my Widget's constructor, I set one of the items as selected by default, using the same methods I used when the items detect a release.
When I debugged, I found that for the LabelItem, select is called without a problem from the constructor (and the result is clear when I first start the application). But, when I click on the items, the application terminates. I saw that I was getting into the select function, but not leaving it. So the problem is here.
Which is very weird, because the select function is just a single line setter.
void LabelItem::select()
{
selected = true;
}
This is the mouseReleaseEvent;
void LayerView::mouseReleaseEvent(QMouseEvent *event)
{
LayerItem *l;
if(event->button() == Qt::LeftButton)
{
l = (LayerItem *) itemAt(event->pos());
if(l->inLabel(event->pos()))
{ //No problem upto this point, if label is clicked on
l->setSelection(true); //in setSelection, I call select() or unselect() of LabelItem,
//which is a child of LayerItem, and the problem is there.
//In the constructor for my main widget, I use setSelection
//for the bottom most LayerItem, and have no issues.
emit selected(l->getId());
}
else if(l->inCheckBox(event->pos()))
{
bool t = l->toggleCheckState();
emit toggled(l->getId(), t);
}
}
}
When I commented the line out in the function, I had no errors. I have not debugged for the other QGraphicsItem, CheckBoxItem, but the application terminates for its events as well. I think the problem might be related, so I'm concentrating on select, for now.
I have absolutely no clue as to what could have caused this and why this is happening. From my past experience, I'm pretty sure it's something simple which I'm stupidly not thinking of, but I can't figure out what.
Help would really be appreciated.
If the LabelItem is on top of the LayerItem, itemAt will most likely return the LabelItem because it is the topmost item under the mouse. Unless the LabelItem is set to not accept any mouse button with l->setAcceptedMouseButtons(0).
Try to use qgraphicsitem_cast to test the type of the item. Each derived class must redefine QGraphicsItem::type() to return a distinct value for the cast function to be able to identify the type.
You also could handle the clicks in the items themselves by redefining their QGraphicsItem::mouseReleaseEvent() method, it would remove the need for the evil cast, but you have to remove the function LayerView::mouseReleaseEvent() or at least recall the base class implementation, QGraphicsView::mouseReleaseEvent(), to allow the item(s) to receive the event.
I have seen these odd behaviours: It was mostly binary incompatibility - the c++ side looks correct, and the crash just does not make sense. As you stated: In your code the "selected" variable cannot be the cause. Do you might have changed the declaration and forgot the recompile all linked objects. Just clean and recompile all object files. Worked for me in 99% of the cases.