一.阻塞 vs 非阻塞
1.模態對話框
阻塞父窗口:打開后,用戶必須先處理該對話框(關閉或完成操作),才能繼續操作父窗口。
應用場景:強制用戶立即響應的場景,如確認對話框、登錄窗口、文件選擇器等。
2.非模態對話框
不阻塞父窗口:打開后,用戶可同時與對話框和父窗口交互。
應用場景:需要長時間操作的工具窗口(如調色板、屬性編輯器)或提示信息(如通知氣泡)。
3.核心特性對比
二.模態對話框原理與應用
1. 工作原理
事件循環阻塞:調用 exec() 啟動局部事件循環
輸入獨占:禁用父窗口及其它窗口輸入
同步返回:對話框關閉后返回 QDialog::Accepted 或 Rejected
2.代碼示例
// 方式1: exec() - 阻塞模態
void MainWindow::showWindowModal()
{
????ParamSettingDialog *dlg = new ParamSettingDialog(this);
????dlg->setAttribute(Qt::WA_DeleteOnClose); // 關閉時自動刪除;不加入這句代碼會有內存泄漏
????connect(dlg, &ParamSettingDialog::accepted, this, &MainWindow::applySettings);
????dlg->exec(); ?// 阻塞模態
}
// 方式2: open() - 非阻塞但模態
void MainWindow::showWindowModal()
{
????ParamSettingDialog *dlg = new ParamSettingDialog(this);
????dlg->setAttribute(Qt::WA_DeleteOnClose); // 關閉時自動刪除
????connect(dlg, &ParamSettingDialog::accepted, this, &MainWindow::applySettings);
????dlg->open(); ?// 非阻塞但模態
}
3.內存管理問題
// 問題代碼 - 內存泄漏
void showDialog() {
????auto *dlg = new ParamSettingDialog();
????dlg->exec(); ?// 對話框關閉后指針未釋放
}
// 正確方案1: 關閉時自動刪除
void safeShowDialog() {
????auto *dlg = new ParamSettingDialog();
????dlg->setAttribute(Qt::WA_DeleteOnClose);
????dlg->exec(); ?// 對話框關閉后自動刪除
}
// 正確方案2: 棧上創建
void stackSafeDialog() {
????ParamSettingDialog dlg;
????dlg.exec(); ?// 自動銷毀
}
三.非模態對話框原理與應用
1.工作原理
異步顯示:show() 立即返回
共享事件循環:與主窗口共享同一事件隊列
并行交互:用戶可同時操作主窗口和對話框
2.創建方式
// 在類聲明中
class MainWindow : public QMainWindow {
????Q_OBJECT
private:
????ParamSettingDialog *m_paramDlg = nullptr; ?// 成員指針
};
// 顯示非模態對話框
void MainWindow::showModelessDialog()
{
????if (!m_paramDlg) {
????????m_paramDlg = new ParamSettingDialog(this); ?// 指定父對象
????????connect(m_paramDlg, &ParamSettingDialog::settingsChanged,
????????????????this, &MainWindow::updateSettings);
????}
????m_paramDlg->show(); ???// 顯示
????m_paramDlg->raise(); ??// 置于頂層
????m_paramDlg->activateWindow(); ?// 激活
}
3.內存管理策略
// 方案1: 父對象自動銷毀 (推薦)
m_dialog = new ParamSettingDialog(this); // 父對象析構時自動刪除
// 方案2: 關閉時自動刪除
m_dialog = new ParamSettingDialog();
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
// 方案3: 手動管理
void MainWindow::closeEvent(QCloseEvent *event)
{
????if (m_dialog) {
????????m_dialog->close();
????????delete m_dialog;
????????m_dialog = nullptr;
????}
????QMainWindow::closeEvent(event);
}
四.內存管理黃金法則
棧優先原則:短生命周期對話框使用棧分配
父對象原則:長生命周期對話框設置父對象
自動刪除標志:setAttribute(Qt::WA_DeleteOnClose)
智能指針:C++17+ 使用 std::unique_ptr 管理