Lazarus

Programming => General => Topic started by: xtm on November 27, 2020, 10:13:59 am

Title: MDI Application problem
Post by: xtm on November 27, 2020, 10:13:59 am
Hi,

i have some problem with an MDI application, which i'm worrking on.

I'd also added TPageControl to MDIChild.

I'd made MainFrm as MDI Form, Child as MDI Child. I've implemented such code:

Code: Pascal  [Select][+][-]
  1. KontaFrm:=TKontaFrm.Create(Self);
  2.   KontaFrm.Parent:=MainFrm.MainPanel;
  3.   {$ifdef WINDOWS}
  4.   KontaFrm.Top:= 0;
  5.   KontaFrm.Left:= 0;
  6.   KontaFrm.Width:= MainFrm.MainPanel.Width - 4;
  7.   KontaFrm.Height:= MainFrm.MainPanel.Height - 4;
  8.   {$else}
  9.   KontaFrm.Align:= alClient;
  10.   {$endif}
  11.   if eKmPasek.Text<>'' then KontaFrm.Konta.Text:=eKmPasek.Text;
  12.   KontaFrm.NazwaOkna;
  13.   KontaFrm.PKFiltr.Text:=KontaFrm.Konta.Text;
  14.   KontaFrm.DKFiltr.Text:=KontaFrm.Konta.Text;
  15.   KontaFrm.OpFiltr.Text:=KontaFrm.Konta.Text;
  16.   KontaFrm.Strony.ActivePage:=KontaFrm.Operacje;
  17.   eKmPasek.Clear;
  18.   KontaFrm.Show;
  19.   KontaFrm.SetFocus;

Problem is, that i can select, switch, focus on Edits, Cobmobox fields with only TAB button. It's no reaction on mouse clicks. Left click doesn't get control active, and right click runs no system popupmenu. There is simply no reaction on mouse clicks.

Where can be a problem? Thank's for all help.
Title: Re: MDI Application problem
Post by: xtm on November 27, 2020, 02:52:56 pm
It was not really elegant, but still only way, that's worked.

I've added OnClick event with SetFocus method to every Control, which was on MDIChild (luckily there was not much of it).

If anyone will have better solution, a'm all ears.
Title: Re: MDI Application problem
Post by: Thaddy on November 27, 2020, 03:25:40 pm
Just a remark: MDI applications are deprecated (by microsoft) for the past 20 years and never worked well with Lazarus.
I suggest to re-engineer to an SDI lay-out. Unless you want your software to have an old school look deliberately.
Title: Re: MDI Application problem
Post by: PeterX on May 16, 2021, 10:55:14 am
There's a lot of people out there that say MDI is dead.

Doing a Forum Search with 'MDI' gives a long list of matches ..
https://forum.lazarus.freepascal.org/index.php?action=search;advanced;search=MDI

Today I saw that it works a little bit, with qt5 ..
https://forum.lazarus.freepascal.org/index.php/topic,51066.msg374371.html#msg374371

Title: Re: MDI Application problem
Post by: jamie on May 16, 2021, 05:35:43 pm
Only those that don't understand it will reject it, mean while they attempt the same thing by putting forms inside of forms which for me also works well.. But I like to use a borderless form so I can design my own border and caption area.
Title: Re: MDI Application problem
Post by: PeterX on May 16, 2021, 06:19:58 pm
.. mean while they attempt the same thing by putting forms inside of forms which for me also works well..
I have a very old project which I can't simply "re-engineer to an SDI lay-out".
...
..
Today I tried some of these TABbed and SomethingElse .. solutions, but nothing looked usable for me.

And today I tried this:   make a TPanel the Parent of one of my "MDIChild" window .. and it worked.
My Child Window is only visible inside the TPanel area.

Next I have to find a way to manage my few TForms that have been Delphi MDI child windows, long time ago ..
Title: Re: MDI Application problem
Post by: jamie on May 16, 2021, 06:29:00 pm
use this to set the parent for windows instead of the Parent property...

Windows.SetParent(TheNewchildForm.handle, TheParentForm.Handle);

and after each change to the borderstyle you will need to reset the Parent via this method..

Title: Re: MDI Application problem
Post by: PeterX on May 16, 2021, 08:59:43 pm
use this to set the parent for windows instead of the Parent property...

Windows.SetParent(TheNewchildForm.handle, TheParentForm.Handle);

and after each change to the borderstyle you will need to reset the Parent via this method..
Thanks a lot !

I would have spent hours and hours to dig that out ..  Thumbs up !
Title: Re: MDI Application problem
Post by: PeterX on May 16, 2021, 11:29:54 pm
Hm, looks easy at first. But then ..


