Event handler of another frame not getting called - wxWidgets - c++

Good day to all,
I'm working on a C++ program using wxWidgets wherein a frame has a button named "Calibrate Button" which is used to calibrate HSV values using a trackbar. When the user selects this button, a live feed video, a control panel which contains the trackbar for adjusting HSV values, a threshold image which represents the changes in the calibration of the HSV values, and another frame which contains a button named "SAVE VALUES" appears. When the user clicks the Save Values button, it saves whatever the values that have been set in the trackbar into a textfile.
My problem is, whenever i click that button, it does not perform what it is intended to do, which is to save the HSV values in a txtfile.
Here is the main code which is responsible for creating the additional frame when the user selects the Calibrate Button.
void TemplateFrame::OncalibTrackerButtonClick(wxCommandEvent& event)
{
**some code for initializing the live video feed, the trackbars, etc.**
CalibrationWindow* calibWindow = new CalibrationWindow(this);
calibWindow->setHSVvalues(H_MIN,S_MIN,V_MIN,H_MAX,S_MAX,V_MAX);
calibrationModeTracker = true;
**the following code after this line would be a pseudocode of what I am doing once the button has been click already
while(calibrationModeTracker){
calibWindow->Show(); // shows the "SAVE VALUES" frame
wxYield();
read live feed video
createTrackbars();
show live feed video
show threshold image
}
}
Inside the while loop, users would be able to click the "SAVE VALUES" button which would save the HSV values in a txtfile.
On the other hand, here is the event handler function of the newly created frame (CalibrationWindow.cpp) after clicking Calibrate Button which contains the Save Values button
void CalibrationWindow::OnSaveClick(wxCommandEvent& event)
{
ofstream myfile;
stringstream oss(stringstream::in | stringstream::out);
string f;
f = "//home//ianlangley//Desktop//Savefiles//HSVvalues_left.txt";
f = f.append(oss.str());
myfile.open(f.c_str());
if (myfile.is_open()){
myfile<<CalibrationWindow::getlow_H()<<"\n";
myfile<<CalibrationWindow::getlow_S()<<"\n";
myfile<<CalibrationWindow::getlow_V()<<"\n";
myfile<<CalibrationWindow::gethigh_H()<<"\n";
myfile<<CalibrationWindow::gethigh_S()<<"\n";
myfile<<CalibrationWindow::gethigh_V();
myfile.close();
}
}
Lastly, here is the code inside the header file: CalibrationWindow.h
class CalibrationWindow: public wxFrame
{
public:
CalibrationWindow(wxWindow* parent,wxWindowID id=wxID_ANY);
virtual ~CalibrationWindow();
void setHSVvalues(int lowH,int lowS, int lowV,int highH,int highS, int highV);
int getlow_H();
int getlow_S();
int getlow_V();
int gethigh_H();
int gethigh_S();
int gethigh_V();
//(*Declarations(CalibrationWindow)
wxButton* LeftHandButton;
wxButton* RightHandButton;
//*)
protected:
//(*Identifiers(CalibrationWindow)
static const long ID_BUTTON2;
static const long ID_BUTTON1;
//*)
private:
int lowH,lowS,lowV,highH,highS,highV;
//(*Handlers(CalibrationWindow)
void OnRightHandButtonClick(wxCommandEvent& event);
void OnLeftHandButtonClick(wxCommandEvent& event);
//*)
DECLARE_EVENT_TABLE()
};
Thank you to those who will be able to help me with this problem.

Related

Closing Popup and setting button label

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.

Programmatic creation of image button in cppwinrt

