我正在为 Windows 控制台项目开发一个屏幕,并且一直在努力解决以下问题。
场景:
我试图猜测光标在字符串的哪个位置。
示例:
如果我将光标移动到随机位置(3,16),我希望能够计算出字符串相应的索引/位置。
我尝试了不同的公式,欧几里德距离在这里不起作用,因为字符串一行一行。 这个功能我已经从头开始好几次了,现在又要从0开始了
如果有人可以建议我应该使用的公式,我将不胜感激
public static int GetStringIndex(int startX, int startY, string text)
{
int index = -1;
int currentX = Console.CursorLeft;
int currentY = Console.CursorTop;
return index;
}
如果我理解正确的话,这就是你想要的:
int current = currentX + currentY * Console.BufferWidth;
int start = startX + startY * Console.BufferWidth;
return start <= current && current < start + text.Length ? current - start : -1;
当您将控制台视为一个大的一维数组时,这很容易。
我不确定我是否理解问题...但下一步将帮助其他像我一样找不到答案的人。 所以你有一行文本,你需要找到插入符位置(单击键盘向左或向右)。您有 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);