我正在 WinForms .Net 2.0 应用程序中开发一个类似自定义超级终端的应用程序。我在面板中有一个多行文本框,您可以在其中与硬件设备交互。
我的客户想要一个自定义插入符,一个大小为一个字符空间的填充矩形,而不是默认的垂直线。
我知道 .Net 默认情况下不提供执行此操作的选项,但必须有一些 Windows 函数来执行此操作。
这些是 Windows 提供的 Native Caret 函数列表,您可以将它们用于您的应用程序。
[DllImport("User32.dll")]
static extern bool CreateCaret(IntPtr hWnd, int hBitmap, int nWidth, int nHeight);
[DllImport("User32.dll")]
static extern bool SetCaretPos(int x, int y);
[DllImport("User32.dll")]
static extern bool DestroyCaret();
[DllImport("User32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
[DllImport("User32.dll")]
static extern bool HideCaret(IntPtr hWnd);
参考 SharpDevelop,源代码@ src\Libraries\ICSharpCode.TextEditor\Project\Src\Gui\Caret.cs
假设有一个带有文本框的表单:
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
public Form1()
{
InitializeComponent();
}
private void Form1_Shown(object sender, EventArgs e)
{
CreateCaret(textBox1.Handle, IntPtr.Zero, 10, textBox1.Height);
ShowCaret(textBox1.Handle);
}
}
我会使用 System.Drawing 绘制自定义光标(位图),也许使用计时器让它像另一个光标一样闪烁。
获取光标的当前位置(以像素为单位)并在该光标上绘制位图。找到正确的位置可能很棘手,但应该是可行的。
在这里查看 winforms 中的所有者绘制的文本框。
用途:
richTextBoxConsole.GetPositionFromCharIndex(cursorPos)
隐藏正常的插入符并绘制自己的插入符?未经测试,但我认为应该可以工作。
我不确定我是否理解问题...但下一步将帮助其他像我一样找不到答案的人。 所以你有一行文本,你需要找到插入符位置(单击键盘向左或向右)。您有 TextRenderer.MeasureString() 和 TextRenderer.DrawText()。想法很简单,我们需要util函数
private SizeF CalculateTextSize(String _text, int begin, int end)
计算给定文本的SizeF。所以如果需要找到插入符位置,
size = CalculateTextSize(text, 0, index)
和沃利亚
caretPos = new Point(x + size.Width, y)
另外,你需要通过(clickeX,clickedY)找到
index
的位置。
for(int i=0; i < text.Lenght; i++)
{
SizeF size = CalculateTextSize(text, 0, i);
Rectangle rect = new Rectangle(x, y, size.Width, lineHeight);
if(rect.Contains(clickedX,clickedY))
{
index = i;
break;
}
}
IDEA 与多行自定义文本编辑配合良好
using MyDirectX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace MyRenderText2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
LoadFont();
text = "Олександр Буханенко";
location = new Point(100, 33);
}
String text;
int index = 0;
Font font;
private void LoadFont()
{
font = new Font("Calibri", 12f);
}
Point location;
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.AntiqueWhite);
RenderRect();
RenderText();
}
private void RenderText()
{
Graphics g = this.CreateGraphics();
TextRenderer.DrawText(g, text, font, location, Color.Red, TextFormatFlags.NoPadding);
g.Dispose();
}
private void RenderRect()
{
SizeF textSize = new SizeF(0, 0);
textSize = CalculateTextSize(text, 0, text.Length);
Graphics g = this.CreateGraphics();
g.DrawRectangle(Pens.Blue, new Rectangle(location.X, location.Y, (int)textSize.Width, (int)textSize.Height));
g.Dispose();
}
private SizeF CalculateTextSize(String _text, int begin, int end)
{
String text = _text.Substring(begin, end - begin);
SizeF textSize = new SizeF(0, 0);
Graphics g = this.CreateGraphics();
textSize = TextRenderer.MeasureText(g, text, font, new Size(0, 0), TextFormatFlags.NoPadding);
g.Dispose();
return textSize;
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
Size size = new Size(0, 0);
size = GetCaretSize();
Point pos = new Point(0, 0);
pos = GetCaretPos();
Win32.CreateCaret(this.Handle, IntPtr.Zero, 1, size.Height);
Win32.SetCaretPos(pos.X, pos.Y);
Win32.ShowCaret(this.Handle);
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
Win32.DestroyCaret();
}
private Size GetCaretSize()
{
Size caretSize = new Size(0, 0);
String s = "1";
SizeF sSize = new SizeF(0, 0);
sSize = this.CalculateTextSize(s, 0, 1);
caretSize.Width = 1;
caretSize.Height = (int)sSize.Height;
return caretSize;
}
private Point GetCaretPos()
{
Point pos = new Point(0, 0);
String text1 = text.Substring(0, index);
String text2 = text.Substring(index);
String[] lines = text1.Split('\r');
String lastLineText1 = lines[lines.Length - 1];
//calculate x
SizeF lastLineText1Size = new SizeF(0, 0);
lastLineText1Size = CalculateTextSize(lastLineText1, 0, lastLineText1.Length);
pos.X = location.X + (int)lastLineText1Size.Width;
//calculate y
pos.Y = location.Y;
SizeF text1Size = new SizeF(0, 0);
text1Size = CalculateTextSize(text1, 0, text1.Length);
pos.Y += (int)text1Size.Height;
String s = "1";
SizeF sSize = new SizeF(0, 0);
sSize = CalculateTextSize(s, 0, 1);
pos.Y -= (text.Substring(0, index).Length != 0 ? 1 : 0) * (int)sSize.Height;
return pos;
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
Point pos = new Point(0, 0);
String s1 = "", s2 = "";
switch (e.KeyCode)
{
case Keys.Left:
index--;
index = Math.Max(index, 0);
//this.Invalidate();
pos = GetCaretPos();
Win32.HideCaret(this.Handle);
Win32.SetCaretPos(pos.X, pos.Y);
Win32.ShowCaret(this.Handle);
break;
case Keys.Right:
index++;
index = Math.Min(index, text.Length);
//this.Invalidate();
pos = GetCaretPos();
Win32.HideCaret(this.Handle);
Win32.SetCaretPos(pos.X, pos.Y);
Win32.ShowCaret(this.Handle);
break;
case Keys.Back:
s1 = text.Substring(0, Math.Max(index - 1, 0));
s2 = text.Substring(index);
text = s1 + s2;
index--;
index = Math.Max(0, index);
pos = GetCaretPos();
Win32.SetCaretPos(pos.X, pos.Y);
this.Invalidate();
break;
case Keys.Delete:
s1 = text.Substring(0, index);
s2 = text.Substring(Math.Min(index + 1, text.Length));
text = s1 + s2;
this.Invalidate();
break;
}
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (int)Keys.Back)
return;
String s1 = "", s2 = "";
s1 = text.Substring(0, index);
s2 = text.Substring(index);
text = s1 + e.KeyChar + s2;
index++;
Point pos = new Point(0, 0);
pos = GetCaretPos();
Win32.SetCaretPos(pos.X, pos.Y);
this.Invalidate();
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
}
}
}
改变
Win32.CreateCaret(...), Win32.ShowCaret(...), Win32.SetCaretPos(...), Win32.DestroyCaret(...)
到
CreateCaret(...), ShowCaret(...)...
[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);