Hiding application from taskbar in Delphi doesn't work - delphi

I want my application to minimize to the system tray, and not be visible on the taskbar. I followed the suggestions from this and this answer and changed the MainFormOnTaskBar property in the project source:
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.MainFormOnTaskBar := False;
Application.Run;
end.
Next I tried this:
procedure TForm1.Button1Click(Sender: TObject);
begin
Self.Hide;
WindowState := wsMinimized;
TrayIcon1.Visible := True;
end;
and this variant:
procedure TForm1.ApplicationEvents1Minimize(Sender: TObject);
begin
Self.Hide;
WindowState := wsMinimized;
TrayIcon1.Visible := True;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Application.Minimize;
end;
but while the tray icon shows correctly the application still shows in the taskbar. What am I doing wrong?

David suggests that what I see in the taskbar is not my main form, but my application. Following his advice I hid that using ShowWindow:
procedure TForm1.Button1Click(Sender: TObject);
begin
Self.Hide;
WindowState := wsMinimized;
TrayIcon1.Visible := True;
ShowWindow(Application.Handle, SW_Hide);
end;
Problem solved. Thanks, David.

Related

How to run application without focus? (alternative way)

procedure TForm1.FormCreate(Sender: TObject);
begin
ShowWindow(Handle, SW_SHOWNOACTIVATE);
end;
Unfortunately, the above code does not work well in conjunction with an activated jvTrayIcon component (tvVisibleTaskBar:=false). The Main form remains visible with missing UI elements:
Have you tried setting
Application.MainFormOnTaskbar := False;
Application.ShowMainForm := false;
before your
Application.CreateForm(TForm1, Form1);
in the .dpr-file

SDI application with multiple instances shown on taskbar

I've created an SDI application using the Delphi Berlin VCL template. I can create additional instances by programming File|New as follows:
procedure TSDIAppForm.FileNew1Execute(Sender: TObject);
var
LNewDoc: TSDIAppForm;
begin
LNewDoc := TSDIAppForm.Create(Application);
LNewDoc.Show;
end;
Only the owner form shows on the taskbar. Also, closing the owner form closes all the instances. How do I unlink the additional instances so that they operate independently and show individually on the taskbar?
Closing the TForm that is assigned as the Application.MainForm exits the app, that is by design.
If you want the MainForm to act like any other SDI window and be closed independently without exiting the app if other SDI windows are still open, you will have to create a separate TForm to act as the real MainForm and then hide it from the user (set Application.ShowMainForm to false at startup before Application.Run() is called), and then you can create TSDIAppForm objects as needed. When the last TSDIAppForm object is closed, you can then close the MainForm, or call Application.Terminate() directly, to exit the app.
To give each TSDIAppForm its own Taskbar button, you need to override the virtual CreateParams() method:
How can I get taskbar buttons for forms that aren't the main form?
Try this:
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMyRealMainForm, MyRealMainForm);
Application.CreateForm(TSDIAppForm, SDIAppForm);
SDIAppForm.Visible := True;
Application.ShowMainForm := False;
Application.Run;
end.
procedure TSDIAppForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := 0;
end;
procedure TSDIAppForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
procedure TSDIAppForm.FormDestroy(Sender: TObject);
begin
if Screen.FormCount = 2 then // only this Form and the MainForm
Application.Terminate;
end;
procedure TSDIAppForm.FileNew1Execute(Sender: TObject);
var
LNewDoc: TSDIAppForm;
begin
LNewDoc := TSDIAppForm.Create(Application);
LNewDoc.Show;
end;

Assign Font From TComboBox D7

