The "main loop"

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.
Post Reply
Zeal
Earned a small fee
Earned a small fee
Posts: 18
Joined: Sun Jun 03, 2007 3:37 pm

The "main loop"

Post by Zeal » Sat Jun 23, 2007 1:55 am

Im a little fuzzy on the whole IMPLEMENT_APP concept. It seems like when I use that, wx is running its own internal main loop, which makes me wonder how im supposed to include MY main loop (which is unrelated to wx).

So, how can I still have control over my own main loop, and also init/pump/unit wx widgets at the same time? Heres a little test program, (which seems to work for the wxInit/Uninit part), but I have no idea how to run/pump the main wx event loop).

Code: Select all

//main.cpp

#include <wx/wxprec.h>
#include "windows.h"
#include "main.h"

//do i need this?
//IMPLEMENT_APP_NO_MAIN(MyApp)

//=========
//WinMain()
//=========
int WINAPI WinMain( HINSTANCE hI, HINSTANCE hPrevI, LPSTR lpCmdLine, int nCmdShow ) {

	wxInitialize();

	//my main loop
	bool mainQuit = false;
	while ( !mainQuit ) {

		//wx widgets main loop goes here

	}

	wxUninitialize();

	return 0;

}

bool MyApp::OnInit()
{
   MyFrame *frame = new MyFrame( "Hello World", wxPoint(50,50), wxSize(450,340));
   frame->Show(TRUE);
   return TRUE;
} 

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(ID_Quit, MyFrame::OnQuit)
    EVT_MENU(ID_About, MyFrame::OnAbout)
END_EVENT_TABLE()

MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame((wxFrame *)NULL, -1, title, pos, size)
{
    wxMenu *menuFile = new wxMenu;
    menuFile->Append( ID_About, "&About..." );
    menuFile->Append( ID_Quit, "E&xit" );
    wxMenuBar *menuBar = new wxMenuBar;
    menuBar->Append( menuFile, "&File" );
    wxFrame::SetMenuBar( menuBar );
}

void MyFrame::OnQuit(wxCommandEvent& event)
{
    Close(TRUE);
}

void MyFrame::OnAbout(wxCommandEvent& event)
{
    wxMessageBox("Hello World!");
}

Code: Select all

//main.h

#pragma once

enum
{
    ID_Quit = 100,
    ID_About = 200,
};

class MyApp: public wxApp
{
    virtual bool OnInit();
};

class MyFrame: public wxFrame
{
public:

    MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);

    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);

    DECLARE_EVENT_TABLE()
};

Thanks in advance for any help!

lvdlinden
Earned some good credits
Earned some good credits
Posts: 147
Joined: Thu May 17, 2007 7:03 am
Location: 's-Hertogenbosch, Netherlands

Post by lvdlinden » Sat Jun 23, 2007 6:56 am

You could look into the source code, for example in src/common/appcmn.cpp. But you could also create your own main loop in a separate thread which you can probably start in wxApp::OnInit.

Zeal
Earned a small fee
Earned a small fee
Posts: 18
Joined: Sun Jun 03, 2007 3:37 pm

Post by Zeal » Sat Jun 23, 2007 8:29 am

I thought about putting wx in its own thread, but im still unsure how write the 'message pump'.

For example, when I write a simple 'single window' app, I include a little message pump that translates windows messages so the window can be moved, resized, ect...

Code: Select all

	MSG winmsg;
	while ( PeekMessage( &winmsg, NULL, 0, 0, PM_REMOVE ) ) {
		TranslateMessage( &winmsg );
		DispatchMessage( &winmsg );
	}
Im sure wxwidgets has a similar 'translate/dispatch' interface, which would allow me to run the loop inside my main loop. I skimmed through the app source, but will have to take a closer look later.

Zeal
Earned a small fee
Earned a small fee
Posts: 18
Joined: Sun Jun 03, 2007 3:37 pm

Post by Zeal » Mon Jun 25, 2007 12:35 am

Well I found..
// ----------------------------------------------------------------------------
// main event loop implementation
// ----------------------------------------------------------------------------

int wxAppBase::MainLoop()
{
wxEventLoopTiedPtr mainLoop(&m_mainLoop, new wxEventLoop);

return m_mainLoop->Run();
}

void wxAppBase::ExitMainLoop()
{
// we should exit from the main event loop, not just any currently active
// (e.g. modal dialog) event loop
if ( m_mainLoop && m_mainLoop->IsRunning() )
{
m_mainLoop->Exit(0);
}
}

bool wxAppBase::Pending()
{
// use the currently active message loop here, not m_mainLoop, because if
// we're showing a modal dialog (with its own event loop) currently the
// main event loop is not running anyhow
wxEventLoop * const loop = wxEventLoop::GetActive();

return loop && loop->Pending();
}

bool wxAppBase::Dispatch()
{
// see comment in Pending()
wxEventLoop * const loop = wxEventLoop::GetActive();

return loop && loop->Dispatch();
}
Which makes it sound like I CAN 'start' the main loop on my own, but correct me if im wrong, but the above seems to trigger the main loop to run forever. Im looking for a way to run it 'once' (ie do a single pass and dispatch all currently queued messages).