[example project] ...
Title: Re: MDI Application problem
Post by: PeterX on May 16, 2021, 11:55:17 pm
attachement, with comments in Title Bar ..
Title: Re: MDI Application problem
Post by: PeterX on May 17, 2021, 10:34:59 am
Just found this :

http://www.oocities.org/br/hipernetjr/lmdi/index_ptbr.html

I will take a look at this sourcecode, maybe I will find what I am missing.
(I also do not need the full Delphi MDI functionality to make my program running ..)
Title: Re: MDI Application problem
Post by: PeterX on May 17, 2021, 09:12:58 pm
Funny thing to play around with ..

Title: Re: MDI Application problem
Post by: jamie on May 18, 2021, 01:00:40 am
if you use a borderless window for the child forms you can process the LM_NCHITTEST so that you can send back modified info for example for the location of where the mouse is.. For example, you can report it to be over a caption area, a drag area etc..

 With this, you can create a custom form that has a special title bar, Thumb Tac etc...

 It's a change from the boring windows standard forms which by the way, do not follow the themes when you do that..  :o

 But who likes those themes anyways....
 
 I could most likely punch out a quick demo on how to create a form to look this way...
Title: Re: MDI Application problem
Post by: PeterX on May 18, 2021, 12:37:59 pm
I could most likely punch out a quick demo on how to create a form to look this way...
Yes please !

Because I only found this, here in the Forum ..
https://forum.lazarus.freepascal.org/index.php/topic,34633.msg227372.html#msg227372


In the meantime I got forward a little bit.
I can send a ( simulated ''maximized'' ) Child Window to the back, to make the other ones visible again ..
Title: Re: MDI Application problem
Post by: PeterX on May 18, 2021, 09:41:44 pm
.. you can process the LM_NCHITTEST so that you can send back modified info for example for the location of where the mouse is..
message LM_NCHitTest helped me setting the focus to the actual ChildWindow, thanks !

Code: Pascal  [Select][+][-]
  1. procedure TChildForm.LMNCHitTest(var Msg: TLMNCHitTest);
  2. begin
  3.    inherited;
  4.    Self.BringToFront;
  5.    if Self.Focused = FALSE
  6.      then Self.SetFocus;
  7. ...
  8. ..
  9.  

But it detects the Mouse Pointer ( .. position) only over the frame of the ChildWindow, not over the TMemo ..
Title: Re: MDI Application problem
Post by: lucamar on May 18, 2021, 10:33:33 pm
But it detects the Mouse Pointer ( .. position) only over the frame of the ChildWindow, not over the TMemo ..

Of course, because "over the memo" it's clear that you're in the client area. N(on)C(lient)HitTest is only sent to give you the oportunity of ignoring or processing hits in the non-client area (borders frame, caption bar, etc.)
Title: Re: MDI Application problem
Post by: PeterX on May 18, 2021, 10:57:18 pm
.. N(on)C(lient)HitTest ..
Okay .. helps to know what it means ..  :o

But how to catch "any" message to recognize that I am "anywhere" in my ClientWindow ?

Probably by hacking into
Code: Pascal  [Select][+][-]
  1.     procedure WndProc( var TheMessage: TLMessage); override;

??
Title: Re: MDI Application problem
Post by: jamie on May 19, 2021, 12:36:12 am
I am a little confused as to what you want at this time... BUt, here is some code that shows you how to get mouse inputs. Here I use the left button down but you use others like the mouse move etc..

 If you use mouse move then you need to call other functions to see what control is under it of course..
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,Lmessages;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     procedure Button1Click(Sender: TObject);
  17.   private
  18.  
  19.   public
  20.    Procedure UserInput(sender:Tobject; Msg:Cardinal);
  21.   end;
  22.  
  23. var
  24.   Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.lfm}
  29.  
  30. { TForm1 }
  31. Procedure Tform1.UserInput(sender:Tobject; Msg:Cardinal);
  32. Begin
  33.   If Msg = LM_LBUTTONDOWN THen beep;
  34. end;
  35.  
  36. procedure TForm1.Button1Click(Sender: TObject);
  37. begin
  38.  Application.AddOnUserInputHandler(@UserInput, true);
  39. end;
  40.  
  41. end.
  42.  
  43.  
Title: Re: MDI Application problem
Post by: Fred vS on May 19, 2021, 12:55:53 am
Hello.

