如何在ComplexTextBox右侧显示外置按钮?继承控件布局问题求助
解决继承自TextBox的自定义控件外侧显示按钮的问题
问题核心是TextBox派生控件默认会裁剪超出自身边界的子控件,因为ClipToBounds属性默认是true,所以你把按钮位置设为(this.Size.Width, 0)时,按钮完全在控件范围外,被裁剪得看不见。
下面是具体解决步骤:
1. 关闭控件的裁剪功能
直接设置控件的ClipToBounds为false,允许子控件显示在控件边界之外:
this.ClipToBounds = false;
2. 调整文本显示区域,避免按钮遮挡内容
按钮在右侧的话,得给TextBox的文本区域留出按钮宽度,不然输入的文本会被按钮挡住。有两种方式实现:
方式一:重写ClientRectangle属性
protected override System.Drawing.Rectangle ClientRectangle { get { Rectangle baseRect = base.ClientRectangle; // 右侧减去按钮宽度,保证文本不被覆盖 return new Rectangle(baseRect.X, baseRect.Y, baseRect.Width - m_btnOpenCharDialog.Width, baseRect.Height); } }
方式二:处理WM_NCCALCSIZE消息(更底层的调整)
如果重写ClientRectangle不生效,可以通过窗口消息调整客户区:
protected override void WndProc(ref Message m) { const int WM_NCCALCSIZE = 0x0083; if (m.Msg == WM_NCCALCSIZE && m.WParam != IntPtr.Zero) { NCCALCSIZE_PARAMS paramsData = Marshal.PtrToStructure<NCCALCSIZE_PARAMS>(m.LParam); // 右侧缩进按钮宽度 paramsData.rgrc0.Right -= m_btnOpenCharDialog.Width; Marshal.StructureToPtr(paramsData, m.LParam, false); } base.WndProc(ref m); } // 配套的结构体定义 [StructLayout(LayoutKind.Sequential)] private struct NCCALCSIZE_PARAMS { public RECT rgrc0; public RECT rgrc1; public RECT rgrc2; public IntPtr lppos; } [StructLayout(LayoutKind.Sequential)] private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
3. 处理控件大小变化,保持按钮位置正确
构造函数里的位置设置只在初始化时生效,控件大小改变时按钮会跑偏,得订阅SizeChanged事件更新位置:
// 在构造函数里添加订阅 this.SizeChanged += ComplexTextboxWithButtonAside_SizeChanged; // 初始化按钮位置 UpdateButtonLocation(); // 事件处理和位置更新方法 private void ComplexTextboxWithButtonAside_SizeChanged(object sender, EventArgs e) { UpdateButtonLocation(); } private void UpdateButtonLocation() { // 按钮贴控件右侧,垂直居中 m_btnOpenCharDialog.Location = new Point(this.Width, (this.Height - m_btnOpenCharDialog.Height) / 2); }
完整修改后的构造函数示例
public ComplexTextboxWithButtonAside() { InitializeComponent(); m_btnOpenCharDialog = new KstaButton(); m_specialCharDialogForm = new ComplexTextboxWithButtonAside(this.components); m_specialCharDialogForm.CharacterConfirmedContainer += OnCharacterConfirmedContainer; // 关闭裁剪,允许按钮显示在控件外 this.ClipToBounds = false; m_btnOpenCharDialog.Parent = this; this.Controls.Add(m_btnOpenCharDialog); // 按钮属性设置 this.m_btnOpenCharDialog.Image = global::Ksta.Presentation.Properties.Resources.IconLEA; this.m_btnOpenCharDialog.Name = "m_btnOpenCharDialog"; this.m_btnOpenCharDialog.ReadOnlyMode = false; this.m_btnOpenCharDialog.Size = new System.Drawing.Size(20, 20); this.m_btnOpenCharDialog.TabIndex = 0; this.m_btnOpenCharDialog.Text = ""; this.m_btnOpenCharDialog.UseVisualStyleBackColor = true; this.m_btnOpenCharDialog.BringToFront(); this.m_btnOpenCharDialog.Click += OnOpenButtonClick; // 订阅大小变化事件,更新按钮位置 this.SizeChanged += ComplexTextboxWithButtonAside_SizeChanged; UpdateButtonLocation(); }
内容的提问来源于stack exchange,提问作者Phuong Nguyen
相关产品推荐
相关产品推荐

