wxwidget structure understanding

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.
paddle
Knows some wx things
Knows some wx things
Posts: 43
Joined: Sat Oct 12, 2019 4:57 pm

wxwidget structure understanding

Post by paddle »

Hi there,
I'm new to wxwidgets, and I'm trying to port a console project to enable more features, buttons to control some stuff, display database entries and so on. However I have trouble understanding how to adapt my code.

A simplified version of it is :

Code: Select all

#include <stdio.h>
...
#include <string>
#include "tree.hh"

#define LIMITESCR 10
#define IDKEY 5002177


typedef struct Structexample
{
    std::array<long long, 5> longlongarray;
    sqlite3 *db;
    std::vector<std::array<long long, 5> > vectorofarray;
	int sleep;

} structexample;

//function declare
void functionexample(structexample *gm);

//function code
void functionexample(structexample *gm){
	//do some stuff on the structexample
}

int main(int argc, char* argv[]) {
	//Initialisation
	structexample gm;
	gm.longlongarray = {0,0,0,0,0};
	gm.sleep = 0;
	int rc = sqlite3_open("memory.db", &gm.db);

	while(1){
		if(gm.sleep==0) {
			//do some stuff, call some functions....
			functionexample(&gm);
		}
	}

	sqlite3_close(gm.db);
	 return 0;
}
So basically I want the main loop to run, and have play and pause buttons for example to change the gm.sleep value to run/pause.
Meanwhile having a table to show the database which is being updated by the loop.
And some wxTextCtrl to input some values in the structexample at run time.

But I am not sure how and where to do this as there is no main() function in the xxxMain.cpp. There's onInit() function in xxxApp.cpp but I don't understand, if I initialize the structexample here for example, how can I access it from handler functions?
And where to put the main loop?

Thanks for your help and sorry if it's noob questions.
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxwidget structure understanding

Post by doublemax »

You can't transfer a console application to a GUI application 1:1. A GUI app is not purely sequential as a console app. You do your initialization in wxApp::OnInit or the constructor of any Window and then wait for a user event, e.g. a button click. Then you do some work in the event handler. There is no classical main() loop.

If you need an operation that runs for longer, it should be put into a worker thread so that you don't block the GUI. That seems to be necessary for your use case, which unfortunately makes everything more complicated.

- subclass wxFrame for your GUI
- subclass wxThread, this will be run your (modified) while loop.
- have a wxMessageQueue to send commands (and/or data) from the main thread to the worker thread, e.g. when a parameter changes, or to stop, resume or quit the processing

For the GUI updates you have two options:
a) the "official" way: send a wxEvent from the worker thread to the main thread with information about the update. If you need to transfer more than an INT and a string, you need to define your own event class
b) my preferred way: Have data structure that the worker thread writes information into. In the main thread, just have a timer event with a relatively low frequency of about 10-20hz. In the timer event handler, read data from that data structure and update the GUI elements.

https://docs.wxwidgets.org/trunk/classwx_thread.html
https://docs.wxwidgets.org/trunk/classw ... _01_4.html
Use the source, Luke!
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: wxwidget structure understanding

Post by alys666 »

Code: Select all

typedef struct Structexample
{
    std::array<long long, 5> longlongarray;
    sqlite3 *db;
    std::vector<std::array<long long, 5> > vectorofarray;
	int sleep;

} structexample;
here you defined 2 types - Structexample and equal to it - structexample.
write just
struct TypeName{...};
and TypeName will be a name of this type.

You must create separate thread and put in his body the code of your main function.
Main function of console app is also just a body of application default thread. So nothing unusual.
ubuntu 20.04, wxWidgets 3.2.1
paddle
Knows some wx things
Knows some wx things
Posts: 43
Joined: Sat Oct 12, 2019 4:57 pm

Re: wxwidget structure understanding

Post by paddle »

Thanks for your reply!
I get it now. Indeed it has to be a separated thread or the GUI is blocked. It makes sense.

I will dig into this. Meanwhile I still have to setup the environment which is still not working unfortunately (cf other post on forum).

Perhaps do you have a template of such application with worker thread ? It would really help get me started.
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxwidget structure understanding

Post by doublemax »

