I'm creating a Basic Button event for a University Project and I'm having problems trying to access an Entity's child.
I am using a Component model in order to create and display all objects on the screen and one "button" is comprised of 3 separate components, a TextComponent that displays what the button does i.e. "Start Game", a SpriteComponent that creates and displays an image above the text, and a ShapeComponent that acts as a "Bounding Box" for my button. This component functions purely as a sort of Event Handler, checking to see if the mouse is inside the shape's bounding box and if so, allows the user to interact with it (like display a message).
Below is the code for one of my buttons.
static shared_ptr<Entity> btnStartGame;
void MainMenuScene::Load() {
//START GAME BUTTON
auto txtNewGame = makeEntity();
auto t = txtNewGame->addComponent<TextComponent>("New Game");
t->getText().setOrigin(t->getText().getGlobalBounds().width / 2, t->getText().getGlobalBounds().height / 2);
txtNewGame->setPosition(Vector2f(280.f, 500.f));
auto sword = makeEntity();
auto s = sword->addComponent<SpriteComponent>();
s->Sprite("Sword.png", IntRect(0, 0, 60, 60));
sword->setPosition(Vector2f(370.f, 540.f));
auto btnStartGame = makeEntity();
auto b = btnStartGame->addComponent<ShapeComponent>();
b->setShape<sf::RectangleShape>(Vector2f(200.f, 105.f));
b->getShape().setFillColor(Color(224, 190, 20)); //just so I can see where it is
b->getShape().setOrigin(b->getShape().getGlobalBounds().width / 2, b->getShape().getGlobalBounds().height / 2);
btnStartGame->setPosition(Vector2f(Engine::GetWindow().getSize().x / 4 - 40.f, 525.f));
}
Once the Bounding box is created, I do a validation check in the Update function in order to see if the mouse is currently inside the ShapeComponent's bounding box. I get the component of the btnStartGame Entity and get it's GlobalBounds, after this is done, I check to see if the mouse is currently inside the box However this line causes an error.
if (btnStartGame->get_components<ShapeComponent>()[0]->getShape().getGlobalBounds().contains(Engine::GetWindow().mapPixelToCoords(sf::Mouse::getPosition())))
{
cout << "level 1 selected" << endl;
}
I get a Read Access Violation Error at this line in Vector
pointer _Unchecked_begin() _NOEXCEPT
{ // return pointer for beginning of mutable sequence
return (this->_Myfirst());
}
Does anyone know why this is happening? I thought at first it was a pointer error but that didn't seem to fix anything.
Solved the problem.
I had created a shared_ptr and instead of referencing the Entity I had created, I was trying to point to a new one inside the Load() function.
Removing the Auto from btnStartGame solved the issue
btnStartGame = makeEntity();
Related
I'm writing a C++ wxWidgets calculator application. I want to compress trigonometric function buttons into a single one to save on space, using what's basically a split button. If you left click on it, the current option is used. If you right click, a popup menu is opened, which contains all the buttons; when you click on one of them, it is used and the big button changes.
I've been suggested to use wxComboBox and other stuff for this job, but I preferred using wxPopupTransientWindow because this way I can display the buttons in a grid, making everything - in my opinion - neater.
Problem is, when I choose an option from the menu, the main button's ID changes (because when I reopen the menu the previously clicked button is light up as its ID and the big button's ID match), but the label does not. Furthermore, the popup is supposed to close itself when you left click on one of the buttons, but it does not.
This is the code for the custom button in the popup which is supposed to do all that stuff:
void expandButton::mouseReleased(wxMouseEvent& evt)
{
if (pressed) {
pressed = false;
paintNow();
wxWindow* mBtn = this->GetParent()->GetParent();
mBtn->SetLabel(this->GetLabel());
mBtn->SetId(this->GetId());
this->GetParent()->Close(true);
}
}
This is the code for the custom button in the main frame which opens up the popup (temporary setup just to test if the whole thing is working):
void ikeButton::rightClick(wxMouseEvent& evt) // CREA PANNELLO ESTENSIONE
{
if (flags & EXPANDABLE)
{
std::vector<expandMenuInfo> buttons;
buttons.push_back(expandMenuInfo(L"sin", 3001));
buttons.push_back(expandMenuInfo(L"cos", 3002));
buttons.push_back(expandMenuInfo(L"tan", 3003));
buttons.push_back(expandMenuInfo(L"arcsin", 3004));
buttons.push_back(expandMenuInfo(L"arccos", 3005));
buttons.push_back(expandMenuInfo(L"arctan", 3006));
wxPoint p = this->GetScreenPosition();
size_t sz = this->GetSize().GetHeight() / 1.15;
expandMenu* menu = new expandMenu(this, buttons, sz, wxPoint(
p.x, p.y + this->GetSize().GetHeight() + 2));
menu->SetPosition(wxPoint(
menu->GetPosition().x - ((menu->GetSize().GetWidth() - this->GetSize().GetWidth()) / 2),
menu->GetPosition().y));
menu->Popup();
}
}
Let me know if I need to show more code.
This is probably a terrible way of doing this, but this is basically the first "serious" application I'm creating using the wxWidgets framework. Any help is appreciated.
when I choose an option from the menu, the main button's ID changes
(because when I reopen the menu the previously clicked button is light
up as its ID and the big button's ID match), but the label does not.
If you're creating the popup menu like in your previous post, you had a popup window with a panel as its child and the buttons were then children of the panel layed out with a sizer.
If that's still the case, this->GetParent() and should be the panel, this->GetParent()->GetParent() should be the popup. So this->GetParent()->GetParent()->GetParent() should be the trig function button (assuming you created the popup with the trig function button as the parent).
So I think the line wxWindow* mBtn = this->GetParent()->GetParent(); should be changed to wxWindow* mBtn = this->GetParent()->GetParent()->GetParent();.
Or slightly shorter wxWindow* mBtn = this->GetGrandParent()->GetParent();;
the popup is supposed to close itself when you left click on one of
the buttons, but it does not.
It looks like wxPopupTransientWindow has a special Dismiss method that is supposed to be used to close it.
So I think the line this->GetParent()->Close(true); should be changed to this->GetGrandParent()->Dismiss(); (Assuming as above that the buttons in the popup are children pf a panel).
Alternately, if you want a solution that will work regardless of the parentage of the controls in the popup window, you could have a utility function to find the popup ancestor which would look something like this:
wxPopupTransientWindow* FindPopup(wxWindow* w)
{
wxPopupTransientWindow* popup = NULL;
while ( w != NULL )
{
popup = wxDynamicCast(w, wxPopupTransientWindow);
if ( popup )
{
break;
}
w = w->GetParent();
}
return popup;
}
This uses the wxDynamicCast function which is slightly different from the c++ dynamic_cast expression. wxDynamicCast uses wxWidgets' RTTI system to check if the given pointer can be converted to the given type.
Then the mouseReleased method could use this utility function something like this:
void expandButton::mouseReleased(wxMouseEvent& evt)
{
if (pressed) {
pressed = false;
paintNow();
wxPopupTransientWindow* popup = FindPopup(this);
if (popup ) {
wxWindow* mBtn = popup->GetParent();
mBtn->SetLabel(this->GetLabel());
mBtn->SetId(this->GetId());
mBtn->Refresh();
popup->Dismiss();
}
}
}
I'm not sure why you're setting trig function button to have a new id, but I assume you have a reason.
To make the SetLabel method work in your custom button class, I think the easist thing is to call the SetLabel() method in the button's constructor. This will store the string passed to the constructor in the button's internal label member.
Based on other questions, I think the ikeButton constructor looks something like this:
ikeButton::ikeButton(wxFrame* parent, wxWindowID id, wxString text,...
{
...
this->text = text;
To store the label, you would need to change the line this->text = text; to
SetLabel(text);
And when you draw the button, I think the method you use looks like this:
void ikeButton::render(wxDC& dc)
{
...
dc.DrawText(text, ...);
}
You would need to change, the line dc.DrawText(text, ...); to
dc.DrawText(GetLabel(), ...);
Likewise, any other references to the button's text member should be changed to GetLabel() instead.
Finally, when you set the label in the expandButton::mouseReleased method, it might be a good idea to call button's Refresh() method to force the button to redraw itself. I added that my suggestion for the mouseReleased method above.
Using Cocos2d-x and C++, I'm trying to play and pause an animation for a sprite.
I'm using version 3.15.1 of Cocos2dx.
I have a class called PlayerSprite which is derrived from the cocos2d::Sprite class. Inside PlayerSprite initialization, I've setup my animation with the following code:
SpriteBatchNode* playerSpriteBatch = SpriteBatchNode::create("player.png");
SpriteFrameCache* spriteFrameCache = SpriteFrameCache::getInstance();
spriteFrameCache->addSpriteFramesWithFile("player.plist");
Vector<SpriteFrame*> animFrames(2);
char str[18] = { 0 };
for (int i = 1; i < 3; i++) {
sprintf(str, "player_idle_%d.png", i);
SpriteFrame* frame = spriteFrameCache->getSpriteFrameByName(str);
animFrames.pushBack(frame);
}
Animation* idleAnim = Animation::createWithSpriteFrames(animFrames, 0.8f);
self->idleAction = self->runAction(RepeatForever::create(Animate::create(idleAnim)));
self->idleAction->setTag(0);
When I run the code, it works fine and the animation loops correctly.
In my void update() method, I am trying to pause/play the action/animation based of weather the player is moving or idle.
I do this with the following code:
const bool isIdleActionRunning = this->getNumberOfRunningActionsByTag(0) > 0 ? true : false;
const bool isMoving = !vel.isZero();
if (!isMoving && !isIdleActionRunning) {
// Player is idle AND animation is not running
// Run animation
this->runAction(idleAction);
} else if (isMoving && isIdleActionRunning) {
// Player is moving but animation is running
// Pause animation
this->stopActionByTag(0);
}
When I run this code now, my character falls, and as soon as he hits the gound, I get an error at this->runAction(idleAction); saying:
Access violation reading location 0xDDDDDDE5
I believe this is caused due to this->stopActionByTag(0) deleting the action pointer. I've tried to clone the action to avoid this but have had no success.
I know this is a bit late and you might already have solved this but here goes...
Your problem is that you cannot use one instance of Action (idleAction) multiple times. So, once you have run it and removed it, it is released and cannot be used. So, you have 2 options now,
Either create a new idleAction Action every time before running the action.
Or, have an idleAction retained and don't run it ever. Instead, create a clone of this idleAction and run a new clone each time. i.e.
idleAction->retain();
const bool isIdleActionRunning = this->getNumberOfRunningActionsByTag(0) > 0 ? true : false;
const bool isMoving = !vel.isZero();
if (!isMoving && !isIdleActionRunning) {
// Player is idle AND animation is not running
// Run animation
Action idleActionClone = idleAction->clone();
this->runAction(idleActionClone);
} else if (isMoving && isIdleActionRunning) {
// Player is moving but animation is running
// Pause animation
this->stopActionByTag(0);
}
Solution: call retain() to keep your action.
It's a matter of memory management of cocos2d-x.
In create() function of your RepeatForever class (derived from Ref), the reference count is set to 1 and there is a line of code ret->autorelease() before returning the object, which means this object will be released automatically at the end of this frame.
You called runAction() function the same frame you created it, the action is retained by ActionManager, it's reference count set to 2, and then 1 at the end of the frame (autorelease).
After your stopping it, it's released by ActionManager, reference count set to 0 and it's deleted. After this you use your action, it will be an access violation method.
*Edit: don't forget to release the action manually when PlayerSprite is deleted, or it's a leak.
When you stop action it's being recycled from memory. In order to play action once more, you have to recreate it. So you may just make a creator function, which returns your animation. The downside is you're recreating animation each time and it'll also play from the beginning (technically you can rewind it).
But I've developed a simpler technique to pause/resume animations:
Let's say you have an action:
action = MoveBy::create(5.0f, Vec2(50, 100));
Now, you can embed this action into Speed action like this:
action = Speed::create(MoveBy::create(5.0f, Vec2(50, 100)), 1.0f);
1.0f - is speed, so it's normal action rate. Now to pause just call:
action->setSpeed(0.0f);
and to resume:
action->setSpeed(1.0f);
you can also use different speed if you need it for some reason or another ;)
#include <gtk/gtk.h>
//Defined a comboBox like this
combo = gtk_combo_box_new_text();
//Added entries like this
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "string");
//How to get a particular entry deleted from the list of entries in the ComboBox combo?
How do I delete a particular entry in the comboBox? For example - The ComboBox dropdown has entries like "Foo", "Boo", "Hoo" etc. Now I want to select "Boo" and then remove it? How do I do that ?
//Segmentation fault while removal error
mcve -
fixed = gtk_fixed_new();
combo = gtk_combo_box_new_text();
gtk_fixed_put(GTK_FIXED(fixed), combo, 50, 50);
label = gtk_label_new("Rooms");
gtk_fixed_put(GTK_FIXED(fixed), label, 50, 30 );
gtk_table_attach_defaults (GTK_TABLE (table), fixed, 2, 3, 0, 2);
g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(combo_selected), (gpointer) label);
In this callback function I just copy the current selection to a globally declared string. Next, in some other function I try to run this -
gtk_combo_box_remove_text (GTK_COMBO_BOX(combo), gtk_combo_box_get_active (GTK_COMBO_BOX(combo))); //statement where seg fault occurs
The gtk_combo_box_get_active gives me the appropriate index entry to be removed. Note - GtkWidget *combo is globally defined in the program.
The id of the active(that is currently selected) entry in a combo box can be obtained via gtk_combo_box_get_active and it can be removed with help of gtk_combo_box_text_remove or gtk_combo_box_remove_text
(Depending on which version of the api is used. The former(gtk_combo_box_text_remove) is more up to date).
gtk_combo_box_get_active returns -1 if there is no active item and should therefore be checked before passing it to one of the remove functions. This is especially important if, as in the case presented above, the removing happens in a signal handler. According to the documentation the "changed" signal
[...] is emitted when the active item is changed. This can be due to the user selecting a different item from the list, or due to a call to gtk_combo_box_set_active_iter(). It will also be emitted while typing into the entry of a combo box with an entry. [...]
As far as i understand this includes when the item is deselected(which will presumably happen if it is deleted).
Your handler should therefore look somehow like this:
void combo_selected(GtkComboBox *widget, gpointer user_data)
{
int active_id=gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
if(active_id!=-1)
{
//do real work...
}
}
Here's my problem
I'm new to osg and I'm trying to create something like a dropdown list by adding osgWidget::Labels to a osgWidget::Box and then setting this same box as a osgWidget::Frame's window and all this works fine until the part where my callback "labelClicked" is never actually triggered once I click the label.
I tried adding this callback to other widgets such as an input and even the actual frame where I keep the box with the labels, and both worked fine.
Here's the functions that I use to add labels to my dropdown list:
osgWidget::Label* DropdownInput::createLabel(const std::string& l, unsigned int size) {
osgWidget::Label* label = new osgWidget::Label("", "");
label->setFont("fonts/Vera.ttf");
label->setFontSize(size);
label->setFontColor(1.0f, 1.0f, 1.0f, 1.0f);
label->setLabel(l);
return label;
}
void DropdownInput::addLabel(string text){
osg::ref_ptr<osgWidget::Label> label1 = createLabel(text,15);
label1->setName(text);
label1->setPadding(2.0f);
label1->setColor(1,1,1, 1);
label1->setSize(300.0f, 40);
label1->setImage( "img.png" );
label1->addCallback( new osgWidget::Callback(&DropdownInput::labelClicked, this, osgWidget::EVENT_MOUSE_PUSH) );
dropdownContent.push_back(label1); //list where I store the labels for flitering purposes
this->dropdownBox->addWidget(label1);
}
and the callback:
bool DropdownInput::labelClicked(osgWidget::Event& ev) {
cout<<"label clicked!"<<endl;
return true;
}
Already tried to place the labels inside a box inside a frame and adding the callback to this frame instead, and then adding it to the main box but not only did it not resize correctly but also caused lag when filtering the labels which is not an option.
Also tried with other types of events like mouse over and such and still no answer from the label.
I was asked to avoid using other UI libraries, so if possible I would prefer osgWidget based solutions.
So, now I'm a bit lost, any help would be greatly appreciated.
If you didn't find my explanation to be comprehensible enough don't hesitate telling me since it's my first time posting here :)
For labels you should first add the push event to the label event mask:
label->addEventMask(osgWidget::EVENT_MOUSE_PUSH);
Otherwise label->canMousePush() will return false and the callback will never be called.
case 1 : I have a MFC dialog box having a LisBox.
I have added two items in listbox.
Whenever i am double clicking on empty area of list box i.e. not double clicking
on either of two item.
Double click is detecting on empty area of listbox.
case 2: When i created a small MFC test application with listbox. it iis detecting double click only on item, not on empty area.
I compared all properties of both cases but couldn't figure out what is the problem.
Anyone has idea what is going wrong in case 1.
I think it is abnormal process. I've tested your situation in VS2010. In my MFC test application sent LBN_DBLCLK when I double clicked on empty area. If you do not really want to know the reason this weired situation, you can just check whether double click event is occurred on empty area or not. I think it is better way for saving your time.
void CMfcDlgTestDlg::OnLbnDblclkList2()
{
// TODO: Add your control notification handler code here
CListBox* list = (CListBox*)(GetDlgItem(IDC_LIST2));
int cur_sel = list->GetCurSel();
if (cur_sel == -1)
{
return;
}
}
EDIT : FOR ANOTHER CASE
When one of list box item is already selected, how can it handle on ON_LBN_DBLCLK handler?
I think there will be some available methods for solving this, however I use below code and it can be useful way, also.
void CMfcDlgTestDlg::OnLbnDblclkList2()
{
// TODO: Add your control notification handler code here
CListBox* list = (CListBox*)(GetDlgItem(IDC_LIST2));
CPoint cursor;
cursor.x = GetCurrentMessage()->pt.x;
cursor.y = GetCurrentMessage()->pt.y;
list->ScreenToClient(&cursor);
BOOL is_outside = FALSE;
UINT item_index = list->ItemFromPoint(cursor, is_outside);
if(is_outside)
{
//mouse clicked on empty area
return ;
}
else
{
// do something with 'item_index'
}
}
I hope this will help you a little.