Recent

Author Topic: Buttons and other visual components disappearing  (Read 5539 times)

guest48704

  • Guest
Buttons and other visual components disappearing
« on: August 13, 2018, 03:02:37 pm »
The only way I have found to make a form appear after sending it to the tray is:

procedure TForm1.WMSysCommand;
begin
     if (Msg.CmdType = SC_MINIMIZE) then begin
        Form1.Hide;
        end
        else
        inherited;
end;

procedure TForm1.TrayIcon1Click( Sender : TObject) ;
begin
     //Restore window after minimize:
     ShowWindow(Form1.Handle, SW_SHOW);   //only this will show form after Hide
     Form1.BringToFront;
     Application.ProcessMessages;
end;

  The problem is that when the form appears, most all of the buttons (TBGRAButton, TLabels)
and other components are no longer visible.  They are there because I can still click on them
and get a response.  Is there any cure for this or a different way to get a form to reappear?

  Thanks.

Handoko

  • Hero Member
  • *****
  • Posts: 5129
  • My goal: build my own game engine using Lazarus
Re: Buttons and other visual components disappearing
« Reply #1 on: August 13, 2018, 03:11:24 pm »
I use this code in one of my program, it works correctly on Linux. I ever tested it on Windows, it seemed to work without problem too.

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   { TfrmMain }
  4.  
  5.   TfrmMain = class(TForm)
  6.     // ...
  7.     mniShow: TMenuItem;
  8.     mnuTray: TPopupMenu;
  9.     TrayIcon: TTrayIcon;
  10.     // ...
  11.   end;
  12.  
  13. procedure TfrmMain.TrayIconClick(Sender: TObject);
  14. var
  15.   isClosed: Boolean;
  16. begin
  17.   isClosed := not(Showing);
  18.   Show;
  19.   mniShow.Enabled := False;
  20.   if isClosed then mnuTray.PopUp;
  21. end;

It is closed-source, so I can't post the whole source code here.

BasicOne

  • New Member
  • *
  • Posts: 15
Re: Buttons and other visual components disappearing
« Reply #2 on: August 13, 2018, 03:42:37 pm »
I am using this code in several applications on Windows 7, Windows 10 and Windows Server 2016:

Code: Pascal  [Select][+][-]
  1. procedure TFormMain.FormWindowStateChange(Sender: TObject);
  2. begin
  3.   if self.WindowState = TWindowState.wsMinimized then
  4.   begin
  5.     self.Hide;
  6.     self.TrayIcon.BalloonHint := 'Application minimized to System Tray';
  7.     self.TrayIcon.ShowBalloonHint;
  8.   end;
  9. end;
  10.  
  11.  
  12. procedure TFormMain.TrayIconClick(Sender: TObject);
  13. begin
  14.   self.WindowState := TWindowState.wsNormal;
  15.   self.Show;
  16.   self.BringToFront;
  17. end;
  18.  

guest48704

  • Guest
Re: Buttons and other visual components disappearing
« Reply #3 on: August 13, 2018, 07:20:56 pm »
Thanks for both examples.  I have had trouble with this for some time.

This worked for me, everything reappears:

procedure TForm1.WMSysCommand;
begin
     if (Msg.CmdType = SC_MINIMIZE) then begin
        Form1.Hide;
        end
        else
        inherited;
end;

procedure TFormMain.TrayIconClick(Sender: TObject);
begin
  self.WindowState := TWindowState.wsNormal;
  self.Show;
  self.BringToFront;
end;

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Buttons and other visual components disappearing
« Reply #4 on: August 13, 2018, 07:56:03 pm »
Thanks for both examples.  I have had trouble with this for some time.

This worked for me, everything reappears:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.WMSysCommand;
  2. begin
  3.      if (Msg.CmdType = SC_MINIMIZE) then begin
  4.         Form1.Hide;
  5.         end
  6.         else
  7.         inherited;
  8. end;
  9.  
  10. procedure TFormMain.TrayIconClick(Sender: TObject);
  11. begin
  12.   self.WindowState := TWindowState.wsNormal;
  13.   self.Show;
  14.   self.BringToFront;
  15. end;
  16.  

For completeness sake, because the form may not be in wsNormal state, you should do something like this:

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. type
  4.   TForm1 = class(TForm)
  5.     {the normal declarations go here}
  6.   private
  7.     FSavedState: TWindowState;
  8.   end;
  9.  
  10. implementation
  11.  
  12. procedure TForm1.WMSysCommand;
  13. begin
  14.   if (Msg.CmdType = SC_MINIMIZE) then begin
  15.     FSavedState := WindowState;
  16.     Hide; { This way it just references Self }
  17.     {
  18.     Form1.Hide; <- You should *never* do this, because one day
  19.                      you *will* want to instantiate a form in other
  20.                      ways, referencing through other variable.
  21.     }
  22.   end else
  23.     inherited;
  24. end;
  25.  
  26. procedure TForm1.TrayIconClick(Sender: TObject);
  27. begin
  28.   WindowState := FSavedState;
  29.   Show;
  30.   BringToFront;
  31. end;
  32.  
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

