我需要弄清楚Windows API中控件的首选大小 - 宽度和高度.据我所知,关于这个问题的唯一官方消息是Windows桌面程序指南的布局页面,这是一个似乎在Windows Vista中引入的文档,以及与Microsoft管理控制台等效的文档,前者似乎是基于它的.
前一页提供了对话框单元和像素中的示例尺寸(不在后一页中的内容!),表面上是96 dpi的9点Segoe UI.我不知道对话单元计算是否从未针对这个新的DPI值进行更新,但无论如何,我尝试了三种不同的方法,并没有任何完全相加.
该程序以两种方式计算,都基于此处和此处的信息.第一个使用结构tmAveCharWidth领域TEXTMETRICS; 第二个使用GetTextExtentPoint32()第一个链接中的函数.然后,它重复该过程,考虑古老的System字体(参见第一个链接).
在Windows 7上运行此程序
BUTTON_SIZE_X 保持在50(几件事所列出的宽度)BUTTON_SIZE_Y 更改为25(具有一行文本的Vista-and-up-only命令链接的列出高度)这样我们基于布局页面的预期大小将是75x41
GetTextExtentPoint32: Segoe UI 9 | baseX 7 baseY 15 | button 50 x 25 -> 88 x 47
tm.tmAveCharWidth: Segoe UI 9 | baseX 6 baseY 15 | button 50 x 25 -> 75 x 47
with system font: System 9
GetTextExtentPoint32: Segoe UI 9 | cX 7 …Run Code Online (Sandbox Code Playgroud) 完全披露:我正在研究我的libui GUI框架的文本API.这包括Windows上的DirectWrite,OS X上的Core Text和其他Unix上的Pango(它使用HarfBuzz进行OpenType整形).我想要指定的文本格式化属性之一是要使用的OpenType功能的集合,这三者都提供了这些功能.DirectWrite是IDWriteTypography.
现在,当您使用这些库绘制一些文本时,默认情况下您将启用一些有用的OpenType功能,例如标准连字(liga),如f + i连字.我认为这是特定于字体的,但事实证明这是特定于正在形成的文本的脚本.Microsoft为OpenType支持的所有脚本提供了指南(在"特定于脚本的开发"下),我可以看到相当复杂的逻辑,可以在HarfBuzz中完成所有这些以确认它.
在Core Text和Pango上,如果我启用其他属性,它们将被添加到这些默认值之上.但是使用DirectWrite,IDWriteTextLayout::SetTypography()这样做会删除默认值:

可以在此处找到生成此输出的程序.
显然我的第一个选择是询问如何获取DirectWrite的默认功能.但是,有人已经在这个网站上这样做了,答案似乎是"不".
我猜测DirectWrite允许我完全控制要应用于某些文本的功能列表.这很好,除了我不能用其他API做到这一点,除非我以某种方式明确禁用默认功能!当然,我不知道这个列表是否会改变,所以硬编码可能不是最好的主意.
即使硬编码是一种选择,我也可以为每个脚本获取HarfBuzz的列表,但是a)它相当复杂 b)脚本有多种可能的整形器,这取决于(我认为)版本兼容性(例如,缅甸).
那么为什么不使用HarfBuzz的列表来重新创建DirectWrite的默认功能列表呢?它似乎想要对其他塑造者准确,所以这应该工作,对吧?好吧,我需要做两件事:找出要使用的脚本,并找出哪些属性用于脚本中字符的位置重要的脚本.
DirectWrite提供了一个接口IDWriteTextAnalyzer,提供执行整形的工具.我可以使用它,但似乎脚本数据在DWRITE_SCRIPT_ANALYSIS结构中返回,并且脚本ID的描述显示"写入系统脚本的从零开始的索引表示.".
这没有用,所以我编写了一个程序来转储我输入的文本的脚本编号.在输入字符串上运行它
????????????????????????? abcd ???? ??? ??????? ????????? ???????? ?????
Run Code Online (Sandbox Code Playgroud)
产生输出
0 - 26 script 3 shapes 0
26 - 5 script 49 shapes 0
31 - 14 script 3 shapes 0
45 - 2 script 1 shapes 1
47 - 25 script 22 …Run Code Online (Sandbox Code Playgroud) 哎呀,当我做出这个答案时,有一件事我忘记了,而且我对自己并不是很确定,而且我似乎无法在MSDN和谷歌以及Stack Overflow搜索中找到相关信息.
Windows API中有许多地方使用负数,或者数字太大而无法使用有符号整数; 例如CW_USEDEFAULT,INVALID_HANDLE_VALUE,GWLP_USERDATA,等等.在C的世界里,一切都很好,花花公子:语言的整数提升规则得到了拯救.
但在Go中,我必须将所有参数传递给函数uintptr(相当于C的uintptr_t).函数的返回值也以这种方式返回,然后我需要进行比较.Go不允许整数提升,并且它不允许您在编译时将有符号常量表达式转换为无符号表达式.
现在,我在我的UI库中设置了一些用于处理这些常量的jerry-rig.(这是这个解决方案在行动中的样子.)但是,我对这个解决方案并不满意; 我觉得它喜欢ABI的事情,我想要完全确定我在做什么.
所以我的问题是:将签名值传递给Windows API函数时如何处理?返回时如何处理?
我的所有常量都是自动生成的(示例输出).自动生成器使用C ffi,我宁愿不用于主项目,因为我可以直接调用DLL(这也使得交叉编译至少在今年剩余时间内更容易).如果我可以以某种方式利用它,例如通过将所有内容都变成表单的C端变量
uintptr_t x_CONST_NAME = (uintptr_t) (CONST_NAME);
Run Code Online (Sandbox Code Playgroud)
这会有所帮助.但如果没有这个答案我就不能这样做.
谢谢!
IRC上的某个人将其改为不同(重新格式化以避免水平滚动):
[19:13] <FraGag> basically, you're asking whether an int with a value of -1
will be returned as 0x00000000FFFFFFFF or as 0xFFFFFFFFFFFFFFFF
if an int is 4 bytes and an uintptr is 8 bytes
Run Code Online (Sandbox Code Playgroud)
基本上这个,但专门用于Windows API互操作,传入的参数,无论uintptr大小.
我对 MSDN 页面WM_PRINTCLIENT和相关功能的以下几个方面感到有些困惑:
我应该从窗口过程返回什么值?该文档完全缺少“返回值”部分。(在 Visual Studio 2012 离线文档光盘版本的页面中也没有。)Raymond Chen 的原始暂存程序返回零;这是首选吗?
的摘要和备注部分WM_PRINTCLIENT表明我应该只绘制客户区,但 LPARAM 列出了所有可能的WM_PRINT标志 - 那么我应该怎么做,忽略它并无条件地只绘制客户区或绘制所有请求的内容?(我对这个问题的意图不是对文档进行二次猜测;我只是希望正确实施此消息。)
为了方便/善意,我也想提供文档中WM_PAINT提到的 wParam 功能中的 DCWM_PAINT作为一个选项。在这种情况下我应该如何解释 LPARAM?或者有什么理由我不应该提供这条替代路线?(推论:如果 LPARAM 被忽略,我应该无条件绘制整个客户区吗?)
谢谢。
更新改写第三部分:
的文档WM_PAINT包括段落
对于一些常用控件,默认的 WM_PAINT 消息处理会检查 wParam 参数。如果 wParam 为非 NULL,则控件假定该值是 HDC 并使用该设备上下文进行绘制。
除了WM_PRINTCLIENT为了完整性之外,我还想在我的控制范围内提供这种行为。有什么理由我不应该这样做吗?如果这样做不会造成伤害,我应该如何解释 lParam,我应该如何绘制整个客户端矩形?
在使用 GDI 进行图形的传统 Windows 程序中,您将不得不担心只绘制需要重绘的窗口区域;这是“更新矩形”,可PAINTSTRUCT.rcPaint通过调用或调用GetUpdateRect(). (这也可以HRGN通过其他方式获得。)
我需要用 Direct2D 做同样的事情吗?MSDN 上的所有示例都只是随意绘制了整个客户区,而在线搜索并没有发现其他任何内容。
或者换句话说,如果我只在更新矩形内绘制,例如手动或使用PushAxisAlignedClip()或,更新矩形之外的部分会发生什么不好的事情PushLayer()?
此外,文档ID2D1HwndRenderTarget::Resize()说
调用此方法后,即使在创建渲染目标时指定了 D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS 选项,也不会定义渲染目标的后台缓冲区的内容。
这是否意味着,无论更新区域将通过(如所示通过调整引起的这幅画从这个网页)是无效的,我应该重新绘制整个窗口(例如,通过调用InvalidateRect(NULL))在一个调整大小?
谢谢。
我隐藏了Gtk小部件,然后尝试显示它,但是没有一个方法"show()","show_all()"或"show_now()"都不起作用.如果没有调用"hide()"小部件显示.
python 3.5.2
gtk3 3.20.8
pygobject-devel 3.20.1
Run Code Online (Sandbox Code Playgroud)
test.py:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
builder = Gtk.Builder()
builder.add_from_file("gui.glade")
infoBar = builder.get_object("infoBar")
window = builder.get_object("window")
window.show_all()
infoBar.hide()
infoBar.show()
Gtk.main()
Run Code Online (Sandbox Code Playgroud)
gui.glade:http://pastebin.com/xKFt1v84
我希望能够支持自定义 Windows 控件中的文本输入,就像 EDIT 和 Rich Edit 控件已经做的那样,但不对其中任何一个控件进行子类化。该控件当前使用 Direct2D 和 DirectWrite 绘制文本,并在带有平台更新的 Windows Vista SP1 或更高版本上运行(如果我决定需要更新的 Direct2D 和 DirectWrite 功能,我可能会将其更改为带有平台更新的 Windows 7 SP1 或更高版本,假设这些功能是在那里可用或仅在 Windows 8 上可用,但这是一个不同的问题......)
就其价值而言,在 OS XI 上我会使用NSTextInputClient,在 GTK+ 上我会使用GtkIMContext。我正在谈论的就是这样的事情。
显而易见的选择是使用WM_CHAR,如果我正确收集的话,如果窗口类是用 注册的RegisterClassW(),那么它本身就是 UTF-16 ,因此无论位置如何都应该“正常工作”。然而,WM_CHAR是由 生成的TranslateMessage(),并且它的文档说没有办法确定 a 是否WM_CHAR已生成,因为TranslateMessage()总是返回非零。我需要能够确定当前的键盘消息是否将由文本系统处理(因此应该被忽略);这尤其正确,因为所有非文本键都需要以独立于布局的方式处理(我已经有了)。
我还在 Windows 7 示例代码中看到了 IMM API 和文本服务框架。我不确定一个是否比另一个更好,而且他们似乎都做同样的事情。他们吗?
就 IMM 而言,有许多WM_IMM_xxx消息我不确定是否应该忽略,并且我发现的每个参考文献似乎都不同意我是否应该在 Unicode 窗口中处理它们。 ..此外,上述了解 IMM 是否会处理给定按键事件的问题仍然悬而未决;有办法吗?
TSF 有一个称为 ACP 的概念,它似乎允许我使用我想要的任何文本存储格式来存储我实际要使用的文本(即,不是正在进行的合成)。这是真的?我希望能够将文本存储为带有属性的 UTF-8,在绘图时转换为 …
这是《在 Windows 上处理自定义控件中的任意文本输入的正确、现代方法是什么?》的延续。WM_CHAR?注塑机?TSF?。
\n\n因此,在尝试了非 IME 布局(美国英语)、非 TSF IME(Windows XP DDK 中的日语 FAKEIME)和 TSF 文本服务(Windows 7 附带的任何内容)后,看来如果活动输入处理器配置文件不是 TSF 文本服务(即,它是TF_PROFILETYPE_KEYBOARDLAYOUT),我仍然需要处理击键和WM_CHAR消息来进行文本输入。
我的问题是我的架构需要一种方式来告知它可以忽略当前的关键消息,因为它已转换为文本输入消息。它不关心这是发生在翻译之前还是之后;它只需要知道这样的翻译将会或已经发生。或者用伪代码术语来说:
\n\n// if I can suppress WM_CHAR generation and synthesize it myself (including if the translation is just dead keys)\ncase WM_KEYDOWN:\ncase WM_SYSKEYDOWN:\n if (WillTranslateMessage())\n InsertChar(GenerateEquivalentChar());\n else\n HandleRawKeyEvent();\n break;\n\n// if I can know if a WM_CHAR was generated (or will be generated; for instance, in the case of dead keys)\ncase WM_KEYDOWN:\ncase …Run Code Online (Sandbox Code Playgroud) 我的 libui 项目必须在 OS X 10.8 及更高版本上编译并以 OS X 10.8 为目标,所以我有
#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_8
#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_8
Run Code Online (Sandbox Code Playgroud)
在 Cocoa 代码的共享头文件中。到目前为止,这已经奏效了;我没有看到任何关于 10.9 之后被弃用的函数的信息。然而,昨晚升级到 10.12 和 Xcode 8 后,我突然看到一大堆弃用警告,例如
/Users/pietro/src/github.com/andlabs/libui/darwin/entry.m:181:28: warning:
'NSRegularControlSize' is deprecated: first deprecated in macOS 10.12
[-Wdeprecated-declarations]
uiDarwinSetControlFont(t, NSRegularControlSize);
^~~~~~~~~~~~~~~~~~~~
NSControlSizeRegular
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSCell.h:102:28: note:
'NSRegularControlSize' has been explicitly marked deprecated here
static const NSControlSize NSRegularControlSize API_DEPRECATED_WITH_REPL...
^
Run Code Online (Sandbox Code Playgroud)
好像我提供的宏被忽略了。我试图弄清楚发生了什么事,但我只是得到了混合信号:苹果开发者网站上的一些消息来源告诉我这确实是 __MAC_OS_X_VERSION_MIN_REQUIRED (并使用数字而不是版本本身的符号常量),而其他人则告诉我我是的。有些来源似乎暗示这些值是由编译器设置决定的?我再也无法说出 Availability.h 想要什么。
就其价值而言,该项目使用 CMake 来构建,并且不直接使用 Xcode 项目。
那么我做错了什么?谢谢。
当我学会了如何自己启动NSApplications时,我使用的代码(基于此处和此处)完成了
[NSApp activateIgnoringOtherApps:YES];
Run Code Online (Sandbox Code Playgroud)
这会在启动时强制应用程序到前端.
我想知道大多数其他应用程序的功能.我希望能够直接从二进制文件和应用程序包中运行程序,而且我没有使用Xcode来构建它(原始构建).所以我可以自然而然地说这种行为.
文档确实说Finder问题NO,但是......为什么Finder?这不是一个从流程内部运行的方法,而不是外部的方法吗?(我无法控制选择.)那么Dock和其他可能的切入点呢?
我甚至竟然拆解10.8 NSApplicationMain()来看看它做了什么,但据我所知,从32位版本开始,除非这个"轻启动"事情发出这个选择器,否则这个选择器永远不会被调用.
这个问题有答案吗?谢谢......如果这令人困惑,我很抱歉; 我试着尽可能清楚地说出来.