2015-10-07 32 views
5

Tôi đang cố gắng để có một điều khiển người dùng có góc tròn. Nó không có kích thước cố định nhưng nó thường không có chiều rộng lớn hơn 120 pixel.Cách tạo Điều khiển người dùng với các góc tròn?

Tôi cần Kiểm soát người dùng và nội dung của nó (nhãn và bảng) để có cạnh tròn và trông giống như một hộp tròn.

Tôi đã sử dụng mã này.

[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)); 
    } 

Điều này cho phép điều khiển góc tròn nhưng sau khi nó đã được chạy lần afew và tôi đã thêm bội số của User Control của tôi với hình thức nó sẽ gây ra một sự rò rỉ và tôi sẽ nhận được WhiteBox với một chữ thập đỏ trên của tôi điều khiển người dùng.

Có cách nào tốt hơn để thực hiện việc này không?

+1

Tôi cũng gặp sự cố này. Và hãy tin tôi, bỏ WinForms và bắt đầu với 'WPF'. Cách tốt hơn để tùy biến !! – kevintjuh93

+0

Bạn sử dụng 'CreateRoundRectRgn' như thế nào? Tương tự như [this] (http://stackoverflow.com/q/17787573/1997232)? Sau đó, tất nhiên bạn sẽ có một rò rỉ xử lý. Bạn có muốn sửa lỗi (sau đó mã bưu điện nơi bạn sử dụng nó) hoặc đang tìm kiếm giải pháp thay thế? Một giải pháp thay thế có thể là điều khiển [trong suốt] (http://stackoverflow.com/q/9358500/1997232) với hình ảnh góc được làm tròn. – Sinatr

+0

Sinatr, bạn chính xác đây là cách tôi đang làm điều này, GetRoundedRegion đang được gọi khi biểu mẫu được sơn lại, tiếc là tôi không thể gọi phương thức này trong OnHandleCreated() như được đề xuất trong liên kết của bạn vì kích thước rất cao và tại xử lý tạo ra các điều khiển kích thước là kích thước mặc định và nó đi abit ngẫu nhiên. – CJM

Trả lời

1

Đặt Region chỉ có ý nghĩa nếu bạn muốn "nhấp qua" vùng trong suốt. Nếu các góc bo tròn không quá lớn và bạn chỉ muốn làm cho các góc trực quan trong suốt, bạn có thể làm tương tự như Button.

Ưu điểm của giải pháp này là bạn có thể có một góc tròn được làm đẹp bằng bí danh ở đây, trong khi các cạnh của khu vực luôn sắc nét. Không đề cập đến trường hợp Region đang giữ tài nguyên không được quản lý và phải được xử lý bằng cách nào đó.

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); 
} 
+0

Thật không may khi tôi cố gắng để vượt qua phương pháp Paint nó chỉ không kích hoạt trên điều khiển người dùng của tôi. – CJM

+0

Tôi đã sửa ví dụ, không giống như sự kiện 'Paint', phương thức' OnPaint' không có đối số 'sender'. – taffer

8

Nếu bạn muốn góc thực sự tròn và không chỉ lừa suốt bạn có thể sử dụng ví dụ này:

private int radius=20; 
[DefaultValue(20)] 
public int Radius 
{ 
    get { return radius; } 
    set 
    { 
     radius = value; 
     this.RecreateRegion(); 
    } 
} 
private GraphicsPath GetRoundRectagle(Rectangle bounds, int radius) 
{ 
    GraphicsPath path = new GraphicsPath(); 
    path.AddArc(bounds.X, bounds.Y, radius, radius, 180, 90); 
    path.AddArc(bounds.X + bounds.Width - radius, bounds.Y, radius, radius, 270, 90); 
    path.AddArc(bounds.X + bounds.Width - radius, bounds.Y + bounds.Height - radius, 
       radius, radius, 0, 90); 
    path.AddArc(bounds.X, bounds.Y + bounds.Height - radius, radius, radius, 90, 90); 
    path.CloseAllFigures(); 
    return path; 
} 
private void RecreateRegion() 
{ 
    var bounds = new Rectangle(this.ClientRectangle.Location, this.ClientRectangle.Size); 
    bounds.Inflate(-1, -1); 
    this.Region = new Region(GetRoundRectagle(bounds, this.Radius)); 
    this.Invalidate(); 
} 
protected override void OnSizeChanged(EventArgs e) 
{ 
    base.OnSizeChanged(e); 
    this.RecreateRegion(); 
} 