paddle wrote: Sat Oct 26, 2019 12:40 pmPerhaps do you have a template of such application with worker thread ? It would really help get me started.
Drop-in replacement for the "minimal" sample that comes with wxWidgets. Just copy the sample and replace the content of minimal.cpp

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        minimal.cpp
// Purpose:     Minimal wxWidgets sample
// Author:      Julian Smart
// Modified by:
// Created:     04/01/98
// RCS-ID:      $Id: minimal.cpp 70789 2012-03-04 00:28:58Z VZ $
// Copyright:   (c) Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

class ThreadStatus
{
public:
  ThreadStatus()
  {
  };

  void SetInteger( int value ) {
    wxCriticalSectionLocker lock(m_cond);
    m_int = value;
  };

  void SetString( const wxString &value ) {
    wxCriticalSectionLocker lock(m_cond);
    // force deep copy of string data
    m_string = wxString( value.c_str() );
  };

  int GetInteger() {
    wxCriticalSectionLocker lock(m_cond);
    return m_int;
  }

  wxString GetString() {
    wxCriticalSectionLocker lock(m_cond);
    return m_string;
  }

protected:
  int m_int;
  wxString m_string;
  wxCriticalSection m_cond;
};


class DemoThread : public wxThread
{
public:
  DemoThread( ThreadStatus *status ) : wxThread(wxTHREAD_JOINABLE)
  {
    m_status = status;
  };

  ~DemoThread() {};

  virtual void *Entry()
  {
    int i = 0;
    wxString s;

    while( !TestDestroy() )
    {
      i++;
      s.Printf("string value is %d", i * 17 );
      m_status->SetInteger(i);
      m_status->SetString(s);
      wxThread::Sleep(100);
    }

    return NULL;
  };

  virtual void OnExit()
  {
    wxLogDebug("thread %p terminated", this );
  };


protected:
  ThreadStatus *m_status;
};


// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------

// the application icon (under Windows and OS/2 it is in resources and even
// though we could still include the XPM here it would be unused)
#ifndef wxHAS_IMAGES_IN_RESOURCES
    #include "../sample.xpm"
#endif

// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------

// Define a new application type, each program should derive a class from wxApp
class MyApp : public wxApp
{
public:
    // override base class virtuals
    // ----------------------------

    // this one is called on application startup and is a good place for the app
    // initialization (doing it here and not in the ctor allows to have an error
    // return: if OnInit() returns false, the application terminates)
    virtual bool OnInit();
};

// Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame
{
public:
    // ctor(s)
    MyFrame(const wxString& title);
    ~MyFrame();

    // event handlers (these functions should _not_ be virtual)
    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnTimer(wxTimerEvent& event);

private:
    wxStaticText *m_integer_st;
    wxStaticText *m_string_st;
    ThreadStatus m_thread_status;
    wxTimer m_timer;
    DemoThread m_thread;

    // any class wishing to process wxWidgets events must use this macro
    DECLARE_EVENT_TABLE()
};

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

// IDs for the controls and the menu commands
enum
{
    // menu items
    Minimal_Quit = wxID_EXIT,

    // it is important for the id corresponding to the "About" command to have
    // this standard value as otherwise it won't be handled properly under Mac
    // (where it is special and put into the "Apple" menu)
    Minimal_About = wxID_ABOUT
};

// ----------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// ----------------------------------------------------------------------------

// the event tables connect the wxWidgets events with the functions (event
// handlers) which process them. It can be also done at run-time, but for the
// simple menu events like this the static method is much simpler.
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
    EVT_MENU(Minimal_About, MyFrame::OnAbout)
    EVT_TIMER(wxID_ANY, MyFrame::OnTimer )
END_EVENT_TABLE()

// Create a new application object: this macro will allow wxWidgets to create
// the application object during program execution (it's better than using a
// static object for many reasons) and also implements the accessor function
// wxGetApp() which will return the reference of the right type (i.e. MyApp and
// not wxApp)
IMPLEMENT_APP(MyApp)

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// the application class
// ----------------------------------------------------------------------------

// 'Main program' equivalent: the program execution "starts" here
bool MyApp::OnInit()
{
    // call the base class initialization method, currently it only parses a
    // few common command-line options but it could be do more in the future
    if ( !wxApp::OnInit() )
        return false;

    // create the main application window
    MyFrame *frame = new MyFrame("Minimal wxWidgets App");

    // and show it (the frames, unlike simple controls, are not shown when
    // created initially)
    frame->Show(true);

    // success: wxApp::OnRun() will be called which will enter the main message
    // loop and the application will run. If we returned false here, the
    // application would exit immediately.
    return true;
}

// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------

// frame constructor
MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
       , m_thread( &m_thread_status )
{
    // set the frame icon
    SetIcon(wxICON(sample));

#if wxUSE_MENUS
    // create a menu bar
    wxMenu *fileMenu = new wxMenu;

    // the "About" item should be in the help menu
    wxMenu *helpMenu = new wxMenu;
    helpMenu->Append(Minimal_About, "&About\tF1", "Show about dialog");

    fileMenu->Append(Minimal_Quit, "E&xit\tAlt-X", "Quit this program");

    // now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, "&File");
    menuBar->Append(helpMenu, "&Help");

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);
#endif // wxUSE_MENUS

#if wxUSE_STATUSBAR
    // create a status bar just for fun (by default with 1 pane only)
    CreateStatusBar(2);
    SetStatusText("Welcome to wxWidgets!");
#endif // wxUSE_STATUSBAR

    wxPanel *panel = new wxPanel(this, wxID_ANY);

    wxStaticBoxSizer *sbs = new wxStaticBoxSizer(wxVERTICAL, panel, "Thread status");
    wxWindow *parent = sbs->GetStaticBox();

    m_integer_st = new wxStaticText(parent, wxID_ANY, "");
    sbs->Add(m_integer_st, 0, wxALL, 4 );

    m_string_st = new wxStaticText(parent, wxID_ANY, "");
    sbs->Add(m_string_st, 0, wxALL, 4 );

    panel->SetSizer(sbs);

    // start thread
    m_thread.Create();
    m_thread.Run();

    // start timer
    m_timer.SetOwner(this);
    m_timer.Start(250);
}

MyFrame::~MyFrame() {
  // wait for thread termination
  // only works if the thread calls and obeys wxThread::TestDestroy()
  m_thread.Delete();
}



// event handlers
void MyFrame::OnTimer(wxTimerEvent& WXUNUSED(event))
{
  // grab data from ThreadStatus and update wxStaticTexts
  wxString s;
  s << m_thread_status.GetInteger();
  m_integer_st->SetLabel( s );

  m_string_st->SetLabel( m_thread_status.GetString() );
}

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    // true is to force the frame to close
    Close(true);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
}
Use the source, Luke!
paddle
Knows some wx things
Knows some wx things
Posts: 43
Joined: Sat Oct 12, 2019 4:57 pm

Re: wxwidget structure understanding

Post by paddle »

Thanks very much !!

If I understand correctly the minimal sample is a visual studio project right? In your opinion what is better to use for wxwidgets, VisualStudio or Codeblocks?

Being a world-class-newbie I am not sure how to adapt the minimal.cpp you sent me to codeblocks-wxsmith template that the wizard creates. The structure looks much different.

For one thing codeblock template have two cpp files main.cpp and app.cpp. So I'm unsure which part should go where...
Last edited by paddle on Tue Oct 29, 2019 2:14 pm, edited 1 time in total.
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxwidget structure understanding

Post by doublemax »

f I understand correctly the minimal sample is a visual studio project right?
The "minimal" sample can also be built from the command line using the provided make files.
what is better to use [for] wxwidgets, VisualStudio or Codeblocks?
Depends. VS has no visual editor and is Windows only. But the compiler is much faster and the debugger is better.
For one thing codeblock template have two cpp files main.cpp and app.cpp. So I'm unsure which part should go where..
I don#t use CB, so i can't help with that, sorry. My guess would be to delete all files and just include the minimal.cpp

OTOH it was just meant to be a demo, not as a starting point for a real application.
Use the source, Luke!
paddle
Knows some wx things
Knows some wx things
Posts: 43
Joined: Sat Oct 12, 2019 4:57 pm

Re: wxwidget structure understanding

Post by paddle »

Thanks for your reply!

Yes I could build your minimal and it works great.

Now I'll try to implement it in the codeblocks template. Because the wxsmith visual editor looks rather convenient.

Anyone has a good knowledge of wxsmith here?

There are some things of the wxsmith project syntax that I don't get. For example the use of //(* ... //*)

Code: Select all

#include "MemBApp.h"

//(*AppHeaders
#include "MemBMain.h"
#include <wx/image.h>
//*)

IMPLEMENT_APP(MemBApp);