Using cppwinrt (standard C++, not C++/CX) how would you set the content of a Button to an image, programmatically? Has to be programmatically because cppwinrt does not yet support xaml, in which doing that is easy. Here's what I am trying, which results in a functional but empty button:
Button button = Button();
BitmapImage bitmapImage = BitmapImage();
Uri imageUri = Uri(L"ms-appx:///Assets/Images/stopbutton.png");
bitmapImage.UriSource(imageUri);
Image buttonImage = Image();
buttonImage.Height(30);
buttonImage.Width(30);
buttonImage.Source(bitmapImage);
button.Content(buttonImage);
Then of course I add the button, which does show up nicely, though blank. I've tried an absolute path for the .png, but that also fails. There must be a way to do this programmatically in C++.
Your original code works fine on my side. Just make sure that your image really is inside the Assets/Images folder, that you added it to your project and that it is copied with the app content during the build, by checking if the Content parameter in the image properties is set to True.
Edit
After reading your further requirements. Just set the button padding and border thickness to zero, this will remove any space around the image.
Here is a simple working application with your button creation code:
#include <winrt\Windows.ApplicationModel.Activation.h>
#include <winrt\Windows.Devices.Enumeration.h>
#include <winrt\Windows.Foundation.h>
#include <winrt\Windows.UI.Xaml.h>
#include <winrt\Windows.UI.Xaml.Controls.h>
#include <winrt\Windows.UI.Xaml.Media.Imaging.h>
using namespace winrt;
using namespace winrt::Windows::ApplicationModel::Activation;
using namespace winrt::Windows::Devices::Enumeration;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Media::Imaging;
struct App : ApplicationT<App>
{
void OnLaunched(LaunchActivatedEventArgs const &)
{
Image image;
image.Height(30);
image.Width(30);
image.Source(BitmapImage(Uri(L"ms-appx:///Assets/Images/sample.png")));
Button button;
button.Padding(ThicknessHelper::FromUniformLength(0));
button.BorderThickness(ThicknessHelper::FromUniformLength(0));
button.Content(image);
Window window = Window::Current();
window.Content(button);
window.Activate();
}
static void Initialize(ApplicationInitializationCallbackParams const &)
{
make<App>();
}
static void Start()
{
Application::Start(App::Initialize);
}
};
int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
App::Start();
}
OK, here is what is needed to make a button display an image that fills the button: rather than setting the button.Content to an image, create an ImageBrush with the image and set the button.Background to that ImageBrush, e.g.
Button button = Button();
button.Height(30);
button.Width(30);
BitmapImage bitmapImage = BitmapImage();
Uri imageUri = Uri(L"ms-appx:///Assets/Images/stopbutton.png");
bitmapImage.UriSource(imageUri);
ImageBrush imageBrush = ImageBrush();
imageBrush.ImageSource(bitmapImage);
button.Background(imageBrush);
//The button will now look exactly like the image.

How to load gif using wxWidgets c++?

I need your help! Im currently really new to wxWidgets as a uni student. I am trying to load a .gif file using wxWidgets. I tried using the code below... but it only loads 1 frame, it doesn't move/ change to the other frames, it's basically a still picture. The file is .gif extension, and it has 3 frames or so. The location of the image is already correct. Help would be much appreciated!
Thank you
#include "ImageWindow.h"
#include <wx/stdpaths.h>
#include <wx/filename.h>
BEGIN_EVENT_TABLE(ImageWindow, wxWindow)
EVT_PAINT(ImageWindow::OnPaint)
END_EVENT_TABLE()
ImageWindow::ImageWindow(wxFrame *parent)
: wxWindow(parent, wxID_ANY)
{
this->SetBackgroundColour(wxColour(*wxWHITE));
wxImageHandler *gifLoader = new wxGIFHandler();
wxImage::AddHandler(gifLoader);
this->LoadPotatoBitmap();
}
ImageWindow::~ImageWindow()
{
delete potatoBitmap;
}
void ImageWindow::LoadPotatoBitmap()
{
wxStandardPaths &stdPaths = wxStandardPaths::Get();
wxString fileLocation = stdPaths.GetExecutablePath();
wxImage image(wxT("A:\\Projects\\TestGif\\Assets\\Kuning.gif"),
wxBITMAP_TYPE_GIF);
potatoBitmap = new wxBitmap(image);
}
void ImageWindow::OnPaint(wxPaintEvent &event)
{
wxPaintDC pdc(this);
if (potatoBitmap != nullptr)
{
pdc.DrawBitmap(*potatoBitmap, wxPoint(150, 100), true);
}
}
You are not specifying the index of the image in the constructor and that's why you see the default one as you can see in the wxWdigets documentation:
wxImage::wxImage ( const wxString & name,
wxBitmapType type = wxBITMAP_TYPE_ANY,
int index = -1
)
index Index of the image to load in the case that the image file contains multiple images. This is only used by GIF, ICO and TIFF handlers. The default value (-1) means "choose the default image" and is interpreted as the first image (index=0) by the GIF and TIFF handler and as the largest and most colourful one by the ICO handler.
But, you should also consider wxAnimationCtrl (see this sample)
Use wxAnimationCtrl for playing gif animations
or
Use extract each frame from the gif image and draw one by one using wxTimer.