guest48704

  • Guest
Re: Buttons and other visual components disappearing
« Reply #5 on: August 13, 2018, 11:02:25 pm »
Thanks, I'll start doing it that way.

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Buttons and other visual components disappearing
« Reply #6 on: August 14, 2018, 02:17:04 am »
Your real problem might be making the TrayIcon visible :-)

On Mac Carbon, its got quite a nasty memory leak.

On Linux, it seems the Gnome Developers have waged war on the System Tray and removed the expected GTK2 support for it from Gnome 3.

Ubuntu decided to still support the Unity AppIndicator model and the Trunk version of Lazarus is OK with that but if you want to use it with eg 1.8.4 then you need my patch, find it here -
 https://github.com/tomboy-notes/tomboy-ng/tree/master/patches

But if your end users are using recent eg Redhat derived distros, they need install a Gnome Extension such as TopIcons. The process is clumsy and users resist ....

Much as it pains me to say so, Systray works perfectly under Windows....

David 
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

guest48704

  • Guest
Re: Buttons and other visual components disappearing
« Reply #7 on: August 14, 2018, 01:43:00 pm »
For completeness sake, because the form may not be in wsNormal state, you should do something like this:

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. type
  4.   TForm1 = class(TForm)
  5.     {the normal declarations go here}
  6.   private
  7.     FSavedState: TWindowState;
  8.   end;
  9.  
  10. implementation
  11.  
  12. procedure TForm1.WMSysCommand;
  13. begin
  14.   if (Msg.CmdType = SC_MINIMIZE) then begin
  15.     FSavedState := WindowState;
  16.     Hide; { This way it just references Self }
  17.     {
  18.     Form1.Hide; <- You should *never* do this, because one day
  19.                      you *will* want to instantiate a form in other
  20.                      ways, referencing through other variable.
  21.     }
  22.   end else
  23.     inherited;
  24. end;
  25.  
  26. procedure TForm1.TrayIconClick(Sender: TObject);
  27. begin
  28.   WindowState := FSavedState;
  29.   Show;
  30.   BringToFront;
  31. end;
  32.  

This unfortunately didn't work:

  private
    FSavedState: TWindowState;

procedure TForm1.WMSysCommand;
begin
     if (Msg.CmdType = SC_MINIMIZE) then begin
       FSavedState := WindowState;
       Hide; { This way it just references Self }
//--->>>'TEMPOUT'<<<---      if (Msg.CmdType = SC_MINIMIZE) then begin
//--->>>'TEMPOUT'<<<---         Form1.Hide;
        end
        else
        inherited;
end;

procedure TForm1.TrayIcon1Click( Sender : TObject) ;
begin
//--->>>'TEMPOUT'<<<---      self.WindowState := TWindowState.wsNormal;
//--->>>'TEMPOUT'<<<---      self.Show;
//--->>>'TEMPOUT'<<<---      self.BringToFront;
     WindowState := FSavedState;
     Show;
     BringToFront;
end;

When you click on the tray icon, you get this and have to click on the taskbar button to get the window to appear:

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Buttons and other visual components disappearing
« Reply #8 on: August 14, 2018, 05:02:12 pm »
Curiouseur and curioseur. It should work, it's basically the same code but using a variable instead of a constant.

Hmmm... The references to Self are superfluous but, what happens if you restore them? I mean:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.TrayIcon1Click( Sender : TObject) ;
  2. begin
  3. //--->>>'TEMPOUT'<<<---      self.WindowState := TWindowState.wsNormal;
  4. //--->>>'TEMPOUT'<<<---      self.Show;
  5. //--->>>'TEMPOUT'<<<---      self.BringToFront;
  6.      Self.WindowState := FSavedState;
  7.      Self.Show;
  8.      Self.BringToFront;
  9. end;
  10.  

If that doesn't work, can you post the *whole* test unit?
« Last Edit: August 14, 2018, 05:04:31 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

BasicOne

  • New Member
  • *
  • Posts: 15
Re: Buttons and other visual components disappearing
« Reply #9 on: August 14, 2018, 08:34:23 pm »
I did not test it, but it seems the WindowState has already the target value wsMinimized in the WMSysCommand message handler. You could set a breakpoint there and confirm this with the debugger.

In my FormWindowStateChange() event handler I check for

WindowState = TWindowState.wsMinimized

which means that the property is already set to the target value when the handler is called (the calling is likely initiated by a message like your WMSysCommand). You should store WindowState to FSavedState each time the FormWindowStateChange() is called except when it is wsMinimized, somehow like

Code: Pascal  [Select][+][-]
  1. procedure TFormMain.FormWindowStateChange(Sender: TObject);
  2. begin
  3.   if self.WindowState = TWindowState.wsMinimized then
  4.   begin
  5.     self.Hide;
  6.     self.TrayIcon.BalloonHint := 'Application minimized to System Tray';
  7.     self.TrayIcon.ShowBalloonHint;
  8.   end else FSavedState := self.WindowState;
  9. end;
  10.  


 In this case. you also should set FSavedSate to a default value e.g. in the FormCreate event.