Delphi v7
Let me preface my remedial question by saying that I am not a real programer. I am a Deputy Sheriff and I write an occasional project to help us do what we do.
My current project contains several TDBRichEdit controls. I have assigned various formatting processes to toolbar buttons. I would like to be able to change the RichEdit font using a ComboBox. The combobox is populated with the font list, but it does not affect the font of the TDBRichEdit control. I have been trying to figure this out for over a week and I cannot see the problem.
This is what I have done:
Form OnCreate procedure
procedure TForm1.FormCreate(Sender: TObject);
begin
PageControl1.ActivePage:= TabSheet1;
GetFontNames;
SelectionChange(Self);
CurrText.Name := DefFontData.Name;
CurrText.Size := -MulDiv(DefFontData.Height, 72, Screen.PixelsPerInch);
end;
Form Selection Change
procedure TForm1.SelectionChange(Sender: TObject);
begin
if ActiveControl is TDBRichEdit then
with ActiveControl as
TdbRichEdit do begin
try
Ctrlupdating := True;
Size.Text := IntToStr(SelAttributes.Size);
cmbFont.Text := SelAttributes.Name;
finally
Ctrlupdating := False;
end;
end;
end;
Functions (Except for the "ActiveControl part these are not my functions and I don't have enough knowledge to completely understand them.)
Function TForm1.CurrText: TTextAttributes;
begin
if ActiveControl is TDBRichEdit then
with ActiveControl as
TdbRichEdit do begin
if SelLength > 0 then Result := SelAttributes
else Result := DefAttributes;
end;
end;
function EnumFontsProc(var LogFont: TLogFont; var TextMetric: TTextMetric;
FontType: Integer; Data: Pointer): Integer; stdcall;
begin
TStrings(Data).Add(LogFont.lfFaceName);
Result := 1;
end;
OnDraw event of the combobox
procedure TForm1.cmbFontDrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
with (Control as TComboBox).Canvas do
begin
Font.Name := Screen.Fonts.Strings[Index];
FillRect(Rect) ;
TextOut(Rect.Left, Rect.Top, PChar(Screen.Fonts.Strings[Index]));
end;
end;
OnChange event for the combobox
procedure TForm1.cmbFontChange(Sender: TObject);
begin
if Ctrlupdating then Exit;
CurrText.Name := cmbFont.Items[cmbFont.ItemIndex];
end;
Any Ideas?
In your code you try to modify the text attributes in this code:
procedure TForm1.cmbFontChange(Sender: TObject);
begin
if Ctrlupdating then Exit;
CurrText.Name := cmbFont.Items[cmbFont.ItemIndex];
end;
When this code executes, ActiveControl will be cmbFont. Now look at CurrText.
if ActiveControl is TDBRichEdit then
with ActiveControl as TdbRichEdit do
begin
if SelLength > 0 then
Result := SelAttributes
else
Result := DefAttributes;
end;
So, the first if block will not be entered.
In fact your function appears not to assign anything to Result in this case. You must always assign to Result. The compiler will tell you this when you enable warnings and hints.
Instead of using ActiveControl you should specify the rich edit instance directly. I don't know how your form is arranged, but you'll need to use some other means to work out which rich edit control the change is to be applied to. Perhaps based on the active page of the page control.
I managed to get the combobox working. My code is probably very awkward, but it works. Thank you for your help. I would not have been able to solve this problem without it.
I wrote a separate function for each of the richedit contols. With FormCreate I had to add lines for each of the functions
procedure TForm1.FormCreate(Sender: TObject);
begin
PageControl1.ActivePage:= TabSheet1;
GetFontNames;
SelectionChange(Self);
**CurrText.Name := DefFontData.Name;
CurrText.Size := -MulDiv(DefFontData.Height, 72, Screen.PixelsPerInch);**
end;
In SelectionChange I had to make a call to the PARAGRAPH attributes of the rich edit control. I was not able to do that collectively. I addressed the rich edit control “reProc” only. The others seem to work fine with that one line. I would like to understand that one.
Form Selection Change
procedure TForm1.SelectionChange(Sender: TObject);
begin
if ActiveControl is TDBRichEdit then
with reProc.Paragraph do begin
try do begin
You gave me the idea. I was not able to address all the richedit controls collectively, so I wrote a function for each of the richedit controls separately.
function TForm1.CurrText: TTextAttributes;
begin
if reProc.SelLength > 0 then Result := reProc.SelAttributes
else Result := **reProc.DefAttributes;**
For the OnChange event for the combobox I had to add lines for each of the functions
procedure TForm1.cmbFontChange(Sender: TObject);
begin
if Ctrlupdating then Exit;
**CurrText.Name := cmbFont.Items[cmbFont.ItemIndex];**
end;

ribbon controls

How do I enable ribbon buttons which are disabled after clicking the more commands button in a quickaccessbar using Delphi?
This is a known bug
Quality Central report 70342:
When using Ribbon Controls, if one
adds a quick access toolbar, and then
at runtime chooses "More Commands" to
customize the quick access toolbar,
many (although not always all) of the
action components in various ribbon
groups will become permanently
disabled.
Please see the report itself for more information:
http://qc.embarcadero.com/wc/qcmain.aspx?d=70342
The report is still open, so I it may not have been solved in D2011 either, but Quality Central could be lagging behind a bit.
Update
The report states there is no work around, but Jack Sudarev posted one in the comments:
procedure TForm6.ActionManager1StateChange(Sender: TObject);
begin
UpdateActions(ActionManager1);
end;
procedure TForm6.UpdateActions(ActionManager: TActionManager);
var
i: Integer;
begin
if not Assigned(ActionManager) then
Exit;
for i := 0 to ActionManager.ActionCount - 1 do
begin
(ActionManager.Actions[i] as TAction).Enabled := False;
(ActionManager.Actions[i] as TAction).Enabled := True;
end;
end;
This is what i did:
procedure TmainTranslatform.MyUpdateActions(ActionManager: TActionManager);
var
i: Integer;
begin
if not Assigned(ActionManager) then
Exit;
for i := 0 to ActionManager.ActionCount - 1 do
begin
if (ActionManager.Actions[i] is TFileOpen) then
begin
(ActionManager.Actions[i] as TFileOpen).Enabled := False;
(ActionManager.Actions[i] as TFileOpen).Enabled := True;
end;
if (ActionManager.Actions[i] is TAction) then
begin
(ActionManager.Actions[i] as TAction).Enabled := False;
(ActionManager.Actions[i] as TAction).Enabled := True;
end;
end;
end;

Why doesn't my cursor change to an Hourglass in my FindDialog in Delphi?

I am simply opening my FindDialog with:
FindDialog.Execute;
In my FindDialog.OnFind event, I want to change the cursor to an hourglass for searches through large files, which may take a few seconds. So in the OnFind event I do this:
Screen.Cursor := crHourglass;
(code that searches for the text and displays it) ...
Screen.Cursor := crDefault;
What happens is while searching for the text, the cursor properly changes to the hourglass (or rotating circle in Vista) and then back to the pointer when the search is completed.
However, this only happens on the main form. It does not happen on the FindDialog itself. The default cursor remains on the FindDialog during the search. While the search is happening if I move the cursor over the FindDialog it changes to the default, and if I move it off and over the main form it becomes the hourglass.
This does not seem like what is supposed to happen. Am I doing something wrong or does something special need to be done to get the cursor to be the hourglass on all forms?
For reference, I'm using Delphi 2009.
I guess the reason for this has got sth. to do with Find Dialog being not a form but a Dialog (a Common Dialog).
You can try setting the class cursor (does not have an effect on the controls of the dialog);
procedure TForm1.FindDialog1Find(Sender: TObject);
begin
SetClassLong(TFindDialog(Sender).Handle, GCL_HCURSOR, Screen.Cursors[crHourGlass]);
try
Screen.Cursor := crHourglass;
try
// (code that searches for the text and displays it) ...
finally
Screen.Cursor := crDefault;
end;
finally
SetClassLong(TFindDialog(Sender).Handle, GCL_HCURSOR, Screen.Cursors[crDefault]);
end;
end;
EDIT
An alternative could be to subclass the FindDialog during the search time and respond to WM_SETCURSOR messages with "SetCursor". If we prevent further processing of the message the controls on the dialog won't set their own cursors.
type
TForm1 = class(TForm)
FindDialog1: TFindDialog;
...
private
FSaveWndProc, FWndProc: Pointer;
procedure FindDlgProc(var Message: TMessage);
...
end;
....
procedure TForm1.FormCreate(Sender: TObject);
begin
FWndProc := classes.MakeObjectInstance(FindDlgProc);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
classes.FreeObjectInstance(FWndProc);
end;
procedure TForm1.FindDialog1Find(Sender: TObject);
begin
FSaveWndProc := Pointer(SetWindowLong(FindDialog1.Handle, GWL_WNDPROC,
Longint(FWndProc)));
try
Screen.Cursor := crHourGlass;
try
// (code that searches for the text and displays it) ...
finally
Screen.Cursor := crDefault;
end;
finally
if Assigned(FWndProc) then
SetWindowLong(FindDialog1.Handle, GWL_WNDPROC, Longint(FSaveWndProc));
// SendMessage(FindDialog1.Handle, WM_SETCURSOR, FindDialog1.Handle,
// MakeLong(HTNOWHERE, WM_MOUSEMOVE));
SetCursor(Screen.Cursors[crDefault]);
end;
end;
procedure TForm1.FindDlgProc(var Message: TMessage);
begin
if Message.Msg = WM_SETCURSOR then begin
SetCursor(Screen.Cursors[crHourGlass]);
Message.Result := 1;
Exit;
end;
Message.Result := CallWindowProc(FSaveWndProc, FindDialog1.Handle,
Message.Msg, Message.WParam, Message.LParam);
end;
Try adding Application.ProcessMessages; after you set the cursor.
If this works, be sure to call your Mother, help an old lady cross the street, or maybe plant a tree. Otherwise, the devil will own another little piece of your soul.

Resources