Allow multiple MDI Parent Forms on same Application - delphi

I'm trying follow what was suggested in this answer, changing this part of Vcl.Forms.pas:
procedure TCustomForm.CreateWindowHandle(const Params: TCreateParams);
var
CreateStruct: TMDICreateStruct;
NewParams: TCreateParams;
begin
if (FormStyle = fsMDIChild) and not (csDesigning in ComponentState) then
begin
{if (Application.MainForm = nil) or
(Application.MainForm.ClientHandle = 0) then
raise EInvalidOperation.Create(SNoMDIForm);}
with CreateStruct do
begin
szClass := Params.WinClassName;
szTitle := Params.Caption;
hOwner := THandle(HInstance);
X := Params.X;
Y := Params.Y;
cX := Params.Width;
cY := Params.Height;
style := Params.Style;
lParam := THandle(Params.Param);
end;
WindowHandle := SendStructMessage(Application.MainForm.ClientHandle,
WM_MDICREATE, 0, CreateStruct);
Include(FFormState, fsCreatedMDIChild);
end
else
//...
but still comes the error saying that "no MDI Form is active"
What more is need be made to this suggestion works? Thanks in advance.
Code of test with Forms:
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2 := TForm2.Create(Self); // MDIForm
Form2.Show;
Form3 := TForm3.Create(Form2); // MDIChild
Form3.Show;
end;

