- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
正在处理一个简单的 c GUI 库,我从 winapi 开始后端,现在在计算控件的首选大小时遇到一些问题。我正在将我的结果与 Windows.Forms
的结果进行比较。
现在,我正在使用 Design Specifications and Guidelines - Visual Design Layout 中的值(例如按钮和文本框是 14 个“对话框逻辑单元”高)用于计算 winapi 中的像素大小实现,同时使用 Windows 窗体保持所有默认值。我创建了这些简单的演示实现:
using System.Drawing;
using System.Windows.Forms;
namespace W32CtlTest
{
public class Demo : Form
{
private FlowLayoutPanel panel;
private Button button;
private TextBox textBox;
public Demo() : base()
{
Text = "winforms";
panel = new FlowLayoutPanel();
button = new Button();
button.Text = "test";
button.Click += (sender, args) =>
{
Close();
};
panel.Controls.Add(button);
textBox = new TextBox();
panel.Controls.Add(textBox);
Controls.Add(panel);
}
protected override Size DefaultSize
{
get
{
return new Size(240,100);
}
}
public static void Main(string[] argv)
{
if (argv.Length < 1 || argv[0] != "-s")
{
Application.EnableVisualStyles();
}
Application.Run(new Demo());
}
}
}
使用 C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe/out:demo.exe/lib:C:\Windows\Microsoft.NET\Framework\v4.0.30319/编译引用:System.Windows.Forms.dll,System.Drawing.dll demo.cs
#include <string.h>
#include <windows.h>
#include <commctrl.h>
static HINSTANCE instance;
static HWND mainWindow;
static HWND button;
static HWND textBox;
#define WC_mainWindow L"W32CtlTestDemo"
#define CID_button 0x101
static NONCLIENTMETRICSW ncm;
static HFONT messageFont;
static TEXTMETRICW messageFontMetrics;
static int buttonWidth;
static int buttonHeight;
static int textBoxWidth;
static int textBoxHeight;
/* hack to enable visual styles without relying on manifest
* found at http://stackoverflow.com/a/10444161
* modified for unicode-only code */
static int enableVisualStyles(void)
{
wchar_t dir[MAX_PATH];
ULONG_PTR ulpActivationCookie = 0;
ACTCTXW actCtx =
{
sizeof(actCtx),
ACTCTX_FLAG_RESOURCE_NAME_VALID
| ACTCTX_FLAG_SET_PROCESS_DEFAULT
| ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID,
L"shell32.dll", 0, 0, dir, (LPWSTR)124,
0, 0
};
UINT cch = GetSystemDirectoryW(dir, sizeof(dir) / sizeof(*dir));
if (cch >= sizeof(dir) / sizeof(*dir)) { return 0; }
dir[cch] = L'\0';
ActivateActCtx(CreateActCtxW(&actCtx), &ulpActivationCookie);
return (int) ulpActivationCookie;
}
static void init(void)
{
INITCOMMONCONTROLSEX icx;
icx.dwSize = sizeof(INITCOMMONCONTROLSEX);
icx.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icx);
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
messageFont = CreateFontIndirectW(&ncm.lfStatusFont);
HDC dc = GetDC(0);
SelectObject(dc, (HGDIOBJ) messageFont);
GetTextMetricsW(dc, &messageFontMetrics);
SIZE sampleSize;
GetTextExtentExPointW(dc,
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
52, 0, 0, 0, &sampleSize);
ReleaseDC(0, dc);
buttonWidth = MulDiv(sampleSize.cx, 50, 4 * 52);
buttonHeight = MulDiv(messageFontMetrics.tmHeight, 14, 8);
textBoxWidth = 100;
textBoxHeight = MulDiv(messageFontMetrics.tmHeight, 14, 8);
instance = GetModuleHandleW(0);
}
static LRESULT CALLBACK wproc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
button = CreateWindowExW(0, L"Button", L"test",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
2, 2, buttonWidth, buttonHeight,
w, (HMENU)CID_button, instance, 0);
SendMessageW(button, WM_SETFONT, (WPARAM)messageFont, 0);
textBox = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", L"",
WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL,
6 + buttonWidth, 2, textBoxWidth, textBoxHeight,
w, 0, instance, 0);
SendMessageW(textBox, WM_SETFONT, (WPARAM)messageFont, 0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch (LOWORD(wp))
{
case CID_button:
DestroyWindow(w);
break;
}
break;
}
return DefWindowProcW(w, msg, wp, lp);
}
int main(int argc, char **argv)
{
if (argc < 2 || strcmp(argv[1], "-s"))
{
enableVisualStyles();
}
init();
WNDCLASSEXW wc;
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.hInstance = instance;
wc.lpszClassName = WC_mainWindow;
wc.lpfnWndProc = wproc;
wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
wc.hCursor = LoadCursorA(0, IDC_ARROW);
RegisterClassExW(&wc);
mainWindow = CreateWindowExW(0, WC_mainWindow, L"winapi",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 100,
0, 0, instance, 0);
ShowWindow(mainWindow, SW_SHOWNORMAL);
MSG msg;
while (GetMessageW(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return (int)msg.wParam;
}
用gcc -odemo.exe -O2 demo.c -lgdi32 -lcomctl32
编译
测试代码也有on github
在 Windows 10 上看起来像这样,视觉样式在上一行启用,在下一行禁用:
我很快发现的一件事是 Windows.Forms
没有使用消息字体(如我所料)而是使用 DEFAULT_GUI_FONT
虽然那不是正确的做法是,我相应地更改了 win32 代码,以便更好地比较结果:
为了完整起见,这里是在没有视觉样式的情况下在 Windows 7 上的样子:
现在我的问题是:
使用消息字体是否正确?那么,Windows.Forms 肯定把这个弄错了?
显然,Windows.Forms 为按钮使用 14 DLU 高度,但为文本框使用更小的高度。这与 Design Specifications 矛盾.那么 Windows.Forms 在这里也错了吗?或者 TextBoxes 实际上应该更小,这样文本看起来不像是“悬卡在天花板上”?我认为这确实看起来比 Windows.Forms 做事的方式更好。
比较启用/禁用的视觉样式,我发现在没有视觉样式的情况下,我的按钮和文本框的高度相同,但在 Windows 10 上启用视觉样式后,文本框实际上更高。是否有类似“主题特定指标”之类的东西?如果有,我如何使用它来更正我的计算?
最佳答案
这只是我在这里添加的部分答案以供引用:
事实上,根据this blog entry by Raymond Chen,使用DEFAULT_GUI_FONT
是错误的.所以,不需要相信 winforms做“正确的事”。
Design Specifications指示编辑控件应与按钮高度相同 (14 DLU)。要将这些转换为像素大小,需要对话框基本单位 (DBU),而 GetDialogBaseUnits()只为系统字体返回它们,有MSDN articles描述如何为其他字体计算它们。
1 个垂直 DBU 对应 8 个 DLU,因此一个 Edit 控件将比它包含的文本高 6 个 DLU。这看起来不太好,因为 Edit 控件没有将文本垂直居中,而是在顶部对齐。 winforms通过为 Edit 控件计算较小的尺寸来避免这种情况。缺点是 Edit 控件不能很好地与 Button 对齐。
我找到了一种解决该问题的“hacky”解决方案,方法是在覆盖的窗口过程中缩小 Edit 控件的客户区。以下代码比较结果(并包含使用系统字体以确保完整性的控件):
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <commctrl.h>
typedef struct PaddedControl
{
WNDPROC baseWndProc;
int vshrink;
} PaddedControl;
static HINSTANCE instance;
static HWND mainWindow;
static HWND buttonSF;
static HWND textBoxSF;
static HWND buttonMF;
static HWND textBoxMF;
static HWND buttonMFC;
static HWND textBoxMFC;
static PaddedControl textBoxMFCPadded;
#define WC_mainWindow L"W32CtlTestDemo"
static NONCLIENTMETRICSW ncm;
static HFONT messageFont;
static TEXTMETRICW messageFontMetrics;
static int controlHeightSF;
static int controlHeightMF;
static int buttonWidthSF;
static int buttonWidthMF;
/* hack to enable visual styles without relying on manifest
* found at http://stackoverflow.com/a/10444161
* modified for unicode-only code */
static int enableVisualStyles(void)
{
wchar_t dir[MAX_PATH];
ULONG_PTR ulpActivationCookie = 0;
ACTCTXW actCtx =
{
sizeof(actCtx),
ACTCTX_FLAG_RESOURCE_NAME_VALID
| ACTCTX_FLAG_SET_PROCESS_DEFAULT
| ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID,
L"shell32.dll", 0, 0, dir, (LPWSTR)124,
0, 0
};
UINT cch = GetSystemDirectoryW(dir, sizeof(dir) / sizeof(*dir));
if (cch >= sizeof(dir) / sizeof(*dir)) { return 0; }
dir[cch] = L'\0';
ActivateActCtx(CreateActCtxW(&actCtx), &ulpActivationCookie);
return (int) ulpActivationCookie;
}
static void init(void)
{
INITCOMMONCONTROLSEX icx;
icx.dwSize = sizeof(INITCOMMONCONTROLSEX);
icx.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icx);
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
messageFont = CreateFontIndirectW(&ncm.lfStatusFont);
LONG sysDbu = GetDialogBaseUnits();
HDC dc = GetDC(0);
SelectObject(dc, (HGDIOBJ) messageFont);
GetTextMetricsW(dc, &messageFontMetrics);
SIZE sampleSize;
GetTextExtentExPointW(dc,
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
52, 0, 0, 0, &sampleSize);
ReleaseDC(0, dc);
controlHeightSF = MulDiv(HIWORD(sysDbu), 14, 8);
controlHeightMF = MulDiv(messageFontMetrics.tmHeight, 14, 8);
buttonWidthSF = MulDiv(LOWORD(sysDbu), 50, 4);
buttonWidthMF = MulDiv(sampleSize.cx, 50, 4 * 52);
instance = GetModuleHandleW(0);
}
static LRESULT CALLBACK paddedControlProc(
HWND w, UINT msg, WPARAM wp, LPARAM lp)
{
PaddedControl *self = (PaddedControl *)GetPropW(w, L"paddedControl");
WNDCLASSEXW wc;
switch (msg)
{
case WM_ERASEBKGND:
wc.cbSize = sizeof(wc);
GetClassInfoExW(0, L"Edit", &wc);
RECT cr;
GetClientRect(w, &cr);
cr.top -= self->vshrink;
cr.bottom += self->vshrink;
HDC dc = GetDC(w);
FillRect(dc, &cr, wc.hbrBackground);
ReleaseDC(w, dc);
return 1;
case WM_NCCALCSIZE:
if (!wp) break;
LRESULT result = CallWindowProcW(self->baseWndProc, w, msg, wp, lp);
NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS *)lp;
int height = p->rgrc[0].bottom - p->rgrc[0].top;
self->vshrink = 0;
if (height > messageFontMetrics.tmHeight + 3)
{
self->vshrink = (height - messageFontMetrics.tmHeight - 3) / 2;
p->rgrc[0].top += self->vshrink;
p->rgrc[0].bottom -= self->vshrink;
}
return result;
}
return CallWindowProcW(self->baseWndProc, w, msg, wp, lp);
}
static LRESULT CALLBACK wproc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
buttonSF = CreateWindowExW(0, L"Button", L"sysfont",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
4, 4, buttonWidthSF, controlHeightSF,
w, 0, instance, 0);
buttonMF = CreateWindowExW(0, L"Button", L"msgfont",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
4, 8 + controlHeightSF, buttonWidthMF, controlHeightMF,
w, 0, instance, 0);
SendMessageW(buttonMF, WM_SETFONT, (WPARAM)messageFont, 0);
buttonMFC = CreateWindowExW(0, L"Button", L"msgfont adj",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
4, 12 + controlHeightSF + controlHeightMF,
buttonWidthMF, controlHeightMF,
w, 0, instance, 0);
SendMessageW(buttonMFC, WM_SETFONT, (WPARAM)messageFont, 0);
textBoxSF = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", L"abcdefgh",
WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL,
8 + buttonWidthSF, 4, 100, controlHeightSF,
w, 0, instance, 0);
textBoxMF = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", L"abcdefgh",
WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL,
8 + buttonWidthMF, 8 + controlHeightSF,
100, controlHeightMF,
w, 0, instance, 0);
SendMessageW(textBoxMF, WM_SETFONT, (WPARAM)messageFont, 0);
textBoxMFC = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", L"abcdefgh",
WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL,
8 + buttonWidthMF, 12 + controlHeightSF + controlHeightMF,
100, controlHeightMF,
w, 0, instance, 0);
memset(&textBoxMFCPadded, 0, sizeof(PaddedControl));
textBoxMFCPadded.baseWndProc = (WNDPROC)SetWindowLongPtr(
textBoxMFC, GWLP_WNDPROC, (LONG_PTR)paddedControlProc);
SetPropW(textBoxMFC, L"paddedControl", &textBoxMFCPadded);
SetWindowPos(textBoxMFC, 0, 0, 0, 0, 0,
SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
SendMessageW(textBoxMFC, WM_SETFONT, (WPARAM)messageFont, 0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(w, msg, wp, lp);
}
int main(int argc, char **argv)
{
if (argc < 2 || strcmp(argv[1], "-s"))
{
enableVisualStyles();
}
init();
WNDCLASSEXW wc;
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.hInstance = instance;
wc.lpszClassName = WC_mainWindow;
wc.lpfnWndProc = wproc;
wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
wc.hCursor = LoadCursorA(0, IDC_ARROW);
RegisterClassExW(&wc);
mainWindow = CreateWindowExW(0, WC_mainWindow, L"fontdemo",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 180,
0, 0, instance, 0);
ShowWindow(mainWindow, SW_SHOWNORMAL);
MSG msg;
while (GetMessageW(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return (int)msg.wParam;
}
使用这个 hack 的最后一行控件是迄今为止我能实现的最好的控件:
如您所见,一个仍然存在的问题是 Button 和 Edit 控件的高度看起来与 Windows 10 的视觉样式主题不同。所以我仍然很高兴看到这个问题的更好答案。
关于c - win32 : How to calculate control sizes for a consistent look across windows versions/themes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43892043/
我正在使用JQuery Mobile,有两个可用版本:稳定版和旧版。我不熟悉后者。 什么是旧版?或与稳定版有什么区别? 建议在生产现场中使用哪一个? 非常感谢 最佳答案 旧版本是一个旧的稳定版本,由于
Lotus Notes 具有“版本控制”功能。您可以将其设置为在用户需要单击 File->New->Version 以创建新版本的模式下工作。我想在表单上的按钮中使用该功能。 有没有办法(使用 Lot
关闭。这个问题是opinion-based 。目前不接受答案。 已关闭10 年前。 已锁定。这个问题及其答案是locked因为这个问题是题外话,但却具有历史意义。目前不接受新的答案或互动。 是否有任何
我对使用数据库和数据库设计/创建模式非常陌生,我非常感谢一些建议/建议。我正在创建一个应用程序,用户在其中输入数据,并向用户提供该数据的版本控制。用户可以进入并恢复更改或更新值(有点像 git)等,我
尝试启动带头 Selenium session 时出现此错误。 我使用的命令是driver = webdriver.Chrome(executable_path=r'C:\Users\Administ
Apple 的文档本来可以更清楚地说明如何提交更新版本。 正如标题所问,有什么区别 itunes connect 中的版本号(提交更新时必须提供) xcode 中的捆绑版本 捆绑版本字符串,短 它们有
当我在我的 Android 设备上运行我的应用程序时出现错误: meteor run android-device --settings settings.json --mobile-server=m
v = data.getValues(XP_PHONE); for (int i = 0; i alter 'table_foo', {NAME => 'column_fam_foo', V
我在Google CoLab中有这样一个错误:。以下是我的Cuda和Torch版本:。CUDA版本:。这是pytorch版本:2.0.1+cu118我试图安装Cuda 11.8,但没有成功。
我从其他用户那里发现了“类似”的问题,但没有一个答案有效。我正在尝试安装这些软件包: if (!require("BiocManager")) install.packages("BiocMana
我正在使用 Version Maven Plugin插件 use-latest-versions将 groupID=com.example* 内部依赖版本更新到最新版本的功能。这是使用 Jenkins
我是 Kotlin 应用程序开发的初学者。当我尝试构建应用程序时发生以下错误 - e: C:/Users/Lenovo/.gradle/caches/transforms-2/files-2.1/32
我正在尝试安装一个名为 metaBIT 的程序。我能够将它添加到我的路径中。但是当我执行时: metaBIT -h 它出错并给我这个: Traceback (most recent call last
在使用选项 -smt2 -in 启动 Z3 后,我可以获取 Z3 的版本吗?有点像 (get-z3-version) ; Z3 4.3.2 x64 // Desired reply 最佳答案 在SM
这个问题在这里已经有了答案: What is the difference between Version and 'Runtime Version' in .Net? (1 个回答) 关闭 9 年
new Version(AssemblyFileVersionAttribute.Version) 总是会成功吗? 这是我的代码。 Contract.Ensures(Contract.Result()
我正在尝试针对另一个使用 libcurl 共享库的共享库 (libtheirstuff.so) 交叉编译我自己的共享库 (libmystuff.so),但出现以下错误: libmystuff.so:
在 Bazaar 中,如果您在 foo.html 中有冲突,它将生成额外的 3 个文件 foo.html.BASE foo.html.OTHER foo.html.THIS 那么你可以 diff -N
我的 java 7 和 java 8 都安装在我的 Windows 系统的 C:\Program Files\Java 下 在环境的路径中我像这样指定了java 7的路径。 %JAVA_HOME%/b
#version 330 和 #version 330 core 有什么区别? 核心重要吗? 最佳答案 这两个版本声明是等价的。 核心 是默认值。来自 GLSL 3.30 规范: If no prof
我是一名优秀的程序员,十分优秀!