カスタムボタンキャプションを使用してVB.NETでメッセージボックスを表示する簡単な方法はありますか?Managed C ++でカスタムボタンテキストを使用してMessageBoxを作成する簡単な方法は何ですか?、Stack Overflowアーカイブにありますが、ManagedC ++用です。
8 に答える
MessageBox は、他のウィンドウと同じように変更できる単純なウィンドウを使用します。これは非常に長い間 Windows で可能でした。すでに 20 年以上も前からです。ただし、ネイティブのwinapiを隠し、それでできることすべてを公開していないフレンドリーなクラスラッパーが多すぎるため、テクニックはあいまいになっています。支持された回答からわかるように、プログラマーはこれが不可能であると自動的に想定するようになりました。これは、Petzold が著書 "Programming Windows" で教えてくれた種類のプログラミングです。MessageBox をカスタム フォームまたはウィンドウに置き換えるのは実際にはかなり難しく、テキストに合わせて重要な自動レイアウトを行い、助けなしでローカライズをサポートします。それはまさにあなたが好きではないようですが:)
とにかく、メッセージ ボックス ウィンドウは簡単に見つけることができます。これは UI スレッドによって所有され、一意にする特別なクラス名を持っています。EnumThreadWindows() はスレッドが所有するウィンドウを列挙し、GetClassName() はウィンドウの種類を確認できます。次に、SetWindowText() を使用してテキストをボタンに挿入します。
プロジェクトに新しいクラスを追加し、以下に示すコードを貼り付けます。次のようなコードで呼び出します。
Nobugz.PatchMsgBox(New String() {"Da", "Njet"})
MsgBox("gack", MsgBoxStyle.YesNo)
コードは次のとおりです。
Imports System.Text
Imports System.Runtime.InteropServices
Public Class Nobugz
Private Shared mLabels() As String '' Desired new labels
Private Shared mLabelIndex As Integer '' Next caption to update
Public Shared Sub PatchMsgBox(ByVal labels() As String)
''--- Updates message box buttons
mLabels = labels
Application.OpenForms(0).BeginInvoke(New FindWindowDelegate(AddressOf FindMsgBox), GetCurrentThreadId())
End Sub
Private Shared Sub FindMsgBox(ByVal tid As Integer)
''--- Enumerate the windows owned by the UI thread
EnumThreadWindows(tid, AddressOf EnumWindow, IntPtr.Zero)
End Sub
Private Shared Function EnumWindow(ByVal hWnd As IntPtr, ByVal lp As IntPtr) As Boolean
''--- Is this the message box?
Dim sb As New StringBuilder(256)
GetClassName(hWnd, sb, sb.Capacity)
If sb.ToString() <> "#32770" Then Return True
''--- Got it, now find the buttons
mLabelIndex = 0
EnumChildWindows(hWnd, AddressOf FindButtons, IntPtr.Zero)
Return False
End Function
Private Shared Function FindButtons(ByVal hWnd As IntPtr, ByVal lp As IntPtr) As Boolean
Dim sb As New StringBuilder(256)
GetClassName(hWnd, sb, sb.Capacity)
If sb.ToString() = "Button" And mLabelIndex <= UBound(mLabels) Then
''--- Got one, update text
SetWindowText(hWnd, mLabels(mLabelIndex))
mLabelIndex += 1
End If
Return True
End Function
''--- P/Invoke declarations
Private Delegate Sub FindWindowDelegate(ByVal tid As Integer)
Private Delegate Function EnumWindowDelegate(ByVal hWnd As IntPtr, ByVal lp As IntPtr) As Boolean
Private Declare Auto Function EnumThreadWindows Lib "user32.dll" (ByVal tid As Integer, ByVal callback As EnumWindowDelegate, ByVal lp As IntPtr) As Boolean
Private Declare Auto Function EnumChildWindows Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal callback As EnumWindowDelegate, ByVal lp As IntPtr) As Boolean
Private Declare Auto Function GetClassName Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal name As StringBuilder, ByVal maxlen As Integer) As Integer
Private Declare Auto Function GetCurrentThreadId Lib "kernel32.dll" () As Integer
Private Declare Auto Function SetWindowText Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal text As String) As Boolean
End Class
いいえ。
でカスタム フォームを作成する必要がありますFormBorderType = FixedDialog
。
ここに小さなチュートリアルがあります:
.NET でのダイアログ ボックスの作成
James D. Murray 著、2007 年 6 月 12 日、70-526 の下
Microsoft 認定試験: 70-526 (MCTS)
目的: Windows フォーム アプリケーションでカスタム ダイアログ ボックスを作成して使用する。
言語: Visual Basic 2005 (このエントリの C# バージョンについては、ここをクリックしてください)
C# で作成した .NET アプリケーションでダイアログ ボックスを初めて作成する必要があったときのことを覚えています。長年の Visual Basic プログラマーとして、Visual Studio.NET に含まれているダイアログ ボックス テンプレートを使用すれば、これは簡単に実現できると思っていました。驚いたことに、C# 用のフォーム テンプレートは存在しませんでしたが、Visual Basic 2005 用のフォーム テンプレートはありました。 .NET フォームを Windows ダイアログ ボックスに:
ステップ 1: フォームを .NET プロジェクトに追加し、「DialogBoxForm」という名前を付けます。
ステップ 2: フォームの右下の領域に 2 つのボタンをドロップし、「OKButton」と「CancelButton」という名前を付けます。
ステップ 3: フォームの次のプロパティを変更して、フォームの外観と動作を標準のダイアログ ボックスのように調整します。
プロパティ値の説明 -------------------------------------------------- -------------------------------------------------- ------------------------- AcceptButton OK ボタンのインスタンス フォームが値 DialogResult.OK を返すようにします。モーダル ダイアログ ボックスでのみ使用されます。 CancelButton キャンセル ボタン インスタンス フォームが値 DialogResult.Cancel を返すようにします。モーダル ダイアログ ボックスでのみ使用されます。 FormBorderStyle FixedDialog タイトル バーにコントロール ボックスのないサイズ変更不可のフォームを作成します。 HelpButton True [閉じる] ボタンの横のキャプション バーに [ヘルプ] ボタンが表示されます。これらのボタンを表示するには、ControlBox プロパティを True にする必要があります。 MaximizeBox False タイトル バーの [最大化] ボタンを非表示にします。 MinimizeBox False タイトル バーの [最小化] ボタンを非表示にします。 ShowIcon False タイトル バー アイコンはダイアログ ボックスに表示されません。 ShowInTaskBar False Windows タスク バーにフォームが存在することを示しません。 開始位置 CenterParent ダイアログ ボックスの最初の位置は、その親フォームの上です。 必要に応じたサイズ ダイアログ ボックスに必要な固定サイズ。
これらのプロパティは、フォームの [プロパティ] ウィンドウを使用するか、フォームの Load イベントに配置されたコードを使用して設定できます。
Me.AcceptButton = OKButton
Me.CancelButton = CancelButton
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.FixedDialog
Me.HelpButton = True
Me.MaximizeBox = False
Me.MinimizeBox = False
Me.ShowInTaskbar = False
Me.ShowIcon = False
Me.StartPosition = FormStartPosition.CenterParent
ステップ 4 : 次のボタン クリック イベント ハンドラーをフォームに追加します。
Private Sub OKButton_Click (オブジェクトとしての ByVal 送信者、EventArgs としての _ByVal e) ' ユーザーが [OK] ボタンをクリックしました Me.DialogResult = Windows.Forms.DialogResult.OK サブ終了 Private Sub CancelButton_Click (オブジェクトとしての ByVal 送信者、EventArgs としての _ByVal e) ' ユーザーが [キャンセル] ボタンをクリックしました Me.DialogResult = Windows.Forms.DialogResult.Cancel サブ終了
ステップ 5 : フォームの場合と同様に、データをダイアログ ボックスに出し入れするために必要なプロパティを追加します。
プライベート _LoginName を文字列として プライベート _LoginPassword を文字列として Public プロパティ LoginName() As String 得る _LoginName を返す エンドゲット Set(文字列としての ByVal 値) _ログイン名 = 値 エンドセット End プロパティ Public プロパティ LoginPassword() As String 得る _LoginPassword を返す エンドゲット Set(文字列としての ByVal 値) _LoginPassword = 値 エンドセット End プロパティ
ステップ 6: フォームの ShowDialog() を呼び出して、ダイアログ ボックスをモーダルに表示します。
Public Sub ShowDialogBox() Dim ダイアログを新しい DialogBoxForm として dialog.LoginName = "JDMurray" dialog.LoginPassword = 文字列.空 dialog.ShowDialog() = Windows.Forms.DialogResult.OK の場合 Debug.WriteLine("ログイン名: " & dialog.LoginName) Debug.WriteLine("パスワード: " & dialog.LoginPassword) そうしないと ' ユーザーが [キャンセル] ボタンをクリックしました 終了条件 サブ終了
ステップ 7 : ダイアログ ボックスをモードレスで表示するには、代わりに DialogBoxForm の Show() メソッドを呼び出します。DialogBoxForm の Close イベントにイベント ハンドラーを追加して、ユーザーがダイアログ ボックスを閉じるタイミングを知る必要があります。
Public Sub ShowDialogBox() Dim dialog As DialogBoxForm = New DialogBoxForm dialog.LoginName = "JDMurray" dialog.Password = 文字列.Empty AddHandler dialog.FormClosed、AddressOf dialog_FormClosed ダイアログ.表示() ' Show() メソッドはすぐに戻ります サブ終了 Private Sub dialog_FormClosed(ByVal sender As Object, _ ByVal e As FormClosedEventArgs) ' このメソッドは、ユーザーがダイアログ ボックスを閉じたときに呼び出されます サブ終了
いいえ、メッセージボックスのデフォルト ボタン テキストにアクセスまたはリダイレクトする方法はありません。
これを行う唯一の方法は、独自のコードを作成するか、インターネットにある多くの無料のものの 1 つを使用することです。
解決策があります。CBTフックをインストールすることで、メッセージとボタンのフォント、ダイアログの背景、ダイアログの配置、アイコン、ボタンのキャプション、タイムアウト、さらには追加のコントロールの挿入など、さまざまなMessageBoxの視覚設定をその場で調整できます。
完全なソリューション:拡張MessageBox.NETアセンブリ http://www.news2news.com/vfp/?solution=5
これは完全に機能する試用版であり、通常のバージョンには完全なC#ソースコードが含まれています。
Daniel Nolan によるソリューション、VB.Net のコード
<DllImport("kernel32.dll")> _
Private Shared Function GetCurrentThreadId() As UInteger
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As HookProc, ByVal hInstance As IntPtr, ByVal threadId As Integer) As Integer
End Function
<DllImport("user32.dll")> _
Private Shared Function SetDlgItemText(ByVal hWnd As IntPtr, ByVal nIDDlgItem As Integer, ByVal lpString As String) As Boolean
End Function
Private Delegate Function HookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Shared dlgHookProc As HookProc
Private Const WH_CBT As Long = 5
Private Const HCBT_ACTIVATE As Long = 5
Private Const ID_BUT_OK As Integer = 1
Private Const ID_BUT_CANCEL As Integer = 2
Private Const ID_BUT_ABORT As Integer = 3
Private Const ID_BUT_RETRY As Integer = 4
Private Const ID_BUT_IGNORE As Integer = 5
Private Const ID_BUT_YES As Integer = 6
Private Const ID_BUT_NO As Integer = 7
Private Const BUT_OK As String = "Save"
Private Const BUT_CANCEL As String = "Cancelar"
Private Const BUT_ABORT As String = "Stop"
Private Const BUT_RETRY As String = "Continue"
Private Const BUT_IGNORE As String = "Ignore"
Private Const BUT_YES As String = "Si"
Private Const BUT_NO As String = "No"
Private Shared _hook As Integer = 0
Private Shared Function DialogHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
If nCode < 0 Then
Return CallNextHookEx(_hook, nCode, wParam, lParam)
End If
If nCode = HCBT_ACTIVATE Then
SetDlgItemText(wParam, ID_BUT_OK, BUT_OK)
SetDlgItemText(wParam, ID_BUT_CANCEL, BUT_CANCEL)
SetDlgItemText(wParam, ID_BUT_ABORT, BUT_ABORT)
SetDlgItemText(wParam, ID_BUT_RETRY, BUT_RETRY)
SetDlgItemText(wParam, ID_BUT_IGNORE, BUT_IGNORE)
SetDlgItemText(wParam, ID_BUT_YES, BUT_YES)
SetDlgItemText(wParam, ID_BUT_NO, BUT_NO)
End If
Return CallNextHookEx(_hook, nCode, wParam, lParam)
End Function
Private Sub btn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn.Click
dlgHookProc = New HookProc(AddressOf DialogHookProc)
_hook = SetWindowsHookEx(CInt(WH_CBT), dlgHookProc, IntPtr.op_Explicit(0), CInt(GetCurrentThreadId()))
Dim dlgEmptyCheck As DialogResult = MessageBox.Show("Text", "Caption", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3)
If dlgEmptyCheck = DialogResult.Abort Then
End If
UnhookWindowsHookEx(_hook)
End Sub
ダイアログを表示するボタンにこれを追加します。これはカスタム フォーム メッセージ ボックスです。
private void DGroup_Click(object sender, EventArgs e)
{
messageBox m = new messageBox();
m.ShowDialog();
if (m.DialogResult == DialogResult.Yes)
{
//del(groups.php?opt=del&id=613','asdasd');
String[] asd = new String[2];
asd[0] = "groups.php?opt=del&id=613";
asd[1] = "asdasd";
addgroup.Document.InvokeScript("del",asd);
}
else
if (m.DialogResult == DialogResult.No)
{
MessageBox.Show("App won´t close");
}
}
このコードを messageBox に追加します。
private void deleteGroupOnly_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Yes;
this.Close();
}
private void deleteAll_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.No;
this.Close();
}
private void cancel_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
同じことを行う C# コードは、MSDN フォーラムの記事https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3087899&SiteID=1にあります。
Win32 フックを使用してボタンのキャプションを変更する C# スニペットを次に示します ( http://icodesnip.com/snippet/csharp/custom-messagebox-buttonsから入手)。
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll")]
private static extern bool SetDlgItemText(IntPtr hWnd, int nIDDlgItem, string lpString);
delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
static HookProc dlgHookProc;
private const long WH_CBT = 5;
private const long HCBT_ACTIVATE = 5;
private const int ID_BUT_OK = 1;
private const int ID_BUT_CANCEL = 2;
private const int ID_BUT_ABORT = 3;
private const int ID_BUT_RETRY = 4;
private const int ID_BUT_IGNORE = 5;
private const int ID_BUT_YES = 6;
private const int ID_BUT_NO = 7;
private const string BUT_OK = "Save";
private const string BUT_CANCEL = "Cancel";
private const string BUT_ABORT = "Stop";
private const string BUT_RETRY = "Continue";
private const string BUT_IGNORE = "Ignore";
private const string BUT_YES = "Yeeh";
private const string BUT_NO = "Never";
private static int _hook = 0;
private static int DialogHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
{
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
if (nCode == HCBT_ACTIVATE)
{
SetDlgItemText(wParam, ID_BUT_OK, BUT_OK);
SetDlgItemText(wParam, ID_BUT_CANCEL, BUT_CANCEL);
SetDlgItemText(wParam, ID_BUT_ABORT, BUT_ABORT);
SetDlgItemText(wParam, ID_BUT_RETRY, BUT_RETRY);
SetDlgItemText(wParam, ID_BUT_IGNORE, BUT_IGNORE);
SetDlgItemText(wParam, ID_BUT_YES, BUT_YES);
SetDlgItemText(wParam, ID_BUT_NO, BUT_NO);
}
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
private void Button_Click(object sender, EventArgs e)
{
dlgHookProc = new HookProc(DialogHookProc);
_hook = SetWindowsHookEx((int)WH_CBT, dlgHookProc, (IntPtr)0, (int)GetCurrentThreadId());
DialogResult dlgEmptyCheck = MessageBox.Show("Text", "Caption", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3);
if (dlgEmptyCheck == DialogResult.Abort)
{
}
UnhookWindowsHookEx(_hook);
}