using wxWidgets in library

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3197
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: using wxWidgets in library

Post by ONEEYEMAN » Tue Mar 12, 2019 5:47 pm

Hi,
Then that's it - just Show() the dialog without title and button(s) on show and then hide it on Hide().
No "wxGetApp" calls are necessary.

Thank you.

ppsmurf
Earned a small fee
Earned a small fee
Posts: 14
Joined: Tue Jan 22, 2019 9:14 am

Re: using wxWidgets in library

Post by ppsmurf » Wed Mar 13, 2019 8:28 am

ONEEYEMAN wrote:
Tue Mar 12, 2019 5:47 pm
Hi,
Then that's it - just Show() the dialog without title and button(s) on show and then hide it on Hide().
No "wxGetApp" calls are necessary.

Thank you.
But only with Pinpad->Show() the dialog looks like this (viz. attachment), thats why I added wxGetApp.OnRun() I guess. (With wxGetApp.OnRun() dialog looks OK)

Code: Select all

Pkcs11PinPadDialog::Pkcs11PinPadDialog() : mainSizer(nullptr), staticText1(nullptr), wxDialog(NULL, wxID_ANY, "Enter PIN", wxDefaultPosition, wxSize(350, 250)) {
	mainSizer = new wxBoxSizer(wxVERTICAL);
	
	staticText1 = new wxStaticText(this, wxID_ANY, "Please enter PIN on pinpad reader keyboard... ");
	staticText1->Wrap(330);
	mainSizer->Add(staticText1, 0, wxALL, 10);

	this->SetSizer(mainSizer);
	this->Layout();

	this->Centre(wxBOTH);
}
What I'm doing wrong?
Thank you.
Attachments
pinpad_wrong.png
pinpad_wrong.png (1.49 KiB) Viewed 188 times

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3197
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: using wxWidgets in library

Post by ONEEYEMAN » Wed Mar 13, 2019 2:39 pm

Hi,
Can you post screenshot with the call for "wxGetApp().OnRun()"?

Thank you.

ppsmurf
Earned a small fee
Earned a small fee
Posts: 14
Joined: Tue Jan 22, 2019 9:14 am

Re: using wxWidgets in library

Post by ppsmurf » Wed Mar 13, 2019 3:22 pm

The wxStaticText is shown as empty white box. There should be text inside, see attachment, this is with the call "wxGetApp().OnRun()".

Thank you.
Attachments
pinpad.png
pinpad.png (2.42 KiB) Viewed 163 times

ppsmurf
Earned a small fee
Earned a small fee
Posts: 14
Joined: Tue Jan 22, 2019 9:14 am

Re: using wxWidgets in library

Post by ppsmurf » Thu Mar 14, 2019 2:06 pm

Hi,
does anyone have any idea please? I need to solve this, but I really don't know how.

I have few more questions.
1) How "wx objects" are freed?

Code: Select all

MyDialog* dlg = new MyDialog(); // wxDialog
dlg->ShowModal();
I didn't see "delete" in any example (or am I blind? :D). Do i need "delete dlg;" please?

2) I have problem with wxDialog on macOS. With "ShowModal()" dialog is shown, but it is not responding - mouse cursor have loading animation, dialog buttons dont work etc.
By trial and error I found, that if this is a second shown dialog, it works fine.

Code: Select all

class MyDialog: public wxDialog
{

public:
	MyDialog(int i = 0);

	void OnButton(wxCommandEvent& event);
	void OnIdle(wxIdleEvent& event);

private:	
	wxButton* m_btnOk;
	int m_i;
	
	wxDECLARE_EVENT_TABLE();
};

MyDialog::MyDialog(int i) : m_i(i), wxDialog(NULL, wxID_ANY, "caption", wxDefaultPosition, wxSize(600, 350)){

	wxSize btnSize(80, 22);
	m_btnOk = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, btnSize);

	wxBoxSizer* baseSizer = new wxBoxSizer(wxVERTICAL);
	baseSizer ->Add(m_btnOk); 
	
	SetSizer(baseSizer);
	Layout();

	Centre(wxBOTH);
}

void AutoDelete::OnButton(wxCommandEvent& event) {
	EndModal();
	Destroy();
}