For MDI and docking forms you may use mseide-msegui (https://github.com/mse-org/mseide-msegui).

Here a MSE-MDI Demo video (https://user-images.githubusercontent.com/3421249/118732862-70347780-b83b-11eb-8b82-2198d070a73a.mp4).

Fre;D
Title: Re: MDI Application problem
Post by: PeterX on May 19, 2021, 01:02:30 am
I am a little confused as to what you want at this time...
In my earlier Code Examples, even when selecting another ChildWindow than the first one,
the Input Focus stayed on the first created ChildWindow.
=> So when hitting the Keyboard, the Chars still appeared in the TEdit of the first created ChildWindow.

Now, in my last code example '04',  I (mis)used LM_NCHitTest to change the Input Focus (=> TMemo) to the actually selected ChildWindow.

But now, still the Focus only changes if I cross the borders/frame of another ChildWindow.
=> I want the Input Focus to move to the ChildWindow where the mouse is over.
( Does this violate any Microsoft UserInterface GuideLines ? .. )

The misbehaviore appears when two ChildWindows do overlap
(and so I do not touch any border of a underlying ChildWindow when moving the mouse cursor)
 .. in my Code Example.


.. difficult to describe in words, I should be able to upload a video of that misbehaviore
(or You compile my last Example and play around with it, moving and touching the ChildWindows with Your Mouse Pointer ..)

Probably Your
Code: Pascal  [Select][+][-]
  1. Application.AddOnUserInputHandler(@UserInput, true);
is the way out for me. I'll try that tomorrow ..  O:-)
Title: Re: MDI Application problem
Post by: jamie on May 19, 2021, 01:32:21 am
I just created a simple app with two forms, use the second for as the child forms...

first form has a button to create these child forms.

The child forms has a TEDIT on them...

When I put a few in the window and use the mouse to click between them, the EDIT control for the one I clicked on becomes focused.

So that must not be your problem..

I think what you want is to wave the mouse across the forms and have them automatically jump forward and become focused without clicks, is that it ?
Title: Re: MDI Application problem
Post by: jamie on May 19, 2021, 02:07:32 am
Ok, I put this in a project... because it got to tedious otherwise..

This shows how to move over the forms and it detects what forms they are and it will also pass through the children controls..

this only works in the client area..

if you want also the non-client response too, then you need to use the LM_NCMouseMove or hittest.

I have a TEDIT on the forms hugging the side of the client so you can see how if you hover over a child first before a client area it will still be able to seek down through until it finds the window.

Demo Attached;
Title: Re: MDI Application problem
Post by: PeterX on May 19, 2021, 10:58:09 am
I think what you want is to wave the mouse across the forms and have them automatically jump forward and become focused without clicks, is that it ?
Originally this was not my intention.

The root of the problem was
that when selecting another ChildWindow than the first created ChildWindow,
the Input Focus stayed on the first created ChildWindow.

But this actual resulting behaviore - ChildWindow on MouseOver becomes the first in z-order, plus gets Input Focus - is indeed a nice thing  :)
But I really don't know if this behaviore was intended by Microsoft GUI Guidelines ..  :D
Title: Re: MDI Application problem
Post by: PeterX on May 19, 2021, 08:45:28 pm
Demo Attached;
assimilated ..  8-)

Title: Re: MDI Application problem
Post by: jamie on May 20, 2021, 02:53:58 am
The trunk has working MDI for windows.

its a simple matter, a main form that is a parent MDI, a child form that is a the childMDI..

just set the formStyle property...

Each time you create a Child MDI it becomes a child window of the parent MDI.

TMyCHildMDI.Create(MyParentMDI);

It gets added...
you will need to adjust the frame size and position so that it appears in the window.
Title: Re: MDI Application problem
Post by: PeterX on May 20, 2021, 11:34:05 am
The trunk has working MDI for windows.
I have an old Delphi 5 Template project in my repository  (the original Delphi 5 Template)
that waits for being compiled successfully under Lazarus ..

But I don't like this much working with a Lazarus trunk version ..
So I'd prefer waiting for this win32 MDI code being releaed with one of the next official Lazarus releases.

https://bugs.freepascal.org/view.php?id=36582
Title: Re: MDI Application problem
Post by: jamie on May 20, 2021, 03:31:48 pm
There is still a problem with mdi as I noticed that still exist even with the trunk.
And that is if minimize a child it does as you expect however, if resize the parent in the state the min child form does not follow its parent.

 I fixed this myself in the parent resize event to keep this updated.
Title: Re: MDI Application problem
Post by: PeterX on May 20, 2021, 08:36:37 pm
There is still a problem with mdi as I noticed that still exist even with the trunk.
And that is if minimize a child it does as you expect however, if resize the parent in the state the min child form does not follow its parent.

 I fixed this myself in the parent resize event to keep this updated.
