ポップアップ テキスト ウィンドウに 2 つの列を作成する簡単な方法はありますか?
-
09-06-2019 - |
質問
これは簡単なことのように思えました。テキスト ウィンドウをポップアップして、2 列のデータ (左側に説明、右側に表示される対応する値) を表示したいだけでした。私はフォームをあまり扱ったことがないので、適切と思われる最初のコントロールである TextBox を取得しただけです。タブを使用すると 2 番目の列を簡単に作成できると思いましたが、うまく機能しないことがわかりました。
私がこれを試みた方法には 2 つの問題があるようです (下記を参照)。まず、フォントが非常に複雑で、カーニングの問題などがあるため、MeasureString 関数はあまり正確ではないということを多くの Web サイトで読みました。2 つ目は、TextBox コントロールがその下の StringFormat として何を使用しているのかわからないことです。
とにかく、結果として、右の列には必ずタブごとに項目が表示されることになります。自分でテキスト ウィンドウを展開して、すべてを自分で行うこともできると思いますが、これを行う簡単な方法はないでしょうか?
TextBox textBox = new TextBox();
textBox.Font = new Font("Calibri", 11);
textBox.Dock = DockStyle.Fill;
textBox.Multiline = true;
textBox.WordWrap = false;
textBox.ScrollBars = ScrollBars.Vertical;
Form form = new Form();
form.Text = "Recipe";
form.Size = new Size(400, 600);
form.FormBorderStyle = FormBorderStyle.Sizable;
form.StartPosition = FormStartPosition.CenterScreen;
form.Controls.Add(textBox);
Graphics g = form.CreateGraphics();
float targetWidth = 230;
foreach (PropertyInfo property in properties)
{
string text = String.Format("{0}:\t", Description);
while (g.MeasureString(text,textBox.Font).Width < targetWidth)
text += "\t";
textBox.AppendText(text + value.ToString() + "\n");
}
g.Dispose();
form.ShowDialog();
解決
必要に応じて、この VB.Net コードを C# に変換できます。ここでの理論は、コントロール内のタブのサイズを変更するということです。
Private Declare Function SendMessage _
Lib "user32" Alias "SendMessageA" _
(ByVal handle As IntPtr, ByVal wMsg As Integer, _
ByVal wParam As Integer, ByRef lParam As Integer) As Integer
Private Sub SetTabStops(ByVal ctlTextBox As TextBox)
Const EM_SETTABSTOPS As Integer = &HCBS
Dim tabs() As Integer = {20, 40, 80}
SendMessage(ctlTextBox.Handle, EM_SETTABSTOPS, _
tabs.Length, tabs(0))
End Sub
バージョンも C# に変換しました。VS2005 でテストされ、動作します。
この using ステートメントをフォームに追加します。
using System.Runtime.InteropServices;
これをクラス宣言の直後に置きます。
private const int EM_SETTABSTOPS = 0x00CB;
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr h, int msg, int wParam, int[] lParam);
タブストップを設定する場合は、このメソッドを呼び出します。
private void SetTabStops(TextBox ctlTextBox)
{
const int EM_SETTABSTOPS = 203;
int[] tabs = { 100, 40, 80 };
SendMessage(textBox1.Handle, EM_SETTABSTOPS, tabs.Length, tabs);
}
これを使用するために私がやったことは次のとおりです。
private void Form1_Load(object sender, EventArgs e)
{
SetTabStops(textBox1);
textBox1.Text = "Hi\tWorld";
}
他のヒント
ありがとうマット。あなたのソリューションは私にとって非常にうまくいきました。これがあなたのコードの私のバージョンです...
// This is a better way to pass in what tab stops I want...
SetTabStops(textBox, new int[] { 12,120 });
// And the code for the SetTabsStops method itself...
private const uint EM_SETTABSTOPS = 0x00CB;
[DllImport("User32.dll")]
private static extern uint SendMessage(IntPtr hWnd, uint wMsg, int wParam, int[] lParam);
public static void SetTabStops(TextBox textBox, int[] tabs)
{
SendMessage(textBox.Handle, EM_SETTABSTOPS, tabs.Length, tabs);
}
本当に表形式のものが必要な場合は、Mr.ハレンの答えは良いものです。DataGridView は、非常に Excel スプレッドシートのような外観を提供します。
(HTML のテーブルに似た) 2 列のレイアウトが必要なだけの場合は、TableLayoutPanel を試してください。各テーブルセル内で標準コントロールを使用できるため、希望するレイアウトが得られます。
唯一の方法は、あなたがやっていることと同様のことを行うことだと思いますが、固定フォントを使用し、タブの展開を心配する必要がないようにスペースで独自のパディングを行うことです。
テキスト ボックスでは HTML を使用できませんか?その場合は、HTML を使用してテキストを表にフォーマットします。それ以外の場合は、テキストをデータグリッドに追加してから、それをフォームに追加してみてください。