如何在Unity项目中创建非模态Windows风格MessageBox弹窗
解决Unity桌面端非阻塞Windows风格弹窗问题
方案1:异步调用Windows原生MessageBox(非阻塞)
原生MessageBox是模态阻塞的,但可以通过子线程异步调用,避免卡住Unity主线程。代码示例:
using System.Threading; using UnityEngine; using System.Runtime.InteropServices; public class NonBlockingMsgBox : MonoBehaviour { [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type); public void ShowNonBlocking(string message, string title) { Thread msgThread = new Thread(() => { MessageBox(IntPtr.Zero, message, title, 0); }); msgThread.Start(); } }
如果需要获取用户点击结果(确定/取消),可以用AutoResetEvent做线程同步,将结果传回主线程后再处理,注意不要在子线程直接操作Unity对象。
方案2:修复WinForms引用并实现非阻塞弹窗
如果想用WinForms的标准Windows风格弹窗,先解决引用问题:
- 打开Unity Player Settings → Other Settings,将
Api Compatibility Level设置为.NET Framework - 在Visual Studio中右键项目 → 添加引用,勾选
System.Windows.Forms和System.Drawing
之后就可以用子线程启动非阻塞Form:
using System.Windows.Forms; using UnityEngine; using System.Threading; public class WinFormsPopup : MonoBehaviour { public void ShowPopup(string message, string title) { Thread formThread = new Thread(() => { Form popupForm = new Form { Text = title, Size = new System.Drawing.Size(320, 160), StartPosition = FormStartPosition.CenterScreen }; Label msgLabel = new Label { Text = message, Dock = DockStyle.Fill, TextAlign = System.Drawing.ContentAlignment.MiddleCenter }; popupForm.Controls.Add(msgLabel); Button okBtn = new Button { Text = "确定", Dock = DockStyle.Bottom }; okBtn.Click += (s, e) => popupForm.Close(); popupForm.Controls.Add(okBtn); Application.Run(popupForm); }); formThread.SetApartmentState(ApartmentState.STA); formThread.Start(); } }
子线程启动的Form不会阻塞Unity主线程,游戏逻辑和角色交互可以正常运行。
方案3:纯Unity实现仿Windows风格非阻塞弹窗
用UGUI制作完全匹配Windows风格的自定义弹窗,全程在Unity主线程运行,无外部依赖:
- 制作弹窗预制体:添加Canvas → Panel(仿Windows窗口的边框、标题栏)→ Text(显示消息)→ Button(确认/取消)
- 用代码控制弹窗的显示隐藏:
using UnityEngine; using UnityEngine.UI; public class CustomWindowsPopup : MonoBehaviour { [SerializeField] private GameObject popupPrefab; public void ShowPopup(string message) { GameObject popup = Instantiate(popupPrefab, transform.root); Text msgText = popup.GetComponentInChildren<Text>(); Button okBtn = popup.GetComponentInChildren<Button>(); msgText.text = message; okBtn.onClick.AddListener(() => Destroy(popup)); } }
这种方式最灵活,可自定义程度高,且完全不会阻塞游戏逻辑,生物角色可以正常和玩家交互。
内容的提问来源于stack exchange,提问作者Walter Medly
相关产品推荐
相关产品推荐