I found this problem today, too.
But coudn't find out how to fix this.

I was not able to move the minimized ChildWin,
to "dock" it to the bottom of the "Client Area".
How did You solve that ?  :o
Title: Re: MDI Application problem
Post by: jamie on May 20, 2021, 11:04:54 pm
Because I am too tired to code this out using the basic routes of LCL so I copied something from a project..

In this project the child forms were being parented via a TPANEL which works the same I guess so if you are doing something different just change the naming...
 This isn't perfect but enough to give you some ideas and I used the Message method so you need to implement or override the WMSIZE message..
Code: Pascal  [Select][+][-]
  1. procedure TForm1.wmSize(var Msg: TMessage);
  2. Var
  3.  L,H :integer;
  4.  WS :WINDOWPLACEMENT;
  5. begin
  6.   Inherited wmsize(TLMsize(Msg));
  7.   H := GetSystemMetrics(SM_CYMINSPACING);
  8.   If H and $0F <> 0 Then H := (H and $FFFFFFF0)+$10;//Seems we need to obey 16 byte page size in heigth;
  9.   For L := 0 To Panel1.ComponentCount-1 do
  10.   Begin
  11.    if (Panel1.Components[L] is TCustomForm) Then
  12.     With TForm(Panel1.Components[l]) do
  13.      Begin
  14.       Ws.Length := SizeOf(WS);
  15.       GetWindowPlaceMent(Handle, WS);
  16.       If WindowState= wsMinimized then
  17.        Begin
  18.         WS.ptMinPosition.y := Panel1.Height-H;
  19.         WS.Flags := WPF_SETMINPOSITION;
  20.         Ws.ShowCmd := SW_MINIMIZE;
  21.         SetWindowPlacement(Handle, WS);
  22.        End Else
  23.       if WS.rcNormalPosition.Top > Panel1.Height Then
  24.        Begin
  25.         WS.rcNormalPosition.Top := Panel1.Height-H;
  26.         Ws.RCNormalPosition.Bottom -=H;
  27.         SetWindowPlacement(Handle, Ws);
  28.        end;
  29.      end;
  30.   end;
  31. End;                                          
  32.  
Title: Re: MDI Application problem
Post by: PeterX on May 20, 2021, 11:28:06 pm
Got it, thanks !

Now I need to clean up my code, before uploading.
Title: Re: MDI Application problem
Post by: PeterX on May 21, 2021, 04:20:23 pm
MDIsimulator06.zip

works better than before, but I still have trouble
finding the right place in the source code
for storing / reloading "OldPosition" ..
Title: Re: MDI Application problem
Post by: PeterX on May 21, 2021, 10:29:01 pm
Changes from minimized to normal to (simulated) maximized and back. This works now.
Title: Re: MDI Application problem
Post by: PeterX on May 22, 2021, 11:18:23 am
I am waiting since about 2016 for a working MDI in LCL (win32).
With a - very very old - large project in my hands, born under Delphi 5, twenty years ago.
But until today I never had the knowledge of how to implement MDI, or how to simulate it.

Just a remark: MDI applications are deprecated (by microsoft) for the past 20 years ..
I still do not understand why people make such general statements like that.
Indeed I would never recommend starting a new Project based on MDI today.

=> https://docs.microsoft.com/en-us/windows/win32/winmsg/multiple-document-interface
The official Microsoft Website does indeed no more recommend MDI, yes.
"Many new and intermediate users find it difficult to learn to use MDI applications.
Therefore, you should consider other models for your user interface.
"

But Microsoft would terminate all the apps out there that still use MDI
if they would wipe out native MDI support in Windows.

Microsoft explains us - statement from date 05/31/2018:
"However, you can use MDI for applications which do not easily fit into an existing model."
https://docs.microsoft.com/en-us/windows/win32/winmsg/multiple-document-interface


Microsoft has never improved MDI anymore (I think ..) over the last years
because it's a "dead" user interface.
But Microsoft has never stopped supporting MDI in Windows OS.


MDI applications ... never worked well with Lazarus.
I can agree with that.

But, as even old Delphi 5 compiled MDI applications do still work (more or less ..),
this is a Lazarus LCL win32 widgetset issue, not a Microsoft issue.


So I hope, my "MDIsimulator" helps out a little bit here, keeping some old MDI projects alive.
Or the existing win32 MDI code in Trunk is committed for a upcoming Lazarus Release Version one day ..

