2013-04-07 11 views
32

winformsのテキストボックスには、ボックスの最後に埋め込みボタンを作成するプロパティがありますか?winformsのテキストボックス内のボタン

クロームアドレスボックスにお気に入りボタンのようなもの:

enter image description here


:私はまた、いくつかのExcel形式で、次のようなものを見てきました

enter image description here

編集

私はクリックイベントハンドラを追加したハンスアンパッサンの答えを追ってきたし、正常に動作するように見える:あなたがあなた自身のユーザーコントロールを作成する必要があるというようなことを行うために

protected override void OnLoad(EventArgs e) { 
     var btn = new Button(); 
     btn.Size = new Size(25, textBoxFolder.ClientSize.Height + 2); 
     btn.Location = new Point(textBoxFolder.ClientSize.Width - btn.Width, -1); 
     btn.Cursor = Cursors.Default; 
     btn.Image = Properties.Resources.arrow_diagright; 
     btn.Click += btn_Click;  
     textBoxFolder.Controls.Add(btn); 
     // Send EM_SETMARGINS to prevent text from disappearing underneath the button 
     SendMessage(textBoxFolder.Handle, 0xd3, (IntPtr)2, (IntPtr)(btn.Width << 16)); 
     base.OnLoad(e); 
    } 

    [System.Runtime.InteropServices.DllImport("user32.dll")] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); 

    private void btn_Click(object sender, EventArgs e) { 
     MessageBox.Show("hello world"); 
    } 
+7

@Highcore、あなたは絶望的なワントリックポニーです。あなたの無視タグに[winforms]タグを追加してください、私はあなたのwpf rantsをもう見たくありません。 –

+0

@HighCore私はハンスが言っているのと同じことの前にあなたに告げました。 WinFormsの質問は今から避けることを強くお勧めします。 –

+0

@HansPassant ....私はちょうど今出発し、質問に追いつく - 良い人が彼を怖がっているように見える! – whytheq

答えて

44

TextBox内のボタンを取得するには、Controlsコレクションのボックスに追加するだけです。また、ボックス内のテキストがボタンの下に表示されないようにするには、妥当な何かを行う必要があります。それはちょっとしたピンボケが必要です。このように:

protected override void OnLoad(EventArgs e) { 
     var btn = new Button(); 
     btn.Size = new Size(25, textBox1.ClientSize.Height + 2); 
     btn.Location = new Point(textBox1.ClientSize.Width - btn.Width, -1); 
     btn.Cursor = Cursors.Default; 
     btn.Image = Properties.Resources.star; 
     textBox1.Controls.Add(btn); 
     // Send EM_SETMARGINS to prevent text from disappearing underneath the button 
     SendMessage(textBox1.Handle, 0xd3, (IntPtr)2, (IntPtr)(btn.Width << 16)); 
     base.OnLoad(e); 
    } 

    [System.Runtime.InteropServices.DllImport("user32.dll")] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); 

は(きれいにビットマップを選んでいるはずです)、私は右マージンをテストしながらこのように見えた:

enter image description here

+0

+1 Hansに感謝 - 私のプロジェクトに実装されているかどうかを確認します。直観的に見える - ビットマップを見つける:プロジェクトリソースへのインポート。ビットマップ名を与える;新しい名前付きビットマップでコードを使用してください.... – whytheq

+0

はうまくいくようです:私は 'btn.Click + = btn_Click;'という行を追加して何かをします。私はいくつかの良いコードを台無しにした場合、私が100%確信していないものを持ってOPを修正します。 – whytheq

+0

@ハンス・パッセンジャー - これは素晴らしいソリューションです。ありがとうございます。 SendMessage関数の仕組みについて詳しく説明してください。 – JWiley

0

号。テキストボックスとボタンから簡単にまとめることができます。難しいことは、テキストボックスに似たプロパティが必要な場合は、それらをすべて作成する必要があるということです。結局それは多くのコードです。

+0

私がOPで示した2番目のスクリーンプリントはExcelフォームからのものなので、どこかにあるはずですか?私はそれをExcelライブラリから継承できますか? – whytheq

+1

@whytheq - Excelは、Windows APIとMFCを使用してC++で書かれています。それはカスタム書かれたコントロールです。 WinFormsでこれを行うことができますが、カスタムコントロールを作成する必要があります。私はWPFの学習をお勧めします。これをもっと簡単に行う – thorkia

+0

@thorkia - 優れたアイデアのように見えますが、少し遠いところでしたが、OPのHansソリューション+コメントをチェックしてください。 – whytheq

3

