Archive Browser
Download TextBoxTabStops.zip, last updated 25/05/2019 (56.09 KB)
Download- md5: c19ff63a08cba2440f23c149be49025d
- sha1: e41fa65000e766cd66ed012744340b6fe53df4b4
- sha256: d3b220e4c5e4753d7b761ee0eb978600bdc14f6a9bbee50117e66a1a052d642c
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Cyotek.Demo.TextBoxTabStops.Design;
// Setting tab stops in a Windows Forms TextBox control
// https://www.cyotek.com/blog/setting-tab-stops-in-a-windows-forms-textbox-control
// This work is licensed under the Creative Commons Attribution 4.0 International License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.
// Found this example useful?
// https://www.paypal.me/cyotek
namespace Cyotek.Demo.TextBoxTabStops
{
[Designer(typeof(RulerDesigner))]
internal sealed class Ruler : Control
{
#region Private Fields
private const TextFormatFlags _flags = TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine;
private int[] _tabStops;
#endregion Private Fields
#region Public Constructors
public Ruler()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.Selectable, false);
base.TabStop = false;
base.ForeColor = SystemColors.ControlDarkDark;
this.ResetTabStops();
}
#endregion Public Constructors
#region Public Properties
[DefaultValue(typeof(SystemColors), "ControlDarkDark")]
public override Color ForeColor
{
get { return base.ForeColor; }
set { base.ForeColor = value; }
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DefaultValue(false)]
public new bool TabStop
{
get { return base.TabStop; }
set { base.TabStop = value; }
}
#endregion Public Properties
#region Protected Properties
protected override Size DefaultSize
{ get { return new Size(100, 22); } }
#endregion Protected Properties
#region Public Methods
public static int MulDiv(int number, int numerator, int denominator)
{
//https://stackoverflow.com/a/25065519/148962
return (int)((((long)number * numerator) + (denominator >> 1)) / denominator);
}
public void ResetTabStops()
{
_tabStops = new[] { 32 };
this.Invalidate();
}
public void SetTabStops(int[] tabStops)
{
if (tabStops == null || _tabStops.Length == 0)
{
throw new ArgumentNullException(nameof(tabStops));
}
_tabStops = tabStops;
this.Invalidate();
}
public void SetTabStops(int tabStop)
{
_tabStops = new[] { tabStop };
this.Invalidate();
}
#endregion Public Methods
#region Protected Methods
protected override void OnPaint(PaintEventArgs e)
{
Graphics g;
Rectangle inner;
Size size;
int y;
int tabWidth;
base.OnPaint(e);
// TODO: Need to intercept the scroll events for the underlying textbox
// in order to calculate an offset. But this is getting beyond the scope
// of what this demonstration was supposed to be about
g = e.Graphics;
size = this.ClientSize;
y = 7;
g.Clear(this.BackColor);
inner = new Rectangle(0, 3, size.Width - 1, size.Height - 10);
using (Font font = new Font(this.Font.FontFamily, 7F))
using (Pen pen = new Pen(this.ForeColor))
{
g.FillRectangle(SystemBrushes.Window, inner);
g.DrawRectangle(pen, inner);
DrawRuler(g, inner, y, font, pen);
y = inner.Bottom + 2;
int x;
int previousTabStop;
Form owner;
owner = this.FindForm();
x = 4;
tabWidth = 0;
previousTabStop = 0;
for (int i = 0; i < _tabStops.Length; i++)
{
int mappedTabWidth;
// TODO: MapDialogRect isn't working for me, probably because
// the .NET windows aren't being created as dialogs
//NativeMethods.RECT rect;
//rect = new NativeMethods.RECT
//{
// left=1,
// top=1,
// right = _tabStops[i],
// bottom = _tabStops[i]
//};
//Console.WriteLine(NativeMethods.MapDialogRect(owner.Handle, ref rect));
// using hardcoded value of 6 to match current font. likely to break on high DPI or if different font used
mappedTabWidth = MulDiv(_tabStops[i] - previousTabStop, 6, 4);
previousTabStop = _tabStops[i];
tabWidth = mappedTabWidth;
x += tabWidth;
g.DrawLine(pen, x, y, x, y + 2);
}
for (; x < inner.Width; x += tabWidth)
{
g.DrawLine(pen, x, y, x, y + 2);
}
}
}
#endregion Protected Methods
#region Private Methods
private void DrawRuler(Graphics g, Rectangle bounds, int y, Font font, Pen pen)
{
for (int x = bounds.Left + 101; x < bounds.Width + 100; x += 100)
{
string text;
Size textSize;
text = ((x - 1) / 100).ToString();
textSize = TextRenderer.MeasureText(g, text, font, Size.Empty, _flags);
TextRenderer.DrawText(g, text, font, new Point(x - (textSize.Width / 2), 2 + ((textSize.Height) - bounds.Height) / 2), this.ForeColor, _flags);
g.DrawLine(pen, x - 75, y + 1, x - 75, y + 3);
g.DrawLine(pen, x - 50, y, x - 50, y + 5);
g.DrawLine(pen, x - 25, y + 1, x - 25, y + 3);
}
}
#endregion Private Methods
}
}
Donate
This software may be used free of charge, but as with all free software there are costs involved to develop and maintain.
If this site or its services have saved you time, please consider a donation to help with running costs and timely updates.
Donate