none
画像入力系のテキストボックスについて RRS feed

  • 質問

  • お世話になります。

    開発言語は、C#。Windows From アプリケーション。

    対象のVisual Studio は、2010となります。

    このたび、ピクチャボックスに表示した画像に対して文字を入力するなどの処理を行いたいと考えています。

    上記の要件に伴い、GIMP等の画像編集系アプリケーションのような文字入力を行えるテキストボックスを使用したいのですが、

    有償、無償にかかわらずこの手のコンポーネントをご存じの方はいらっしゃいますでしょうか。

    ご存知の方がいらっしゃいましたら、教えて頂けると幸いです。

    やりたいこととしましては、マウスのドラッグにて幅を決定、

    その後、その領域に文字を入力するということを行いたいと思っています。

    恐れ入りますが、多少の情報でも構いませんので、書込みをお待ちしております。

    2015年9月26日 0:52

回答

  • こんな?

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    namespace WindowsFormsApplication4
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                this.BackColor = Color.Black;
                this.Width = 500;
                this.Height = 500;
    
    
                Panel panel = new Panel();
                panel.Location = new Point(10, 10);
                panel.Width = this.ClientSize.Width - 10;
                panel.Height = this.ClientSize.Height - 10;
    
                pictureBox1 = new PictureBox();
                pictureBox1.BackColor = Color.White;
                pictureBox1.Dock = DockStyle.Fill;
                pictureBox1.Width = this.ClientSize.Width - 10;
                pictureBox1.Height = this.ClientSize.Height - 10;
                pictureBox1.BorderStyle = BorderStyle.None;
                pictureBox1.Paint += pictureBox1_Paint;
                pictureBox1.MouseDown += pictureBox1_MouseDown;
                pictureBox1.MouseUp += pictureBox1_MouseUp;
    
                textBox1 = new TextBox();
                textBox1.BorderStyle = BorderStyle.None;
                textBox1.Multiline = true;
                textBox1.ScrollBars = ScrollBars.None;
                textBox1.Height = 10000;
                textBox1.TextChanged += textBox1_Changed;
                textBox1.KeyDown += textBox1_Changed;
                textBox1.KeyUp += textBox1_Changed;
    
                panel.Controls.Add(pictureBox1);
                panel.Controls.Add(textBox1);
                this.Controls.Add(panel);
    
                pictureBox1.BringToFront();
                textBox1.BringToFront();//IMEに対応するためにPictureBoxの背面に隠して配置
                textBox1.Visible = false;
    
                textBox1.Font = this.Font = new System.Drawing.Font("Meiryo", 20, System.Drawing.FontStyle.Bold);
                textBrush = Brushes.LimeGreen;
                pictureBox1.ImageLocation = "TestImage.jpg";
    
                //TextBoxの内側余白の計算(てきとー)
                textBox1.Width=100;
                textBox1.Text = string.Empty.PadLeft(10, 'A');
                margin = textBox1.GetPositionFromCharIndex(1).X - (textBox1.GetPositionFromCharIndex(2).X - textBox1.GetPositionFromCharIndex(1).X);
                textBox1.Text = string.Empty;
    
                pen1 = new Pen(Brushes.Black) { DashPattern = new float[] { 2, 2 }, DashOffset = 0 };
                pen2 = new Pen(Brushes.White) { DashPattern = new float[] { 2, 2 }, DashOffset = 2 };
                caretPen = new Pen(textBrush, 2);
    
            }
            int margin;
            private PictureBox pictureBox1;
            private TextBox textBox1;
            Brush textBrush;//文字用ブラシ
            Rectangle rect;//文字入力範囲(pictureBox1座標)
            Pen pen1;//枠線描画用
            Pen pen2;//枠線描画用
            Pen caretPen;
            private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
            {
                CommitText();
                rect.Location = e.Location;
                rect.Width = 0;
                rect.Height = 0;
            }
    
            private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
            {
                Point p0 = rect.Location;
                Point p1 = e.Location;
    
                rect.Location = new Point(Math.Min(p0.X, p1.X), Math.Min(p0.Y, p1.Y));
                rect.Width = Math.Abs(p0.Y - p1.X);
                rect.Height = Math.Abs(p0.Y - p1.Y);
    
                var location=textBox1.Parent.PointToClient(pictureBox1.PointToScreen(rect.Location));
                textBox1.Left = location.X - margin;
                textBox1.Top = location.Y;
                textBox1.Width = rect.Width+margin*2;
                textBox1.Height = 10000;
                textBox1.Visible = true;
                pictureBox1.BringToFront();
    
                textBox1.Focus();
                pictureBox1.Refresh();
            }
    
            private void textBox1_Changed(object sender, EventArgs e)
            {
                if (textBox1.SelectionLength > 0)
                {
                    textBox1.SelectionLength = 0;
                }
                pictureBox1.Refresh();
            }
    
            private void pictureBox1_Paint(object sender, PaintEventArgs e)
            {
                Draw(e.Graphics, true);
            }
    
            private void CommitText()
            {
                if (pictureBox1.Image != null)
                {
                    using (Graphics g = Graphics.FromImage(pictureBox1.Image))
                    {
                        Draw(g, false);
                    }
                }
                textBox1.Text = string.Empty;
                textBox1.Visible = false;
            }
    
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
            const int EM_POSFROMCHAR = 0x00D6;
    
            private void Draw(Graphics g, bool isDrawCaretAndRectangle)
            {
                if (rect.Width > 0 && rect.Height > 0)
                {
                    int w = (int)pen1.Width;
                    Rectangle rectArea = new Rectangle(rect.Left - w, rect.Top - w, rect.Width + w + w, rect.Height + w + w);
                    if (isDrawCaretAndRectangle)
                    {
                        g.DrawRectangle(pen1, rectArea);
                        g.DrawRectangle(pen2, rectArea);
                    }
    
                    if (textBox1.Font != null && textBrush != null)
                    {
                        g.DrawString(textBox1.Text, textBox1.Font, textBrush, rect);
    
                        if (isDrawCaretAndRectangle)
                        {
                            Point caretPos = rectArea.Location;
                            if (textBox1.SelectionStart> 0)
                            {
                                StringFormat sf = new StringFormat();
                                sf.SetMeasurableCharacterRanges(new CharacterRange[] { new CharacterRange(textBox1.SelectionStart - 1, 1) });
                                var regions = g.MeasureCharacterRanges(textBox1.Text, textBox1.Font, rectArea, sf);
                                var r = regions[0].GetBounds(g);
                                caretPos.X = (int)r.Right;
                                caretPos.Y = (int)r.Top;
                            }
    
                            g.DrawLine(caretPen, caretPos.X, caretPos.Y, caretPos.X, caretPos.Y + textBox1.Font.Height);
                        }
                    }
                }
            }
        }
    }
    #WPFなら背景が透明なTextBoxを置くだけで済むんだけどね

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答の候補に設定 星 睦美 2015年9月28日 2:28
    • 回答としてマーク 星 睦美 2015年10月9日 1:35
    2015年9月26日 15:17

