簡體   English   中英

捕獲 TableLayoutPanel 特定區域的圖像

[英]Capture image of specific area of a TableLayoutPanel

我有一個使用TableLayoutPanel控件的項目。
我想要捕獲該TableLayoutPanel特定區域的圖像。
我有一個圖像(已捕獲)寬度和高度信息。 我也有開始結束單元格索引信息,我成功捕獲但捕獲的區域是錯誤的。

在此處輸入圖片說明

這是我的代碼:

private void getImage()
{
    int totalWidth = 250 // image width size;
    int totalHeight = 200 // image height size;

    int LeftBottomCellColumnIndex = 3
    int LeftBottomCellRowIndex = 4

    int LeftTopCellColumnIndex = 3
    int LeftBottomCellRowIndex = 2 // I also have all cells index info

    Bitmap bm = new Bitmap(totalWidth, totalHeight);
    tableLayoutPanel2.DrawToBitmap(bm, new Rectangle(0, 0, totalWidth, totalHeight)); // 0,0 problem is here. I do not know what I have to put there

    string path = @"C:\Users\prdn5\TestDrawToBitmap.bmp";
    FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
    bm.Save(fs, ImageFormat.Bmp);
    fs.Flush();
    fs.Close();
}

由於某種原因,TableLayoutPanel 不會通過屬性或方法直接公開單元格邊界。 但當然它會計算這些值供內部使用,因為它需要繪制其單元格的邊界。

它的OnPaintBackground方法對此負責。
當 Control 需要重新繪制自身時,會重新計算 Cells 邊界,並且對於每個 Cell,Control 會引發CellPaint事件。 它的TableLayoutCellPaintEventArgs參數返回當前單元格的邊界和列/行坐標。
由於每次修改/調整 TableLayoutPanel 大小時都會引發此事件,因此我們可以使用CellPaint事件處理程序來存儲這些引用。

在這里,我使用Dictionary<TableLayoutPanelCellPosition, Rectangle>來存儲每個單元格的坐標並將其映射到其邊界。

Layout事件處理程序設置一個布爾字段,導致僅在必要時重建字典(因為 TableLayoutPanel 的布局已更改)。

▶ Dictionary Key 是TableLayoutPanelCellPosition,因為它允許快速簡單的相等比較。 當然,如果需要,您可以使用不同類型的對象。

▶ 假設 TableLayoutPanel 被命名為tlp1

▶ 不處理在運行時添加和/或刪除列/行。 如果需要,請在Layout事件處理程序而不是 Form Constructor 中重新定義 Dictionary。

public partial class SomeForm : Form
{
    Dictionary<TableLayoutPanelCellPosition, Rectangle> tlpCells = null;
    bool calcCells = false;

    public SomeForm() {
        InitializeComponent();

        // Set the DoubleBuffered property via reflection (if needed)
        var flags = BindingFlags.Instance | BindingFlags.NonPublic;
        tlp1.GetType().GetProperty("DoubleBuffered", flags).SetValue(tlp1, true);

        tlpCells = new Dictionary<TableLayoutPanelCellPosition, Rectangle>();
        for (int x = 0; x < tlp1.ColumnCount; x++) {
            for (int y = 0; y < tlp1.RowCount; y++) {
                tlpCells.Add(new TableLayoutPanelCellPosition(x, y), Rectangle.Empty);
            }
        }
    }

    private void tlp1_Layout(object sender, LayoutEventArgs e) => calcCells = true;

    private void tlp1_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
    {
        if (calcCells) {
            var cellPos = new TableLayoutPanelCellPosition(e.Column, e.Row);
            tlpCells[cellPos] = e.CellBounds;

            if (cellPos.Column == tlp1.ColumnCount - 1 && 
                cellPos .Row == tlp1.RowCount - 1) calcCells = false;
        }
    }
}

要從當前鼠標位置獲取單元格,請調用GetSelectedCell() ,傳遞相對於 TableLayoutPanel 的當前指針位置:

var cell = GetSelectedCell(tlp1.PointToClient(MousePosition));
// If called from the MouseMove, MouseDown etc handlers, use the MouseEventArgs instead
var cell = GetSelectedCell(e.Location);

// [...]

private TableLayoutPanelCellPosition GetSelectedCell(Point position) 
    => tlpCells.FirstOrDefault(c => c.Value.Contains(position)).Key;

現在,要從一系列單元格生成位圖,您只需要指定開始(左、上)和結束(右、下)單元格並將這些值引用傳遞給TlpCellRangeToBitmap()方法(它也可以用作擴展方法)。
如果includeBorders參數設置為true ,它將包括單元格的外部邊框(請參閱可視化示例)。 添加代碼以檢查 TableLayoutPanel 是否實際具有邊框( BorderStyle屬性)。
包含單元格范圍的 Rectangle 由GetCellRangeBounds()返回:此方法是獨立的,可用於其他目的。

例如,將 PictureBox 的 Image 屬性設置為生成的 Bitmap:

var cellStart = new TableLayoutPanelCellPosition(2, 2);
var cellEnd = new TableLayoutPanelCellPosition(3, 5);

somePictureBox.Image?.Dispose();
somePictureBox.Image = TlpCellRangeToBitmap(tlp1, cellStart, cellEnd, false);

// [...]

private Bitmap TlpCellRangeToBitmap(TableLayoutPanel tlp, TableLayoutPanelCellPosition cellStart, TableLayoutPanelCellPosition cellEnd, bool includeBorders)
{
    // The 3rd parameter includes or excludes the external borders
    var selRect = GetCellRangeBounds(cellStart, cellEnd, includeBorders);
    using (var image = new Bitmap(tlp.Width + 1, tlp.Height + 1)) {
        tlp.DrawToBitmap(image, new Rectangle(Point.Empty, tlp.Size));
        return image.Clone(selRect, PixelFormat.Format32bppArgb);
    }
}

private Rectangle GetCellRangeBounds(TableLayoutPanelCellPosition start, TableLayoutPanelCellPosition end, bool extBorders)
{
    var cellStart = tlpCells[start];
    var cellEnd = tlpCells[end];
    if (extBorders) {
        cellStart.Location = new Point(cellStart.X - 1, cellStart.Y - 1);
        cellEnd.Size = new Size(cellEnd.Width + 2, cellEnd.Height + 2);
    }
    return new Rectangle(cellStart.Location, new Size(cellEnd.Right - cellStart.X, cellEnd.Bottom - cellStart.Y));
}

這是它的工作原理:

TableLayoutPanel 單元格范圍到位圖

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM