Qt的MDI中多个子窗口响应一个菜单事件的优雅实现(动态slot)
問(wèn)題:
用過(guò)MFC的人都知道,MDI中,某個(gè)菜單或者按鈕,在視圖中可以添加響應(yīng)函數(shù),在文檔中也可以添加響應(yīng)函數(shù),在框架中也可以添加它的響應(yīng)函數(shù),優(yōu)先級(jí)分別是視圖、文檔、框架,而且MFC自動(dòng)將消息發(fā)給當(dāng)前激活的視圖或者文檔。
解決思路:
在Qt中,菜單/按鈕的響應(yīng)是通過(guò)信號(hào)/槽來(lái)實(shí)現(xiàn)的,在MDI中,多個(gè)視圖經(jīng)常需要響應(yīng)同一個(gè)菜單,且是激活的視圖去響應(yīng),這有兩種處理方法,一 是,由主窗口接收事件再轉(zhuǎn)調(diào)用當(dāng)前激活窗口,二是,通過(guò)disconnect/connect動(dòng)態(tài)修改信號(hào)槽。第一種方法,當(dāng)這樣的菜單事件比較多時(shí),比 較繁瑣;如果多個(gè)視圖分屬不同子類,只要其中一個(gè)子類實(shí)現(xiàn)了一個(gè)處理函數(shù),其他子類都需要添加這樣的處理函數(shù)(即使啥也不干),另外,在主窗口轉(zhuǎn)調(diào)用時(shí), 還需要做類型轉(zhuǎn)換(或者通過(guò)虛函數(shù)),總而言之,比較復(fù)雜。
這里,我按照第二種方法,通過(guò)少量代碼實(shí)現(xiàn)了動(dòng)態(tài)修改信號(hào)槽。思路是:
1、自定義一個(gè)結(jié)構(gòu),將connect信息保存起來(lái);
2、當(dāng)MDI的子窗口焦點(diǎn)切換時(shí),將connect信息中的receiver全部換成當(dāng)前窗口,并重新connect;
該方法只需要在mainwindow中做這些工作即可,比較簡(jiǎn)潔優(yōu)雅。
關(guān)鍵代碼粘貼如下
class MainWindow : public QMainWindow {//......void dynamic_connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method); void set_dynamic_connect_receiver(const QObject * receiver); //...... struct MdiConnectInfo { MdiConnectInfo(const QObject * sender1, const char * signal1, const QObject * receiver1, const char * method1) { sender = sender1; strcpy(signal,signal1); receiver = receiver1; strcpy(method, method1); } const QObject * sender; char signal[100]; const QObject * receiver; char method[100]; }; std::vector<MdiConnectInfo> m_mdiConnects; }; MainWindow::MainWindow() { //...... connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(onMdiActived())); //...... } void MainWindow::dynamic_connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method) { m_mdiConnects.push_back(MdiConnectInfo(sender, signal, receiver, method)); } void MainWindow::set_dynamic_connect_receiver(const QObject * receiver) { for (int i = 0; i < m_mdiConnects.size(); i++) { MdiConnectInfo item = m_mdiConnects[i]; disconnect(item.sender, item.signal, item.receiver, item.method); } for (int i = 0; i < m_mdiConnects.size(); i++) { MdiConnectInfo item = m_mdiConnects[i]; connect(item.sender, item.signal, receiver, item.method); m_mdiConnects[i].receiver = receiver; } } void MainWindow::onMdiActived() { QWidget* child = activeMdiChild(); if (child) { set_dynamic_connect_receiver(child); } } void MainWindow::createActions() { //...... zoomInAct = new QAction(QIcon(":/images/zoomIn.png"), tr("Zoom In"), this); zoomInAct->setStatusTip(tr("Zoom in view")); dynamic_connect(zoomInAct, SIGNAL(triggered()), this, SLOT(zoomInView())); zoomOutAct = new QAction(QIcon(":/images/zoomOut.png"), tr("Zoom Out"), this); zoomOutAct->setStatusTip(tr("Zoom out view")); dynamic_connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(zoomOutView())); zoomFitAct = new QAction(QIcon(":/images/zoomFit.png"), tr("Zoom Fit"), this); zoomFitAct->setStatusTip(tr("Zoom fit view")); dynamic_connect(zoomFitAct, SIGNAL(triggered()), this, SLOT(zoomFitView())); zoomPanAct = new QAction(QIcon(":/images/zoomPan.png"), tr("Pan Zoom"), this); zoomPanAct->setStatusTip(tr("Pan zoom view")); dynamic_connect(zoomPanAct, SIGNAL(triggered()), this, SLOT(zoomPanView())); //...... }?
?
作一下解釋:
1、通過(guò)MdiConnectInfo結(jié)構(gòu)和m_mdiConnects變量,將connect信息保存起來(lái);具體是通過(guò)函數(shù)dynamic_connect來(lái)完成的;
2、當(dāng)MDI的子窗口焦點(diǎn)切換時(shí),其響應(yīng)函數(shù)onMdiActived()中,將connect信息中的receiver全部換掉,具體是通過(guò)?set_dynamic_connect_receiver來(lái)完成的;
上述代碼運(yùn)行正常。
?
轉(zhuǎn)載于:https://www.cnblogs.com/zgrpmc/p/5420181.html
總結(jié)
以上是生活随笔為你收集整理的Qt的MDI中多个子窗口响应一个菜单事件的优雅实现(动态slot)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 影院售票系统
- 下一篇: java field, property