2

I'm attempting to implement a MVP pattern in my latest project. Currently using the VCL library that comes with C++ Builder 2007. My thinking is I don't need to do Application->Run(), or worse Application->CreateForm() which creates a main form and loop on that form. I don't want a main form, I want a main Presenter, instead.

My question then becomes how to create threaded TForms?

Option 1: If there is only one message loop (the Presenter) then every random thread in my system would have to post a message to this main thread and have it create forms.

Option 2: Every form has its own message loop. Now random threads can new and delete them as needed. Posting messages is still used for communications between them.

If option 2 is recommended does anyone have any advice on implementing this approach?

EDIT: How might I change the following to allow for creating the form using new and still allow the loop to work?

// Start VCL library
pApplication->Initialize();

// Create the Main form and assign the MainForm property
pApplication->CreateForm(__classid(TForm1), &pFormMain);

// Show the form
pFormMain->Show();

// Run the loop
pApplication->Run();
pcunite
  • 1,197
  • 15
  • 23
  • 3
    The MVP pattern in no way requires or specifies threads. You *have* to have a message loop. All windows should be created on one thread. Do not have random threads create windows. Diverting from these rules will get you into deep trouble. – Hans Passant Mar 12 '11 at 18:09
  • I'd argue the TApplication already functions as a presenter, and implementing one will at best cause you to reinvent the wheel. :) – Tommy Andersen Mar 12 '11 at 18:34
  • @Hans, Wise words, I shall do as you're suggesting. @TommyA, yes it is in a way, but it is too restrictive which is why I will ask the a question of @Ken White. – pcunite Mar 12 '11 at 18:38

2 Answers2

3

You don't put each form in its own thread. You put each form in the main thread.

A thread only has one message loop. The exception to this is the special message loop that is run when a form is shown modally.

pApplication->Run(); runs your message loop. When posted messages are processed they get dispatched to the appropriate window procedure. When messages are sent they are delivered synchronously direct to the window procedure.

You can create and show as many forms as you like and service them all from the same message loop. Not only can you do this, it is the way to do things.

How you map this knowledge onto your MVP framework is another matter, but running your GUI out of a single thread is a fixed point in any solution.

EDIT

You ask how, with VCL, to run a message loop if you don't have a visible main form. You have two options:

  1. Create an invisible form before you callpApplication->Run();.
  2. Run your own message loop.

In my view option 1 is by far the better option.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • @David, Thank you. How then do I, using the VCL framework, make it so the loop runs without having to assign it to the first form? I don't really want a MainForm, I want a message loop, have to, and then I will post to that loop to create forms as needed. Should I use a hidden form, a message only window? – pcunite Mar 12 '11 at 18:58
  • @David, that seems to be the way. Just so you know ... TApplication has it own hidden window I think ... creating my own loop would be okay if I never create a TApplication, but seems like a lot of work, might as well use wxWidgets I guess. Hmmm... – pcunite Mar 12 '11 at 19:16
  • 1
    @pcunite TApplication does create a window. But if you don't call `pApplication->CreateForm()` at least once before calling `pApplication->Run()` then your program will terminate immediately. – David Heffernan Mar 12 '11 at 19:21
  • @David, Yeah I'm noticing that ... You know, I just want to access the messages that the loop processes, maybe I could override a TApplication method. – pcunite Mar 12 '11 at 19:24
  • 1
    @pcunite Easiest is to declare a form, a subclass of TForm. Create it with CreateForm(). Set Visible to false. Call pAppliction->Run(). Then use the form's Handle property as your window handle and handle any messages in the form's WndProc, or however you are meant to handle messages in C++ VCL (I'm really a Delphi guy). – David Heffernan Mar 12 '11 at 19:28
  • @David, yeah, that is the answer. I wish the VCL was a little bit more helpful than this. But thanks! – pcunite Mar 12 '11 at 20:16
  • @pcunite I don't quite see your problem with the VCL. Since you need a window to handle the messages, what's the hardship of it being a hidden form? – David Heffernan Mar 12 '11 at 20:19
  • @David, not hardship because a hidden window is easy, just that I would rather use the already existing hidden window TApplication has created and just override its message loop. Seems a shame to have to make another window (aka TForm). I'm trying to create a clean Presenter class, it should be what handles messages, not some message only form. – pcunite Mar 12 '11 at 21:20
  • @pcunite Your presenter will handle the messages. The hidden form gets no messages. It's just there to stop the VCL deciding to quit the program. The first form created in a call to CreateForm is decreed to be the main form. When that main form closes, it's game over. So you just create a hidden form and do absolutely nothing with it. – David Heffernan Mar 12 '11 at 21:24
1

You can't safely create threaded forms using the VCL, because the VCL isn't thread-safe.

Also, each form already contains it's own message loop. TApplication simply dispatches messages to each form's loop.

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • I totally get that and you're right, this is why I can catch messages in each of the forms. My question now ... see my edit ... – pcunite Mar 12 '11 at 18:42
  • @pcunite, I think @David Heffernan answered the question asked by your edit. If not, can you clarify it a little? – Ken White Mar 12 '11 at 19:38