あなたが別のライブラリへの参照を追加するために喜んでいる場合は、クリプトンツールキット(https://github.com/ComponentFactory/Kryptonから入手可能)の使用を検討することができます。リボン、ナビゲータ、またはワークスペースの機能を使用しないで無料で使用できる基本的なツールキットでは、記述したように視覚的に表示されるさまざまなコントロール(テキストボックスを含む)に「ボタン仕様」を追加できます。

7

ここは、TextBoxサブクラスにラップされた回答です。

public class ButtonTextBox : TextBox { 
    private readonly Button _button; 

    public event EventHandler ButtonClick { add { _button.Click += value; } remove { _button.Click -= value; } } 

    public ButtonTextBox() { 
     _button = new Button {Cursor = Cursors.Default}; 
     _button.SizeChanged += (o, e) => OnResize(e); 
     this.Controls.Add(_button); 
    } 

    public Button Button { 
     get { 
      return _button; 
     } 
    } 

    protected override void OnResize(EventArgs e) { 
     base.OnResize(e); 
     _button.Size = new Size(_button.Width, this.ClientSize.Height + 2); 
     _button.Location = new Point(this.ClientSize.Width - _button.Width, -1); 
     // Send EM_SETMARGINS to prevent text from disappearing underneath the button 
     SendMessage(this.Handle, 0xd3, (IntPtr)2, (IntPtr)(_button.Width << 16)); 
    } 

    [System.Runtime.InteropServices.DllImport("user32.dll")] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); 

} 
+0

悲しいことに、このバージョンを使用していくつかの非常に奇妙な副作用があります。たとえば、ButtonTextBoxの下にある "Button"メンバーを展開することで、デザイナー内のButtonのImageフィールドを設定できますが、Debug/Runを押すと、Buttonはイメージを忘れてデザイナーに戻ります。同様に... – MrCC

1

ハンスアンパッサンの素敵なアイデアのマイナー追加 - テキストボックスがサイズ変更可能であるならば、それは場所がClientSizeに調整しますだように、あなたは根本的なボタンにバインドを追加することができ、同様に変更:

//Adjust the Location of the button on Size Changes of the containing textBox. 
    var binding = new Binding("Location", textBox1, "ClientSize"); 
    binding.Format += (s, e) => e.Value = e.Value is Size ? new Point(((Size)e.Value).Width - btn.Width, -1) : new Point(0, 0); 
    btn.DataBindings.Add(binding); 
1

ボタンを見て正しく動作させるには、受け入れられたソリューションを少し拡張して、少し微調整する必要があります。ここでは、検索ボックスの微調整されている:

private static readonly int SEARCH_BUTTON_WIDTH = 25; 

    private void ConfigureSearchBox() 
    { 
     var btn = new Button(); 
     btn.Size = new Size(SEARCH_BUTTON_WIDTH, searchBox.ClientSize.Height + 2); 
     btn.Dock = DockStyle.Right; 
     btn.Cursor = Cursors.Default; 
     btn.Image = Properties.Resources.Find_5650; 
     btn.FlatStyle = FlatStyle.Flat; 
     btn.ForeColor = Color.White; 
     btn.FlatAppearance.BorderSize = 0; 
     btn.Click += btn_Click; 
     searchBox.Controls.Add(btn); 
     this.AcceptButton = btn; 
     // Send EM_SETMARGINS to prevent text from disappearing underneath the button 
     SendMessage(searchBox.Handle, 0xd3, (IntPtr)2, (IntPtr)(btn.Width << 16)); 
    } 

    [System.Runtime.InteropServices.DllImport("user32.dll")] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); 

    private void btn_Click(object sender, EventArgs e) 
    { 
     MessageBox.Show("hello world"); 
    } 
3

は私がコントロール「のSendMessage(int型、int型、int型)」メソッドが含まれていることをリフレクターで見たが、私は別の方法を発見しました。

using System; 
using System.Reflection; 
using System.Windows.Forms; 

static class ControlExtensions 
{ 
    static BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; 
    static Type[] SendMessageSig = new Type[] { typeof(int), typeof(int), typeof(int) }; 

    internal static IntPtr SendMessage(this Control control, int msg, int wparam, int lparam) 
    { 
     MethodInfo MethodInfo = control.GetType().GetMethod("SendMessage", flags, null, SendMessageSig, null); 

     return (IntPtr)MethodInfo.Invoke(control, new object[] { msg, wparam, lparam }); 
    } 
} 

ButtonTextBoxでWndProcをオーバーライドすることで、目的の効果を得ることができます。

public class ButtonTextBox : TextBox 
{ 
    Button button; 

    public ButtonTextBox() 
    { 
     this.button = new Button(); 
     this.button.Dock = DockStyle.Right; 
     this.button.BackColor = SystemColors.Control; 
     this.button.Width = 21; 
     this.Controls.Add(this.button); 
    } 

    protected override void WndProc(ref Message m) 
    { 
     base.WndProc(ref m); 

     switch (m.Msg) 
     { 
      case 0x30: 
       int num = this.button.Width + 3; 
       this.SendMessage(0xd3, 2, num << 16); 
       return; 
     } 
    } 
} 

これはもっと安全な方法だと思います。

+0

アップはソリューションに投票しましたが、私はそれが何をしているのか不思議に思っていました。それらの数字は何を表していますか? – Lara

+0

返事をありがとう。私は0x0030はWM_SETFONTメッセージだが、wParamはフォントのハンドルで、lParamの下位ワードは再描画するブール値でなければならない理由は2、num << 16だと分かっていますか?また、ハンスの答えが一番良いと思いますか?自己完結型のクラスが私にとってもっと望ましいです。 – Lara

関連する問題