Anyonw know how that can be done?

AndyVincent
In need of some credit
In need of some credit
Posts: 4
Joined: Thu Jun 14, 2007 10:46 am
Location: UK
Contact:

Post by AndyVincent » Mon Jun 25, 2007 3:42 pm

According to the documentation, wxApp::Dispatch will dispatch a single event that's in the queue. wxApp::Pending will tell you if there are any in the queue.

Code: Select all

void DispatchPendingMessages(wxApp& app)
{
    while (app.Pending())
    {
        app.Dispatch();
    }
}
http://www.wxwidgets.org/manuals/stable ... ppdispatch

Zeal
Earned a small fee
Earned a small fee
Posts: 18
Joined: Sun Jun 03, 2007 3:37 pm

Post by Zeal » Tue Jun 26, 2007 1:24 am

Ok cool that looks like just what I need. But where am I getting the 'app' from? All i am doing is calling wxInit()/wxUninit(). At what point should I be 'making' the app object?

diagonalfish
In need of some credit
In need of some credit
Posts: 1
Joined: Thu Jun 28, 2007 7:00 pm

Post by diagonalfish » Thu Jun 28, 2007 7:09 pm

(Hi, I'm new! I saw this topic and noticed that it was exactly what I've been trying to do...)

The 'app' you're looking for can be obtained by using the global pointer 'wxTheApp' which is created when you use the IMPLEMENT_APP_NO_MAIN macro, from what I understand.

More important, however, is the problem that there is no event loop actually created or running if all we're doing is using wxInitialize/wxUninitialize (I just checked this). Thus, Dispatch() and Pending() don't work. What we need is a way to create a wxEventLoop ourselves and running the loop that AndyVincent suggested, while at the same time not letting it take over the program. Anyone have any ideas?

Zeal
Earned a small fee
Earned a small fee
Posts: 18
Joined: Sun Jun 03, 2007 3:37 pm

Post by Zeal » Fri Jun 29, 2007 12:00 pm

Cool thanks for the info about wxTheApp, but sounds like its not enough... Im sure this has to be possible... but how!?

Zeal
Earned a small fee
Earned a small fee
Posts: 18
Joined: Sun Jun 03, 2007 3:37 pm

Post by Zeal » Wed Sep 26, 2007 9:02 am

Took a break for awhile (focused on non gui things), but now im at a point where im ready to implement wxWidgets, but I still have this 'main loop' prooblem. I did a forum search and all I could find was a possible solution using wxTimer()? Doesnt seem right...

Is there no way to just pump the dang event queue manually?

mattropolis
In need of some credit
In need of some credit
Posts: 4
Joined: Mon Sep 17, 2007 11:30 pm

Post by mattropolis » Tue Oct 16, 2007 8:16 pm

Zeal wrote:Took a break for awhile (focused on non gui things), but now im at a point where im ready to implement wxWidgets, but I still have this 'main loop' prooblem. I did a forum search and all I could find was a possible solution using wxTimer()? Doesnt seem right...

Is there no way to just pump the dang event queue manually?
Did you ever get an answer for this? I'm also looking for a solution as well...

User avatar
Disch
Experienced Solver
Experienced Solver
Posts: 99
Joined: Wed Oct 17, 2007 2:01 am

Post by Disch » Wed Oct 17, 2007 2:29 am

I'm really interested in this too. For the program I'm working on, I need constant CPU attention. The easiest way for me to do what I want is to manually pump the event queue.

The alternatives I've been considering (creating a seperate thread, using idle events) are much less appealing and would really complicate my code.

Zeal
Earned a small fee
Earned a small fee
Posts: 18
Joined: Sun Jun 03, 2007 3:37 pm

Post by Zeal » Fri Oct 19, 2007 5:56 pm

Nope still no answer.. kinda given up in favor of a temporary alternative gui solution. Although someday ill come back to wx, so if anyone has an answer I would still love to hear it!

User avatar
Disch
Experienced Solver
Experienced Solver
Posts: 99
Joined: Wed Oct 17, 2007 2:01 am

Post by Disch » Sat Oct 20, 2007 5:18 pm

One theory I had (which I didn't test!) was to hijack the event loop in an idle event. Something like:

Code: Select all

void MyApp::OnIdle(wxIdleEvent& event)
{
  event.Skip();

  if(inidle)
    return;

  inidle = 1;

  while(wantprogramopen)
  {
    /* hijacked new program loop */
    while(Pending())
      Dispatch();

    /* do whatever else you want your loop to do here */
  }
}
However this seemed very sketchy to me... so I decided against going this route in favor of just calling RequestMore for more idle messages. Currently, I'm doing something like this:

Code: Select all

void SchApp::OnIdle(wxIdleEvent& event)
{
  event.Skip();

  if(!event.MoreRequested())
    event.RequestMore();

  /*  do whatever else you want your loop to do here  */
}
This actually works suprisingly well as long as you remember to call ::wxMilliSleep() (since the constant RequestMore()s will prevent the program from sleeping)

Post Reply