It is always a bit tricky to find out if some properties affected by an event are set before or after the event was triggered. I had this problem not only with Delphi and Lazarus, but also with C#. Maybe it is an operation system issue. I also recall some components that split the handling of one event into OnBefore... and OnAfter...

guest48704

  • Guest
Re: Buttons and other visual components disappearing
« Reply #10 on: August 14, 2018, 10:22:31 pm »
Code: Pascal  [Select][+][-]
  1. procedure TFormMain.FormWindowStateChange(Sender: TObject);
  2. begin
  3.   if self.WindowState = TWindowState.wsMinimized then
  4.   begin
  5.     self.Hide;
  6.     self.TrayIcon.BalloonHint := 'Application minimized to System Tray';
  7.     self.TrayIcon.ShowBalloonHint;
  8.   end else FSavedState := self.WindowState;
  9. end;
  10.  

  I just tried using this code and it does the tray operation ok, but it doesn't remove the taskbar button.  This code does everything correctly:

procedure TForm1.WMSysCommand;
begin
     if (Msg.CmdType = SC_MINIMIZE) then begin
        Self.Hide;
        end
        else
        inherited;
end;

procedure TForm1.TrayIcon1Click( Sender : TObject) ;
begin
     Self.WindowState := TWindowState.wsNormal;
     Self.Show;
     Self.BringToFront;
end;


  I am not sure what lucamar means by 'what happens if you restore them?'.

BasicOne

  • New Member
  • *
  • Posts: 15
Re: Buttons and other visual components disappearing
« Reply #11 on: August 14, 2018, 11:35:17 pm »
In my applications the FormWindowStateChange() method is functioning well on all Windows Systems I use if the minimize is triggered by an event in the running application.

Nevertheless, if I want to minimize to system tray during initialization the application is sent to tray but the minimized form is not hidden like in your sample image. I do the initialization either in the OnCreate event or, if I need all forms of the application already created for initialization, in an initialization function called from the *.lpr file just before Application.Run. The messaging seems to be not fully functioning before Application.Run (well, I think it is a problem with the message queue because the self.Hide will likely just send a message to the operating system and this message seems to be lost in this case)

For starting minimized and hidden e.g. according a configuration item in the ini file of my application I therefore set a flag and minimize from within a timer event.

lucamar seems to reference the self. prefix. This is not needed but I often use it because of the code completion functionality of the editor.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Buttons and other visual components disappearing
« Reply #12 on: August 14, 2018, 11:40:27 pm »
I am not sure what lucamar means by 'what happens if you restore them?'.

I meant that in my code I had deleted all the "Self. references in the method calls and that may have triggered some unwanted behaviour (though I can't see how!), but I see you have already restored them.

Anyway, the important thing is: if your code works for you, go ahead and use it. Just, please, test to see what happens if you minimize a maximized form. Users (at least the ones like myself) don't like it when their applications restore to a different state that the one they were in before minimizing.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

guest48704

  • Guest
Re: Buttons and other visual components disappearing
« Reply #13 on: August 15, 2018, 02:24:07 am »
In my applications the FormWindowStateChange() method is functioning well on all Windows Systems I use if the minimize is triggered by an event in the running application.

Nevertheless, if I want to minimize to system tray during initialization the application is sent to tray but the minimized form is not hidden like in your sample image. I do the initialization either in the OnCreate event or, if I need all forms of the application already created for initialization, in an initialization function called from the *.lpr file just before Application.Run. The messaging seems to be not fully functioning before Application.Run (well, I think it is a problem with the message queue because the self.Hide will likely just send a message to the operating system and this message seems to be lost in this case)

For starting minimized and hidden e.g. according a configuration item in the ini file of my application I therefore set a flag and minimize from within a timer event.

lucamar seems to reference the self. prefix. This is not needed but I often use it because of the code completion functionality of the editor.

  Yes, this is what is happening.  When you come into the procedure TForm1.WMSysCommand, the FSavedState := WindowState is piching up a SC_MINIMIZE message, so you are not really saving the former WindowState.

guest48704

  • Guest
Re: Buttons and other visual components disappearing
« Reply #14 on: August 15, 2018, 02:33:16 pm »
Here is the only way I was able to effectively save the WindowState.

procedure TForm1.WMSysCommand(VAR Msg: TWMSysCommand);
begin
     if (Msg.CmdType = SC_MINIMIZE) then begin
        Form1.Hide;
        end
        else begin
        inherited;
        end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);  // interval = 1 second (1000)
begin
     if WindowState <> wsMinimized then
        FSavedState := WindowState;
end;

procedure TForm1.TrayIcon1Click(Sender: TObject);
begin
     self.WindowState := FSavedState;
     self.Show;
     self.BringToFront;
end; 

Lazarus doesn't seem to have an event handler like Delphi's 'Application.OnMessage := TrapEvent'.  That would have been a good place to trap the WindowState.

 

TinyPortal © 2005-2018