Tell me, please, how can I implement text input / output on canvas, as it is done in the new Paint
in Windows7
, with the ability to edit the text, change the font and so on. Or, how to write a component like RichEdit
, but with the ability to make it transparent and output the text from it to the canvas.
4 answers
That's right, I didn’t have to draw the text to the canvas, of course, I can come up with an algorithm, but for now, I think this code will help: I once wrote a graphic editor on a course, outputting text using this algorithm:
- Select the "Text" button and then click on the desired place in the Image;
- Then I print the form-mini-text editor where you need to enter text;
- Next, enter the text and customize: font, color, angle, etc., or click Cancel;
- We press on the button - the text is as needed.
Procedure Code:
procedure TGraphEditorForm.ImageEditMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); Var OldBkFontColor: TColorRef; // цвет шрифта OldBkBGColor: TColorRef; // цвет под текстом OldBkMode: Integer; begin // ...................... // If (SpeedButtonText.Down) Then Begin ModRes:=TextForm.ShowModal; // вызываю форму для набора текста SpeedButtonText.Down:=False; // утопил кнопку на главной форме If (ModRes=mrCancel) Then // если отмена, то Begin MessageBox(0, PChar('Добавление текста отменено.'), PChar('Графический редактор'), MB_OK Or MB_ICONINFORMATION Or MB_APPLMODAL Or MB_TOPMOST); SpeedButtonText.Down:=False; End Else // иначе: добавляю текст Begin ImagePicture.Canvas.Font:=TextForm.FontDialog.Font; // устанавливаю шрифт If (TextForm.ColorDialog.Color<>clWhite) Then // если цвет под текстом не белый Begin OldBkFontColor:=SetTextColor(ImagePicture.Canvas.Handle, TextForm.FontDialog.Font.Color); // устанавливаю цвет текста и запоминаю цвет шрифта OldBkBGColor:=SetBkColor(ImagePicture.Canvas.Handle, TextForm.ColorDialog.Color); // устанавливаю цвет под текстом и запоминаю старый OldBkMode:=SetBkMode(ImagePicture.Canvas.Handle, OPAQUE); // режим рисования (установил новый и запомнил старый) CanvasSetAngle(ImagePicture.Canvas, TextForm.SpinEditAngle.Value); // устанавливаю угол вывода текста ImagePicture.Canvas.TextOut(X, Y, TextForm.LabeledEdit.Text); // вывожу сам текст (* возвращаю старые настройки, установленные ранее *) SetBkMode(ImagePicture.Canvas.Handle, OldBkMode); SetBkColor(ImagePicture.Canvas.Handle, OldBkBGColor); SetTextColor(ImagePicture.Canvas.Handle, OldBkFontColor); End Else Begin CanvasSetAngle(ImagePicture.Canvas, TextForm.SpinEditAngle.Value); // устанавливаю угол вывода текста ImagePicture.Canvas.TextOut(X, Y, TextForm.LabeledEdit.Text); // устанавливаю угол вывода текста End; End; End; // ...................... // end;
I must say that this is not all that you can do with the font in graphics mode: somewhere (I don’t remember exactly where, probably in a large database, know Delphi) saw that you can change the weight, height and something else in the font .
And something like that, I believe, can be done like this:
- On the OnMouseMove handler for Image, draw a frame for the text (create a flag and assign truth to it);
- On a key press event, write text to it (if flag = true), if key = Enter finish input (assign false to the flag and draw a frame, but for the frame to be erased correctly) 2 Image components are required: on one we draw and select everything (it should be transparent) (Transparent = True, color of transparency - by default - the very first lower point of the Image component))). I'll try to do it, but I promise nothing.
It seems to be something like this (such as a transparent Memo-field (RichEdit instead of Memo also goes)). At once I will say that there is one drawback: you cannot resize with a mouse (you can think about how to do it, but I have no time).
The idea is:
- We create a project by throwing 2 Image components (first on the other) so that they have the same size and one lies exactly under the other, well, the SpeedButton button (AllowAllUp = True, GroupIndex = (not zero)).
- Add a form to the project, on which we throw Memo or RichEdit.
- We stretch these components to the entire shape (Align = alClient).
- For the form, set the property Transparent = true and TransparentColor choose any color (but not the one that can have a font, although you can also change it programmatically, of course, if necessary).
- For the RichEdit or Memo component, set the background color of the form, like the TransparentColor.
With the development of forms you can do away - we proceed to coding (I will describe in brief):
- Select the rectangular area with the OnMouseMove handler of the Image component.
- Then, on the OnMouseUp handler, we show our second form in it.
- We write the text, we close by pressing Enter.
Further, I hope, in the code everything will be clear.
CODE of the main form (the other one doesn’t need to write anything with his hands, just set the properties!)
var Form1: TForm1; StrMas: Array[0..199] Of ShortString; TextInImage, AllText: String; StartX, StartY, OldX, OldY, Wdt, Hgt, TextX, TextY, LineInd: Integer; Drag, DragShape: Boolean; implementation uses TextEditorUnit; {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin OldX:=0; OldY:=0; StartX:=0; StartY:=0; AllText:=''; TextInImage:=''; Image.Canvas.Brush.Color:=clWhite; Image.Canvas.FillRect(Rect(0, 0, Image.Width, Image.Height)); ImagePic.Canvas.Brush.Color:=clWhite; ImagePic.Canvas.FillRect(Rect(0, 0, ImagePic.Width, ImagePic.Height)); ImagePic.Canvas.Font:=FontDialog.Font; end; procedure TForm1.ImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin // устанавливаю параметры If (SpeedButtonText.Down) Then Begin StartX:=X; StartY:=Y; Drag:=True; TextInImage:=''; End; end; procedure TForm1.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin If Not(SpeedButtonText.Down) Then Exit; If Not(Drag) Then Exit; With Image.Canvas Do Begin // закрашиваю область Pen.Color:=clWhite; Pen.Style:=psSolid; Rectangle(StartX, StartY, OldX, OldY); // перерисовываю область Pen.Color:=clFuchsia; Pen.Style:=psDash; Rectangle(StartX, StartY, X, Y); End; // изменяю старые координаты OldX:=X; OldY:=Y; end;
Code Continuation
procedure TForm1.ImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); Var i, N, mr, OldBkMode: Integer; Str: String; begin If Not (SpeedButtonText.Down) Then Exit; // сбрасываю параметры Drag:=False; Wdt:=Abs(StartX-OldX); Hgt:=Abs(StartY-OldY); TextX:=StartX; TextY:=StartY; SpeedButtonText.Down:=False; // устанавливаю форму в выделенную рамку If (StartX<OldX) Then TextEditorForm.Left:=StartX+Image.Left+ScrollBox.Left+Form1.Left+3 Else TextEditorForm.Left:=OldX+Image.Left+ScrollBox.Left+Form1.Left+3; If (StartY<OldY) Then TextEditorForm.Top:=StartY+Image.Top+ScrollBox.Top+Form1.Top+22 Else TextEditorForm.Top:=OldY+Image.Top+ScrollBox.Top+Form1.Top+22; // подгоняю размер формы TextEditorForm.Width:=Wdt+4; TextEditorForm.Height:=Hgt+4; // PS константные значения могут различаться, т. к. это пиксели mr:=TextEditorForm.ShowModal; // показываю форму N:=TextEditorForm.Memo.Lines.Count-1; // кол-во введённых строк // закрашиваю область With Image.Canvas Do Begin Pen.Color:=clWhite; Pen.Style:=psSolid; Rectangle(StartX, StartY, OldX, OldY); End; ImagePic.Picture.Bitmap.Canvas.Font:=FontDialog.Font; // OldBkMode:=SetBkMode(ImagePic.Picture.Bitmap.Canvas.Handle, TRANSPARENT); // Закомментированные процедуры работают только в цикле почему-то... // Так не прокатывает With ImagePic.Canvas Do Begin // Построчно вывожу текст For i:=0 To N Do Begin Str:=TextEditorForm.Memo.Lines.Strings[i]; OldBkMode:=SetBkMode(ImagePic.Picture.Bitmap.Canvas.Handle, TRANSPARENT); TextOut(StartX, StartY, Str); SetBkMode(ImagePic.Picture.Bitmap.Canvas.Handle, OldBkMode); StartY:=StartY+TextHeight(Str)+2; End; End; // SetBkMode(ImagePic.Picture.Bitmap.Canvas.Handle, OldBkMode); TextEditorForm.Memo.Lines.Clear; end; procedure TForm1.ButtonFontClick(Sender: TObject); begin If Not(FontDialog.Execute) Then Exit; TextEditorForm.Memo.Font:=FontDialog.Font; Image.Canvas.Font:=FontDialog.Font; ImagePic.Canvas.Font:=FontDialog.Font; end; procedure TForm1.ButtonOpenImageClick(Sender: TObject); begin If Not(OpenPictureDialog.Execute) Then Exit; ImagePic.Picture.LoadFromFile(OpenPictureDialog.FileName); Image.Width:=ImagePic.Width; Image.Height:=ImagePic.Height; end; end.
If something is not clear, I can send the source to E-mail.
You can do this:
- Having processed the MouseClick event on Image, when clicked, we remember the position where we clicked (X1, Y1)
- Next, handle the event MouseButtonDown (like), draw a frame from X1, Y1 to the current position of the mouse, and of course we remember X2, Y2
- Handle the MouseButtonUp event, i.e. when the button is released, we create the RichEdit element in X1, Y1, set the dimensions to X2, Y2, set the frame property - is absent, and focus on it.
- For the created RichEdit, we process the exit event from it, that is, when we switch to the canvas, we write the value from RichEdit to the string variable, after which we print this variable using the Canvas TextOut function to X1, Y1, or in the center of the rectangle from X1, Y1 to X2, Y2
Delphi is not worth it now, so I can not give an example) But the logic seems to be this) Be creative)
Text output to canvas
...canvas.textout(x,y,text)
http://www.beluch.ru/progr/100comp/3_2.htm
For example, the text from Edit'a
will be black and transparent in the Image1
image, that is, there will be no background.
Image1.Canvas.Font.Color:=clBlack; Image1.Canvas.Brush.Style:=bsClear; Image1.Canvas.TextOut(5,5,Edit1.text);