Và ảnh chụp màn hình sẽ là:

enter image description here

Sự khác biệt giữa phương pháp này và minh bạch:

  • Đặt vùng tròn, điều khiển có góc thực sự tròn và bạn có thể thấy những gì đằng sau phần tròn mặc dù khi nó trong suốt, bạn sẽ thấy nền của biểu mẫu.
  • Đặt vùng tròn, khi bạn nhấp vào phần được xóa tròn, nhấp qua vùng và chạm vào phía sau, nhưng nếu bạn sử dụng nhấp chuột trong suốt, hãy nhấp vào vùng trong suốt sẽ được điều khiển bởi điều khiển.

Bạn có thể sử dụng bất kỳ tùy chọn nào trong số 2 tùy chọn này. Làm cho khu vực minh bạch hoặc thiết lập dựa trên yêu cầu của bạn.

+0

Bạn sẽ thêm đường viền vào phần này bằng cách nào? Tôi cần một cái gì đó giống như FixedSingle BorderStyle, và có được đặt trên điều khiển nhưng khi đoạn mã trên thực hiện nó dường như bị loại bỏ. – Sam07

+0

@Sam 'GetRoundRectagle' trả về một đường dẫn mà bạn có thể sử dụng đường dẫn trong' e.Graphics.DrawPath() 'để vẽ một đường viền xung quanh đường dẫn. Chỉ cần đọc hai ghi chú cuối cùng của câu trả lời một cách cẩn thận. (Đối với các cạnh mượt mà hơn, bạn có tùy chọn giữ cho vùng không thay đổi và chỉ làm cho màu điều khiển hỗ trợ màu trong suốt, sự khác biệt chỉ là khi chồng chéo một số điều khiển để hiểu rõ hơn về ý nghĩa của chúng tôi, hãy xem [bài đăng này] (http://stackoverflow.com/questions/35467199/is-this-possible-to-have-triangular-picturebox-instead-of-the-rectangular-one), bạn có thể thấy nó hữu ích). –

0

Tôi đã trả lời câu hỏi của riêng mình.

Theo nhận xét của Sinatr tôi đã tìm thấy tôi không thể sử dụng OnHandleCreated như tôi cần thiết để chuẩn bị vẽ đối tượng trước khi tôi biết kích thước của nó là bao nhiêu. Theo liên kết Sinatr cung cấp GetRoundedRegion exception

Vì vậy, những gì tôi đã làm được thêm một biến IntPtr vào UserControl của tôi được gán cho phương pháp CreateRoundRectRgn mỗi lớp có tay cầm. Trước khi điều này gây ra tôi đang sử dụng DeleteObject để loại bỏ các xử lý cũ.

Không phải là giải pháp tối ưu nhưng dường như vẫn hoạt động tốt.

Các đề xuất khác trong khi tốt, không hoạt động trong trường hợp của tôi.

+0

Câu trả lời tôi đã đăng hoạt động đúng cách, bạn có thể xem ảnh chụp màn hình. Và nó sử dụng GDI + :) –

+0

Phương pháp của bạn hoạt động Reza nhưng các góc không giống nhau và các mặt điều khiển của tôi co lại phần nào. Một số fiddling sẽ sửa chữa im này chắc chắn. Tôi có thể sẽ quay lại và thực hiện giải pháp của bạn trong tương lai khi tôi có thời gian rảnh vì tôi nghĩ đó là một giải pháp tốt hơn, bây giờ tôi hài lòng với những gì tôi có. Chúc mừng mặc dù :) – CJM

+0

Cảm ơn bạn đã bình luận của bạn. các góc không giống nhau sẽ được cố định một cách đơn giản. –

Các vấn đề liên quan