( Hint:  in  "MDIsimulator" Forms do not set Mainform to fsMDIForm / ChildForm to fsMDIChild - this is not real MDI ! )
Title: Re: MDI Application problem
Post by: PeterX on May 23, 2021, 06:53:55 pm
The trunk has working MDI for windows.
I tried this today .. works !
Title: Re: MDI Application problem
Post by: jamie on May 23, 2021, 07:45:18 pm
Years ago with smaller res screens the MDI didn't always work well for users but since many now have far more screen res you can now build MDI apps with lots of childs in the parent and still have room..
Title: Re: MDI Application problem
Post by: PeterX on May 23, 2021, 09:19:52 pm
 :D    8)    ::)    >:D

Everybody wants this back:
Title: Re: MDI Application problem
Post by: jamie on May 23, 2021, 11:34:23 pm
Lets not get carried away!  :D
Title: Re: MDI Application problem
Post by: bpranoto on May 24, 2021, 05:24:09 am
Wow cool,

Will it work on other platform? It will be great if you publish your work. Thanks
Title: Re: MDI Application problem
Post by: PeterX on May 24, 2021, 02:19:18 pm
Wow cool,

Will it work on other platform? It will be great if you publish your work. Thanks
I already attached my example "MDIsimulator" as sourcecode in earlier posts here.
But "MDIsimulator" is only a playground for trying to simulate MDI behavior under Windows.
I don't know how far this maybe works on other platforms. Please download and try.


I did not do any work inside Lazarus LCL sources.
So I'm sorry, I cannot publish anything else.

The Multi Document Interface thing inside Lazarus that I was talking about
in my latest posts, is the win32 widgetset. Windows only.
And currently exists in Trunk only (developer version), not in the current 2.0.12 Lazarus.
=>
https://wiki.lazarus.freepascal.org/Getting_Lazarus#Getting_Lazarus_from_Subversion_server


For MDI You could try qt5 widgetset - which is said to be working under Windows, Linux and MacOS.
But I know nothing about that widgetset ..
=>
https://wiki.lazarus.freepascal.org/Qt5_Interface
Title: Re: MDI Application problem
Post by: bpranoto on May 24, 2021, 05:11:56 pm
I already attached my example "MDIsimulator" as sourcecode in earlier posts here.
But "MDIsimulator" is only a playground for trying to simulate MDI behavior under Windows.
I don't know how far this maybe works on other platforms. Please download and try.

It doesn't compile in Linux. After commenting out Windows uses clause, I got this:

Code: Pascal  [Select][+][-]
  1. Compile Project, Target: exeOutput/MDIsimulator: Exit code 1, Errors: 6
  2. subunit.pas(46,37) Error: Identifier not found "TWMSysCommand"
  3. subunit.pas(46,61) Error: Identifier not found "WM_SYSCOMMAND"
  4. subunit.pas(46,74) Error: Illegal expression after message directive
  5. subunit.pas(47,48) Error: Identifier not found "TWMWindowPosChanging"
  6. subunit.pas(47,79) Error: Identifier not found "WM_WINDOWPOSCHANGING"
  7. subunit.pas(47,99) Error: Illegal expression after message directive
  8.  



Quote
For MDI You could try qt5 widgetset - which is said to be working under Windows, Linux and MacOS.

Yes, I have played with it some times ago. The MDI works well. The thing was I couldn't use qt5 widget set because it doesn't support Raw printing which I needed that time.
Title: Re: MDI Application problem
Post by: PeterX on May 24, 2021, 06:13:46 pm
As TChildForm.WMSysCommand() does nothing for You,
in Your OS, You can delete this function.


WMWindowPosChanging() does something and cannot be dropped ..

I found something that might help here =>
Topic: Porting Win32 code to Apple Mac
https://forum.lazarus.freepascal.org/index.php?topic=37959.0


[Edit]
Looks like this now:
Code: Pascal  [Select][+][-]
  1.     procedure WMWindowPosChanging(var Message: TLMWindowPosChanging); message LM_WINDOWPOSCHANGING;
Title: Re: MDI Application problem
Post by: PeterX on May 27, 2021, 12:58:19 am
Found something while playing around with the Example code today ..

https://forum.lazarus.freepascal.org/index.php/topic,54771.msg407060/topicseen.html#new
Title: Re: MDI Application problem
Post by: PeterX on May 31, 2021, 01:09:28 am
I kept on working on this thing,
and some bugs are solved.

- wrong "Old Size" stored on ChildWin Create
- from Minimized directly to Maximized lead to wrong stored Size
- uses real wsMaximized property now

But there's still missing a lot ..
TinyPortal © 2005-2018