bool MemBApp::OnInit()
{
    //(*AppInitialize
    bool wxsOK = true;
    wxInitAllImageHandlers();
    if ( wxsOK )
    {
    	MemBFrame* Frame = new MemBFrame(0);
    	Frame->Show();
    	SetTopWindow(Frame);
    }
    //*)
    return wxsOK;

}
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxwidget structure understanding

Post by doublemax »

For example the use of //(* ... //*)
I think this marks the auto-generated code parts. If you modify this file, you need to make your changes outside of these markers, otherwise they get lost.
Use the source, Luke!
paddle
Knows some wx things
Knows some wx things
Posts: 43
Joined: Sat Oct 12, 2019 4:57 pm

Re: wxwidget structure understanding

Post by paddle »

It sounds like this indeed thanks !

Another thing that is unclear for me, is that for what I understand :

Code: Select all

IMPLEMENT_APP(MyApp)
Will implement the app and call MyApp::OnInit()
Where the frame object *frame is defined

Code: Select all

MyFrame *frame = new MyFrame("Minimal wxWidgets App");
But then after this function, what is the frame constructor?

Code: Select all

MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
       , m_thread( &m_thread_status )
What I don't understand is that it doesn't seem to use the frame object that has been created at the pointer *frame. What is MyFrame::MyFrame? Note sure of what is the syntax ::
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxwidget structure understanding

Post by doublemax »

What is MyFrame::MyFrame? Note sure of what is the syntax ::
That's plain C++ knowledge, has nothing to do with wxWidgets. Please read this up somewhere else.

Code: Select all

MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
       , m_thread( &m_thread_status )
MyFrame::MyFrame defines a constructor for MyFrame. This gets executed if a MyFrame is constructed, like:

Code: Select all

MyFrame *frame = new MyFrame("Minimal wxWidgets App");
Use the source, Luke!
paddle
Knows some wx things
Knows some wx things
Posts: 43
Joined: Sat Oct 12, 2019 4:57 pm

Re: wxwidget structure understanding

Post by paddle »

Ok got it now. It's the constructor concept that I was missing.
Thanks!
paddle
Knows some wx things
Knows some wx things
Posts: 43
Joined: Sat Oct 12, 2019 4:57 pm

Re: wxwidget structure understanding

Post by paddle »

Ok I think I understood the structure of your demo code now! :D

One question though, why using a

Code: Select all

m_thread_status.GetInteger();
And not just

Code: Select all

m_thread_status.m_int;
Is that because the ThreadStatus class data should be protected by wxCriticalSectionLocker lock(m_cond); everytime we want to get or set some data?

Another problem I'm facing now is that the wxSmith project doesn't have a usual declaration for the project Frame. So I don't know where to modify the frame to add the thread.

In XxxApp.cpp (where Xxx is the project name) there's :

Code: Select all

XxxFrame* Frame = new XxxFrame(0);
But I cannot find where the XxxFrame is defined.

In XxxMain.cpp there's :

Code: Select all

//(*InternalHeaders(XxxFrame)
#include <wx/intl.h>
#include <wx/string.h>
//*)

//(*IdInit(XxxFrame)
const long XxxFrame::ID_PANEL1 = wxNewId();
const long XxxFrame::idMenuQuit = wxNewId();
const long XxxFrame::idMenuAbout = wxNewId();
const long XxxFrame::ID_STATUSBAR1 = wxNewId();
//*)

XxxFrame::XxxFrame (wxWindow* parent,wxWindowID id)
{
...
But nothing like :

Code: Select all

class XxxFrame : public wxFrame
{
public:
    ...
};
Anyone know how to do it?

(I'll try to ask on codeblocks forum but currently I can't create an account there the confirmation email does not seem to go through..)
paddle
Knows some wx things
Knows some wx things
Posts: 43
Joined: Sat Oct 12, 2019 4:57 pm

Re: wxwidget structure understanding

Post by paddle »

Solved, the class is defined in the XxxMain.h.
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxwidget structure understanding

Post by doublemax »

Is that because the ThreadStatus class data should be protected by wxCriticalSectionLocker lock(m_cond); everytime we want to get or set some data?
Yes. Technically you don't need the protection for atomic variables like an integer. You could also make a pure struct with only integers and remove all the critical section stuff. But when i'd post that, someone would come out and start nagging about it ;)

It's only for "clean" demonstration purposes.
Use the source, Luke!
Post Reply