User Tools

Site Tools


blog:2025-05-08-001



2025-05-08 用 C# Winform 實作一個diff 比較的視窗

  • 用 C# Winform 實作一個diff 比較的視窗
  • diff比較的對象為2個RichTextBox,不一樣的Line要把該行設為粉紅背景
  • 用一個Bar要做Highlight 有不同的Row,且這個Bar不能超過該Winform 的Size,且等比例顯示整個比較兩個 RichTextBox的Overview,有不同的Line在相對的位置顯示紅線,當滑鼠點在該Line就將RichTextBor捲動到該對應的Line

Detail

  • 要在 C# WinForms 中實作一個 diff 比較的視窗,您可以使用兩個 RichTextBox 控制項來顯示兩個文本,並使用一個自訂的 Panel 來顯示不同的行。以下是實作的步驟和程式碼範例:

步驟 1:建立 WinForms 專案

  • 打開 Visual Studio,建立一個新的 Windows Forms 應用程式專案。
  • 在設計視圖中,添加以下控制項:
    • 兩個 RichTextBox 控制項(設置 Name 為 rtbLeft 和 rtbRight)。
    • 一個 Panel 控制項(設置 Name 為 panelOverview),用來顯示不同的行。
    • 一個 Button 控制項(設置 Name 為 btnCompare,設置 Text 為「比較」)。

步驟 2:設計介面

  • 在設計視圖中,將 RichTextBox 和 Panel 控制項適當安排,確保 Panel 的大小足夠以顯示比較結果。

步驟 3:編寫程式碼

  • 在 MainForm.cs 中,添加以下程式碼:
  • using System;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace DiffComparison
    {
        public partial class MainForm : Form
        {
            public MainForm()
            {
                InitializeComponent();
                panelOverview.Paint += PanelOverview_Paint;
                rtbLeft.SelectionChanged += RtbLeft_SelectionChanged;
                rtbRight.SelectionChanged += RtbRight_SelectionChanged;
            }
    
            private void btnCompare_Click(object sender, EventArgs e)
            {
                CompareTexts();
            }
    
            private void CompareTexts()
            {
                string[] leftLines = rtbLeft.Lines;
                string[] rightLines = rtbRight.Lines;
    
                rtbLeft.Clear();
                rtbRight.Clear();
    
                for (int i = 0; i < Math.Max(leftLines.Length, rightLines.Length); i++)
                {
                    if (i < leftLines.Length)
                    {
                        rtbLeft.AppendText(leftLines[i] + Environment.NewLine);
                        if (i < rightLines.Length && leftLines[i] != rightLines[i])
                        {
                            rtbLeft.SelectionStart = rtbLeft.GetFirstCharIndexFromLine(i);
                            rtbLeft.SelectionLength = leftLines[i].Length;
                            rtbLeft.SelectionBackColor = Color.Pink;
                        }
                    }
    
                    if (i < rightLines.Length)
                    {
                        rtbRight.AppendText(rightLines[i] + Environment.NewLine);
                        if (i < leftLines.Length && leftLines[i] != rightLines[i])
                        {
                            rtbRight.SelectionStart = rtbRight.GetFirstCharIndexFromLine(i);
                            rtbRight.SelectionLength = rightLines[i].Length;
                            rtbRight.SelectionBackColor = Color.Pink;
                        }
                    }
                }
    
                panelOverview.Invalidate(); // 重新繪製概覽面板
            }
    
            private void PanelOverview_Paint(object sender, PaintEventArgs e)
            {
                Graphics g = e.Graphics;
                int lineHeight = rtbLeft.Font.Height;
                int leftLineCount = rtbLeft.Lines.Length;
                int rightLineCount = rtbRight.Lines.Length;
                int maxLines = Math.Max(leftLineCount, rightLineCount);
    
                for (int i = 0; i < maxLines; i++)
                {
                    if (i < leftLineCount && i < rightLineCount && rtbLeft.Lines[i] != rtbRight.Lines[i])
                    {
                        int y = i * lineHeight;
                        g.FillRectangle(Brushes.Red, new Rectangle(0, y, panelOverview.Width, lineHeight));
                    }
                }
            }
    
            private void RtbLeft_SelectionChanged(object sender, EventArgs e)
            {
                ScrollToCorrespondingLine(rtbLeft);
            }
    
            private void RtbRight_SelectionChanged(object sender, EventArgs e)
            {
                ScrollToCorrespondingLine(rtbRight);
            }
    
            private void ScrollToCorrespondingLine(RichTextBox rtb)
            {
                int lineIndex = rtb.GetLineFromCharIndex(rtb.SelectionStart);
                rtb.ScrollToCaret(); // 滾動到當前選擇行
                panelOverview.Invalidate(); // 重新繪製概覽面板
            }
        }
    }

說明

  • 比較文本:使用 CompareTexts 方法來比較兩個 RichTextBox 的內容,並將不同的行設置為粉紅色背景。
  • 繪製概覽:在 Panel 的 Paint 事件中,使用 Graphics 物件來繪製紅色矩形,表示不同的行。
  • 滾動功能:在 RichTextBox 的 SelectionChanged 事件中,根據當前選擇的行滾動到相對應的行,並更新概覽面板。

注意事項

  • 確保 Panel 的大小足夠以顯示所有行的概覽。
  • 可能需要進一步調整 Panel 的繪製邏輯,以確保紅線的顯示與行的對應位置正確。

執行結果

  • 執行這個應用程式後,可以在兩個 RichTextBox 中輸入文本,點擊「比較」按鈕,將會顯示不同的行,並且在概覽面板中以紅線標示出來。
  • 當在任一 RichTextBox 中點擊不同的行時,另一個 RichTextBox 會自動滾動到該行。

TAGS

  • 22 person(s) visited this page until now.

blog/2025-05-08-001.txt · Last modified: 2025/05/08 17:40 by jethro