簡體   English   中英

如何創建帶圓角的用戶控件?

[英]How to create a User Control with rounded corners?

我正在嘗試使用圓角的用戶控件。 它沒有固定的大小,但它的寬度通常不會超過 120 像素。

我需要用戶控件及其內容(標簽和表格)具有圓形邊緣並且看起來像一個圓框。

我用過這個代碼。

[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
    private static extern IntPtr CreateRoundRectRgn
    (
        int nLeftRect, // x-coordinate of upper-left corner
        int nTopRect, // y-coordinate of upper-left corner
        int nRightRect, // x-coordinate of lower-right corner
        int nBottomRect, // y-coordinate of lower-right corner
        int nWidthEllipse, // height of ellipse
        int nHeightEllipse // width of ellipse
    );

    public static System.Drawing.Region GetRoundedRegion(int controlWidth, int controlHeight)
    {
            return System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, controlWidth - 5, controlHeight - 5, 20, 20));
    } 

這為控件提供了圓角,但在它運行了幾次之后,我將多個用戶控件添加到表單中,這將導致泄漏,我將在我的用戶控件上獲得帶有紅叉的白框。

有沒有更好的方法來做到這一點?

如果你想要真正的圓角而不僅僅是透明的技巧,你可以使用這個例子:

private int radius = 20;
[DefaultValue(20)]
public int Radius
{
    get { return radius; }
    set
    {
        radius = value;
        this.RecreateRegion();
    }
}

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern IntPtr CreateRoundRectRgn(int nLeftRect, int nTopRect,
    int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse);

private GraphicsPath GetRoundRectagle(Rectangle bounds, int radius)
{
    float r = radius;
    GraphicsPath path = new GraphicsPath();
    path.StartFigure();
    path.AddArc(bounds.Left, bounds.Top, r, r, 180, 90);
    path.AddArc(bounds.Right - r, bounds.Top, r, r, 270, 90);
    path.AddArc(bounds.Right - r, bounds.Bottom - r, r, r, 0, 90);
    path.AddArc(bounds.Left, bounds.Bottom - r, r, r, 90, 90);
    path.CloseFigure();
    return path;
}

private void RecreateRegion()
{
    var bounds = ClientRectangle;

    //using (var path = GetRoundRectagle(bounds, this.Radius))
    //    this.Region = new Region(path);

    //Better round rectangle
    this.Region = Region.FromHrgn(CreateRoundRectRgn(bounds.Left, bounds.Top,
        bounds.Right, bounds.Bottom, Radius, radius));
    this.Invalidate();
}

protected override void OnSizeChanged(EventArgs e)
{
    base.OnSizeChanged(e);
    this.RecreateRegion();
}

屏幕截圖將是:

在此處輸入圖片說明

這種方法和透明化的區別:

  • 設置圓形區域,控件有真正的圓角,盡管它是透明的,但您可以看到圓形部分后面的內容,您將看到表單的背景。
  • 設置圓形區域,當您點擊移除的圓形部分時,點擊穿過該區域並到達后面,但如果您使用透明技巧點擊透明區域將由控件處理。

您可以使用這兩個選項中的任何一個。 根據您的要求制作透明或設置區域。

下載

您可以在此處下載代碼或克隆存儲庫:

只有當您想“點擊”透明區域時,設置Region才有意義。 如果圓角不是那么大,而您只想使圓角在視覺上透明,您可以像Button那樣做。

此解決方案的優點是您可以在這里有一個很好的抗鋸齒圓角,而區域的邊緣總是很鋒利。 沒有提到Region實例持有非托管資源,應該以某種方式處置。

protected override void OnPaint(PaintEventArgs e)
{
    PaintTransparentBackground(this, e);
    // TODO: Paint your actual content here with rounded corners
}

private static void PaintTransparentBackground(Control c, PaintEventArgs e)
{
    if (c.Parent == null || !Application.RenderWithVisualStyles)
        return;

    ButtonRenderer.DrawParentBackground(e.Graphics, c.ClientRectangle, c);
}

我已經回答了我自己的問題。

根據 Sinatr 的評論,我發現我無法使用 OnHandleCreated,因為我需要在知道對象大小之前繪制對象。 按照鏈接 Sinatr 提供的GetRoundedRegion 異常

所以我所做的是向我的 UserControl 添加一個 IntPtr 變量,該變量在每次繪制時都分配在 CreateRoundRectRgn 方法上。 在此觸發之前,我正在使用 DeleteObject 刪除舊句柄。

不是最佳解決方案,但目前似乎工作正常。

其他建議雖然很好,但在我的情況下不起作用。

暫無
暫無

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

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