Question
ももたろう on Fri, 12 Jul 2019 08:16:43
visual studio 2019を使用しています。
プロジェクトはWindowsフォームアプリケーションで、C#を選択しています。
コントロールのtextboxに右余白を入れたいのですが、方法が分かりません。
win32apiなどを使用してできないでしょうか?
プログラミングは始めたばかりなので、分かりやすく教えていただきたいです。
Replies
gekka on Fri, 12 Jul 2019 10:25:37
こんな?
using System; using System.Windows.Forms; namespace WindowsFormsApp1 { public partial class Form1 : Form { TextBox textBox1; public Form1() { InitializeComponent(); textBox1 = new TextBox(); textBox1.Dock = DockStyle.Fill; textBox1.AcceptsReturn = true; textBox1.Multiline = true; textBox1.ScrollBars = ScrollBars.Vertical; Random rnd = new Random(); for (int i = 0; i < 100; i++) { textBox1.AppendText(string.Empty.PadRight(rnd.Next(200), '*') + "\r\n"); } this.Controls.Add(textBox1); MenuStrip menu = new MenuStrip(); this.Controls.Add(menu); var mitem = new ToolStripMenuItem("Test"); mitem.Click += Mitem_Click; menu.Items.Add(mitem); } private void Mitem_Click(object sender, EventArgs e) { SetMargin(this.textBox1, 10, 50); } private void SetMargin(TextBox textBox, ushort left, ushort right) { uint margin = (uint)left + ((uint)right << 16); SendMessage(textBox.Handle, EM_SETMARGINS, EC_RIGHTMARGIN | EC_LEFTMARGIN, new UIntPtr(margin)); //反映させる textBox1.Width--; textBox1.Width++; } [System.Runtime.InteropServices.DllImport("user32.dll")] static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, UIntPtr lParam); const int EM_SETMARGINS = 0x00D3; const int EM_GETMARGINS = 0x00D4; const int EC_LEFTMARGIN = 1; const int EC_RIGHTMARGIN = 2; const int EC_USEFONTINFO = 0xFFFF; } }
魔界の仮面弁士 on Fri, 12 Jul 2019 12:55:18
① 下記の "CustomTextBox.cs" を用意します。
using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; public sealed class CustomTextBox : TextBox { public CustomTextBox() { Multiline = true; } /// <summary> /// テキストボックスの内側の入力領域を取得・設定します。 /// </summary> public Rectangle ClientArea { get { const int EM_GETRECT = 0x00B2; IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf<Rectangle>()); var msg = Message.Create(Handle, EM_GETRECT, IntPtr.Zero, ptr); base.WndProc(ref msg); Rectangle rect = Marshal.PtrToStructure<Rectangle>(ptr); Marshal.FreeCoTaskMem(ptr); return rect; } set { // 複数行テキストボックスでなければ、領域サイズは変更できない if (!Multiline) { return; } const int EM_SETRECT = 0xB3; IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf<Rectangle>()); Marshal.StructureToPtr(value, ptr, false); var msg = Message.Create(Handle, EM_SETRECT, IntPtr.Zero, ptr); base.WndProc(ref msg); Marshal.FreeCoTaskMem(ptr); Refresh(); ClientAreaChanged?.Invoke(this, EventArgs.Empty); } } public EventHandler ClientAreaChanged; }
② プロジェクトをビルドしてから、改めて Form1 のデザイン画面を開くと、ツールボックスに「CustomTextBox」コントロールが追加されているので、それを Form1 に貼ります。
③ Form1 の Load イベントに、下記のコードを追加します。
var rect = customTextBox1.ClientArea; rect.Width -= 20; // 右端を 20px 空ける // rect.Inflate(-15, -15); // 領域全体を 15px 小さくする customTextBox1.ClientArea = rect;
ももたろう on Tue, 16 Jul 2019 06:06:53
gekka様、ありがとうございます。
実際にコードを入力して実行したら、右余白ができました。
何か、魔法のようで不思議に感じます。
uint margin = (uint)left + ((uint)right << 16);
の「<<」は、シフトでしょうか、どうしてシフトするのでしょうか。
IntPtr、UIntPtrは普段、あまりお目見えしないものです。
ネット検索しても、よく分かりませんでした。
ももたろう on Tue, 16 Jul 2019 06:10:49
魔界の仮面弁士様、ご返信ありがとうございます。
魔界の仮面弁士 on Tue, 16 Jul 2019 06:33:12
uint margin =(uint)left+ ((uint)right<< 16);
の「<<」は、シフトでしょうか、どうしてシフトするのでしょうか。
SendMessage の LPARAM パラメーターは、Win16/Win32 環境では32bit長、Win64環境では64bit長ですが、EM_SETMARGINS メッセージの LPARAM に対しては、どの環境でも 32bit 分だけが使われる仕様です。
そしてその 32bit 幅のうち、上位16bit部分が右マージン、下位16bit分が左マージンを意味します。
各マージンは 16bit 幅なので、今回は ushort left, ushort right と定義されています。
でもって、上位ワードにあたる right を 16bit 分だけ左シフトして足し合わせたのが今回の値。
ushort left = 0x1234;
ushort right = 0x5678;
uint margin = (uint)left + ((uint)right << 16);
というコードからは、uint margin = 0x56781234; という値が得られます。
ももたろう on Wed, 17 Jul 2019 00:08:47
魔界の仮面弁士様、ご説明していただきありがとうございます。
32ビット中、上位16ビットと下位16ビットで右マージンと左マージンに分かれているのですね。
驚きました。
ありがとうございます。