void AutoDelete::OnIdle(wxIdleEvent & event) {	

    if(m_i == 0){
    	std::cout << "OnIdle event in first dialog" << std::endl;
        EndModal(0);
	    Destroy();
	    return;
    }

	std::cout << "OnIdle event in second dialog" << std::endl;
}

Code: Select all

MyDialog* dlg = new MyDialog(0); 
dlg->ShowModal();

MyDialog* dlg2 = new MyDialog(1); 
dlg2->ShowModal();
First dialog close imediately and second works fine. (Edit: I just found, this doesnt work every time, sometimes second dialog is not responding too.)


Please can anybody give me hint, what might be the problem?
Thank you.

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3197
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: using wxWidgets in library

Post by ONEEYEMAN » Thu Mar 14, 2019 2:29 pm

Hi,
ppsmurf wrote:
Thu Mar 14, 2019 2:06 pm
Hi,
does anyone have any idea please? I need to solve this, but I really don't know how.
I'm unfortunately out of ideas. Maybe someone else chime in?
ppsmurf wrote:
Thu Mar 14, 2019 2:06 pm
I have few more questions.
1) How "wx objects" are freed?

Code: Select all

MyDialog* dlg = new MyDialog(); // wxDialog
dlg->ShowModal();
I didn't see "delete" in any example (or am I blind? :D). Do i need "delete dlg;" please?
Dialogs objects usually created on the stack and not on the heap and so they are deleted automatically.

Code: Select all

MyDialog dlg(); // wxDialog
int ret = dlg.ShowModal();
if( ret == wxID_OK )
{
// OK button was pressed
}
ppsmurf wrote:
Thu Mar 14, 2019 2:06 pm
2) I have problem with wxDialog on macOS. With "ShowModal()" dialog is shown, but it is not responding - mouse cursor have loading animation, dialog buttons dont work etc.
By trial and error I found, that if this is a second shown dialog, it works fine.

Code: Select all

class MyDialog: public wxDialog
{

public:
	MyDialog(int i = 0);

	void OnButton(wxCommandEvent& event);
	void OnIdle(wxIdleEvent& event);

private:	
	wxButton* m_btnOk;
	int m_i;
	
	wxDECLARE_EVENT_TABLE();
};

MyDialog::MyDialog(int i) : m_i(i), wxDialog(NULL, wxID_ANY, "caption", wxDefaultPosition, wxSize(600, 350)){

	wxSize btnSize(80, 22);
	m_btnOk = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, btnSize);

	wxBoxSizer* baseSizer = new wxBoxSizer(wxVERTICAL);
	baseSizer ->Add(m_btnOk); 
	
	SetSizer(baseSizer);
	Layout();

	Centre(wxBOTH);
}

void AutoDelete::OnButton(wxCommandEvent& event) {
	EndModal();
	Destroy();
}

void AutoDelete::OnIdle(wxIdleEvent & event) {	

    if(m_i == 0){
    	std::cout << "OnIdle event in first dialog" << std::endl;
        EndModal(0);
	    Destroy();
	    return;
    }

	std::cout << "OnIdle event in second dialog" << std::endl;
}

Code: Select all

MyDialog* dlg = new MyDialog(0); 
dlg->ShowModal();

MyDialog* dlg2 = new MyDialog(1); 
dlg2->ShowModal();
First dialog close imediately and second works fine. (Edit: I just found, this doesnt work every time, sometimes second dialog is not responding too.)


Please can anybody give me hint, what might be the problem?
Thank you.
What OSX version you are testing it under?
How did you configured wxWidgets? I.e. what was the exact "configure" line you used?

Thank you.

ppsmurf
Earned a small fee
Earned a small fee
Posts: 14
Joined: Tue Jan 22, 2019 9:14 am

Re: using wxWidgets in library

Post by ppsmurf » Fri Mar 15, 2019 8:35 am

ONEEYEMAN wrote:
Thu Mar 14, 2019 2:29 pm
What OSX version you are testing it under?
How did you configured wxWidgets? I.e. what was the exact "configure" line you used?
../configure --with-osx_cocoa --with-macosx-version-min=10.7 --with-macosx-sdk=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk CC=clang CXX=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ CXXFLAGS="-stdlib=libc++ -std=c++11" OBJCXXFLAGS="-stdlib=libc++ -std=c++11" LDFLAGS=-stdlib=libc++ --with-libpng=builtin --with-libjpeg=builtin --with-zlib=builtin --without-libtiff --with-expat=builtin --disable-shared --disable-debug_flag

