这里主要分析QtCreator中OutputPane的相关内容,可以看到QtCreator在状态栏有四个Checkable按钮,如下图所示
checkable按钮的实现方式基本一致,这里仅以其中一种General Message来说明问题。在插件源码的coreplugin中,相关类有ModeManager,MessageManager,MessageOutputWindow,OutputPaneManager,OutputPaneToggleButton,OutputPaneManageButton,OutputPanePlaceHolder,MiniSplitterHandle,OutputWindow以及StatusBarManager和StatusBarWidget。这里首先看一下他们之间的关系。
接下来详细解释与分析一下(高手勿喷,请多指教)。
MainWindow的构造函数都做了些什么?
MainWindow应该做的都只是各种管理器的初始化工作,如何布局是由ModeManager来管理的,ModeManager通过各个不同的Mode来呈现不同的界面布局。
IMode就是这些Mode的接口类,在后面会详细介绍。先看MainWindow,初始化分为了三个部分:构造函数、init()、extensionsInitialized()。在Qt Creator中,很多Manager使用单例模式,但是这些单例模式可以说是一种不自动的,没有根据成员m_instance的状态来判断是创建实例还是直接返回,每一个Manager都需要create一下(好处不详,没有分析出来,望高手赐教)。在构造函数中就是调用这些create(),合情合理,构造函数不就是创建嘛。先上段代码看看:
MainWindow::MainWindow() : Utils::AppMainWindow(), m_coreImpl(new ICore(this)), ..... m_actionManager(new ActionManager(this)), m_editorManager(0), ..... m_statusBarManager(0), m_modeManager(0), ..... m_activeContext(0), m_generalSettings(new GeneralSettings), m_shortcutSettings(new ShortcutSettings), ..... m_toggleSideBarAction(0), ..... m_toggleSideBarButton(new QToolButton){ (void) new DocumentManager(this); OutputPaneManager::create(); setWindowTitle(tr("Qt Creator")); ...... ...... registerDefaultContainers(); registerDefaultActions(); ...... m_modeStack = new FancyTabWidget(this); m_modeManager = new ModeManager(this, m_modeStack); m_modeManager->addWidget(m_progressManager->progressView()); m_statusBarManager = new StatusBarManager(this); m_messageManager = new MessageManager; m_editorManager = new EditorManager(this); m_editorManager->hide(); m_externalToolManager = new ExternalToolManager(); setCentralWidget(m_modeStack); ....... statusBar()->insertPermanentWidget(0, m_toggleSideBarButton); .......}
撇掉与输出窗口无关的东西,上面的代码就是与Output相关的代码。
m_actionManager用于管理菜单,关于Output仅用于注册快捷键。
1. OutputPaneManager::create()
完成OutputPaneManager创建,在其构造函数中添加了“清除action”,“prevAction”,“nextAction”,”最大化最小化”,”关闭“等输出窗口上toolbar的一些action。这几个action是所有输出类窗口的公共action,也就是说,所有的输出类窗口都会有这几个action。
2. registerDefaultContainers() 和 registerDefaultActions()
用于添加主窗口的菜单,具体添加方法参见
3.new FancyTabWidget 和 new ModeManager
FancyTabWidget是Qt Creator窗口最左边的一列,包括欢迎、编辑、调试、设计、项目、分析、帮助,下边还有一个大家都熟悉的cornerWidget(放着构建、构建运行等几个按钮)。ModeManager用于管理各种Mode,比如EditMode,WelcomeMode等等,每一个FancyTabWidget中的Tab对应一个Mode,从这里可以看出,可以通过添加IMode的子类以在FancyTabWidget中添加Tab。ModeManager的构造函数完成FancyTabWidget的Tab改变所引起的信号的槽,并添加cornerWidget(在FancyTabWidget中,并没有添加,只是添加了一个占位的布局而已)。
4. new StatusBarManager(this) 和 new MessageManager
StatusBarManager的构造函数完成根据StatusBarWidget的个数(四个)向StatusBar添加Widget的功能(其实就相当于将状态栏分成了四个部分),并将他们存放在QList<QWidget*>中以便以后使用。来一段代码
StatusBarManager::StatusBarManager(MainWindow *mainWnd) : QObject(mainWnd), m_mainWnd(mainWnd){ for (int i = 0; i <= StatusBarWidget::Last; ++i) { QWidget *w = new QWidget(); m_mainWnd->statusBar()->insertPermanentWidget(i, w); w->setLayout(new QHBoxLayout); w->setVisible(true); w->layout()->setMargin(0); m_statusBarWidgets.append(w); } m_mainWnd->statusBar()->insertPermanentWidget(StatusBarWidget::Last+1, new QLabel(), 1);}
个人认为这里使得状态栏的分组个数固定,设计并不是很好,插件希望添加按钮到状态栏时就遇到了困难,需要修改StatusBarWidget,并重新编译Core插件,不知道是我理解的不够深入还是怎么。MessageManager的构造函数并没有做什么实质性的东西。
statusBar()->insertPermanentWidget(0, m_toggleSideBarButton);在状态栏的最左边添加了一个按钮用于显示/隐藏边栏。
MainWindow的init()做了些什么?
先上代码,已经去掉无关代码。
bool MainWindow::init(QString *errorMessage){ Q_UNUSED(errorMessage) ..... ExtensionSystem::PluginManager::addObject(m_coreImpl); m_statusBarManager->init(); m_modeManager->init(); ....... m_outputView = new Core::StatusBarWidget; m_outputView->setWidget(OutputPaneManager::instance()->buttonsWidget()); m_outputView->setPosition(Core::StatusBarWidget::Second); ExtensionSystem::PluginManager::addObject(m_outputView); m_messageManager->init(); return true;}
1. m_statusBarManager->init()
仅将对象池的objectAdded() 和aboutToRemoveObject()两个信号关联到了相应的槽函数objectAdded(QObject*)和aboutToRemoveObject(QObject*)。当有对象添加到对象池当中时,就使用Aggregation来查询是否是StatusBarWidget类型,如果是该类型,就将相对应的Widget添加到状态栏的相应位置当中,并添加到窗口列表(QMap<QWidget *, IContext *> m_contextWidgets)当中。aboutToRemoveObject就是从窗口列表中删除。
2. m_modeManager->init()
与StatusBarManager一样,仅将对象池的objectAdded() 和aboutToRemoveObject()两个信号关联到了相应的槽函数objectAdded(QObject*)和aboutToRemoveObject(QObject*)。他查询的是IMode类型,如果是IMode类型,就将其添加到FancyTabWidget当中,并链接相应的槽,注册快捷键。
3.new Core::StatusBarWidget()之后的几句代码
创建了一个Widget,这个Widget由OutputPaneManager来负责填充,并设置这个widget放在状态栏的第2个位置上(有4个位置),添加这个StatusBarWidget到对象池,相应的槽函数完成真正的插入工作。
4. MessageManager::init()
该函数中创建MessageOutputWindow,并将其添加到对象池中。
MainWindow的extensionsInitialized()都做了些什么?
简要代码如下:
void MainWindow::extensionsInitialized(){ ....... m_statusBarManager->extensionsInitalized(); OutputPaneManager::instance()->init(); ....... // reading the shortcut settings must be done after all shortcuts have been registered m_actionManager->d->initialize(); .......}
1. m_statusBarManager->extensionsInitalized()
该函数为空,可以进行扩展。
2. OutputPaneManager::instance()->init()
首先在主窗口的menuBar中添加菜单,关联”清空“,”最大化/最小化“操作。然后从对象池当中得到所有的IOutputPane,并将它们根据在状态栏中的位置进行排序。然后将每个IOutputPane的输出窗口outputWidget添加到QStackedWidget当中,将toolBarWidget添加到输出窗口上边的工具栏m_opToolBarWidgets(也是一个StackedWidget)中。
好,先写这么多,以后继续补充。