C# ToolStripMenuItem dropdownitems项太多如何平铺展开
软糖来回答把。自己平铺多个List控件,制源当点击dropdown时,图片显示这些控件,绘绘制并把要显示的制源项,根据编号,图片sar美国线源码分配到这些控件中。绘绘制
自己写控件。制源
上图是图片软糖写的GDI绘制的控件,给出部分源码以供参考
using System;
using System.Collections.Generic;
using System.Drawing;
using 引擎.绘图.GDI;
using 引擎.输入;
namespace 引擎.界面 {
/// <summary>
/// 可以输入文本,绘绘制点击下拉箭头选择列表项目,制源在右边还可以附带几个按钮
/// </summary>
public class 下拉框 : 文本框,图片linklist的源码 I组合控件 {
/// <summary>内置的列表控件</summary>
public 列表框 列表;
/// <summary>附加按钮的文字</summary>
public List<string> 按钮文字 = new List<string>();
/// <summary>按钮的宽度</summary>
public int 按钮宽度 = ;
/// <summary>箭头图案的缩小比例。默认为0.表示%。绘绘制</summary>
public double 图案缩小比例 = 0.;
/// <summary>展开状态在- 到 之间</summary>
public int 展开状态 = 0;
/// <summary>最大的制源显示行数</summary>
public int 显示行数 = 8;
/// <summary>显示名称的那列的宽度</summary>
public int 名称列宽 = ;
/// <summary>TODO: 双击可以输入文本</summary>
public bool 禁用输入 = false;
/// <summary>展开所需帧数: / 展开速度</summary>
public int 展开速度 = ;
/// <summary>当鼠标移出列表时关闭列表</summary>
public bool 鼠标移出后关闭列表 = true;
/// <summary>箭头的元素样式</summary>
public 箭头样式 箭头样式;
/// <summary>默认网格线的边框样式</summary>
public static 边框 默认网格线 = new 边框(, Color.FromArgb(, , ), 1.0f);
public 下拉框() : base(false) {
初始化参数();
初始化事件();
宽 = ;
高 = ;
背景色 = Color.FromArgb(, Color.LightSlateGray);// Color.FromArgb(, , );
列表 = new 列表框();
列表.列数 = 1;
列表.格高 = ;
列表.背景色 = Color.FromArgb(, Color.LightSlateGray);
列表.网格线 = 默认网格线;
列表.可见 = false;
列表.自动卷动.速度 = ;
列表.自动卷动.允许 = 2;
列表.自动卷动.判定边距 = ;
列表.格式 = 文字靠中;
//列表选择项目时
列表.选择项目时 += (上次选中号) => {
if (展开状态 >= ) {
//文字 变为 值 (为null时) 变为 名称 (也为null时) 变为空字符串""
if (列表.项.非空(列表.选中号)) {
string str = 列表.项[列表.选中号].值;
if (str == null) {
str = 列表.项[列表.选中号].名称;
if (str == null) { 文字 = ""; } else { 文字 = str; }
}
else { 文字 = str; }
}
已选中 = false;
隐藏TextBox(false);
关闭列表();
}
};
//初始化热点区域
热区 = new Region(矩形);
同步列表框();
更新输入矩形();
//矩形变化时同步绑定的列表框
矩形改变后 += (x, y, w, h) => { 同步列表框(); 更新输入矩形(); };
}
public override void 初始化参数() {
文字 = nameof(下拉框);
格式 = 文字靠中;
字体 = 默认字体;
文字画笔 = 默认文字画笔;
阴影画笔 = 默认阴影画笔;
描边钢笔 = 默认描边钢笔;
鼠标离开时 += 文本框鼠标移开;
箭头样式 = 箭头样式.白色;
}
public override void 初始化事件() {
//当点击下拉箭头时
鼠标按下时 = (e) => {
if (矩形.Contains(e.x, e.y)) {
if (e.键位 == E键位.鼠标左键) {
更新输入矩形();
if (e.x > 箭头X) {
展开或关闭列表();
}
else {
//显示TextBox
if (已选中 == false && 已禁用 == false) {
已选中 = true;
显示TextBox(this);
}
else if (已选中 == true && 已禁用 == false) {
已选中 = false;
隐藏TextBox();
}
展开或关闭列表();
}
}
}
};
}
public void 加入面板(面板 面板) {
面板.添加(列表);
}
public int 箭头W { get { return 矩形.Height - 4; } }
protected int 箭头X { get { return 矩形.X + 矩形.Width - (矩形.Height - 4); } }
public new Rectangle 文字矩形 {
get {
return new Rectangle(X + 1, Y + 2, Math.Max(宽 / 2, 宽 - 2 - 按钮宽度 * 按钮文字.Count - 箭头W), 高 - 4);
}
}
public Rectangle 右边矩形 { get { return new Rectangle(箭头X, 矩形.Y + 2, 箭头W - 1, 箭头W - 1); } }
public Rectangle 下拉箭头矩形 {
get {
int XFix = (int)(箭头W * 图案缩小比例);
return new Rectangle(箭头X + XFix, 矩形.Y + 2 + XFix,
箭头W - 2 * XFix, 箭头W - 2 * XFix);
}
}
#region "文本框显示和隐藏"
/// <summary>当鼠标移出输入框后隐藏。</summary>
public override void 文本框鼠标移开(按键消息 e) {
if (鼠标移出后关闭列表) { 关闭列表(); 隐藏TextBox(false); }
else { 隐藏TextBox(false); }
}
/// <summary>更新输入框的图片矩形。</summary>
public override void 更新输入矩形() {
输入矩形.X = X - 1;
输入矩形.Y = Y - 高 + 1;
输入矩形.Width = 宽 + 2;
输入矩形.Height = Y - 输入矩形.Y + 1;
热区.MakeEmpty();
热区.Union(矩形);
热区.Union(输入矩形);
热区.Union(new Rectangle(列表.X, 列表.Y, 列表.宽, 显示行数 * 列表.格高));
}
#endregion
public void 同步列表框() {
if (列表 == null) { return; }
列表.矩形 = new Rectangle(X, Y + 高, 宽, 显示行数 * 列表.格高);
列表.格宽 = 列表.宽 / 列表.列数;
if (列表.面板 == null) {
if (面板 != null) { 面板.添加(列表); }
}
}
protected void 计算列表高() {
列表.高 = 显示行数 * 列表.格高 * Math.Abs(展开状态) / ;
}
public virtual void 展开或关闭列表() {
if (展开状态 == 0) {
列表.可见 = true;
展开状态 = 1;
} else if (展开状态 == ) {
展开状态 = -;
}
}
public virtual void 关闭列表() {
已选中 = false;
展开状态 = 0;
列表.可见 = false;
}
public override void 绘制(画家 画家) {
if (可见) {
if (展开状态 > 0 && 展开状态 < ) {
展开状态 = 展开状态 + 展开速度;
if (展开状态 >= ) { 展开状态 = ; }
计算列表高();
}
else if (展开状态 < 0) {
展开状态 = 展开状态 + 展开速度;
if (展开状态 >= 0) { 展开状态 = 0; 列表.可见 = false; }
计算列表高();
}
绘制底纹(画家);
绘制文字内容(画家);
绘制箭头(画家);
绘制边框(画家);
}
//DEBUG
//string str = string.Format("{ 0},{ 1},{ 2}",
// 面板.鼠标X, 面板.鼠标Y,点在控件中(面板.鼠标X, 面板.鼠标Y));
//画家.绘制漂浮文字描边(str, , , 默认字体, 默认文字画笔.资源, 默认描边钢笔.资源);
//画家.填充区域(默认透明画笔.资源, 热区);
}
public virtual void 绘制文字内容(画家 画家) {
if (背景色.A != 0) {
var Brush = new SolidBrush(背景色);
画家.填充矩形(Brush, 文字矩形);
Brush.Dispose();
}
绘制文字(文字, 画家, 文字矩形, true);
}
public virtual void 绘制箭头(画家 画家) {
画家.绘制矩形(箭头样式.钢笔.资源, 右边矩形);
画家.填充矩形(箭头样式.背景画笔.资源, 右边矩形);
画家.填充三角箭头(箭头样式.画笔.资源, 下拉箭头矩形, E方向.下);
}
}
}
源码阅读忆丛()Minigui
探索GUI的历史与实现
对于GUI的细节仍然存在一些困惑,似乎总是有新的东西需要学习。年轻时,对《Windows程序设计》、MFC等书籍充满热情,那些API的神奇之处让人着迷。然而,花费大量时间深入学习,有人给我源码却似乎事倍功半,微软似乎更倾向于教人如何使用,而非深入解释实现原理。尽管如此,还是尝试实现过文字版的GUI,涉及基本的按钮、滚动条、菜单等元素。但一些细节仍不清楚。
通过网络搜索,了解到魏永明的源码 生成 pythonMinigui项目是对Windows GUI和GDI的模仿。通过下载vc6版本的MinGUI,能够进行调试。在分析代码时,发现事件回调、消息链等常见功能并无特别之处。而DefaultMainWinProc、InvalidateRect、PopupMenuTrackProc等函数则更具实际意义。GUI就像是在显存沙漠中绘画,有其既定规则。DefaultMainWinProc负责实现画最大、预约排号 源码最小按钮、窗口方框等常规操作,而绘制的动作有其先后顺序,即消息的先后处理。
GDI部分则展示了如何在显存中书写文字,包括粗体、斜体等效果;如何绘制图标和位图;关键的rgn裁剪矩形技术,用于加速绘制,矩形外的绘制不会进行。rgn裁剪矩形的运算包括加、减、合、并等,对应着窗口的各种移动和形状改变。不同线程之间的窗口管理由HWND_DESKTOP统一处理,desktop-common.c相当于窗口管理器,不同程序无法直接获取其他窗口的位置和大小,由其进行统一管理。desktop包含三个线程,分别负责捕捉键盘、鼠标消息,以及实际消息的处理,以及窗口给desktop的消息交由DesktopWinProc统一处理。
MinGUI的模拟版本在调试方面虽能使用,但功能实现上有缺失。相比之下,libminigui-1.0.提供了完整的gui、gdi、kernel代码,定义了大部分的画窗套路和动作,只需要关注关键部分和自己定义的动作即可。
Linux的GUI采用了xwindows,通过socket将xclient进程中的窗口绘制信息传输到xserver,由xserver统一处理。xclient之间互相不知道窗口的位置和大小,因此都通过xserver进行绘制,xserver还包含了窗口管理器。而MinGUI在一个进程的多个线程中实现,不存在窗口管理器与进程间位置信息传递的问题。
Windows使用wink.sys作为窗口管理器,作为内核态程序,用户态的动态链接库在不同进程间数据段不同,但内核态的数据段统一,因此实现了窗口管理。Windows显示流畅的原因之一在于窗口管理机制与MinGUI的desktop类似,但实现机制有所不同。
工作繁忙,业余时间进行学习。尽管以前对GUI有过大量无用功,但这次的探索仅用几天时间便有所收获。
三个关于windows api的问题(非MFC)
第一个使用LoadBitmap加载,CreateWindowEx创建启动logo窗口,第4个参数Style设置为WS_BORDER|WS_POPUP,
像这样HWND hWndSplash = CreateWindowEx(WS_EX_TOOLWINDOW, Win->GetClassName().c_str(), "SplashWindow", WS_BORDER|WS_POPUP,
ScreenPosX, ScreenPosY, bmpWidth, bmpHeight, (HWND) NULL, (HMENU) NULL, hInstance, (LPVOID) NULL);
在回调函数的WM_PAINT消息里面画logo,
主程序窗口先隐藏,关闭启动画面后再用ShowWindow显示主程序窗口,
第二个问题,GetDC然后保存就可以了,可以参考一下这个:/infsafe/archive////.aspx
现在用纯win的好像比较少见了
现在用纯win的人好像不多了
2024-12-28 18:34
2024-12-28 17:00
2024-12-28 16:58
2024-12-28 16:50
2024-12-28 16:24