- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一些执行自定义绘图的代码。基本上它是具有所见即所得编辑器的表格填充程序。编辑器允许设置缩放级别。我的标签宽度相对于表单上的其他所有内容跳转到不同大小时遇到问题。
我用来输出文本的代码示例如下。我很确定问题与字体大小的变化与其他所有内容的缩放方式不匹配有关。缩放级别必须改变足够大,以便在文本更改之前将字体提升到下一个大小,即使表单上的所有其他内容都随着每次更改而移动几个像素。
这会导致两个不同的问题 - 文本可能看起来很小但有很多空白,或者文本将是两个大的并且与下一个控件重叠。当我有一行完整的文本时,事情看起来真的很糟糕。一个单词标签的变化不足以导致任何问题。
我曾考虑过限制缩放级别 - 现在我有一个以 1% 为增量的滑块。但我看不出任何一组级别比任何其他级别更好。我的表单有多个不同字体大小的标签,它们在不同时间在较短和较长之间跳跃。
MultDiv 函数对结果进行四舍五入。我可以截断这个值以确保我总是更小而不是更长,但这看起来同样糟糕,因为在这些缩放级别下间隙看起来要大得多。
代码注意事项:
这是目前在 Delphi 7 上的。这是我们最后一个没有向前推进的项目,因此欢迎提供与 Delphi 新版本相关的答案。
我们对此进行了调查,我确实看到存在 ExtDrawText 函数。但是,更改为该功能似乎并没有什么不同。
边界框的右侧设置为 0 并且文本绘制时没有剪切,因为我们用于构建表单定义的工具不会跟踪文本的右边界。我们只是在视觉上将其排列到正确的位置。
procedure OutputText(Canvas: TCanvas; LineNumber: integer; CurrentZoomLevel: integer; FontSize: integer; Text: string);
const
FormatFlags = DT_BOTTOM + DT_SINGLELINE + DT_NOPREFIX + DT_LEFT + DT_NOCLIP;
var
OutputBox: TRect;
ZoomedLineHeight: integer;
begin
ZoomedLineHeight := MulDiv(UnZoomedLineHeight, CurrentZoomLevel, 96);
Canvas.Font.Height := -MulDiv(FontSize, CurrentZoomLevel, 96);
OutputBox.Left := ZoomedLineHeight;
OutputBox.Right := 0;
OutputBox.Top := (LineNumber * ZoomedLineHeight);
OutputBox.Bottom := OutputBox.Top + ZoomedLineHeight;
DrawText(Canvas.Handle, PChar(Text), length(Text), OutputBox, FormatFlags);
end;
procedure DrawGrid(Canvas: TCanvas);
var
StartPt: TPoint;
EndPt: TPoint;
LineCount: integer;
HeaderString: string;
OutputBox: TRect;
begin
Canvas.Pen.Style := psSolid;
Canvas.Pen.Width := 1;
StartPt.X := 0;
StartPt.Y := LineHeight;
EndPt.X := Canvas.ClipRect.Right;
EndPt.Y := LineHeight;
LineCount := 0;
while (StartPt.Y < Canvas.ClipRect.Bottom) do
begin
StartPt.Y := StartPt.Y + LineHeight;
EndPt.Y := EndPt.Y + LineHeight;
Inc(LineCount);
if LineCount mod 5 = 0 then
Canvas.Pen.Color := clRed
else
Canvas.Pen.Color := clBlack;
Canvas.MoveTo(StartPt.X, StartPt.Y);
Canvas.LineTo(EndPt.X, EndPt.Y);
end;
StartPt.X := 0;
StartPt.Y := 2 * LineHeight;
EndPt.X := 0;
EndPt.Y := Canvas.ClipRect.Bottom;
LineCount := 0;
while StartPt.X < Canvas.ClipRect.Right do
begin
StartPt.X := StartPt.X + LineHeight;
EndPt.X := EndPt.X + LineHeight;
Inc(LineCount);
if LineCount mod 5 = 0 then
Canvas.Pen.Color := clRed
else
Canvas.Pen.Color := clBlack;
Canvas.MoveTo(StartPt.X, StartPt.Y);
Canvas.LineTo(EndPt.X, EndPt.Y);
if Canvas.Pen.Color = clRed then
begin
HeaderString := IntToStr(LineCount);
OutputBox.Left := StartPt.X - (4 * LineHeight);
OutputBox.Right := StartPt.X + (4 * LineHeight);
OutputBox.Top := 0;
OutputBox.Bottom := OutputBox.Top + (LineHeight * 2);
DrawText(Canvas.Handle, PChar(HeaderString), Length(HeaderString),
OutputBox, DT_BOTTOM + DT_SINGLELINE + DT_NOPREFIX + DT_CENTER);
end;
end;
end;
procedure OutputText(Canvas: TCanvas; LineNumber: integer; Text: string);
const
FormatFlags = DT_BOTTOM + DT_SINGLELINE + DT_NOPREFIX + DT_LEFT + DT_NOCLIP;
var
OutputBox: TRect;
begin
OutputBox.Left := LineHeight;
OutputBox.Right := 0;
OutputBox.Top := (LineNumber * LineHeight);
OutputBox.Bottom := OutputBox.Top + LineHeight;
Windows.TextOut(Canvas.Handle, OutputBox.Left, OutputBox.Top, PChar(Text), Length(Text));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered := false;
end;
procedure TForm1.FormResize(Sender: TObject);
begin
Invalidate;
end;
procedure TForm1.FormPaint(Sender: TObject);
const
ShortString = 'Short';
MediumString = 'This is a little longer';
LongString = 'Here is something that is really long here is where I see the problem with zooming.';
PhysicalHeight = 500;
PhysicalWidth = 400;
var
DC: HDC;
OldMode, i, xy: integer;
LF: TLogFont;
OldFont: HFONT;
begin
Canvas.Brush.Style := bsClear;
FillChar(LF, SizeOf(TLogFont), 0);
LF.lfOutPrecision := OUT_TT_ONLY_PRECIS;
LF.lfFaceName := 'Arial';
LF.lfHeight := -12;
DC := Self.Canvas.Handle;
OldMode := SetMapMode(DC, MM_ISOTROPIC);
// OldMode := SetMapMode(DC, MM_HIMETRIC);
SetWindowExtEx(DC, PhysicalWidth, PhysicalHeight, nil);
SetViewportExtEx(DC, Self.Width, Self.Height, nil);
try
OldFont := Windows.SelectObject(DC, CreateFontIndirect(LF));
DrawGrid(Self.Canvas);
OutputText(Self.Canvas, 3, ShortString);
OutputText(Self.Canvas, 4, MediumString);
OutputText(Self.Canvas, 5, LongString);
DeleteObject(SelectObject(DC, OldFont));
finally
SetMapMode(DC, OldMode);
end;
end;
最佳答案
根本问题是您试图通过更改 Height
来缩放文本。 .鉴于 Windows API 使用整数坐标系,因此只有某些离散的字体高度是可能的。例如,如果您的字体高 20 像素,缩放值为 100%,那么您基本上只能设置为 5% 倍数的缩放值。更糟糕的是,即使使用 TrueType 字体,也并非所有这些字体都能提供令人满意的结果。
多年来,Windows 已经有了处理这个问题的工具,遗憾的是 VCL 没有包装(并且它也没有真正在内部使用) - 映射模式。 Windows NT 介绍 transformations ,但是 SetMapMode()
已经在 16 位 Windows IIRC 中可用。
通过设置像 MM_HIMETRIC
这样的模式或 MM_HIENGLISH
(取决于您以米还是弗隆来衡量)您可以计算字体高度和边界矩形,并且由于像素非常小,因此可以精细地放大或缩小。
通过设置 MM_ISOTROPIC
或 MM_ANISOTROPIC
在 OTOH 模式下,您可以继续使用相同的字体高度和边界矩形值,并且只要缩放值发生变化,您就可以调整页面空间和设备空间之间的转换矩阵。
SynEdit 组件套件曾经有一个使用 MM_ANISOTROPIC
的打印预览控件(在 SynEditPrintPreview.pas 文件中)。映射模式以允许在不同缩放级别预览可打印文本。如果它仍然在 SynEdit 中或者如果您可以找到旧版本,这可能很有用。
编辑:
为方便起见,使用 Delphi 4 和 Delphi 2009 进行测试的小演示:
procedure TForm1.FormCreate(Sender: TObject);
begin
ClientWidth := 1000;
ClientHeight := 1000;
DoubleBuffered := False;
end;
procedure TForm1.FormPaint(Sender: TObject);
var
DC: HDC;
OldMode, i, xy: integer;
LF: TLogFont;
OldFont: HFONT;
begin
Canvas.Brush.Style := bsClear;
FillChar(LF, SizeOf(TLogFont), 0);
LF.lfOutPrecision := OUT_TT_ONLY_PRECIS;
LF.lfFaceName := 'Arial';
DC := Canvas.Handle;
OldMode := SetMapMode(DC, MM_HIMETRIC);
try
SetViewportOrgEx(DC, ClientWidth div 2, ClientHeight div 2, nil);
Canvas.Ellipse(-8000, -8000, 8000, 8000);
for i := 42 to 200 do begin
LF.lfHeight := -5 * i;
LF.lfEscapement := 100 * i;
OldFont := Windows.SelectObject(DC, CreateFontIndirect(LF));
xy := 2000 - 100 * (i - 100);
Windows.TextOut(DC, -xy, xy, 'foo bar baz', 11);
DeleteObject(SelectObject(DC, OldFont));
end;
finally
SetMapMode(DC, OldMode);
end;
end;
procedure TForm1.FormResize(Sender: TObject);
begin
Invalidate;
end;
ExtTextOut()
API 调用将可选的字符来源整数数组作为最后一个参数。我知道的大多数代码示例都没有使用它,但您可以使用它在某些字符之间插入额外的像素以将文本行的宽度拉伸(stretch)到所需的值,或者将字符靠得更近以缩小宽度。它或多或少会像这样:
GetTextExtentExPoint()
用于计算默认字符位置数组的 API 函数。最后一个有效值应该是整个字符串的宽度。 ExtTextOut()
的调用中使用计算出的字符位置数组. 关于delphi - 如何在不更改有效文本宽度的情况下绘制缩放文本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1918332/
请在标记为重复之前阅读。 我正在创建一组依赖智能卡进行身份验证的应用程序。到目前为止,每个应用程序都单独控制智能卡读卡器。几周后,我的一些客户将同时使用多个应用程序。因此,我认为创建一个控制身份验证过
我想设置一个小程序,从数据库中检索信息,然后根据请求将该信息分发给另一个程序。例如,一个名为“Master”的程序将从数据库中检索数据并创建一个对象集合(列表、数组等,无论哪种效果最好),然后一个名为
我有两台电脑,都装有 XE2。我以为我在两者上安装了相同的安装,但在其中一个上安装第 3 方软件包时遇到问题,而另一个则正常。 无论如何,我希望两者都一样。最简单的人可能只是通过移入我的 Dropbo
有冲突吗? 最佳答案 所有新版本的 Delphi 始终可以安全地安装到旧版本的下一个版本。 每个新版本都应安装在其自己的目录中。 如果您要安装多个版本,请始终先安装最旧的版本,然后再安装最新版本。 我
快速提问:如果我从代码中删除 // 或 (* *) 中的注释,Delphi 2007 的执行时间会受到影响吗?最终结果是一个可能包含数千行注释的 EXE 文件。 最佳答案 编译器会简单地忽略注释,并且
我必须对照另一个文件检查文件的每一行。 如果第二个文件中存在第一个文件中的一行,则必须删除它。 现在,我正在使用2个列表框,并且“对于listbox1.items.count-1可以开始...” 我的
我正在尝试在访问数据库中添加一些数据。但是我有麻烦,因为这会返回错误: ADOQuery1 missing sql property 实现了对代码的几次修改,到目前为止没有任何效果。 我究竟做错了什么
我用Delphi 5编写了一个程序,在Windows 8 32位PC上可以正常运行。我发现在Windows 7 64位笔记本电脑上运行它最终会导致reallocmem错误,而该错误在32位PC上不会发
看来这是我需要的工具,用于提取XML并与TClientDataset连接。我已经在几篇文章和文档中看到了它,但是我无法在XE2组件列表中找到它-在任何地方!应该在哪里?是否在可能未安装的可选软件包中?
我正在寻找一个非常通用的TDBTree组件,我想听听一些建议。我正在特别寻找一种显示主记录和“ n”个链接表记录的记录。 (我的意思是来自各个表的记录)。例如,TDBTree将钩接到主表,明细表1,附
我需要将按钮制作成旋转三角形的形状(或者说是任何多边形)。谁能提供任何建议? 最佳答案 查看Win32 API CreatePolygonRgn()和SetWindowRgn()函数,以创建一个HRG
你好专家 我的JvPasswordForm1有一个旧的JVC组件。 似乎该组件不再存在:它替换为哪个组件? 重新获得 最佳答案 尝试查找TJvLoginDialog,TjvPassword已合并到其中
几天前,我已经设置了我的开发环境(在装有Win 7的VM和域上的用户的VM上安装了delphi 2009),并安装了我的组件(jedi's,devExpress,ADS等)。 今天,我启动机器,打开d
开始对控件进行子分类的正确位置/时间是什么? 恢复原始窗口proc的正确时间是几点? 现在我在表单创建过程中子类化: procedure TForm1.FormCreate(Sender: TObje
有人可以给我一些有关如何登录访问的网页(使用任何网络浏览器)的指示吗?我应该建立一个全球代理....钩住网络....吗?我需要记录的只是页面地址,而不是其中包含的信息。 我正在使用Delphi。 谢谢
我创建了一个像 TMyClass = class(TObject) private FList1: TObjectList; FList2: TObjectList; public end;
我有一个BPG文件,我已对其进行修改以用作我们公司的自动构建服务器的make文件。为了使其正常工作,我必须进行更改 用途*用途 'unit1.pas'中的unit1 * unit1 'unit2.pa
我将Delphi 7代码迁移到了Delphi XE4。我在Delphi XE4的LoadFromStram方法中遇到错误,但对于Delphi 7来说也可以正常工作。 错误: First chance
我正在尝试学习一些新技巧,以便更好地组织我在 Delphi 中的单元中的一些源代码。 我注意到我访问的一些函数或方法似乎是类中的类,但是我还没有成功地在类中创建一个工作类,虽然它编译得很好,但在执行代
我有一个包含许多类的大单元,现在我想通过将某些类分成新的单元来重构该单元。 我不得不承认我缺乏使用Delphi内置IDE功能的经验。利用内置功能“查找|查找对类型的本地引用”并没有多大帮助,因为类方法
我是一名优秀的程序员,十分优秀!