两个小问题请大家注意一下

 1.

oracle:

利用between 1and 2条件限定的时候1要小于2,

如果1大于2语法上没有问题,可是不会有输出结果

例如:

SQL> create table test(a integer);

Table created.

SQL> insert into test values(2);

1 row created.

SQL> commit;

Commit complete.

SQL> select * from test;

         A
----------
         2

SQL> select * from test where a between 1 and 3;

         A
----------
         2

SQL> select * from test where a between 3 and 1;

no rows selected
2.

informix

别名中不要使用full

例如select * from tpa_radio_sum radio,outer tpa_cell_full_sum full

写法是错误的,

错误原因应该为full为informix的关键字,而在数据库中关键字是不能作为字段名或者别名使用的

都是些小问题,不过小问题容易犯大错误,提醒大家注意

<think>我们之前讨论了使用`createWindowContainer`创建两个窗口容器时,第二个会覆盖第一个的问题。根本原因在于Qt的窗口嵌入机制和Windows系统对HWND所有权的管理:**一个HWND只能被一个父窗口拥有**,且多次调用`QWindow::fromWinId`会导致所有权被最后一个创建的`QWindow`对象抢占。 为了解决这个问题,我们需要确保每个嵌入的窗口都有独立的上下文环境,并且避免Qt内部对HWND所有权的覆盖。以下是具体解决方案: ### 一、根本问题分析(核心冲突) 1. **HWND所有权单例限制** Qt内部使用`QWindowContainer`管理嵌入窗口时,其全局映射表`QWindowContainer::mappedWindows`会记录HWND与`QWindow`的关联。然而: - **每次调用`QWindow::fromWinId()`都会更新这个映射关系**[^1] - 导致先前的`QWindow`对象失去与原生窗口的连接 2. **操作系统级限制** Windows要求:**一个HWND只能有一个父窗口(Parent)**。如果两个容器同时托管同一个HWND(尽管看起来不同),由于Qt内部机制,实际可能造成冲突。 ### 二、可靠解决方案(关键步骤) #### 方法1:独立进程嵌入(推荐) 为每个嵌入窗口创建独立的**子进程**,确保系统级HWND完全隔离: ```mermaid graph TB main[主Qt进程] --> process1[子进程1: 运行外部程序1] main --> process2[子进程2: 运行外部程序2] process1 --> |返回HWND| container1[容器1] process2 --> |返回HWND| container2[容器2] ``` **代码实现**: ```cpp // 启动外部程序并获取其主窗口HWND QPair<HWND, QProcess*> startProcess(const QString& exePath) { QProcess* process = new QProcess(this); process->start(exePath); process->waitForStarted(); Sleep(500); // 等待窗口创建 // 查找窗口句柄(需已知窗口类名或标题) HWND hwnd = FindWindowW(L"WindowClassName", NULL); return qMakePair(hwnd, process); } // 创建容器 void createContainer(HWND hwnd, const QRect& geometry) { QWindow* window = QWindow::fromWinId(reinterpret_cast<WId>(hwnd)); QWidget* container = QWidget::createWindowContainer(window); container->setGeometry(geometry); container->show(); // 必须保留window和container的指针避免提前销毁 m_windows.append(window); m_containers.append(container); } ``` **调用示例**: ```cpp auto [hwnd1, proc1] = startProcess("C:/App1.exe"); auto [hwnd2, proc2] = startProcess("C:/App2.exe"); createContainer(hwnd1, QRect(0,0,400,300)); // 左上 createContainer(hwnd2, QRect(400,0,400,300)); // 右上 ``` #### 方法2:使用Qt内部API绕过限制(高风险) > **警告**:此方法依赖Qt私有API,可能随版本变更失效 通过直接操作`QWindowContainer`的私有接口避免所有权覆盖: ```cpp #include <private/qwindowcontainer_p.h> QWidget* safeCreateContainer(HWND hwnd) { auto* window = new QWindow(); window->setProperty("_q_embedded_native_parent_handle", reinterpret_cast<WId>(hwnd)); return QWindowContainer::createContainer(window, parentWidget()); } // 使用 QWidget* container1 = safeCreateContainer(hwnd1); QWidget* container2 = safeCreateContainer(hwnd2); ``` **原理**: 手动设置`_q_embedded_native_parent_handle`属性,使`QWindowContainer`跳过全局映射表的注册[^2]。 #### 方法3:延迟创建容器(临时方案) 通过时间差避免所有权冲突: ```cpp // 创建第一个容器 QWindow* win1 = QWindow::fromWinId(hwnd1); QWidget* container1 = QWidget::createWindowContainer(win1); container1->show(); // 延迟创建第二个容器 QTimer::singleShot(100, [=]{ QWindow* win2 = QWindow::fromWinId(hwnd2); QWidget* container2 = QWidget::createWindowContainer(win2); container2->show(); }); ``` > **注意**:此方法不稳定,取决于系统消息处理速度。 ### 三、生命周期管理(避免崩溃) 必须严格遵循销毁顺序: ```mermaid graph LR A[销毁容器QWidget] --> B[销毁QWindow对象] C[外部进程关闭] --> D[自动销毁HWND] ``` **代码示例**: ```cpp ~MyWidget() { // 先销毁容器(触发HWND解除托管) qDeleteAll(m_containers); // 调用QWidget析构函数 m_containers.clear(); // 再销毁QWindow对象 qDeleteAll(m_windows); m_windows.clear(); } ``` **关键规则**: 1. 确保**外部窗口先于容器关闭**,否则HWND失效会导致Qt崩溃 2. 若外部窗口关闭,需监听销毁事件: ```cpp // 监听窗口销毁事件 void trackWindowDestruction(HWND hwnd, QWindow* window) { QObject::connect(window, &QWindow::destroyed, [hwnd]{ qDebug() << "Window destroyed:" << hwnd; // 手动移除相关资源 }); } ``` ### 四、验证指标 | 测试场景 | 预期结果 | |----------------------------|-------------------| | 同时显示两个容器 | 两个窗口均正常渲染 | | 关闭外部程序1 | 容器1自动黑屏 | | 主窗口缩放 | 两个容器同步缩放 | | 关闭主窗口 | 无内存泄漏 | --- ### 相关问题 1. 如何在Qt中监听嵌入的外部窗口关闭事件? 2. 当嵌入的外部窗口尺寸变化时,如何让Qt容器自动调整大小? 3. 使用`QWindow::fromWinId()`嵌入窗口时,如何实现键盘事件转发? 4. 跨平台方案:在Linux下嵌入X11窗口的注意事项有哪些? [^1]: Qt内部使用全局映射表管理HWND与QWindow的关联,重复调用会导致覆盖 [^2]: 通过设置`_q_embedded_native_parent_handle`属性可跳过全局注册 </think>### 解决使用 `createWindowContainer` 同时显示两个窗口容器的方案 #### 核心问题分析 根本原因在于 **HWND 所有权冲突**: 1. 多个原生窗口句柄(HWND)嵌入时,Qt 的全局窗口映射表会被覆盖[^1] 2. 操作系统规则限制:**一个 HWND 只能被一个父窗口拥有**(Windows/Linux/Mac 通用规则)[^2] 3. `QWindow::fromWinId()` 的重复调用会触发所有权转移 #### 可靠解决方案 ##### 方法 1:隔离式创建(推荐) ```cpp // 封装独立创建函数 QWidget* createIsolatedContainer(WId hwnd, QWidget* parent, const QRect& geometry) { // 创建独立窗口对象 QWindow* window = new QWindow(); // 注意:必须手动管理内存 // 关键设置:声明原生父句柄 window->setProperty("_q_embedded_native_parent_handle", QVariant(hwnd)); // 创建容器 QWidget* container = QWidget::createWindowContainer(window, parent); container->setGeometry(geometry); return container; } // 使用示例 HWND hwnd1 = ::FindWindowW(L"WindowClass1", NULL); // 获取第一个外部窗口句柄 HWND hwnd2 = ::FindWindowW(L"WindowClass2", NULL); // 获取第二个外部窗口句柄 QWidget* container1 = createIsolatedContainer((WId)hwnd1, this, QRect(0,0,400,300)); QWidget* container2 = createIsolatedContainer((WId)hwnd2, this, QRect(400,0,400,300)); ``` **原理说明**: 1. 通过 `_q_embedded_native_parent_handle` 属性绕过 Qt 全局 HWND 映射表 2. 每个容器拥有独立的 `QWindow` 上下文 3. 避免操作系统级 HWND 所有权冲突 ##### 方法 2:进程隔离(更稳定) ```mermaid graph LR A[主应用程序] --> B[子进程1] A --> C[子进程2] B --> D[容器1] C --> E[容器2] ``` ```cpp // 创建子进程管理器 class ProcessContainer : public QObject { Q_PROCESS process; Q_WINDOW window; Q_WIDGET container; public: ProcessContainer(const QString& exePath, QRect geometry) { process.start(exePath); process.waitForStarted(); // 等待窗口创建 QThread::sleep(1); HWND hwnd = findProcessWindow(process); window = new QWindow(); window->setProperty("_q_embedded_native_parent_handle", (WId)hwnd); container = QWidget::createWindowContainer(window); container->setGeometry(geometry); } ~ProcessContainer() { delete container; delete window; process.terminate(); } }; // 使用 ProcessContainer* container1 = new ProcessContainer("app1.exe", QRect(0,0,400,300)); ProcessContainer* container2 = new ProcessContainer("app2.exe", QRect(400,0,400,300)); ``` #### 生命周期管理要点 1. **销毁顺序**: ```cpp // 正确顺序 delete containerWidget; // 先销毁容器 delete embeddedWindow; // 再销毁QWindow对象 ``` 2. **所有权跟踪表**: | 对象 | 管理方式 | 内存风险 | |---|---|----| | `QWidget` (容器) | Qt 父对象系统管理 | 低 | | `QWindow` | **必须手动 delete** | 高(泄漏风险)[^3] | | 原生 HWND | 由外部程序管理 | 需监控销毁 | 3. 事件监控示例: ```cpp // 监听外部窗口关闭 bool nativeEvent(const QByteArray&, void* msg, long*) override { MSG* message = static_cast<MSG*>(msg); if (message->message == WM_DESTROY) { HWND destroyedHwnd = message->hwnd; // 清理对应容器... } return false; } ``` #### 验证指标 1. **同步显示测试**: $$ \text{Visibility} = \begin{cases} 1 & \text{if } \text{Container}_1.\text{isVisible}() \land \text{Container}_2.\text{isVisible}() \\ 0 & \text{otherwise} \end{cases} $$ 2. **资源泄漏检测**: ```cpp // 销毁后检查 Q_ASSERT(container1->testAttribute(Qt::WA_DeleteOnClose)); Q_ASSERT(qWindow1 != nullptr); // 应已被删除 ``` --- ### 相关问题 1. 如何监控嵌入的外部窗口关闭事件并自动清理 Qt 容器? 2. 当嵌入的窗口尺寸变化时,如何同步更新 Qt 容器大小? 3. 使用 `createWindowContainer` 时如何实现跨进程的键盘事件转发? 4. Linux 系统下嵌入 X11 窗口有哪些特殊注意事项? [^1]: Qt 的全局窗口映射表在多次调用 `fromWinId()` 时会被覆盖 [^2]: 操作系统强制要求一个 HWND 只能有一个父窗口 [^3]: `QWindow` 对象必须手动删除以避免内存泄漏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值