Здравствуйте, Аноним, Вы писали:
VS>>Возникла необходимость печатать по кругу. Скажите куда посмотреть? А>А нельзя ли поподробнее, что значит, "печатать по кругу"?
ну типа как на компакт дисках
С Уважением.
Re[3]: круговая печать
От:
Аноним
Дата:
20.09.06 12:39
Оценка:
VS>ну типа как на компакт дисках
Т.е. тебе текст надо выводить не прямой, а по какому-то пути?
VS>>а если серьезно, то вроде как там только 2 функции вывода текста TextOut и DrawText
mcf>Дык печатай каждую буковку отдельно, определяй местоположение и наклон.
это первое что пришло мне в голову, но возможно есть какое-то готовое решение? API?
Здравствуйте, Viktor Sklyar, Вы писали:
VS>Здравствуйте, mcf, Вы писали:
VS>это первое что пришло мне в голову, но возможно есть какое-то готовое решение? API?
agg умеет рисовать текст вдоль кривой.
см. здесь
Здравствуйте, dotidot, Вы писали:
D>Здравствуйте, Viktor Sklyar, Вы писали:
VS>>Здравствуйте, mcf, Вы писали:
VS>>это первое что пришло мне в голову, но возможно есть какое-то готовое решение? API? D>agg умеет рисовать текст вдоль кривой. D>см. здесь
вот спасибо, такой библиотеки я еще не видел. Прекрасная работа.
вот. буду переделывать на С++, результаты мне нравятся
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Math, Menus, Spin;
type
TForm1 = class(TForm)
GroupBox1: TGroupBox;
SpinEdit1: TSpinEdit;
SpinEdit2: TSpinEdit;
MainMenu1: TMainMenu;
Font1: TMenuItem;
FontDialog1: TFontDialog;
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Font1Click(Sender: TObject);
private{ Private declarations }public{ Public declarations }end;
var
Form1: TForm1;
implementation{$R *.DFM}var
OS: OSVERSIONINFO;
IsNT,
FChanged: Boolean;
procedure CanvasTextOutAngle(c: TCanvas; x,y: Integer; d: Integer; s: string);
{-----------------------------------------------------------
PURPOSE
To output rotated text in the same font as the font on
the supplied canvas. The font must also be a scaleable
font.
INPUT PARAMETERS
c - The canvas on which to output the text. The font for
the canvas must be a scalable font.
x,y - The x,y screen coordinates you would normally
supply the TextOut procedure.
d - The angle in tenths of degrees. For example 10 would
be 1 degree. 450 would be 45 degrees. 1 would be
1/10 of a degree.
s - The text to be output to the canvas.
HISTORY
6/18/1995 First version written by Curtis Keisler.
11/23/1999 First version written by Walter Schick walter@xynx.com.
Added support for Win NT, speeded-up somewhat, cleaned-up code.
-----------------------------------------------------------}var
LogRec: LOGFONT; //Storage area for font information
OldFontHandle, //The old font handle
NewFontHandle: HFONT; //Temporary font handlebegin
if (IsNT) and (d>6000) then d:=d-740;
SetTextAlign(c.Handle, TA_BASELINE);
GetObject(c.Font.Handle, SizeOf(LogRec), @LogRec);
LogRec.lfEscapement:=d;
if (IsNT) then LogRec.lfOrientation:=-d;
LogRec.lfQuality:=PROOF_QUALITY;
NewFontHandle:=CreateFontIndirect(LogRec);
OldFontHandle:=SelectObject(c.Handle,NewFontHandle);
TextOut(c.Handle, x, y, PChar(s), 1);
NewFontHandle:=SelectObject(c.Handle,OldFontHandle);
DeleteObject(NewFontHandle);
end;
procedure CircularText(c: TCanvas; CenterX, CenterY: Integer; Radius: Integer;
StartAngle: Integer; s: string; Style: Integer);
{-----------------------------------------------------------
PURPOSE
Calculates the position and angle of each character
from the input string; they are drawn inside a circle
defined by its center and radius, starting from the top
INPUT PARAMETERS
c - The canvas on which to output the text. The font for
the canvas must be a scalable font.
CenterX, CenterY - The circle center screen coordinates.
Radius - The circle radius length.
StartAngle - Angle where writing begins
s - The text to be output to the canvas.
Style - 0 : Left-Justified
1 : Center-Justified
1 : Right-Justified
CALLS
Calls CanvasTextOutAngle
HISTORY
4/30/1999 Added Center- and Right-justified text
4/29/1999 Straighten up trigonometry: removed fudge factor;
added StartAngle
4/27/1999 First version written by Jacques Oberto.
11/23/1999 Modifications written by Walter Schick.
Added Options and fonts, cleaned-up some code,
some other minor changes
-----------------------------------------------------------}var
RotAngle: Extended; //Rotation angle of each character
PosAngle: Extended; //Angle on the circle at which to draw each character
TotalAngle: Extended; //Cumulated RotAngles
Offset: Extended; //Angle between left and middle of the character
FinalAngle: Extended; //Total angle ocupied by text
DummyAngle: Extended;
i: Integer;
begin
FinalAngle:=0;
//calculated total angle occupied by textfor i:=1 to length(s) do FinalAngle:=FinalAngle + ArcSin((c.TextWidth(s[i]))/Radius);
case Style of
1: DummyAngle:=FinalAngle / 2;
2: DummyAngle:=FinalAngle;
ELSE
DummyAngle := FinalAngle
end;
Startangle:=StartAngle - Round(RadToDeg((DummyAngle))) +
Round(RadToDeg(ArcSin((c.TextWidth(s[1])/2)/Radius)));
TotalAngle:=0 ;
for i:=1 to length(s) do
begin//Trigonometry: angle = ArcSin(opposite side / adjacent side)
Offset:=ArcSin((c.TextWidth(s[i])/2)/Radius);
RotAngle:=RadToDeg(TotalAngle) + StartAngle;
//We want 0 degree on top of the circle so we need to remove 90 degrees
PosAngle:=DegToRad(Rotangle-90);
CanvasTextOutAngle(Form1.Canvas,
//x coord on the circle circumference, for a given angle & radius
Round((Radius )*cos(PosAngle-Offset))+ CenterX,
//y coord , same
Round((Radius )*sin(PosAngle-Offset))+ CenterY,
//Angle in 10th degrees, negative because rotation is opposite
Round(RotAngle * -10), s[i]);
//Increases TotalAngle by half angle of character + half angle of next characterIF i < LENGTH(s) // efg, 23 Jan 2000. Avoid range check error.THEN TotalAngle:=TotalAngle + ArcSin((c.TextWidth(s[i])/2 + c.TextWidth(s[i+1])/2)/Radius);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Form1.Refresh;
SetBkMode(Canvas.Handle,TRANSPARENT);
Canvas.Ellipse(4,4,350,350);
if not FChanged then
begin
Canvas.Font.Name:='Arial';
Canvas.Font.Size:=18;
end;
try
CircularText(Canvas, 178, 178, SpinEdit2.Value, SpinEdit1.Value, Edit1.Text, 1);
Except on EInvalidOp do
begin
MessageDlg('Please choose a greater radius', mtWarning, [mbOK], 0);
end;
end;
end;
procedure TForm1.Font1Click(Sender: TObject);
begin
if FontDialog1.Execute then
begin
Canvas.Font:=FontDialog1.Font;
FChanged:=true;
end;
end;
begin
OS.dwOSVersionInfoSize:=SizeOf(OSVERSIONINFO);
GetVersionEx(OS);
IsNT:=OS.dwPlatformId=VER_PLATFORM_WIN32_NT;
end.
Для получения параметров текущего шрифта можно использовать функцию GetObject примерно таким (для Win API) образом (подсмотрено в MFC в реализации CFont::GetLogFont):
LOGFONT lgFont; // создаем структуру на стеке, LocalAlloc/LocalFree, new/delete здесь незачем использовать
HFONT hFont; // здесь должен быть хэндл текущего шрифта
HFONT hNewFont = NULL; // здесь будет хэндл нового шрифтаif (::GetObject(hFont, sizeof(lgFont), &lgFont))
{
// меняем нужные поля в lgFont;
// ...
// Создаем шрифт c модифицированными параметрами
hNewFont = ::CreateFontIndirect (&lgFont);
if (hNewFont != NULL)
{
// выбираем новый шрифт в контексте устройства и печатем что хотим
}
}
На счет WTL не знаю, но, возможно, что у CFont есть готовая функции типа GetLogFont.
Если нет, то вышеприведенный код переделать для WTL нетрудно.
void TextOutAngle(CDC & dc, int x, int y, int d, CString & s)
{
dc.SetTextAlign(TA_BASELINE);
CFont oldFont = dc.GetCurrentFont();
LOGFONT lf;
oldFont.GetLogFont(lf);
strcpy(lf.lfFaceName, "Arial"); //только вот незадача, тут если не выбирать самому шрифт
//(а его выбирать не нужно, а использовать текущий), то буквы не поворачиваются!!)
//вот у меня в тестовом приложении вообще по умолчанию System Font
lf.lfQuality = PROOF_QUALITY;
lf.lfEscapement = d;
CFont newFont;
newFont.CreateFontIndirect(&lf);
dc.SelectFont(newFont);
dc.TextOut(x, y, s, 1);
dc.SelectFont(oldFont);
}
V>несколько смущает вызов функции без ссылки на графические контекст
Это нормально, т.к. сам по себе шрифт существует отдельно от контекста устройства,
это самостоятельный объект ОС. В контексте устройства сам шрифт не хранится,
используется только его хэндл как указатель на объект.
Соответственно, если у нас уже есть хэндл шрифта,
то для получения информации о шрифте контекст устройства не нужен. Ты же не используешь
контекст устройства при вызове CreateFontIndirect.
Здравствуйте, Alex_Avr, Вы писали:
A_A>Это нормально, т.к. сам по себе шрифт существует отдельно от контекста устройства, A_A>это самостоятельный объект ОС. В контексте устройства сам шрифт не хранится, A_A>используется только его хэндл как указатель на объект.
A_A>Соответственно, если у нас уже есть хэндл шрифта, A_A>то для получения информации о шрифте контекст устройства не нужен. Ты же не используешь A_A>контекст устройства при вызове CreateFontIndirect.
да, я понимаю, но на входе имеем только HDC и от него мы пляшем
V>void TextOutAngle(CDC & dc, int x, int y, int d, CString & s)
V>{
// ...
V> LOGFONT lf;
V> oldFont.GetLogFont(lf);
V> strcpy(lf.lfFaceName, "Arial"); //только вот незадача, тут если не выбирать самому шрифт
V> //(а его выбирать не нужно, а использовать текущий), то буквы не поворачиваются!!)
V> //вот у меня в тестовом приложении вообще по умолчанию System Font
V> lf.lfQuality = PROOF_QUALITY;
V> lf.lfEscapement = d;
// ...
V>}
V>
Похоже, что дело в том, что системный шрифт по умолчанию является растровым
(типа FixedSys/MS Sans Serif/MS Serif), а не векторным (TrueType/OpenType шрифтом, типа Aria/Times New Roman/Helvetica).
Вращение же растровых шрифтов Win API не поддерживает.