21

カスタムボタンキャプションを使用してVB.NETでメッセージボックスを表示する簡単な方法はありますか?Managed C ++でカスタムボタンテキストを使用してMessageBoxを作成する簡単な方法は何ですか?、Stack Overflowアーカイブにありますが、ManagedC ++用です

4

8 に答える 8

27

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
于 2008-10-24T22:37:59.330 に答える
19

いいえ。
でカスタム フォームを作成する必要があります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)
        ' このメソッドは、ユーザーがダイアログ ボックスを閉じたときに呼び出されます
    サブ終了
于 2008-10-24T18:49:32.957 に答える
7

いいえ、メッセージボックスのデフォルト ボタン テキストにアクセスまたはリダイレクトする方法はありません。

これを行う唯一の方法は、独自のコードを作成するか、インターネットにある多くの無料のものの 1 つを使用することです。

無料の MsgBoxGo!

于 2008-10-24T19:02:26.223 に答える
2

解決策があります。CBTフックをインストールすることで、メッセージとボタンのフォント、ダイアログの背景、ダイアログの配置、アイコン、ボタンのキャプション、タイムアウト、さらには追加のコントロールの挿入など、さまざまなMessageBoxの視覚設定をその場で調整できます。

完全なソリューション:拡張MessageBox.NETアセンブリ http://www.news2news.com/vfp/?solution=5

これは完全に機能する試用版であり、通常のバージョンには完全なC#ソースコードが含まれています。

于 2010-05-16T23:38:07.283 に答える
2

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
于 2016-02-09T17:29:04.023 に答える
1

ダイアログを表示するボタンにこれを追加します。これはカスタム フォーム メッセージ ボックスです。

    private void DGroup_Click(object sender, EventArgs e)
    {
        messageBox m = new messageBox();
        m.ShowDialog();
        if (m.DialogResult == DialogResult.Yes)
        {
            //del(groups.php?opt=del&amp;id=613','asdasd');
            String[] asd = new String[2];
            asd[0] = "groups.php?opt=del&amp;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();
    }
于 2010-12-22T08:26:41.977 に答える
1

同じことを行う C# コードは、MSDN フォーラムの記事https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3087899&SiteID=1にあります。

于 2008-10-24T19:10:37.830 に答える
0

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);
        }
于 2011-09-15T11:39:17.890 に答える