すべての返信

  • こんな?

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    namespace WindowsFormsApplication4
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                this.BackColor = Color.Black;
                this.Width = 500;
                this.Height = 500;
    
    
                Panel panel = new Panel();
                panel.Location = new Point(10, 10);
                panel.Width = this.ClientSize.Width - 10;
                panel.Height = this.ClientSize.Height - 10;
    
                pictureBox1 = new PictureBox();
                pictureBox1.BackColor = Color.White;
                pictureBox1.Dock = DockStyle.Fill;
                pictureBox1.Width = this.ClientSize.Width - 10;
                pictureBox1.Height = this.ClientSize.Height - 10;
                pictureBox1.BorderStyle = BorderStyle.None;
                pictureBox1.Paint += pictureBox1_Paint;
                pictureBox1.MouseDown += pictureBox1_MouseDown;
                pictureBox1.MouseUp += pictureBox1_MouseUp;
    
                textBox1 = new TextBox();
                textBox1.BorderStyle = BorderStyle.None;
                textBox1.Multiline = true;
                textBox1.ScrollBars = ScrollBars.None;
                textBox1.Height = 10000;
                textBox1.TextChanged += textBox1_Changed;
                textBox1.KeyDown += textBox1_Changed;
                textBox1.KeyUp += textBox1_Changed;
    
                panel.Controls.Add(pictureBox1);
                panel.Controls.Add(textBox1);
                this.Controls.Add(panel);
    
                pictureBox1.BringToFront();
                textBox1.BringToFront();//IMEに対応するためにPictureBoxの背面に隠して配置
                textBox1.Visible = false;
    
                textBox1.Font = this.Font = new System.Drawing.Font("Meiryo", 20, System.Drawing.FontStyle.Bold);
                textBrush = Brushes.LimeGreen;
                pictureBox1.ImageLocation = "TestImage.jpg";
    
                //TextBoxの内側余白の計算(てきとー)
                textBox1.Width=100;
                textBox1.Text = string.Empty.PadLeft(10, 'A');
                margin = textBox1.GetPositionFromCharIndex(1).X - (textBox1.GetPositionFromCharIndex(2).X - textBox1.GetPositionFromCharIndex(1).X);
                textBox1.Text = string.Empty;
    
                pen1 = new Pen(Brushes.Black) { DashPattern = new float[] { 2, 2 }, DashOffset = 0 };
                pen2 = new Pen(Brushes.White) { DashPattern = new float[] { 2, 2 }, DashOffset = 2 };
                caretPen = new Pen(textBrush, 2);
    
            }
            int margin;
            private PictureBox pictureBox1;
            private TextBox textBox1;
            Brush textBrush;//文字用ブラシ
            Rectangle rect;//文字入力範囲(pictureBox1座標)
            Pen pen1;//枠線描画用
            Pen pen2;//枠線描画用
            Pen caretPen;
            private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
            {
                CommitText();
                rect.Location = e.Location;
                rect.Width = 0;
                rect.Height = 0;
            }
    
            private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
            {
                Point p0 = rect.Location;
                Point p1 = e.Location;
    
                rect.Location = new Point(Math.Min(p0.X, p1.X), Math.Min(p0.Y, p1.Y));
                rect.Width = Math.Abs(p0.Y - p1.X);
                rect.Height = Math.Abs(p0.Y - p1.Y);
    
                var location=textBox1.Parent.PointToClient(pictureBox1.PointToScreen(rect.Location));
                textBox1.Left = location.X - margin;
                textBox1.Top = location.Y;
                textBox1.Width = rect.Width+margin*2;
                textBox1.Height = 10000;
                textBox1.Visible = true;
                pictureBox1.BringToFront();
    
                textBox1.Focus();
                pictureBox1.Refresh();
            }
    
            private void textBox1_Changed(object sender, EventArgs e)
            {
                if (textBox1.SelectionLength > 0)
                {
                    textBox1.SelectionLength = 0;
                }
                pictureBox1.Refresh();
            }
    
            private void pictureBox1_Paint(object sender, PaintEventArgs e)
            {
                Draw(e.Graphics, true);
            }
    
            private void CommitText()
            {
                if (pictureBox1.Image != null)
                {
                    using (Graphics g = Graphics.FromImage(pictureBox1.Image))
                    {
                        Draw(g, false);
                    }
                }
                textBox1.Text = string.Empty;
                textBox1.Visible = false;
            }
    
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
            const int EM_POSFROMCHAR = 0x00D6;
    
            private void Draw(Graphics g, bool isDrawCaretAndRectangle)
            {
                if (rect.Width > 0 && rect.Height > 0)
                {
                    int w = (int)pen1.Width;
                    Rectangle rectArea = new Rectangle(rect.Left - w, rect.Top - w, rect.Width + w + w, rect.Height + w + w);
                    if (isDrawCaretAndRectangle)
                    {
                        g.DrawRectangle(pen1, rectArea);
                        g.DrawRectangle(pen2, rectArea);
                    }
    
                    if (textBox1.Font != null && textBrush != null)
                    {
                        g.DrawString(textBox1.Text, textBox1.Font, textBrush, rect);
    
                        if (isDrawCaretAndRectangle)
                        {
                            Point caretPos = rectArea.Location;
                            if (textBox1.SelectionStart> 0)
                            {
                                StringFormat sf = new StringFormat();
                                sf.SetMeasurableCharacterRanges(new CharacterRange[] { new CharacterRange(textBox1.SelectionStart - 1, 1) });
                                var regions = g.MeasureCharacterRanges(textBox1.Text, textBox1.Font, rectArea, sf);
                                var r = regions[0].GetBounds(g);
                                caretPos.X = (int)r.Right;
                                caretPos.Y = (int)r.Top;
                            }
    
                            g.DrawLine(caretPen, caretPos.X, caretPos.Y, caretPos.X, caretPos.Y + textBox1.Font.Height);
                        }
                    }
                }
            }
        }
    }
    #WPFなら背景が透明なTextBoxを置くだけで済むんだけどね

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答の候補に設定 星 睦美 2015年9月28日 2:28
    • 回答としてマーク 星 睦美 2015年10月9日 1:35
    2015年9月26日 15:17
  • 回答ありがとうございます。

    やはり、自作して作るのが一番良いですかね…。

    コードの提示、ありがとうございます。

    ご提示頂いたソースを試してみたところ、カスタマイズさせて頂いて良い感じに動きそうです。

    こちらでも、ピクチャボックスを使用して、描画処理を行うコントロールを試している所でしたので、

    gekkaさんの提示いただいたソースと合わせて、頑張ってみます。

    確かに、今回の件はWPFを使った方が早いような気もしてきました…。

    非常に助かります。検索しても、なかなか、見つからなかったものですから…。

    他にコンポーネントをご存じの方等いらっしゃいましたら、情報頂けると幸いです。

    2、3日後にはクローズ致しますので、もう少し、継続して情報を集めさせて頂けると幸いです。

    2015年9月27日 0:08
  • フォーラム オペレーターの星 睦美です。takeshi-reki さん、こんにちは。

    今回はgekka さんの回答に私から[回答としてマーク] させていただきました。もしtakeshi-reki さんからの[回答としてマーク] をいただける場合には、遠慮なく一旦 [回答としてのマークの解除] をして投稿者から[回答としてマーク] をお願いいたします。それでは今後ともフォーラムをお役立てください。

    ・フォーラムのヘルプ


    フォーラム オペレーター 星 睦美 - MSDN Community Support

    2015年10月9日 1:41