【发布时间】:2008-09-24 01:58:08
【问题描述】:
我正在为我正在编写的应用程序寻找免费的 winforms 组件。我基本上需要一个在侧栏中包含行号的文本框。能够将其中的数据制成表格也是一大优势。
有人知道可以做到这一点的预制组件吗?
【问题讨论】:
-
Windows,而不是 Windows。请修复。打扰我了:p
我正在为我正在编写的应用程序寻找免费的 winforms 组件。我基本上需要一个在侧栏中包含行号的文本框。能够将其中的数据制成表格也是一大优势。
有人知道可以做到这一点的预制组件吗?
【问题讨论】:
参考Wayne's post,这里是相关代码。它使用 GDI 在文本框旁边绘制行号。
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
SetStyle(ControlStyles.UserPaint, True)
SetStyle(ControlStyles.AllPaintingInWmPaint, True)
SetStyle(ControlStyles.DoubleBuffer, True)
SetStyle(ControlStyles.ResizeRedraw, True)
End Sub
Private Sub RichTextBox1_SelectionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.SelectionChanged
FindLine()
Invalidate()
End Sub
Private Sub FindLine()
Dim intChar As Integer
intChar = RichTextBox1.GetCharIndexFromPosition(New Point(0, 0))
intLine = RichTextBox1.GetLineFromCharIndex(intChar)
End Sub
Private Sub DrawLines(ByVal g As Graphics, ByVal intLine As Integer)
Dim intCounter As Integer, intY As Integer
g.Clear(Color.Black)
intCounter = intLine + 1
intY = 2
Do
g.DrawString(intCounter.ToString(), Font, Brushes.White, 3, intY)
intCounter += 1
intY += Font.Height + 1
If intY > ClientRectangle.Height - 15 Then Exit Do
Loop
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
DrawLines(e.Graphics, intLine)
End Sub
Private Sub RichTextBox1_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.VScroll
FindLine()
Invalidate()
End Sub
Private Sub RichTextBox1_UserScroll() Handles RichTextBox1.UserScroll
FindLine()
Invalidate()
End Sub
RichTextBox 被这样覆盖:
Public Class UserControl1
Inherits System.Windows.Forms.RichTextBox
Public Event UserScroll()
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = &H115 Then
RaiseEvent UserScroll()
End If
MyBase.WndProc(m)
End Sub
End Class
(xtremedotnettalk.com 论坛上的 divil 代码。)
【讨论】:
查看SharpDevelop C# 编译器/IDE 源代码。他们有一个带有行号的复杂文本框。您可以查看源代码,弄清楚他们在做什么,然后自己实施。
【讨论】:
http://www.xtremedotnettalk.com/showthread.php?s=&threadid=49661&highlight=RichTextBox 有一个项目的代码。
您可以使用用户/密码登录网站下载zip文件:bugmenot/bugmenot
【讨论】:
CodePlex for .net 中有一个源代码编辑组件, http://www.codeplex.com/ScintillaNET
【讨论】:
这里有一些 C# 代码可以做到这一点。它基于 Wayne 引用的来自 xtremedotnettalk.com 的代码。我进行了一些更改以使其实际显示编辑器文本,而原来的并没有这样做。但是,公平地说,原始代码作者确实提到它需要工作。
这是代码 (NumberedTextBox.cs)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
namespace NumberedTextBoxLib {
public partial class NumberedTextBox : UserControl {
private int lineIndex = 0;
new public String Text {
get {
return editBox.Text;
}
set {
editBox.Text = value;
}
}
public NumberedTextBox() {
InitializeComponent();
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
editBox.SelectionChanged += new EventHandler(selectionChanged);
editBox.VScroll += new EventHandler(OnVScroll);
}
private void selectionChanged(object sender, EventArgs args) {
FindLine();
Invalidate();
}
private void FindLine() {
int charIndex = editBox.GetCharIndexFromPosition(new Point(0, 0));
lineIndex = editBox.GetLineFromCharIndex(charIndex);
}
private void DrawLines(Graphics g) {
int counter, y;
g.Clear(BackColor);
counter = lineIndex + 1;
y = 2;
int max = 0;
while (y < ClientRectangle.Height - 15) {
SizeF size = g.MeasureString(counter.ToString(), Font);
g.DrawString(counter.ToString(), Font, new SolidBrush(ForeColor), new Point(3, y));
counter++;
y += (int)size.Height;
if (max < size.Width) {
max = (int) size.Width;
}
}
max += 6;
editBox.Location = new Point(max, 0);
editBox.Size = new Size(ClientRectangle.Width - max, ClientRectangle.Height);
}
protected override void OnPaint(PaintEventArgs e) {
DrawLines(e.Graphics);
e.Graphics.TranslateTransform(50, 0);
editBox.Invalidate();
base.OnPaint(e);
}
///Redraw the numbers when the editor is scrolled vertically
private void OnVScroll(object sender, EventArgs e) {
FindLine();
Invalidate();
}
}
}
这里是 Visual Studio 设计器代码 (NumberedTextBox.Designer.cs)
namespace NumberedTextBoxLib {
partial class NumberedTextBox {
/// Required designer variable.
private System.ComponentModel.IContainer components = null;
/// Clean up any resources being used.
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
private void InitializeComponent() {
this.editBox = new System.Windows.Forms.RichTextBox();
this.SuspendLayout();
//
// editBox
//
this.editBox.AcceptsTab = true;
this.editBox.Anchor = ((System.Windows.Forms.AnchorStyles) ((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.editBox.Location = new System.Drawing.Point(27, 3);
this.editBox.Name = "editBox";
this.editBox.Size = new System.Drawing.Size(122, 117);
this.editBox.TabIndex = 0;
this.editBox.Text = "";
this.editBox.WordWrap = false;
//
// NumberedTextBox
//
this.Controls.Add(this.editBox);
this.Name = "NumberedTextBox";
this.Size = new System.Drawing.Size(152, 123);
this.ResumeLayout(false);
}
private System.Windows.Forms.RichTextBox editBox;
}
}
【讨论】:
editBox.Font而不是Font,这样得到数字标签的位置会更好:y = editBox.GetPositionFromCharIndex(editBox.GetFirstCharIndexFromLine(counter - 1));
我猜这取决于字体大小,我使用“Courier New, 9pt, style=bold”
NumberedTextBox.cs
public partial class NumberedTextBox : UserControl
{
private int _lines = 0;
[Browsable(true),
EditorAttribute("System.ComponentModel.Design.MultilineStringEditor, System.Design","System.Drawing.Design.UITypeEditor")]
new public String Text
{
get
{
return editBox.Text;
}
set
{
editBox.Text = value;
Invalidate();
}
}
private Color _lineNumberColor = Color.LightSeaGreen;
[Browsable(true), DefaultValue(typeof(Color), "LightSeaGreen")]
public Color LineNumberColor {
get{
return _lineNumberColor;
}
set
{
_lineNumberColor = value;
Invalidate();
}
}
public NumberedTextBox()
{
InitializeComponent();
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
editBox.SelectionChanged += new EventHandler(selectionChanged);
editBox.VScroll += new EventHandler(OnVScroll);
}
private void selectionChanged(object sender, EventArgs args)
{
Invalidate();
}
private void DrawLines(Graphics g)
{
g.Clear(BackColor);
int y = - editBox.ScrollPos.Y;
for (var i = 1; i < _lines + 1; i++)
{
var size = g.MeasureString(i.ToString(), Font);
g.DrawString(i.ToString(), Font, new SolidBrush(LineNumberColor), new Point(3, y));
y += Font.Height + 2;
}
var max = (int)g.MeasureString((_lines + 1).ToString(), Font).Width + 6;
editBox.Location = new Point(max, 0);
editBox.Size = new Size(ClientRectangle.Width - max, ClientRectangle.Height);
}
protected override void OnPaint(PaintEventArgs e)
{
_lines = editBox.Lines.Count();
DrawLines(e.Graphics);
e.Graphics.TranslateTransform(50, 0);
editBox.Invalidate();
base.OnPaint(e);
}
private void OnVScroll(object sender, EventArgs e)
{
Invalidate();
}
public void Select(int start, int length)
{
editBox.Select(start, length);
}
public void ScrollToCaret()
{
editBox.ScrollToCaret();
}
private void editBox_TextChanged(object sender, EventArgs e)
{
Invalidate();
}
}
public class RichTextBoxEx : System.Windows.Forms.RichTextBox
{
private double _Yfactor = 1.0d;
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
private enum WindowsMessages
{
WM_USER = 0x400,
EM_GETSCROLLPOS = WM_USER + 221,
EM_SETSCROLLPOS = WM_USER + 222
}
public Point ScrollPos
{
get
{
var scrollPoint = new Point();
SendMessage(this.Handle, (int)WindowsMessages.EM_GETSCROLLPOS, 0, ref scrollPoint);
return scrollPoint;
}
set
{
var original = value;
if (original.Y < 0)
original.Y = 0;
if (original.X < 0)
original.X = 0;
var factored = value;
factored.Y = (int)((double)original.Y * _Yfactor);
var result = value;
SendMessage(this.Handle, (int)WindowsMessages.EM_SETSCROLLPOS, 0, ref factored);
SendMessage(this.Handle, (int)WindowsMessages.EM_GETSCROLLPOS, 0, ref result);
var loopcount = 0;
var maxloop = 100;
while (result.Y != original.Y)
{
// Adjust the input.
if (result.Y > original.Y)
factored.Y -= (result.Y - original.Y) / 2 - 1;
else if (result.Y < original.Y)
factored.Y += (original.Y - result.Y) / 2 + 1;
// test the new input.
SendMessage(this.Handle, (int)WindowsMessages.EM_SETSCROLLPOS, 0, ref factored);
SendMessage(this.Handle, (int)WindowsMessages.EM_GETSCROLLPOS, 0, ref result);
// save new factor, test for exit.
loopcount++;
if (loopcount >= maxloop || result.Y == original.Y)
{
_Yfactor = (double)factored.Y / (double)original.Y;
break;
}
}
}
}
}
NumberedTextBox.Designer.cs
partial class NumberedTextBox
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.editBox = new WebTools.Controls.RichTextBoxEx();
this.SuspendLayout();
//
// editBox
//
this.editBox.AcceptsTab = true;
this.editBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.editBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.editBox.Location = new System.Drawing.Point(27, 3);
this.editBox.Name = "editBox";
this.editBox.ScrollPos = new System.Drawing.Point(0, 0);
this.editBox.Size = new System.Drawing.Size(120, 115);
this.editBox.TabIndex = 0;
this.editBox.Text = "";
this.editBox.WordWrap = false;
this.editBox.TextChanged += new System.EventHandler(this.editBox_TextChanged);
//
// NumberedTextBox
//
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Controls.Add(this.editBox);
this.Name = "NumberedTextBox";
this.Size = new System.Drawing.Size(150, 121);
this.ResumeLayout(false);
}
private RichTextBoxEx editBox;
#endregion
}
【讨论】: