How to Print a form in Delphi? - delphi

After searching around the web for about half an hour i've decided to ask for some help.
Currently i'm using this code:
procedure TViewSalesActivity.btnPrintClick(Sender: TObject);
begin
with TPrintDialog.Create(nil) do
ViewSalesActivity.PrintScale:= 1.5
try
if Execute then
ViewSalesActivity.Print;
finally
Free;
end;
end;
To print a whole form.
The form includes buttons, text, captions and edit boxes etc.
The only problem is that the printout is to scale of the computer window; which is way too small. It is also stuck in the top left hand corner of the page. Is there any way to make it fill a whole page/ majority of the page?

Assuming which the ViewSalesActivity variable is a TForm descendant, try setting the PrintScale property to poPrintToFit
ViewSalesActivity.PrintScale:=poPrintToFit;
ViewSalesActivity.Print;

Related

The anchor property of components when the application is maximized in Delphi

I have three buttons placed at the right on my form. The buttons' anchor property parameters akTop, akRight are set to true, the other ones left to false so that the buttons always remain at the right side near the boarder when the form is resized. Then I set the form's WindowState property to wsMaximized so that it covers the whole screen when run at start-up. But when I start the application the buttons are closer to the middle rather than on the right. But when I resize the form at design-time everything seems to work just fine.
Here are some snapshots to show you exactly what I mean:
At design-time:
At run-time:
Please, explain what I'm doing wrong and how to fix this so that it works as intended.
This looks like the buttons are being created with their designed positions, the form is then set to Maximized, then the anchor properties are set or put in place.
In design time the anchors are already set and so that’s why you see them move as you want. To prove my theory on this make the form much smaller, run the application and notice that the items are in their smaller design time locations.
An easy fix to get what you want. Keep the Window state at wsNormal and on FormShow (which occurs after Create) do this:
procedure TForm1.FormShow(Sender: TObject);
begin
self.WindowState := wsMaximized;
end;
You will see the results you want.
I have seen your answer in one of those tutorials. But realy dont remember was which one. You can watch all videos, even you will learn more things. it will not time waste all the way.
Link: Learn Delphi TV
Also you can try something like below if you are lazy enough to watch videos. Put this code in form resize:
buttoncreate.left := panel.width - (buttoncreate.width + buttonedit.width + buttondelete.width);
buttonedit.left := panel.width - (buttonedit.width + buttondelete.width);
buttondelete.left := panel.width - buttondelete.width;

"Stay on top" main form and modal dialogs in Delphi XE