Please, does anyone have an idea, why after "dialog->Show()" I see dialog with white rectangles instead of objects (buttons, staticText etc.)? Maybe some bad initialization or something? Can't the problem be I dont have event loop started? Or "Show()" starts own loop? I'll be glad for any hint.

Thank you.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 1925
Joined: Sun Jan 03, 2010 5:45 pm

Re: using wxWidgets in library

Post by PB » Fri Mar 15, 2019 9:34 am

I know nothing about OSX and I haven't done anything like you describe but that is not enough to stop me from giving my two cents. ;)

Are you sure the approach you use is robust enough to use?

If I had to do something like this I would try something like
1. When initializing my library (this approach would require having Init/Shutdown function for the library, I do not know if it is possible to do on OSX automatically, especially shutting down), I would create a std::thread where I would initialize wxWidgets as usual and stored the pointer to its wxApp instance. The wxWidgets thread would normally have no UI displayed.
2. When the library client calls a library function requiring displaying the dialog, I would queue a thread event to the application in "wxWidgets" thread asking it to display the dialog. In the "wxWidgets" thread the application instance would handle the event and display the dialog while the library function would wait on a thread synchronization object which would be set in wxWidgets thread when the dialog is closed. The data could be exchanged using e.g. a shared variable.

But I am certainly no expert so the approach described above may be utterly wrong and useless.

ppsmurf
Earned a small fee
Earned a small fee
Posts: 14
Joined: Tue Jan 22, 2019 9:14 am

Re: using wxWidgets in library

Post by ppsmurf » Fri Mar 15, 2019 10:18 am

PB wrote:
Fri Mar 15, 2019 9:34 am
Are you sure the approach you use is robust enough to use?
This is my first experience with wxWidgets, I'm not sure if my approach is correct. That's why I start this topic :).
PB wrote:
Fri Mar 15, 2019 9:34 am
If I had to do something like this I would try something like
1. When initializing my library (this approach would require having Init/Shutdown function for the library, I do not know if it is possible to do on OSX automatically, especially shutting down), I would create a std::thread where I would initialize wxWidgets as usual and stored the pointer to its wxApp instance. The wxWidgets thread would normally have no UI displayed.
2. When the library client calls a library function requiring displaying the dialog, I would queue a thread event to the application in "wxWidgets" thread asking it to display the dialog. In the "wxWidgets" thread the application instance would handle the event and display the dialog while the library function would wait on a thread synchronization object which would be set in wxWidgets thread when the dialog is closed. The data could be exchanged using e.g. a shared variable.

But I am certainly no expert so the approach described above may be utterly wrong and useless.
Well exactly this was my first thought :D. I implemented it and it works perfectly on windows, but then I found at macOS GUI is allowed only in main thread. In cross-platform applications is best practice use GUI from main thread I guess. And I don't want have GUI in main thread and everything else in second, that would be pretty wierd.

Thank you!

PB
Part Of The Furniture
Part Of The Furniture
Posts: 1925
Joined: Sun Jan 03, 2010 5:45 pm

Re: using wxWidgets in library

Post by PB » Fri Mar 15, 2019 11:16 am