GLFW Keyboard Input Registers As Multiple Clicks

In my current LWJGL application I am using the GLFW window input handler which I have set up a class to handle called Keyboard.java which extends GLFWKeyCallback. I have correctly set up my keyboard input class but when I click on a key if i do not click if fast enough (very quickly) then it registers as multiple clicks. I have presented some documentation below:
Keyboard Class
public class Keyboard extends GLFWKeyCallback {
//Variables
public static boolean keys[] = new boolean[65536];
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
keys[key] = action == GLFW_PRESS;
}
}
Implementation
public static void handleInput() {
if (Keyboard.keys[GLFW_KEY_SPACE]) {
System.out.println("Space");
glfwPollEvents();
}
}
The above method is implemented in the main game loop and is called once a frame.
Result
Initialised LWJGL Version: 3.1.2 build 29
Space
Space
Space
Space
The above: "Space" should be outputted every time that I click space but when I click it relatively fast, Then i get the above result of many "spaces".
Conclusion: Is it possible for a click of space to be registered only once no matter how long you hold it. Thanks
In your handleInput() function, you are testing to see if Keyboard.keys[GLFW_KEY_SPACE] is true, and if it is, you execute the statement. The problem is that this test only becomes false when you stop hitting space, which could take seconds to happen.
My suggestion: once you tested for Keyboard.keys[GLFW_KEY_SPACE], make it false.
public static void handleInput() {
if (Keyboard.keys[GLFW_KEY_SPACE]) {
Keyboard.keys[GLFW_KEY_SPACE] = false;
System.out.println("Space");
glfwPollEvents();
}
}

captureScreen in cocos-2d C++ - how to use or save the captured image?

I want to have a button in my (iOS) app that takes a screenshot of the current screen and then attaches it to a text message.
Like I have seen in this other app...
I have message sending working, and I think I have screenshot working, but I don't know where the screenshot is saved or how to use it.
My message sending is called from a button in the app...
void GameOverScene::messageCallBack(cocos2d::Ref *sender) {
CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(ALL_BUTTONS_CLICK_SOUND_NAME);
utils::captureScreen( CC_CALLBACK_2(GameOverScene::afterCaptured, this), "screenshot.png" );
__String *messageTextOne = __String::create("sms:&body=Hey,%20I%20just%20hit%20a%20score%20of%20");
__String *messageTextTwo = __String::createWithFormat("%i", score);
__String *messageURL = __String::createWithFormat("%s%s", messageTextOne->getCString(), messageTextTwo->getCString());
Application::getInstance()->openURL(messageURL->getCString());
}
and the screenshot function is...
void GameOverScene::afterCaptured( bool succeed, const std::string &outputFile ) {
if (succeed) {
log("Screen capture succeeded");
Size screenSize = Director::getInstance()->getWinSize();
RenderTexture * tex = RenderTexture::create(screenSize.width, screenSize.height);
tex->setPosition(screenSize.width/2, screenSize.height/2);
tex->begin();
this->getParent()->visit();
tex->end();
tex->saveToFile("Image_Save.png", Image::Format::PNG);
} else {
log("Screen capture failed");
}
}
I get the message in the console "Screen capture succeeded", and my message app opens up with the prefilled text message.
What I need to do is to add the screenshot to this message, but I cant see how to do that, or where the screenshot is saved, or how to use the saved screenshot.
If it succeeded it's saved in private application directory. Use software like iExplorer, find your app and it should be inside Documents directory. If you want to see it in Photos you have manually add it there.
In order to achieve this, you have to call
UIImageWriteToSavedPhotosAlbum
see: How to save picture to iPhone photo library?
You have to create a function in AppController.m and use it from here. You can call objc code from c++. It requires UIImage so first you have to pass filepath and load uiimage from it and then finally add to gallery.
You can use something like this to get the path of image saved:
void CustomLayerColor::saveFile(Node*node, std::string fileName, const renderTextureCallback& callBack) {
float renderTextureWidth = node->getBoundingBox().size.width;
float renderTextureHeight = node->getBoundingBox().size.height;
RenderTexture * renderTexture = RenderTexture::create(renderTextureWidth,renderTextureHeight);
renderTexture->begin();
node->visit();
renderTexture->end();
renderTexture->saveToFile(fileName, Image::Format::PNG, true,callBack);
}
void CustomLayerColor::onSaveFileCallBack(RenderTexture * mRenderTexture, const std::string& savedFileNameWithFullPath) {
}