After the help of comments above (mainly of #Remy Lebeau) follows this code working. I hope that can help someone ahead :-).
// MainForm
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Unit2;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2 := TForm2.Create(Application);
Form2.Show;
end;
// MDIForm
type
TForm2 = class(TForm)
MainMenu1: TMainMenu;
O1: TMenuItem;
procedure O1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses
Unit3;
{$R *.dfm}
procedure TForm2.O1Click(Sender: TObject);
begin
Form3 := TForm3.Create(Self);
Form3.Show;
end;
// MDIChild
type
TForm3 = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
procedure CreateWindowHandle(const Params: TCreateParams); override;
procedure DestroyWindowHandle; override;
protected
FMDIClientHandle: HWND;
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
uses
Unit1;
{$R *.dfm}
procedure TForm3.CreateWindowHandle(const Params: TCreateParams);
var
CreateStruct: TMDICreateStruct;
function GetMDIClientHandle: HWND;
begin
Result := 0;
if (Owner is TForm) then
Result := TForm(Owner).ClientHandle;
if (Result = 0) and (Application.MainForm <> nil) then
Result := Application.MainForm.ClientHandle;
if Result = 0 then
raise EInvalidOperation.Create('No Parent MDI Form');
end;
begin
if (FormStyle = fsMDIChild) and not (csDesigning in ComponentState) then
begin
FMDIClientHandle := GetMDIClientHandle;
with CreateStruct do
begin
szClass := Params.WinClassName;
szTitle := Params.Caption;
hOwner := HInstance;
X := Params.X;
Y := Params.Y;
cX := Params.Width;
cY := Params.Height;
style := Params.Style;
lParam := Longint(Params.Param);
end;
WindowHandle := SendMessage(FMDIClientHandle, WM_MDICREATE, 0, LongInt(#CreateStruct));
Include(FFormState, fsCreatedMDIChild);
end
else
begin
FMDIClientHandle := 0;
inherited CreateWindowHandle(Params);
Exclude(FFormState, fsCreatedMDIChild);
end;
end;
procedure TForm3.DestroyWindowHandle;
begin
if fsCreatedMDIChild in FFormState then
SendMessage(FMDIClientHandle, WM_MDIDESTROY, Handle, 0)
else
inherited DestroyWindowHandle;
FMDIClientHandle := 0;
end;
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := CaFree;
end;

Related

How to create popup menu with scroll bar that also supports sub-menus

I want to add scroll bars (and/or scroll wheel support) to my existing Delphi application's popup menus, because they are often higher than the screen, and the built in scrolling is not good enough. How to make a popup menu with scrollbar? would be a great solution for me, except that it doesn't support sub-menus, which I absolutely require. The author of that solution hasn't been on StackOverflow since last July, so I don't think he'll reply to my comment. Can anyone see how to modify that code to add support for sub-menus? In case it matters, I need it to work with Delphi 2007.
I share #KenWhite's reservations about how users might receive a huge menu. So apologies to him and readers whose sensibilities the following might offend ;=)
Anyway, I hope the code below shows that in principle, it is straightforward
to create a TreeView based on a TPopUpMenu (see the routine PopUpMenuToTree) which reflects the structure of the PopUpMenu, including sub-items,
and make use of the TreeView's automatic vertical scroll bar. In the code, the
PopUpMenu happens to be on the same form as the TreeView, but that's only for
compactness, of course - the PopUpMenu could be on anothe form entirely.
As mentioned in a comment, personally I would base something like this on a
TVirtualTreeView (http://www.soft-gems.net/index.php/controls/virtual-treeview)
because it is far more customisable than a standard TTreeView.
type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
TreeView1: TTreeView; // alClient-aligned
Start1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure TreeView1Click(Sender: TObject);
private
protected
procedure MenuItemClick(Sender : TObject);
procedure PopUpMenuToTree(PopUpMenu : TPopUpMenu; TreeView : TTreeView);
public
end;
var
Form1: TForm1;
[...]
procedure TForm1.FormCreate(Sender: TObject);
var
Item,
SubItem : TMenuItem;
i,
j : Integer;
begin
// (Over)populate a PopUpMenu
for i := 1 to 50 do begin
Item := TMenuItem.Create(PopUpMenu1);
Item.Caption := 'Item ' + IntToStr(i);
Item.OnClick := MenuItemClick;
PopUpMenu1.Items.Add(Item);
for j := 1 to 5 do begin
SubItem := TMenuItem.Create(PopUpMenu1);
SubItem.Caption := Format('Item %d Subitem %d ', [i, j]);
SubItem.OnClick := MenuItemClick;
Item.Add(SubItem);
end;
end;
// Populate a TreeView from the PopUpMenu
PopUpMenuToTree(PopUpMenu1, TreeView1);
end;
procedure TForm1.MenuItemClick(Sender: TObject);
var
Item : TMenuItem;
begin
if Sender is TMenuItem then
Caption := TMenuItem(Sender).Caption + ' clicked';
end;
procedure TForm1.PopUpMenuToTree(PopUpMenu: TPopUpMenu;
TreeView: TTreeView);
// Populates the TreeView with the Items in the PopUpMenu
var
i : Integer;
Item : TMenuItem;
RootNode : TTreeNode;
procedure AddItem(Item : TMenuItem; ParentNode : TTreeNode);
var
Node : TTreeNode;
j : Integer;
begin
Node := TreeView.Items.AddChildObject(ParentNode, Item.Caption, Item);
for j := 0 to Item.Count - 1 do begin
AddItem(Item.Items[j], Node);
end;
end;
begin
TreeView.Items.BeginUpdate;
TreeView.Items.Clear;
try
for i := 0 to PopUpMenu.Items.Count - 1 do begin
AddItem(PopUpMenu.Items[i], Nil);
end;
finally
TreeView.Items.EndUpdate;
end;
end;
procedure TForm1.TreeView1Click(Sender: TObject);
var
Node : TTreeNode;
Item : TMenuItem;
begin
if Sender is TTreeView then begin
Node := TTreeView(Sender).Selected;
Item := TMenuItem(Node.Data);
Item.Click;
end;
end;
Here's what I have done, by merging How to make a popup menu with scrollbar?, MartynA's code, and some of my own:
unit PopupUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
StdCtrls, Menus, ComCtrls;
type
TPopupMode = (pmStandard, pmCustom);
TPopupMenu = class(Menus.TPopupMenu)
private
FPopupForm: TForm;
FPopupMode: TPopupMode;
public
constructor Create(AOwner: TComponent); override;
procedure Popup(X, Y: Integer); override;
property PopupForm: TForm read FPopupForm write FPopupForm;
property PopupMode: TPopupMode read FPopupMode write FPopupMode;
end;
type
TPopupForm = class(TForm)
private
FPopupForm: TForm;
FPopupMenu: TPopupMenu;
FTreeView: TTreeView;
procedure DoResize;
procedure TreeViewClick(Sender: TObject);
procedure TreeViewCollapsedOrExpanded(Sender: TObject; Node: TTreeNode);
procedure TreeViewKeyPress(Sender: TObject; var Key: Char);
procedure WMActivate(var AMessage: TWMActivate); message WM_ACTIVATE;
protected
procedure CreateParams(var Params: TCreateParams); override;
public
constructor Create(AOwner: TComponent; APopupForm: TForm;
APopupMenu: TPopupMenu); reintroduce;
end;
var
PopupForm: TPopupForm;
implementation
{$R *.dfm}
{ TPopupForm }
constructor TPopupForm.Create(AOwner: TComponent; APopupForm: TForm;
APopupMenu: TPopupMenu);
procedure AddItem(Item : TMenuItem; ParentNode : TTreeNode);
var
I : Integer;
Node : TTreeNode;
begin
if Item.Caption <> '-' then begin
Node := FTreeView.Items.AddChildObject(ParentNode, Item.Caption, Item);
Node.ImageIndex := Item.ImageIndex;
for I := 0 to Item.Count - 1 do begin
AddItem(Item.Items[I], Node);
end;
end;
end;
var
I: Integer;
begin
inherited Create(AOwner);
BorderStyle := bsNone;
FPopupForm := APopupForm;
FPopupMenu := APopupMenu;
FTreeView := TTreeView.Create(Self);
FTreeView.Parent := Self;
FTreeView.Align := alClient;
FTreeView.BorderStyle := bsSingle;
FTreeView.Color := clMenu;
FTreeView.Images := FPopupMenu.Images;
FTreeView.ReadOnly := TRUE;
FTreeView.ShowHint := FALSE;
FTreeView.ToolTips := FALSE;
FTreeView.OnClick := TreeViewClick;
FTreeView.OnCollapsed := TreeViewCollapsedOrExpanded;
FTreeView.OnExpanded := TreeViewCollapsedOrExpanded;
FTreeView.OnKeyPress := TreeViewKeyPress;
FTreeView.Items.BeginUpdate;
try
FTreeView.Items.Clear;
for I := 0 to FPopupMenu.Items.Count - 1 do
begin
AddItem(FPopupMenu.Items[I], NIL);
end;
finally
FTreeView.Items.EndUpdate;
end;
DoResize;
end;
procedure TPopupForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WindowClass.Style := Params.WindowClass.Style or CS_DROPSHADOW;
end;
procedure TPopupForm.DoResize;
const
BORDER = 2;
var
ItemRect, TVRect : TRect;
MF : TForm;
Node : TTreeNode;
begin
TVRect := Rect(0, 0, 0, 0);
Node := FTreeView.Items[0];
while Node <> NIL do begin
ItemRect := Node.DisplayRect(TRUE);
ItemRect.Right := ItemRect.Right + FTreeView.Images.Width + 1;
if ItemRect.Left < TVRect.Left then
TVRect.Left := ItemRect.Left;
if ItemRect.Right > TVRect.Right then
TVRect.Right := ItemRect.Right;
if ItemRect.Top < TVRect.Top then
TVRect.Top := ItemRect.Top;
if ItemRect.Bottom > TVRect.Bottom then
TVRect.Bottom := ItemRect.Bottom;
Node := Node.GetNextVisible;
end;
MF := Application.MainForm;
if Top + TVRect.Bottom - TVRect.Top > MF.Top + MF.ClientHeight then begin
TVRect.Bottom := TVRect.Bottom -
(Top + TVRect.Bottom - TVRect.Top - (MF.Top + MF.ClientHeight));
end;
if Left + TVRect.Right - TVRect.Left > MF.Left + MF.ClientWidth then begin
TVRect.Right := TVRect.Right -
(Left + TVRect.Right - TVRect.Left - (MF.Left + MF.ClientWidth));
end;
ClientHeight := TVRect.Bottom - TVRect.Top + BORDER * 2;
ClientWidth := TVRect.Right - TVRect.Left + BORDER * 2;
end;
procedure TPopupForm.TreeViewClick(Sender: TObject);
var
Node : TTreeNode;
Item : TMenuItem;
begin
if Sender is TTreeView then begin
Node := TTreeView(Sender).Selected;
if assigned(Node) then begin
Item := TMenuItem(Node.Data);
if assigned(Item.OnClick) then begin
Item.Click;
Close;
end;
end;
end;
end;
procedure TPopupForm.TreeViewCollapsedOrExpanded(Sender: TObject;
Node: TTreeNode);
begin
DoResize;
end;
procedure TPopupForm.TreeViewKeyPress(Sender: TObject; var Key: Char);
begin
if Ord(Key) = VK_RETURN then begin
TreeViewClick(Sender);
end
else if Ord(Key) = VK_ESCAPE then begin
Close;
end;
end;
procedure TPopupForm.WMActivate(var AMessage: TWMActivate);
begin
SendMessage(FPopupForm.Handle, WM_NCACTIVATE, 1, 0);
inherited;
if AMessage.Active = WA_INACTIVE then
Release;
FTreeView.Select(NIL, []);
end;
{ TPopupMenu }
constructor TPopupMenu.Create(AOwner: TComponent);
begin
inherited;
FPopupMode := pmStandard;
end;
procedure TPopupMenu.Popup(X, Y: Integer);
begin
case FPopupMode of
pmCustom:
with TPopupForm.Create(nil, FPopupForm, Self) do
begin
Top := Y;
Left := X;
Show;
end;
pmStandard: inherited;
end;
end;
end.

Minimize Delphi Form to System Tray

I am a Delphi learner. I am looking for solutions so that Delphi MainForm should be minimized to the System Tray instead of Taskbar. On Right Click on the System Tray Icon there should be some menus like "Restore" and "About" and "Help" etc. System Tray Icons will be loaded from Imagelis1 and it will animate. On Clicking on "Restore" the MainForm will be restored, on clicking on "About" "Form2" will be restored and on clicking on "Help" "Foprm3" will be restored. I have found so many solutions on internet like :
Solution 01
Solution 02
but every solutions have some drawbacks. Some can be done once ony. Some have blurred icon in Windows7. Someone may tell that there is no one to write codes for me and I have to show my codes. Plaese forgive me for this regards. Please give me concrete solution sot that it can be implemented universely without version dependency of windows. It will help every one. Please help me.
This should get you going. Drop a TTrayIcon and a TApplicationEvents on your form. THe following code is from the TTrayIcon - Delphi Example from the docwiki. Use the IDE main menu, and choose Project->View Source, and the line that reads Application.ShowMainFormOnTaskbar := True; to `Application.ShowMainFormOnTaskbar := False;' to keep the application's button from appearing on the Windows Taskbar.
This example uses a tray icon and an application events component on a form. When the application runs, it loads the tray icon, the icons displayed when it is animated, and it also sets up a hint balloon. When you minimize the window, the form is hidden, a hint balloon shows up, and the tray icon is displayed and animated. Double-clicking the system tray icon restores the window.
// Add this to the `TApplicationEvents.OnMinimize` event handler
procedure TForm1.ApplicationEvents1Minimize(Sender: TObject);
begin
{ Hide the window and set its state variable to wsMinimized. }
Hide();
WindowState := wsMinimized;
{ Show the animated tray icon and also a hint balloon. }
TrayIcon1.Visible := True;
TrayIcon1.Animate := True;
TrayIcon1.ShowBalloonHint;
end;
// Add this to the `TForm.OnCreate` event handler
procedure TForm1.FormCreate(Sender: TObject);
var
MyIcon : TIcon;
begin
{ Load the tray icons. }
TrayIcon1.Icons := TImageList.Create(Self);
MyIcon := TIcon.Create;
MyIcon.LoadFromFile('icons/earth1.ico');
TrayIcon1.Icon.Assign(MyIcon);
TrayIcon1.Icons.AddIcon(MyIcon);
MyIcon.LoadFromFile('icons/earth2.ico');
TrayIcon1.Icons.AddIcon(MyIcon);
MyIcon.LoadFromFile('icons/earth3.ico');
TrayIcon1.Icons.AddIcon(MyIcon);
MyIcon.LoadFromFile('icons/earth4.ico');
TrayIcon1.Icons.AddIcon(MyIcon);
{ Set up a hint message and the animation interval. }
TrayIcon1.Hint := 'Hello World!';
TrayIcon1.AnimateInterval := 200;
{ Set up a hint balloon. }
TrayIcon1.BalloonTitle := 'Restoring the window.';
TrayIcon1.BalloonHint :=
'Double click the system tray icon to restore the window.';
TrayIcon1.BalloonFlags := bfInfo;
end;
// Add this to the `TTrayIcon.OnDoubleClick` event handler
procedure TForm1.TrayIcon1DblClick(Sender: TObject);
begin
{ Hide the tray icon and show the window,
setting its state property to wsNormal. }
TrayIcon1.Visible := False;
Show();
WindowState := wsNormal;
Application.BringToFront();
end;
For the menu you get on right-click, add a TPopupMenu to your form, add the items you want on it, write the event handlers for those items as usual, and then assign the PopupMenu to the TrayIcon.PopupMenu property.
The "blurred icons" are caused by you not using the proper icon sizes and Windows being forced to scale (stretch) them. Use an icon editor to create multiple size images for each icon (there can be multiple sizes in one icon file).
I drop a TrayIcon onto myForm, then i add this simple code:
type
TmyForm = class(TForm)
...
TrayIcon: TTrayIcon;
procedure FormCreate(Sender: TObject);
...
procedure TrayIconClick(Sender: TObject);
...
private
{ Private declarations }
procedure OnMinimize(Sender:TObject);
public
{ Public declarations }
end;
procedure TmyForm.FormCreate(Sender: TObject);
begin // When form is created
Application.OnMinimize:=OnMinimize; // Set the event handler for application minimize
end;
procedure TmyForm.OnMinimize(Sender:TObject);
begin // When application is minimized by user and/or by code
Hide; // This is to hide it from taskbar
end;
procedure TmyForm.TrayIconClick(Sender: TObject);
begin // When clicking on TrayIcon
if Visible
then begin // Application is visible, so minimize it to TrayIcon
Application.Minimize; // This is to minimize the whole application
end
else begin // Application is not visible, so show it
Show; // This is to show it from taskbar
Application.Restore; // This is to restore the whole application
end;
end;
This creates a TrayIcon allways visible, and when you click on it:
If the application is Visible, it will be Hidden form taskbar and from screen
If the application is Hidden, it will be Shown form taskbar and from screen
In other words, clicking on TrayIcon the application will change its visibility; just as minimizing it to TrayIcon bar.
...And in Delphi 6, where no TTrayIcon exists, you can use this simple code:
unit MainUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ShellAPI, StdCtrls, Menus;
const WM_ICONTRAY = WM_USER+1;
type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
ShowForm1: TMenuItem;
HideForm1: TMenuItem;
Exit1: TMenuItem;
procedure TrayMessage(var Msg: TMessage); message WM_ICONTRAY;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ShowForm1Click(Sender: TObject);
procedure HideForm1Click(Sender: TObject);
procedure Exit1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
TrayIconData: TNotifyIconData;
end;
var
Form1: TForm1;
MustExit:boolean;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
MustExit:=false;
TrayIconData.cbSize:=SizeOf(TrayIconData);
TrayIconData.Wnd:=Handle;
TrayIconData.uID:=0;
TrayIconData.uFlags:=NIF_MESSAGE + NIF_ICON + NIF_TIP;
TrayIconData.uCallbackMessage:=WM_ICONTRAY;
TrayIconData.hIcon:=Application.Icon.Handle;
StrPCopy(TrayIconData.szTip,Application.Title);
Shell_NotifyIcon(NIM_ADD, #TrayIconData);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Shell_NotifyIcon(NIM_DELETE, #TrayIconData);
end;
procedure TForm1.TrayMessage(var Msg: TMessage);
var p:TPoint;
begin
case Msg.lParam of
WM_LBUTTONDOWN: begin
Form1.Show;
Application.Restore;
end;
WM_RBUTTONDOWN: begin
GetCursorPos(p);
PopUpMenu1.Popup(p.x,p.y);
end;
end;
end;
// Popup "Form Show" menu item OnClick
procedure TForm1.ShowForm1Click(Sender: TObject);
begin
Form1.Show;
end;
// Popup "Form Hide" menu item OnClick
procedure TForm1.HideForm1Click(Sender: TObject);
begin
Form1.Hide;
end;
// Popup "Exit" menu item OnClick
procedure TForm1.Exit1Click(Sender: TObject);
begin
MustExit:=true;
Close;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if MustExit then exit;
Form1.Hide;
Action:=caNone;
end;
end.
I have implemented the following codes. Here everything is fine except one. After minimizing the Form, it goes to "SystemTray" but also available in "TaskBar. For my application, the "AlphaBlend" property of "Form001" is true and "AlphaBlendValue" is "0".
unit KoushikHalder001;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls, Vcl.Imaging.pngimage,
Vcl.AppEvnts, Vcl.ImgList, Vcl.Menus;
type
TForm001 = class(TForm)
Edit001: TEdit;
Background: TImage;
BitBtn001: TBitBtn;
BitBtn002: TBitBtn;
FadeInTimer: TTimer;
FadeOutTimer: TTimer;
FormMinimizeTimer: TTimer;
FormRestoreTimer: TTimer;
TrayIcon: TTrayIcon;
PopupMenu: TPopupMenu;
ImageList: TImageList;
ApplicationEvents: TApplicationEvents;
Form001Close: TMenuItem;
Form001Hide: TMenuItem;
Form001Show: TMenuItem;
Form002Close: TMenuItem;
Form002Hide: TMenuItem;
Form002Show: TMenuItem;
N01: TMenuItem;
N02: TMenuItem;
N03: TMenuItem;
N04: TMenuItem;
N05: TMenuItem;
N06: TMenuItem;
N07: TMenuItem;
N08: TMenuItem;
N09: TMenuItem;
N10: TMenuItem;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormHide(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure BitBtn001Click(Sender: TObject);
procedure BitBtn002Click(Sender: TObject);
procedure FadeInTimerTimer(Sender: TObject);
procedure FadeOutTimerTimer(Sender: TObject);
procedure FormMinimizeTimerTimer(Sender: TObject);
procedure FormRestoreTimerTimer(Sender: TObject);
procedure ApplicationEventsMinimize(Sender: TObject);
procedure TrayIconDblClick(Sender: TObject);
procedure Form001CloseClick(Sender: TObject);
procedure Form001HideClick(Sender: TObject);
procedure Form001ShowClick(Sender: TObject);
procedure Form002CloseClick(Sender: TObject);
procedure Form002HideClick(Sender: TObject);
procedure Form002ShowClick(Sender: TObject);
private
{ Private declarations }
CrossButtonClick: Boolean;
procedure WMNCHitTest(var Msg: TWMNCHitTest) ; message WM_NCHitTest;
procedure WMSysCommand(var Msg: TWMSysCommand) ; message WM_SysCommand;
public
{ Public declarations }
end;
var
Form001: TForm001;
implementation
{$R *.dfm}
uses KoushikHalder002;
procedure TForm001.WMNCHitTest(var Msg: TWMNCHitTest);
begin
inherited;
if ControlAtPos(ScreenToClient(Msg.Pos), True, True, True)= nil
then
begin
if Msg.Result=htClient then Msg.Result := htCaption;
end;
end;
procedure TForm001.WMSysCommand(var Msg: TWMSysCommand);
begin
case Msg.CmdType of
SC_MINIMIZE:
begin
if Form001.AlphaBlendValue > 0 then
begin
Form001.FormMinimizeTimer.Enabled := true;
Exit;
end;
end;
SC_RESTORE:
begin
if Form001.AlphaBlendValue < 220 then
begin
Form001.FormRestoreTimer.Enabled := True;
end;
end;
end;
inherited;
end;
procedure TForm001.ApplicationEventsMinimize(Sender: TObject);
begin
Form001.FormMinimizeTimer.Enabled := true;
TrayIcon.Visible := True;
TrayIcon.Animate := True;
TrayIcon.ShowBalloonHint;
end;
procedure TForm001.BitBtn001Click(Sender: TObject);
begin
if Form002.WindowState = wsMinimized then
begin
Form002.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
end
else
Form002.show;
end;
procedure TForm001.BitBtn002Click(Sender: TObject);
begin
Form002.FadeOutTimer.Enabled := true;
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.Form001CloseClick(Sender: TObject);
begin
Form002.FadeOutTimer.Enabled := true;
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.Form001HideClick(Sender: TObject);
begin
Form001.FormMinimizeTimer.Enabled := true;
end;
procedure TForm001.Form001ShowClick(Sender: TObject);
begin
if Form001.WindowState = wsMinimized then
begin
Form001.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
end
else
Form001.show;
end;
procedure TForm001.Form002CloseClick(Sender: TObject);
begin
Form002.FadeOutTimer.Enabled := true;
end;
procedure TForm001.Form002HideClick(Sender: TObject);
begin
Form002.FormMinimizeTimer.Enabled := true;
end;
procedure TForm001.Form002ShowClick(Sender: TObject);
begin
if Form002.WindowState = wsMinimized then
begin
Form002.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
end
else
Form002.show;
end;
procedure TForm001.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if CrossButtonClick = true
then
begin
CanClose := true;
Exit;
end;
CanClose := false;
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.FormCreate(Sender: TObject);
begin
Form001.FadeInTimer.Enabled := true;
end;
procedure TForm001.FormHide(Sender: TObject);
begin
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.FormShow(Sender: TObject);
begin
Form001.FadeInTimer.Enabled := true;
end;
procedure TForm001.TrayIconDblClick(Sender: TObject);
begin
Form001.FormRestoreTimer.Enabled := true;
TrayIcon.Visible := False;
WindowState := wsNormal;
Application.BringToFront();
end;
procedure TForm001.FadeInTimerTimer(Sender: TObject);
begin
if Form001.AlphaBlendValue >= 220
then
begin
Form001.FadeInTimer.Enabled := false;
end
else
begin
Form001.AlphaBlendValue := Form001.AlphaBlendValue + 10;
CrossButtonClick := false;
end;
end;
procedure TForm001.FadeOutTimerTimer(Sender: TObject);
begin
if Form001.AlphaBlendValue <= 0
then
begin
Form001.FadeOutTimer.Enabled := false;
CrossButtonClick := true;
Self.Close;
end
else
begin
Form001.AlphaBlendValue := Form001.AlphaBlendValue - 10;
CrossButtonClick := true;
end;
end;
procedure TForm001.FormMinimizeTimerTimer(Sender: TObject);
begin
if Form001.AlphaBlendValue > 0 then
begin
Form001.AlphaBlendValue := Form001.AlphaBlendValue - 10;
end
else
begin
Form001.FormMinimizeTimer.Enabled := false;
Perform(WM_SYSCOMMAND, SC_MINIMIZE, 0);
end;
end;
procedure TForm001.FormRestoreTimerTimer(Sender: TObject);
begin
if Form001.AlphaBlendValue < 220 then
begin
Form001.AlphaBlendValue := Form001.AlphaBlendValue + 10;
end
else
begin
Form001.FormRestoreTimer.Enabled := false;
end;
end;
end.
If I do the following
Application.MainFormOnTaskbar := false;
the form is totally invissible. I think there should be one bug. But I am unable to find it.

Minimize Delphi Form to System Tray using Timer

I am a Delphi learner. I am looking for solutions so that Delphi MainForm should be minimized to the System Tray instead of Taskbar using Timer. I have implemented the following codes. Here everything is fine except one. After minimizing the Form, it goes to "SystemTray" but also available in "TaskBar. For my application, the "AlphaBlend" property of "Form001" is true and "AlphaBlendValue" is "0".
unit KoushikHalder001;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls, Vcl.Imaging.pngimage,
Vcl.AppEvnts, Vcl.ImgList, Vcl.Menus;
type
TForm001 = class(TForm)
Edit001: TEdit;
Background: TImage;
BitBtn001: TBitBtn;
BitBtn002: TBitBtn;
FadeInTimer: TTimer;
FadeOutTimer: TTimer;
FormMinimizeTimer: TTimer;
FormRestoreTimer: TTimer;
TrayIcon: TTrayIcon;
PopupMenu: TPopupMenu;
ImageList: TImageList;
ApplicationEvents: TApplicationEvents;
Form001Close: TMenuItem;
Form001Hide: TMenuItem;
Form001Show: TMenuItem;
Form002Close: TMenuItem;
Form002Hide: TMenuItem;
Form002Show: TMenuItem;
N01: TMenuItem;
N02: TMenuItem;
N03: TMenuItem;
N04: TMenuItem;
N05: TMenuItem;
N06: TMenuItem;
N07: TMenuItem;
N08: TMenuItem;
N09: TMenuItem;
N10: TMenuItem;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormHide(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure BitBtn001Click(Sender: TObject);
procedure BitBtn002Click(Sender: TObject);
procedure FadeInTimerTimer(Sender: TObject);
procedure FadeOutTimerTimer(Sender: TObject);
procedure FormMinimizeTimerTimer(Sender: TObject);
procedure FormRestoreTimerTimer(Sender: TObject);
procedure ApplicationEventsMinimize(Sender: TObject);
procedure TrayIconDblClick(Sender: TObject);
procedure Form001CloseClick(Sender: TObject);
procedure Form001HideClick(Sender: TObject);
procedure Form001ShowClick(Sender: TObject);
procedure Form002CloseClick(Sender: TObject);
procedure Form002HideClick(Sender: TObject);
procedure Form002ShowClick(Sender: TObject);
private
{ Private declarations }
CrossButtonClick: Boolean;
procedure WMNCHitTest(var Msg: TWMNCHitTest) ; message WM_NCHitTest;
procedure WMSysCommand(var Msg: TWMSysCommand) ; message WM_SysCommand;
public
{ Public declarations }
end;
var
Form001: TForm001;
implementation
{$R *.dfm}
uses KoushikHalder002;
procedure TForm001.WMNCHitTest(var Msg: TWMNCHitTest);
begin
inherited;
if ControlAtPos(ScreenToClient(Msg.Pos), True, True, True)= nil
then
begin
if Msg.Result=htClient then Msg.Result := htCaption;
end;
end;
procedure TForm001.WMSysCommand(var Msg: TWMSysCommand);
begin
case Msg.CmdType of
SC_MINIMIZE:
begin
if Form001.AlphaBlendValue > 0 then
begin
Form001.FormMinimizeTimer.Enabled := true;
Exit;
end;
end;
SC_RESTORE:
begin
if Form001.AlphaBlendValue < 220 then
begin
Form001.FormRestoreTimer.Enabled := True;
end;
end;
end;
inherited;
end;
procedure TForm001.ApplicationEventsMinimize(Sender: TObject);
begin
Form001.FormMinimizeTimer.Enabled := true;
TrayIcon.Visible := True;
TrayIcon.Animate := True;
TrayIcon.ShowBalloonHint;
end;
procedure TForm001.BitBtn001Click(Sender: TObject);
begin
if Form002.WindowState = wsMinimized then
begin
Form002.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
end
else
Form002.show;
end;
procedure TForm001.BitBtn002Click(Sender: TObject);
begin
Form002.FadeOutTimer.Enabled := true;
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.Form001CloseClick(Sender: TObject);
begin
Form002.FadeOutTimer.Enabled := true;
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.Form001HideClick(Sender: TObject);
begin
Form001.FormMinimizeTimer.Enabled := true;
end;
procedure TForm001.Form001ShowClick(Sender: TObject);
begin
if Form001.WindowState = wsMinimized then
begin
Form001.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
end
else
Form001.show;
end;
procedure TForm001.Form002CloseClick(Sender: TObject);
begin
Form002.FadeOutTimer.Enabled := true;
end;
procedure TForm001.Form002HideClick(Sender: TObject);
begin
Form002.FormMinimizeTimer.Enabled := true;
end;
procedure TForm001.Form002ShowClick(Sender: TObject);
begin
if Form002.WindowState = wsMinimized then
begin
Form002.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
end
else
Form002.show;
end;
procedure TForm001.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if CrossButtonClick = true
then
begin
CanClose := true;
Exit;
end;
CanClose := false;
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.FormHide(Sender: TObject);
begin
Form001.FadeOutTimer.Enabled := true;
end;
procedure TForm001.FormShow(Sender: TObject);
begin
Form001.FadeInTimer.Enabled := true;
end;
procedure TForm001.TrayIconDblClick(Sender: TObject);
begin
Form001.FormRestoreTimer.Enabled := true;
TrayIcon.Visible := False;
WindowState := wsNormal;
Application.BringToFront();
end;
procedure TForm001.FadeInTimerTimer(Sender: TObject);
begin
if Form001.AlphaBlendValue >= 220
then
begin
Form001.FadeInTimer.Enabled := false;
end
else
begin
Form001.AlphaBlendValue := Form001.AlphaBlendValue + 10;
CrossButtonClick := false;
end;
end;
procedure TForm001.FadeOutTimerTimer(Sender: TObject);
begin
if Form001.AlphaBlendValue <= 0
then
begin
Form001.FadeOutTimer.Enabled := false;
CrossButtonClick := true;
Self.Close;
end
else
begin
Form001.AlphaBlendValue := Form001.AlphaBlendValue - 10;
CrossButtonClick := true;
end;
end;
procedure TForm001.FormMinimizeTimerTimer(Sender: TObject);
begin
if Form001.AlphaBlendValue > 0 then
begin
Form001.AlphaBlendValue := Form001.AlphaBlendValue - 10;
end
else
begin
Form001.FormMinimizeTimer.Enabled := false;
Perform(WM_SYSCOMMAND, SC_MINIMIZE, 0);
end;
end;
procedure TForm001.FormRestoreTimerTimer(Sender: TObject);
begin
if Form001.AlphaBlendValue < 220 then
begin
Form001.AlphaBlendValue := Form001.AlphaBlendValue + 10;
end
else
begin
Form001.FormRestoreTimer.Enabled := false;
end;
end;
end.
If I do the following
Application.MainFormOnTaskbar := false;
when the application runs the form is totally invissible. I think there should be one bug. But I am unable to find it. Please help me.
If you want to remove the form from the taskbar then you need to hide it rather than minimize it. Simply call Hide when you have finished fading out the form.
With regards removing the taskbar button, it doesn't actually matter how you configure MainFormOnTaskbar. So, what you should do is set MainFormOnTaskbar as you prefer for the application in its normal mode of operation. That property is not pertinent to whether or not the taskbar button shows.
You should HIDE application. Here is a procedure to Hide and Restore application from TaskBar and Desktop. If you have more than one form visible in your Application uncomment Application.Minimize and Application.Restore:
procedure TMainForm.ChangeApplicationVisibility;
begin
if Visible then
begin
Hide;
// Application.Minimize;
ShowWindow(Application.Handle,SW_Hide);
end
else
begin
Show;
// Application.Restore;
Application.BringToFront;
end;
end;

Adding Characters one by one to TMemo

Could any one tell me how can I add characters one by one from a text file to a Memo?
The text file contains different paragraphs of texts. I want to add the characters of each paragraph one by one till the end of the paragraph. Then after 10 seconds delay the next paragraph to be shown in the Memo.
Thanks,
Sei
You would probably use a TTimer. Drop a TTimer, a TMemo and a TButton on your form. Then do
var
lines: TStringList;
pos: TPoint;
const
CHAR_INTERVAL = 75;
PARAGRAPH_INTERVAL = 1000;
procedure TForm6.Button1Click(Sender: TObject);
const
S_EMPTY_FILE = 'You are trying to display an empty file!';
begin
Memo1.ReadOnly := true;
Memo1.Clear;
Memo1.Lines.Add('');
pos := Point(0, 0);
if lines.Count = 0 then
raise Exception.Create(S_EMPTY_FILE);
while (pos.Y < lines.Count) and (length(lines[pos.Y]) = 0) do inc(pos.Y);
if pos.Y = lines.Count then
raise Exception.Create(S_EMPTY_FILE);
NextCharTimer.Enabled := true;
end;
procedure TForm6.FormCreate(Sender: TObject);
begin
lines := TStringList.Create;
lines.LoadFromFile('C:\Users\Andreas Rejbrand\Desktop\Test.txt');
end;
procedure TForm6.NextCharTimerTimer(Sender: TObject);
begin
NextCharTimer.Interval := CHAR_INTERVAL;
Memo1.Lines[Memo1.Lines.Count - 1] := Memo1.Lines[Memo1.Lines.Count - 1] + lines[pos.Y][pos.X + 1];
inc(pos.X);
if pos.X = length(lines[pos.Y]) then
begin
NextCharTimer.Interval := PARAGRAPH_INTERVAL;
pos.X := 0;
repeat
inc(pos.Y);
Memo1.Lines.Add('');
until (pos.Y = lines.Count) or (length(lines[pos.Y]) > 0);
end;
if pos.Y = lines.Count then
NextCharTimer.Enabled := false;
end;
A thread alternative to a timer. Tests a 'carriage return' in the file for a paragraph:
const
UM_MEMOCHAR = WM_USER + 22;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure UMMemoChar(var Msg: TMessage); message UM_MEMOCHAR;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TCharSender = class(TThread)
private
FCharWait, FParWait: Integer;
FFormHandle: HWND;
FFS: TFileStream;
protected
procedure Execute; override;
public
constructor Create(FileName: string; CharWait, ParagraphWait: Integer;
FormHandle: HWND);
destructor Destroy; override;
end;
constructor TCharSender.Create(FileName: string; CharWait, ParagraphWait: Integer;
FormHandle: HWND);
begin
FCharWait := CharWait;
FParWait := ParagraphWait;
FFormHandle := FormHandle;
FFS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
FreeOnTerminate := True;
inherited Create(False);
end;
destructor TCharSender.Destroy;
begin
FFS.Free;
inherited;
end;
procedure TCharSender.Execute;
var
C: Char;
begin
while (FFS.Position < FFS.Size) and not Terminated do begin
FFS.Read(C, SizeOf(C));
if (C <> #10) then
PostMessage(FFormHandle, UM_MEMOCHAR, Ord(C), 0);
if C = #13 then
Sleep(FParWait)
else
Sleep(FCharWait);
end;
end;
{TForm1}
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Clear;
TCharSender.Create(
ExtractFilePath(Application.ExeName) + 'text.txt', 20, 1000, Handle);
end;
procedure TForm1.UMMemoChar(var Msg: TMessage);
begin
Memo1.SelStart := Memo1.Perform(WM_GETTEXTLENGTH, 0, 0);
Memo1.Perform(WM_CHAR, Msg.WParam, 0);
end;
There's lots of ways to do this, and I'm not sure how you intend to handle newlines. However, all routes lead to TMemo.Lines which is a TStrings instance that wraps up the windows messages needed to interact with the underlying Windows edit control.
For example, these routines should get you started.
procedure AddNewLine(Memo: TMemo);
begin
Memo.Lines.Add('');
end;
procedure AddCharacter(Memo: TMemo; const C: Char);
var
Lines: TStrings;
begin
Lines := Memo.Lines;
if Lines.Count=0 then
AddNewLine(Memo);
Lines[Lines.Count-1] := Lines[Lines.Count-1]+C;
end;

Reserve part of the desktop

How can I reserve one edge of the desktop with Delphi? Something like the Vista Sidebar does.
What you want is called an application desktop toolbar
You must use the TAppBarData Object declared in the ShellAPI unit and the SHAppBarMessage function.
See this simple example.
type
TApplicationTaskBar = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
procedure CreateParams(var Params: TCreateParams); override;
public
{ Public declarations }
end;
var
ApplicationTaskBar: TApplicationTaskBar;
implementation
{$R *.dfm}
Uses
ShellAPI;
procedure TApplicationTaskBar.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.ExStyle := Params.ExStyle or WS_EX_TOOLWINDOW;
Params.Style := (Params.Style OR WS_POPUP) AND (NOT WS_DLGFRAME); //Remove title Bar
end;
procedure TApplicationTaskBar.FormCreate(Sender: TObject);
var
MyTaskBar : TAppBarData;
begin
GlassFrame.Enabled :=True;//Activate Glass , optional
GlassFrame.SheetOfGlass :=True;//optional
Left:=0;
Top :=0;
Width := 300;
Height:= Screen.Height;
FillChar(MyTaskBar, SizeOf(TAppBarData), 0);
MyTaskBar.cbSize := SizeOf(TAppBarData);
MyTaskBar.hWnd := Handle;
MyTaskBar.uCallbackMessage := WM_USER+777; //Define my own Mesaage
MyTaskBar.uEdge := ABE_LEFT;
MyTaskBar.rc := Rect(0, 0, Width, Height);
SHAppBarMessage(ABM_NEW, MyTaskBar);
SHAppBarMessage(ABM_ACTIVATE, MyTaskBar);
SHAppBarMessage(ABM_SETPOS, MyTaskBar);
Application.ProcessMessages;
end;
procedure TApplicationTaskBar.FormDestroy(Sender: TObject);
var
MyTaskBar : TAppBarData;
begin
FillChar(MyTaskBar, SizeOf(TAppBarData), 0);
MyTaskBar.cbSize := SizeOf(TAppBarData);
MyTaskBar.hWnd := Self.Handle;
SHAppBarMessage(ABM_Remove, MyTaskBar);
end;
Check this links
SHAppBarMessage
ABM_ACTIVATE
ABM_SETPOS
ABM_NEW
Bye.

Resources