In Delphi XE Update 1, I’m getting seemingly random behavior of modal forms if the parent (main) form’s FormStyle is set to fsStayOnTop.
1) With MainFormOnTaskbar := False (the old way), everything “just works”. With the new MainFormOnTaskbar := True, modal forms get hidden behind the main form when the main form is set to “stay on top”. In most cases saying
modalForm.PopupParent := self;
just before the call to modalForm.ShowModal seems to help. But not always.
2) All my modal forms are simple, no frills, positioned at MainFormCenter, not using form inheritance, etc. And yet the PopupParent fix only works for about half of them, while the other half still get hidden behind the main form. Strangest of all, in one case the ordering of unrelated lines of code breaks or makes it. See lines marked (1) and (2) in this code:
procedure TEchoMainForm.DBMaintenancePrompt( actions : TMaintenanceActions );
var
frm : TDBMaintenanceForm;
begin
frm := TDBMaintenanceForm.Create( self );
try
frm.Actions := actions; // (1)
frm.PopupParent := self; // (2)
frm.ShowModal;
finally
frm.Free;
end;
end;
When executed in this order, the modal form shows correctly on top of the main form. But when I reverse the lines, the modal form hides behind main. The line marked (1) sets a property of the modal form, which results in several checkboxes being checked on unchecked in a TRzCheckGroup, sitting on a TRzPageControl (from Raize components). This is the setter method that runs when line (1) above executes:
procedure TDBMaintenanceForm.SetActions(const Value: TMaintenanceActions);
var
ma : TMaintenanceAction;
begin
for ma := low( ma ) to high( ma ) do
cgMaintActions.ItemChecked[ ord( ma )] := ( ma in Value );
end;
end;
This is enough for the modal form to show behind the main form if the order of the lines (1) and (2) is reversed.
This might point to TRzCheckGroup (which gets manipulated when the setter code runs), but I have two other forms that show the same problem and do not use TRzCheckGroup (or TRzPageControl). And I could not reproduce the problem with a separate sample app using Raize components. Disabling the form, the pagecontrol or the TRzCheckGroup for the duration of the setter has no effect.
It does not appear to be a timing issue, because when the modal form shows hidden once, it always does. The change in behavior only comes from rearranging the lines of code.
3) One last observation: my modal forms are fairly simple, so they get displayed pretty much instantly, with no visible delay. But when the main form is fsStayOnTop, then very often I can see the modal form show on top of it, then see it get “pushed” behind. Then, on hitting Esc, the (invisible) modal form shows on top of the main form for a fraction of a second, then gets closed.
Either I‘m missing something that’ll seem obvious in hindsight, or this is a call for psychic debugging, I don’t know. Any ideas, please?
UPDATE. I’ve tried to track down the problem on another form where it occurs. It has a few buttons (Raize) and a TSyntaxMemo (an enhanced memo component from eControl.ru). This form has almost nothing in common with the other forms that experience the problem. After removing parts of the code and testing, I can now reproduce the problem by making a tiny change in a method that assigns a string to the memo component:
This is my original code, which causes the form containing the editor to hide behind the main form:
procedure TEditorForm.SetAsText(const Value: string);
begin
Editor.Text := Value;
end;
When I change the assignment to an empty string, the form displays correctly:
procedure TEditorForm.SetAsText(const Value: string);
begin
Editor.Text := ''; // CRAZY! Problem goes away
end;
When I assign a single character to the editor, the form starts hiding again:
procedure TEditorForm.SetAsText(const Value: string);
begin
Editor.Text := 'a'; // Problem is back
end;
Of course the other two problematic forms do not use this editor component or any of its units.
I've tried deleting the memo control and adding it again (think creation order etc.), but it had no effect. Same if I create the memo in code. The form hides as soon as a non-empty string is assigned to the memo's Text property.
I had the same issue some time ago. My solution was to add a Self.BringToFront; to the OnShow event of the modal form.
Windows does not support many top most forms for app. And modal form is topmost by default. But you have this style for your own form.
One decision in mind: remove top most of your main form (no visible effect), call modal form, set back topmost style when modal finished.

How to make a Drawn Line on a Form Invisible in Delphi 7

I am trying to make an analog clock, wherein I would like to make my 'seconds' Line Invisible when the Seconds Changes. I have tried to set the Pen mode to pmNotCopy but it only gives Inverse of Pen Color. What Property must be set in this Form1.Canvas.Pen.Mode:=<Blank> so that My Line Disappears?
Any other Ideas are also appreciated.
Thanks
Modern computers are very fast. If I were you, I'd definitely draw the entire clock from scratch every second. Problem solved. In addition, if you need anti-aliasing, then a simple pen mode trick will never work.
(If you are not using a remote desktop, you might want to employ double-buffering.)
I don't know anything about delphi but just some out if the box thinking:
couldn't you change the color of your line to the background color, making it 'invisible'
You were close. You need to use pmXOR.
Try this:
Create a new Delphi VCL Forms application. Drop a TButton on the bottom of the form (Button1).
Add the code below to the Button1Click event.
Run the application. Click the button, and three parallel lines will be drawn across the top. Click the button again, and the three lines will disappear.
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
Canvas.Pen.Mode := pmXor;
Canvas.Pen.Color := clGreen;
for i := 1 to 3 do
begin
Canvas.MoveTo(50, i * 20);
Canvas.LineTo(Width - 50, i * 20);
end;
end;
All drawing should normally be done in the OnPaint event; I'm intentionally drawing in the Button1Click event for demonstration reasons only.
Just as a note: You should never use Form1 inside an event handler for that form. Referencing the Form1 variable prevents you from creating more than one instance of the form. Use Self instead, and that will automatically refer to the instance the code is running in.

When I add a TPanel to a TToolBar, do I get a TPanel or a TToolButton?

