Not able to use canvas function in Delphi 7 - delphi

I am beginning to learn GDI graphics in Delphi 7. I am having problems in drawing Ellipses , Text etc. on my Main form. Basically I use this code:
Form1.Canvas.TextOut(10,10,'sss');
Is this Canvas Property required to be associated with the Form? I haven't done any thing like that. Help will be appreciated.

Make sure you put all painting code in the form's OnPaint event handler (documentation). This handler is called whenever the form needs to be repainted.
procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.TextOut(10,10,'sss');
end;

Related

FMX: How can I get a forms mousemove events outside of the form

I have a form which I'm painting on (OnPaint). I give the user grips to click on and change the shape. However, I would like to allow the user to move past the edge of the form. How can I get the mouse moments when the mouse goes past the edge. I know this can be done because it works on a TrackBar. And while that is a Component and not a Form, I assume I can change the forms style or register something to make it act in a similar manor.
I plan on making the form background transparent so ideally, the same solution would allow me to get mousemoves over the transparent areas.
FMX uses the AutoCapture property for that. Then the mouse will be captured while the mouse button is down.
constructor TMyGrip.Create(AOwner: TComponent);
begin
inherited;
AutoCapture := True;
CanFocus := True;
end;
This does not work for a form. But you could add a TLayout on the form that fills the entire client.
FMX internally uses FWinService.SetCapture(Self); and FWinService.ReleaseCapture(Self); for this, and this accepts a form. I haven't tested this, but it could happen that you'll confuse the FMX framework quite a bit if you call the internal functions like that.

draw a close button in each Ttabsheet of a TPageControl

I want to implement a close button on a PageControl and I have read this question also How to implement a close button for a TTabsheet of a TPageControl
The thing is I can't figure it out how to implement the code provided in the answer of Ulrichb... are they building a new component descendant from TPageControl or not? if someone could explain where to write that certain code i would be thankfull! I have a single teacher who knows a little bit of delphi at my school but he couldn`t help me out..and I am sorry if this is a silly question but i am new to delphi and programming.
The code in the question you link to does not create a new component. Instead it implements custom drawing by using events of the page control. Specifically these events:
OnDrawTab
OnMouseDown
OnMouseMove
OnMouseLeave
OnMouseUp
You must use the Delphi form designer to connect these event handlers up to the matching events to make the code work.
This approach was probably chosen for simplicity when answering that question but it does not scale to an application with many forms that have page controls. In that situation you would want to derive a new page control component.
If you do that then, rather than using events, you need to override the following methods:
DrawTab
MouseDown
MouseMove
MouseUp
In addition to this you must replicate the OnMouseLeave behaviour. That requires a message handler.
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
....
procedure TMyPageControl.CMMouseLeave(var Message: TMessage);
begin
inherited;
if Message.LParam=0 then
begin
// move OnMouseLeave code here
end;
end;

Why doesn't OnUpdate trigger for invisible components [duplicate]