ppsmurf wrote:
Fri Mar 15, 2019 10:18 am
[I implemented it and it works perfectly on windows, but then I found at macOS GUI is allowed only in main thread. In cross-platform applications is best practice use GUI from main thread I guess. And I don't want have GUI in main thread and everything else in second, that would be pretty wierd.
I am sorry for missing the information that the issue is with OSX not allowing GUI in multiple threads. Primary/secondary was just a convention here. The purpose of creating a separate thread was so that the wxWidgets event loop does not run on the same thread the client application one does.

I am out of ideas then, short of creating a separate process, which could be particularly bad in your case with sensitive data crossing process boundaries.

Try asking also in the mailing list
https://groups.google.com/forum/#!forum/wx-users

PB
Part Of The Furniture
Part Of The Furniture
Posts: 1925
Joined: Sun Jan 03, 2010 5:45 pm

Re: using wxWidgets in library

Post by PB » Fri Mar 15, 2019 12:47 pm

In your wx-users post, you may have not provided enough information, particularly about non-standard wxWidgets use.

FWIW, I tried on MSW "locally" run wxWidgets dialog, seemed to work with this, see GetPin() code. The separate scope for the dialog was required, so that the dialog is destroyed before OnExit() is called.

Code: Select all

#include <wx/wx.h>

#include <iostream>
#include <string>

class PinDialog : public wxDialog
{
public:   
    PinDialog(wxString& pin) : wxDialog(NULL, wxID_ANY, "Enter pin"), m_pin(pin)
    {        
        wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);      
        wxStaticText* pinLabel = new wxStaticText(this, wxID_ANY, "&Pin");        
        wxTextCtrl* pinData = new wxTextCtrl(this, wxID_ANY, m_pin, wxDefaultPosition, wxDefaultSize, 
            wxTE_PASSWORD, wxTextValidator(wxFILTER_DIGITS, &m_pin));

        mainSizer->Add(pinLabel, wxSizerFlags().Border());
        mainSizer->Add(pinData, wxSizerFlags().Border());        
        mainSizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Border().Expand());
        SetSizerAndFit(mainSizer);

        m_secondsLeft = 10;        
        m_endModalTimer.Bind(wxEVT_TIMER, &PinDialog::OnTimer, this);
        m_endModalTimer.Start(1000);
    }        
private:    
    wxString& m_pin;    
    wxTimer m_endModalTimer;
    int m_secondsLeft;

    void OnTimer(wxTimerEvent&) 
    { 
        if ( --m_secondsLeft < 1 )
            EndModal(wxID_CANCEL);        
        else
            SetTitle(wxString::Format("Will close in %d seconds", m_secondsLeft));
    }
};

bool GetPin(std::string& pin)
{
    bool confirmed = false;

    wxApp::SetInstance(new wxApp());
    wxEntryStart(0, NULL);
    wxTheApp->OnInit();

    {
        wxString wxpin(pin);
        PinDialog dlg(wxpin);

        if ( dlg.ShowModal() == wxID_OK )
        {
            pin = wxpin.ToStdString();
            confirmed = true;            
        }
        else
        {
            confirmed = false;
        }        
    }
    
    wxTheApp->OnExit();
    wxEntryCleanup();

    return confirmed;
}

using namespace std;

int main(int, char**)
{      
    while ( true )
    {
        string command;

        cout << "Enter a command (either \"PIN\" or \"EXIT\"): ";
        getline(cin, command);

        if ( command == "PIN" )
        {
            string pin = "1234";

            if ( GetPin(pin) )            
                cout << "Pin is: " <<  pin << endl;            
            else            
                cout << "No pin provided."  << endl;            
        }
        else
        if ( command == "EXIT" )
        {
            cout << "Quitting..." << endl;
            break;
        }
        else
        {
            cout << "ERROR: Unknown command." << endl;
        }
    }

    return 1;
}
I am not saying this will work in a 3rd party library, on OSX, or even that this code is correct...
Last edited by PB on Fri Mar 15, 2019 1:47 pm, edited 1 time in total.

Manolo
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 667
Joined: Mon Apr 30, 2012 11:07 pm

Re: using wxWidgets in library

Post by Manolo » Fri Mar 15, 2019 1:45 pm

If I understand your issue, you want console app (by typical int main(arg, args)) that for some cases shows a dialog.
The dialog must be non-blocking and handle its own events, which needs its own event-loop.
I think this is possible, but overwhelmingly tricky, as it goes against a normal GUI app.

I'd go the other way. I'd create the normal wxApp derived, which creates its event-loop.
But without creating a wxFrame at MyApp::OnInit(). Instead, call here your own "MyMain()".

This "MyMain" would run in a separate thread, not GUI main thread. It can send messages by wxQueueEvent(). You have handlers for these messages and create a frame/dialog in response. The data from these frame/dialog can be passed back to the MyMain thread.

If you find issues for application exit then you can use a hidden frame (created at OnInit) and use "Close" or "Destroy". See https://docs.wxwidgets.org/trunk/overvi ... etion.html

Post Reply