When Delphi (2006) goes quantum: I've got "something" that appears to be both a TToolBar and a TPanel, depending on how you observe it. I'd like to understand what's going on.
Here is how to create it and what happens:
in the DFM
add a TToolBar named bar;
in that TToolBar, put a TPanel.
in the code and at runtime:
the panel appears in the list of buttons bar.Buttons[], let's say at index i
bar.Buttons[i], from the compiler point of view, is a TToolButton
bar.Buttons[i].ClassName = 'TPanel'
(bar.Buttons[i] is TToolButton) = true, but that's the compiler optimising the call to 'is' out;
indeed IsBarButton(bar.Buttons[i]) is false for function IsBarButton (defined below);
bar.Buttons[i].Name is the name I gave the TPanel in the DFM
inspecting the value bar.Buttons[i] in the debugging:
it has a property 'Caption' the real TToolButton's don't have
strangely, it has all properties TToolButton's have, like TToolButton.Indeterminate (=true).
IsToolButton:
function IsToolButton(X : TObject) : boolean;
begin
Result := X is TToolButton;
end;
So bar.Buttons[i] both is and is not a TToolButton... what's up ?
(Bottom story is I'd like to distinguish my TPanel from the genuine TToolButton's. This I can do in more or less hackish ways. My goal by asking this question here, is to get a fuller understanding of what's really happening here.)
Question: what is happening ?
Sub-question: is it legitimate to add a TPanel to a TToolBar ?
The only thing the OS allows to be added to a tool bar is a tool button. To add anything else, you technically need to create a button and then put your other things on top of it. The button that gets added is literally a placeholder. It's there to take up space so the next thing you add gets positioned properly.
You can see this sometimes if the non-tool-button control you add is transparent. Then you can see the tool bar's separator underneath, so it looks like there's a vertical line running through the middle of your control.
When you add a non-tool-button control to the tool bar, the Buttons property indeed lies about the type of the control. You'll notice throughout ComCtrls.pas that TToolBar itself always casts the buttons to TControl and then checks whether they really descend from TToolButton. It's completely legitimate to add non-buttons to a tool bar; that's why the Form Designer allows it in the first place.
I suggest you use the Form Designer to create your tool bar. That way, the IDE will maintain an identifier for you in your form, so you'll always have a direct reference to your panel. You won't have to go hunting for it in the tool bar. Even if you're creating the tool bar manually, it's a good idea to make an extra field to refer to the panel. Even if you move the panel around within the tool bar, it will still be the same object the whole time, so you needn't worry about dangling references.
When you put a couple of buttons and a panel on a toolbar, and a Memo somewhere, then run this code in the form's onCreate:
procedure TForm1.FormCreate(Sender: TObject);
function _IsToolButton(const aObject: TObject): Boolean;
begin
Result := aObject is TToolButton;
end;
function _IsPanel(const aObject: TObject): Boolean;
begin
Result := aObject is TPanel;
end;
var
i: Integer;
begin
for i := 0 to bar.ButtonCount - 1 do begin
Memo.Lines.Add(Format('bar.Buttons[%d].Name: %s', [i, bar.Buttons[i].Name]));
Memo.Lines.Add(Format('bar.Buttons[%d].ClassName: %s', [i, bar.Buttons[i].ClassName]));
Memo.Lines.Add(Format('bar.Buttons[%d] is TToolButton: %s', [i, BoolToStr(_IsToolButton(bar.Buttons[i]), True)]));
Memo.Lines.Add(Format('bar.Buttons[%d] is TPanel: %s', [i, BoolToStr(_IsPanel(bar.Buttons[i]), True)]));
// Memo.Lines.Add(Format('bar.Buttons[%d] has Caption property: %s', [i, 'dunno yet']));
Memo.Lines.Add('');
end;
end;
you'll see that the panel is not a TooButton and most definitely a TPanel.
The debugger showing properties of a ToolButton for the panel, is simply the debugger casting each and every bar.Buttons[i] to a TToolButton. When you right-click on the "Data" tab of the Debug inspector, you can Type Cast it to a TPanel and you will get the correct information.
'is it legitimate?' - well, you are definitely using the toolbar in a way that the creator of the toolbar did not ment it to be used. Will it blow up in your face? Who knows. I guess you could walk through the sourcecode for the toolbar and check if it is safe or not, but what about possible third party tools or components, expecting to find buttons in a toolbar?
I would see if I could find another way of solving my problem. Clever hacks have a tendency to turn out not so clever after all, and it will surely higten the wtf-rate of your code.
Do you have to use a toolbar? What about a flowpanel with buttons and panels instead? Or a panel with a toolbar and a panel?

Making a TPageControl flat in Delphi 7

I don't know whether this question can be answered here, but I hope it will.
I wrote a simple text editor in Delphi 7 that serves as my primary IDE for writing C code under Windows. I run Windows in a VM and I needed something light.
In any case, it uses a TpageControl that gets a new tab whenever you open or create a new file. Pretty standard.
Now, the TPageControl under Delphi has no flat property.
NO I don't mean setting the tab style to tsButtons or tsFlatButtons
the borders cannot be set to "none" and it looks pretty bad when you add a text editor into the tab control.
Is there any way to make a TpageControl flat?
EDIT:
On an open source PageControl that supports flat here's what I found:
procedure TCustomTabExtControl.WndProc(var Message: TMessage);
begin
if(Message.Msg=TCM_ADJUSTRECT) and (FFlat) then
begin
Inherited WndProc(Message);
Case TAbPosition of
tpTop : begin
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Top:=PRect(Message.LParam)^.Top-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
tpLeft : begin
PRect(Message.LParam)^.Top:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Left:=PRect(Message.LParam)^.Left-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
tpBottom : begin
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Bottom:=PRect(Message.LParam)^.Bottom-4;
PRect(Message.LParam)^.Top:=0;
end;
tpRight : begin
PRect(Message.LParam)^.Top:=0;
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=PRect(Message.LParam)^.Right-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
end;
end else Inherited WndProc(Message);
end;
The thing is when I tried something similar on the main application it won't work. It won't even compile.
When the tabs are drawn as buttons, no border is drawn around the display area, so set the Style property to tsButtons or tsFlatButtons. (For non-VCL programmers, this is equivalent to including the tcs_Buttons window style on the tab control.)
An alternative is to use a TNotebook. It holds pages, but it doesn't do any painting at all. You'd have to provide the tabs yourself, such as by setting the tab control's height equal to the height of the tabs, or by using a TTabSet. (TTabSet is available in Delphi 2005; I'm not sure about Delphi 7.)
Regarding the code you found, it would be helpful if you indicated why it doesn't compile, or if you gave a link to where you found it, since I suppose the compilation error was because it refers to fields or properties of the custom class rather than the stock one. Here's what you can try to put it in your own code, without having to write a custom control.
Make two new declarations in your form like this:
FOldTabProc: TWndMethod;
procedure TabWndProc(var Msg: TMessage);
In the form's OnCreate event handler, assign that method to the page control's WindowProc property:
FOldTabProc := PageControl1.WindowProc;
PageControl1.WindowProc := TabWndProc;
Now implement that method and handle the tcm_AdjustRect messsage:
procedure TForm1.TabWndProc(var Msg: TMessage);
begin
FOldTabProc(Msg);
if Msg.Msg = tcm_AdjustRect then begin
case PageControl1.TabPosition of
tpTop: begin
PRect(Msg.LParam)^.Left := 0;
PRect(Msg.LParam)^.Right := PageControl1.ClientWidth;
Dec(PRect(Msg.LParam)^.Top, 4);
PRect(Msg.LParam)^.Bottom := PageControl1.ClientHeight;
end;
end;
end;
end;
You can fill in the other three cases if you need them. Tcm_AdjustRect is a message identifier declared in the CommCtrl unit. If you don't have that message in that unit, declare it yourself; its value is 4904.
I suspect this doesn't stop the control from drawing its borders. Rather, it causes the contained TTabSheet to grow a little bigger and cover up the borders.
I'm using Delphi XE8 and the following seems to do the trick:
ATabControl.Tabs.Clear;
ATabControl.Style := TTabStyle.tsFlatButtons;
ATabControl.Brush.Color := clWhite;
You could always use a commercial solution. I would strongly recommend Raize components, which support flat TPageControls with tabs. The component set is very easy to work with, and supports numerous visual enhancements which in my opinion give a better feel to any application.
(source: raize.com)
Drop two TPageControls, one with tabs as Tabs, with a global height equal to the tabs, and one with flatbuttons and Tabvisible properties set to false, which would be aligned under the first one. Then make sure the tab change on the first TPagecontrol makes the tabs also change in the second one.

Resources