This question already has answers here:
How can I use an action to determine a control's visibility?
(3 answers)
Closed 8 years ago.
When I make a component invisible by setting the connected TAction to invisible, the onupdate event will not trigger anymore. To recreate, do the following.
Create a new VCL forms application
Drop a button, a checkbox and an actionlist on the form.
Create a new action, and connect the button to it.
Write the following code for the actions OnExecute and OnUpdate event:
procedure TForm1.Action1Execute(Sender: TObject);
begin
ShowMessage('Test');
end;
procedure TForm1.Action1Update(Sender: TObject);
begin
TAction(Sender).Enabled := not CheckBox1.Checked;
TAction(Sender).Visible := TAction(Sender).Enabled;
end;
Run the application. The button is visible, and works properly. Check the checkbox, and the button disappears. Uncheck the checkbox. The button doesn't appear. In fact, if you put a breakpoint in Action1Update, you'll never get to it. Why is this, and how do I fix it?
No need to fix this, it works as designed. Only visible controls need to update their state, so only actions whose linked controls are visible are updated. When you hide the button there's no more reason to update the action.
Have the OnUpdate only call a separate routine that does what is required. Then you can call that routine from other places. Action lists were designed for that.
I understand what you're trying to do, and it makes sense that you would want it to work that way. However, here's a workaround for the way it does work.
You can update other controls in an OnUpdate also. You're not limited to updating the control that receives the notification. So, in the action for the control that determines visibility, you can set the visibility of the other controls there. In your case, that's the checkbox:
Create a new action (Action2) and assign it to Checkbox1.
Then in the checkbox action's OnUpdate:
procedure TForm1.Action2Update(Sender: TObject);
begin
Button1.Visible := TAction(Sender).Checked;
end;
Be sure to assign an OnExecute to the checkbox as well. Something as simple as this is fine:
procedure TForm1.Action2Execute(Sender: TObject);
begin
TAction(Sender).Checked := not TAction(Sender).Checked;
end;
To me, this still makes logical sense. You'll be able to look in one spot to see all of the controls whose visibility relies on that checkbox being set.
You can override the InitiateAction method on the form. This will happen whenever the application goes idle, just as on OnUpdate event does for each action.

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.

Custom drawing in TListview descendant

I have a descendant of TListView that offers some additional features, such as sorting and ability to load itself from a TDataset. I now wish to extend this component further so that certain aspects of the drawing can be specified at the time items are added to the list view.
I'm having trouble figuring out which procedure or procedures to override to take control of the drawing. I have overridden DrawItem to change the font style to include strikethrough and then call the inherited DrawItem. If I also specify the style LVS_OWNERDRAWFIXED (in an overriden CreateParams()) my function is called and works as I want except that only the item, and not the subitems, is drawn.
Does anyone know how I can tell the list view to draw the subitems also? I've found one example of a substantially enhanced list view, but this one isn't sufficiently well documented for me to follow exactly what's going on, and I'm hoping not to have to hook quite as many events and windows messages as this one does — it seems to me that simply setting the canvas pen, brush, and font and then having the item draw itself should not be quite so involved.
Here's what I have so far:
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure DrawItem(Item: TListItem; Rect: TRect; State: TOwnerDrawState); override;
procedure TLookupListView.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style or lvs_OwnerDrawFixed;
end;
procedure TLookupListView.DrawItem(Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var I: Integer;
Left: Integer;
begin
Canvas.Font.Style := Canvas.Font.Style + [fsStrikeOut];
inherited DrawItem(Item, Rect, State);
//I know the canvas must be restored here, this is just for proof-of-concept.
end;
PLEASE NOTE: I'm not interested in doing custom drawing in a particular instance of TListView using the supplied events. I know how to do that. I'm trying to "bake in" this functionality to my custom TListview descendant component.
The component has a virtual method IsCustomDrawn() which is called to determine which code paths need to be executed. In the base class implementation it checks whether any of the event handlers to paint the subitems is assigned, but you can override the method to return True for all those paint stages you want handled, even when there is no event handler assigned.
If you want to handle everything in code you should probably override CustomDrawItem() and CustomDrawSubItem() and do everything there. To get everything working I would build the app with debug DCUs, step into from event handlers and look around what the minimum amount of code you can get away with is. The important method to check out is TCustomListView.CNNotify() - here the Windows messages for owner drawing are handled.
Edit:
I forgot to add that you should try to not owner draw the text in the control, but just to set canvas properties in the various paint stages - the reason being that otherwise you will have to make sure that text output is pixel-perfect in all Windows versions, something that the VCL doesn't achieve. You can see this by adding a few columns and rows to a list view and toggling the OwnerDraw property at design time, the text jumps around.
Which version of Delphi are you using? In Delphi 2007 TListView has support for custom-drawing by handling NM_CUSTOMDRAW messages, as described here. TListView already has events defined for custom-drawing subitems, as well as virtual methods you can override in your descendant.

Resources