QtでMDIを扱うときの助けになればと思い書いてみました。でも、文章力が無いので、細かくは説明できません……。ここに書くコードはパブリックドメイン・ライセンスとします。煮るなり焼くなりしてください。ただ、実際に使用したりブログなどで記事として使う場合はここにあるソースのAniLaの部分は自分のプロジェクト名などに書き換えてくださいねっ。
MDIスケルトンのための基底クラスを作る
まずは、私はMDIソフトの骨格となる部分を作っています。複数のアプリが同じ形式でできるようにするために…です。
私がやっている方法では pure virtual な関数を作って、自分が作るアプリのメインウィンドウはこのクラスから派生して作っています。
普通にQtCreaterやVS Qt add in などで雛形を作ると、QMainWindowクラスのサブクラスが作られますが、下記のクラスを挟みこんで使っています。
使用前
QMainWindow — 派生 –> MyWidget
使用後
QMainWindow — 派生 –> AniLaMdi — 派生 –> MyWidget
そして、そのままではSDIのままですので、Qtデザイナーを使って、MyWidget の ui クラスのに QMdiArea を貼り付けます。
QMdiArea はcentralWidgetの中にいっぱいに広がるようにレイアウトを設定しましょう。
そして、AniLaMdi にある関数を呼び出して色々と設定します。設定する過程で自動的に QMidArea のポインターを取得するようになっています。
いろいろな設定といっても、主に pure virtual な関数をメンバに設定するという作業と、各種コネクション用の呼び出しをすることです。実は、下記のファイルだけでは説明不足です。関数にコメントも付けてませんし…。
このクラスを使って実際にどうすればMDIの操作できるウィンドウが出来るのかというのは、また後日、暇なときにでも解説してみたいと思います。
とりあえず、このソースからだけでも何かのヒントを得られる人は得られると思いますし、私ももっとこうしたほうがいいとかアドバイスを貰いたいと思っていますので、この部分をまず公開してみた所存であります。
本当は、MyWidgetに当たる部分も合わせて公開しないとわからない部分も多いと思いますが、なにぶんサンプル用としてのMyWidgetを作っていなくって…、現在実際に売り物として作っているペイントソフトのMyWidgetに当たる部分しか無く…、また、ブログ用にMyWidgetに当たる部分を作成する時間も作れず……、じゃぁ、公開しないほうがいいのかというと、Twitterなどの影響で Low な情報でも公開しちゃうのもアリかなと思えた所存で…、この数日の(本来の自分ではあまりやらないような技術的な記事の)投稿を行っています。
つまり、Lowな情報でも出してしまえ的な風潮にのってみようか…というノリで描いた記事です。
参考にして頂ければ…と思います。
● anilamdi.h ヘッダーファイル
#ifndef ANILAMDI_H
#define ANILAMDI_H
#include <QtDotNetStyle>
#include "anilatoolbarmanager.h"
#define KEY_GEOMETRY "mdi/geometry"
#define KEY_DOCKSTATE "mdi/dockState"
#define KEY_TOOLBARSTATE "mdi/toolBarState"
#define KEY_RECENTLYPATH "mdi/recentlyPath"
#define TOOLBARSTATE_SUFFIX ".TBState"
class AniLaMdi : public QMainWindow
{
Q_OBJECT
public:
AniLaMdi( int dockBarVersion = 0 );
signals:;
void existSubWindows( bool isExist );
void existSubWindow( bool isExist );
public:
void initinstance();
void exitinstance();
public slots:;
virtual bool fileOpen( const QString & path ) = 0;
void styleWinClassic();
void styleWinXP();
void styleWinVista();
void styleWinDotNet();
void styleWinOfficeBlue();
void styleWinOfficeSilver();
void styleWinOfficeOlive();
void styleMotif();
void styleCDE();
void stylePlastique();
void styleCleanlooks();
void aboutQt();
protected:
// Pure virtual function
virtual QString subTitle( QMdiSubWindow * subWindow ) = 0;
virtual bool maybeSave() = 0;
virtual void onInitInstance() = 0;
virtual void onExitInstance() = 0;
virtual void onReadSettings( QSettings & settings ) = 0;
virtual void onWriteSettings( QSettings & settings ) = 0;
virtual void onConnectMainWindow( bool isConnect );
virtual void onConnectSubWindow( bool isConnect,
QMdiSubWindow * subWindow );
virtual void onSubWindowAllClosed();
// functions
static bool connection( bool isConnect,
const QObject * sender,
const char * signal,
const QObject * receiver,
const char * method,
const Qt::ConnectionType & type
= Qt::AutoConnection );
bool setConnection( bool isConnect,
QAction * sender,
const char * signal,
const QObject * receiver,
const char * method );
bool connectToolBarManager( bool isConnect,
QAction * sender,
const char * signal,
const char * method );
bool connectChanged( bool isConnect,
QAction * sender,
const char * method );
bool connectHovered( bool isConnect,
QAction * sender,
const char * method );
bool connectToggled( bool isConnect,
QAction * sender,
const char * method );
bool connectTriggered( bool isConnect,
QAction * sender,
const char * method );
bool connectTriggeredMdiArea( bool isConnect,
QAction * sender,
const char * method );
void connectRecentlyList( bool isConnect,
QMenu * menu );
void connectSubWindowListTail( bool isConnect,
QMenu * menu );
void connectPainListHead( bool isConnect,
QMenu * menu );
void connectForSubWindow( bool isConnect,
QAction * action );
void connectForSubWindows( bool isConnect,
QAction * action );
void addToolBarManager( QAction * action );
void removeToolBarManager( QAction * action );
void updateSubWindowTitles();
void addRecentlyPath( const QString & path );
QString windowFilePath( QMdiSubWindow * subWindow );
QMdiSubWindow * findSubWindow( const QString & path,
const QMdiArea::WindowOrder & order
= QMdiArea::ActivationHistoryOrder,
bool isReverse = true );
// Events
virtual void closeEvent( QCloseEvent * event );
virtual void dragEnterEvent( QDragEnterEvent * event );
virtual void dropEvent( QDropEvent * event );
protected slots:;
void setActiveSubWindow( QWidget * widget );
void setActiveSubWindow( QMdiSubWindow * subWindow );
void clearRecentlyPath();
private:
QMenu * senderMenu();
void removeRecentlyList();
void removeSubWindowListTail();
void removePainListHead();
void readMdiSettings();
void writeMdiSettings();
void connectMdiWidgets( bool isConnect );
private slots:;
void appendRecentlyList();
void appendSubWindowListTail();
void appendPainListHead();
void onSubWindowActivated( QMdiSubWindow * subWindow );
private:
int m_dockBarVersion;
bool m_isInitialize;
QSignalMapper m_windowMapper;
QSignalMapper m_recentlyMapper;
AniLaToolBarManager m_toolBarManager;
QStringList m_recentlyPath;
QList<QAction *> m_actionForSubWindow;
QList<QAction *> m_actionForSubWindows;
QMdiArea * m_mdiArea;
QMdiSubWindow * m_mdiSubWindow;
QHash<QAction*,bool>m_afterActionEnable;
QHash<QWidget*,bool>m_afterWidgetEnable;
};
inline void AniLaMdi::initinstance()
{
if (m_isInitialize) return;
readMdiSettings();
onInitInstance();
show();
connectMdiWidgets( true );
m_isInitialize = true;
}
inline void AniLaMdi::exitinstance()
{
if ( !m_isInitialize ) return;
connectMdiWidgets( false );
hide();
onExitInstance();
writeMdiSettings();
m_isInitialize = false;
}
inline void AniLaMdi::aboutQt()
{
qApp->aboutQt();
}
inline void AniLaMdi::styleWinClassic()
{
QApplication::setStyle( new QWindowsStyle );
}
inline void AniLaMdi::styleWinXP()
{
QApplication::setStyle( new QWindowsXPStyle );
QSysInfo::WinVersion ver = QSysInfo::windowsVersion();
if ( ver != QSysInfo::WV_XP ){
QMessageBox::warning( this,
tr( "Warning" ),
tr( "This style is only available on the Windows XP platform \n"
"because it makes use of Windows XP's style engine." ) );
}
}
inline void AniLaMdi::styleWinVista()
{
QApplication::setStyle( new QWindowsVistaStyle );
QSysInfo::WinVersion ver = QSysInfo::windowsVersion();
if ( ver != QSysInfo::WV_VISTA && ver != QSysInfo::WV_WINDOWS7 ){
QMessageBox::warning( this,
tr( "Warning" ),
tr( "This style is only available on the Windows Vista platform \n"
"because it makes use of Windows Vista's style engine." ) );
}
}
inline void AniLaMdi::styleWinDotNet()
{
QApplication::setStyle( new QtDotNetStyle(QtDotNetStyle::System) );
}
inline void AniLaMdi::styleWinOfficeBlue()
{
QApplication::setStyle( new QtDotNetStyle(QtDotNetStyle::Blue) );
}
inline void AniLaMdi::styleWinOfficeSilver()
{
QApplication::setStyle( new QtDotNetStyle(QtDotNetStyle::Silver) );
}
inline void AniLaMdi::styleWinOfficeOlive()
{
QApplication::setStyle( new QtDotNetStyle(QtDotNetStyle::Olive) );
}
inline void AniLaMdi::styleMotif()
{
QApplication::setStyle( new QMotifStyle );
}
inline void AniLaMdi::styleCDE()
{
QApplication::setStyle( new QCDEStyle );
}
inline void AniLaMdi::stylePlastique()
{
QApplication::setStyle( new QPlastiqueStyle );
}
inline void AniLaMdi::styleCleanlooks()
{
QApplication::setStyle( new QCleanlooksStyle );
}
inline bool AniLaMdi::connection( bool isConnect,
const QObject * sender,
const char * signal,
const QObject * receiver,
const char * method,
const Qt::ConnectionType & type )
{
if ( isConnect ) return connect( sender, signal, receiver, method, type );
return disconnect( sender, signal, receiver, method );
}
inline bool AniLaMdi::setConnection( bool isConnect,
QAction * sender,
const char * signal,
const QObject * receiver,
const char * method )
{
Q_ASSERT( sender );
bool ret = connection( isConnect, sender, signal, receiver, method );
m_afterActionEnable.insert( sender, (isConnect && ret ) );
return ret;
}
inline bool AniLaMdi::connectToolBarManager( bool isConnect,
QAction * sender,
const char * signal,
const char * method )
{
return setConnection( isConnect, sender, signal, &m_toolBarManager, method );
}
inline bool AniLaMdi::connectChanged( bool isConnect,
QAction * sender,
const char * method )
{
return setConnection( isConnect, sender, SIGNAL(changed()), this, method );
}
inline bool AniLaMdi::connectHovered( bool isConnect,
QAction * sender,
const char * method )
{
return setConnection( isConnect, sender, SIGNAL(hovered()), this, method );
}
inline bool AniLaMdi::connectToggled( bool isConnect,
QAction * sender,
const char * method )
{
return setConnection( isConnect, sender, SIGNAL(toggled(bool)), this, method );
}
inline bool AniLaMdi::connectTriggered( bool isConnect,
QAction * sender,
const char * method )
{
return setConnection( isConnect, sender, SIGNAL(triggered(bool)), this, method );
}
inline bool AniLaMdi::connectTriggeredMdiArea( bool isConnect,
QAction * sender,
const char * method )
{
if ( !m_mdiArea ) return false;
return setConnection( isConnect, sender, SIGNAL(triggered(bool)), m_mdiArea, method );
}
inline void AniLaMdi::addToolBarManager( QAction * action )
{
m_toolBarManager.addToolBarManager( action );
}
inline void AniLaMdi::removeToolBarManager( QAction * action )
{
m_toolBarManager.removeToolBarManager( action );
}
inline void AniLaMdi::setActiveSubWindow(QWidget * widget)
{
setActiveSubWindow( qobject_cast<QMdiSubWindow *>(widget) );
}
inline void AniLaMdi::setActiveSubWindow(QMdiSubWindow * subWindow)
{
if ( m_mdiArea && subWindow )
m_mdiArea->setActiveSubWindow( subWindow );
}
inline void AniLaMdi::onConnectMainWindow( bool isConnect )
{
#ifndef QT_NO_DEBUG
QString str = QString( "%1( %2 )" )
.arg("connectMainWindow")
.arg((isConnect)?"true":"false");
qDebug( str.toAscii() );
#endif //QT_NO_DEBUG
}
inline void AniLaMdi::onConnectSubWindow( bool isConnect,
QMdiSubWindow * subWindow )
{
#ifndef QT_NO_DEBUG
QString str = QString( "%1( %2, %3 ) [ %4 ]" )
.arg("connectSubWindow")
.arg((isConnect)?"true":"false")
.arg((qlonglong)subWindow)
.arg(subWindow->windowTitle());
qDebug( str.toAscii() );
#endif //QT_NO_DEBUG
}
inline void AniLaMdi::onSubWindowAllClosed()
{
#ifndef QT_NO_DEBUG
qDebug( "onSubWindowAllClosed()" );
#endif //QT_NO_DEBUG
}
inline void AniLaMdi::connectRecentlyList( bool isConnect,
QMenu * menu )
{
Q_ASSERT( menu );
m_afterWidgetEnable.insert( menu,
connection( isConnect, menu, SIGNAL(aboutToShow()),
this, SLOT(appendRecentlyList()) ) );
}
inline void AniLaMdi::connectSubWindowListTail( bool isConnect,
QMenu * menu )
{
Q_ASSERT( menu );
m_afterWidgetEnable.insert( menu,
connection( isConnect, menu, SIGNAL(aboutToShow()),
this, SLOT(appendSubWindowListTail()) ) );
}
inline void AniLaMdi::connectPainListHead( bool isConnect,
QMenu * menu )
{
Q_ASSERT( menu );
m_afterWidgetEnable.insert( menu,
connection( isConnect, menu, SIGNAL(aboutToShow()),
this, SLOT(appendPainListHead()) ) );
}
inline void AniLaMdi::connectForSubWindow( bool isConnect,
QAction * action )
{
Q_ASSERT( action );
connection( isConnect, this, SIGNAL(existSubWindow(bool)),
action, SLOT(setEnabled(bool)) );
if ( m_mdiArea ){
QList<QMdiSubWindow *> list = m_mdiArea->subWindowList();
emit existSubWindow( list.count() > 0 );
} else emit existSubWindow( false );
}
inline void AniLaMdi::connectForSubWindows( bool isConnect,
QAction * action )
{
Q_ASSERT( action );
connection( isConnect, this, SIGNAL(existSubWindows(bool)),
action, SLOT(setEnabled(bool)) );
if ( m_mdiArea ){
QList<QMdiSubWindow *> list = m_mdiArea->subWindowList();
emit existSubWindows( list.count() > 1 );
} else emit existSubWindow( false );
}
inline QMenu * AniLaMdi::senderMenu()
{
if ( !m_mdiArea || !sender() ) return 0;
return qobject_cast<QMenu *>( sender() );
}
inline void AniLaMdi::clearRecentlyPath()
{
m_recentlyPath.clear();
}
#endif // ANILAMDI_H
AniLaMdi.cpp cppファイル
#include "stdafx.h"
#include "anilamdi.h"
AniLaMdi::AniLaMdi( int dockBarVersion )
: QMainWindow(),
m_windowMapper( this ),
m_toolBarManager( this ),
m_mdiArea( 0 ),
m_mdiSubWindow( 0 ),
m_dockBarVersion( dockBarVersion ),
m_isInitialize( false )
{
}
void AniLaMdi::closeEvent( QCloseEvent * event )
{
if ( !m_mdiArea ) return;
m_mdiArea->closeAllSubWindows();
QList<QMdiSubWindow*> list = m_mdiArea->subWindowList();
if ( list.isEmpty() ) event->accept();
else event->ignore();
}
void AniLaMdi::dragEnterEvent( QDragEnterEvent * event )
{
if ( event->mimeData()->hasFormat( "text/uri-list" ) ){
QList<QUrl> urlList = event->mimeData()->urls();
bool isImage = false;
foreach ( QUrl url, urlList ){
QString path = url.toLocalFile();
if ( !path.isEmpty() && !QImageReader::imageFormat( path ).isEmpty() )
isImage = true;
}
if ( isImage ) event->acceptProposedAction();
}
}
void AniLaMdi::dropEvent( QDropEvent * event )
{
QList<QUrl> urlList = event->mimeData()->urls();
if ( urlList.isEmpty() ) return;
bool isError = false;
foreach ( QUrl url, urlList ){
if ( isError && QMessageBox::question(
this, tr("Question ?"),
tr( "Do you continue reading of a file?" ),
QMessageBox::No | QMessageBox::Yes, QMessageBox::No ) ==
QMessageBox::No ) return;
QString path = url.toLocalFile();
if ( !path.isEmpty() && !QImageReader::imageFormat( path ).isEmpty() )
isError = !fileOpen( path );
}
}
void AniLaMdi::onSubWindowActivated( QMdiSubWindow * subWindow )
{
if ( !m_mdiArea ) return;
// No subWindow or Non-Activate MainWindow
QList<QMdiSubWindow *> list = m_mdiArea->subWindowList();
if ( subWindow ){
// Change activate subWindow
if ( m_mdiSubWindow != subWindow ){
// disconnect old subWindow
if ( m_mdiSubWindow )
onConnectSubWindow( false, m_mdiSubWindow );
// connect new subWindow
onConnectSubWindow( true, subWindow );
m_mdiSubWindow = subWindow;
}
} else {
if ( list.isEmpty() ){
if ( m_mdiSubWindow ){
// disconnect old subWindow
onConnectSubWindow( false, m_mdiSubWindow );
m_mdiSubWindow = subWindow;
onSubWindowAllClosed();
}
}
}
updateSubWindowTitles();
emit existSubWindow( list.count() > 0 );
emit existSubWindows( list.count() > 1 );
}
void AniLaMdi::updateSubWindowTitles()
{
if ( !m_mdiArea ) return;
QList<QMdiSubWindow*> list = m_mdiArea->subWindowList();
// Add a number to the view of the same file.
int count = list.count();
QMap<QString, QList<QMdiSubWindow*>> pathToSubWindow;
if ( count <= 0 ) return;
for ( int i=0; i < count; i++ ){
QString path = windowFilePath( list[i] );
if ( !pathToSubWindow.contains( path ) ){
QList<QMdiSubWindow*> subList;
subList.append( list[i] );
for ( int j=i+1; j < count; j++ )
if ( path == windowFilePath( list[j] ) )
subList.append( list[j] );
pathToSubWindow.insert( path, subList );
}
}
for ( QMap<QString, QList<QMdiSubWindow*>>::iterator
it = pathToSubWindow.begin(), end = pathToSubWindow.end();
it != end; ++it ){
int num = 0;
QList<QMdiSubWindow*> subList = it.value();
if ( subList.count() == 1 )
subList[0]->setWindowTitle( QFileInfo( it.key() ).fileName()
+ QString(" [*]") + subTitle( subList[0] ) );
else {
foreach ( QMdiSubWindow * sub, subList ){
sub->setWindowTitle( QFileInfo( it.key() ).fileName()
+ QString(":%1 [*]").arg(++num) + subTitle( sub ) );
}
}
}
}
void AniLaMdi::readMdiSettings()
{
QSettings settings;
// read main window settings
restoreGeometry( settings.value( KEY_GEOMETRY ).toByteArray() );
restoreState( settings.value( KEY_DOCKSTATE ).toByteArray(),
m_dockBarVersion );
m_recentlyPath = settings.value( KEY_RECENTLYPATH ).toStringList();
// read application settings
onReadSettings( settings );
// read tool bar manager settings
m_toolBarManager.initialization();
m_toolBarManager.restoreState( settings.value(KEY_TOOLBARSTATE).toByteArray(),
m_dockBarVersion );
}
void AniLaMdi::writeMdiSettings()
{
QSettings settings;
// write main window settings
settings.setValue( KEY_RECENTLYPATH, m_recentlyPath );
settings.setValue( KEY_GEOMETRY, saveGeometry() );
settings.setValue( KEY_DOCKSTATE, saveState(m_dockBarVersion) );
// write application settings
onWriteSettings( settings );
// write tool bar manager settings
settings.setValue( KEY_TOOLBARSTATE,
m_toolBarManager.saveState(m_dockBarVersion) );
}
void AniLaMdi::connectMdiWidgets( bool isConnect )
{
// Connect central widget
QWidget * widget = centralWidget();
if ( widget ){
foreach ( QObject * object, widget->children() ){
QMdiArea * mdiArea = qobject_cast<QMdiArea*>( object );
if ( mdiArea ){
m_mdiArea = mdiArea;
connection( isConnect,
m_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)),
this, SLOT(onSubWindowActivated(QMdiSubWindow*)) );
setAcceptDrops( true );
}
}
}
if ( !isConnect ) m_mdiArea = 0;
// Connect recently mappaer
connection( isConnect,
&m_recentlyMapper, SIGNAL(mapped(QString)),
this, SLOT(fileOpen(QString)) );
// Connect window mapper
connection( isConnect,
&m_windowMapper, SIGNAL(mapped(QWidget *)),
this, SLOT(setActiveSubWindow(QWidget *)) );
// Connect subclass(MainWindow) widget
onConnectMainWindow( isConnect );
// after action enbale
for ( QHash<QAction*,bool>::iterator
it = m_afterActionEnable.begin(), end = m_afterActionEnable.end();
it != end; ++it ) it.key()->setEnabled( *it );
m_afterActionEnable.clear();
// after widget enable
for ( QHash<QWidget*,bool>::iterator
it = m_afterWidgetEnable.begin(), end = m_afterWidgetEnable.end();
it != end; ++it ) it.key()->setEnabled( *it );
m_afterWidgetEnable.clear();
}
void AniLaMdi::addRecentlyPath( const QString & path )
{
QStringList list;
list.append( path );
int count = 1;
foreach ( QString file, m_recentlyPath ){
if ( file != path && QFileInfo( file ).isFile() ){
list.append( file );
count ++;
if ( count == 20 ) break;
}
}
m_recentlyPath.clear();
m_recentlyPath.append( list );
}
QString AniLaMdi::windowFilePath( QMdiSubWindow * subWindow )
{
if ( !subWindow ) return QString();
QString path = subWindow->windowFilePath();
if ( !path.isEmpty() ) return path;
QWidget * widget = subWindow->widget();
if ( !widget ) return QString();
return widget->windowFilePath();
}
QMdiSubWindow * AniLaMdi::findSubWindow( const QString & path,
const QMdiArea::WindowOrder & order,
bool isReverse )
{
if ( !m_mdiArea || path.isEmpty() ) return 0;
QList<QMdiSubWindow*> list = m_mdiArea->subWindowList( order );
int count = list.count();
int i = 0, add = 1;
if ( isReverse ){
i = count - 1;
add = -1;
}
for ( ; 0 <= i && i < count ; i += add ){
QMdiSubWindow * subWindow = list[i];
if ( windowFilePath( subWindow ) == path ) return subWindow;
}
return 0;
}
void AniLaMdi::appendRecentlyList()
{
removeRecentlyList();
QMenu * menu = senderMenu();
if ( !menu ) return;
if ( m_recentlyPath.isEmpty() ){
QAction * action =
menu->addAction( tr("There is not the recent file.") );
action->setEnabled( false );
return;
}
int j=0;
foreach ( QString path, m_recentlyPath ){
QString title = path;
if ( j<9 ) title += QString( " (&%1)" ).arg( ++j );
QAction * action = menu->addAction( title );
connect( action, SIGNAL(triggered()),
&m_recentlyMapper, SLOT(map()) );
m_recentlyMapper.setMapping( action, path );
}
menu->addSeparator();
QAction * action =
menu->addAction( tr("Clear the list of the recent file.") );
connect( action, SIGNAL(triggered()),
this, SLOT(clearRecentlyPath()) );
}
void AniLaMdi::removeRecentlyList()
{
QMenu * menu = senderMenu();
if ( !menu ) return;
bool isRecentlyList = false;
QList<QAction*> list = menu->actions();
foreach ( QAction * action, list ){
if ( !isRecentlyList ){
if ( !action->isSeparator() ){
m_recentlyMapper.removeMappings( action );
disconnect( action, SIGNAL(triggered()),
&m_recentlyMapper, SLOT(map()) );
} else isRecentlyList = true;
menu->removeAction( action );
} else disconnect( action, SIGNAL(triggered()),
this, SLOT(clearRecentlyPath()) );
}
menu->clear();
}
#define FLAG_WLT "$$window_list_tail$$"
void AniLaMdi::appendSubWindowListTail()
{
removeSubWindowListTail();
QMenu * menu = senderMenu();
if ( !menu ) return;
QList<QMdiSubWindow*> windowList =
m_mdiArea->subWindowList( QMdiArea::StackingOrder );
if ( windowList.count() < 2 ) return;
QMdiSubWindow * activeWindow = m_mdiArea->activeSubWindow();
bool hasSeparator = ( menu->actions().count() > 0 );
QAction * flagAct = menu->addAction( FLAG_WLT );
flagAct->setVisible( false );
if ( hasSeparator ) menu->addSeparator();
for ( int i=windowList.count()-1, j=1; i>=0; i--, j++ ){
QString title;
if ( windowList[i]->isWindowModified() )
title = windowList[i]->windowTitle().remove('[').remove(']');
else title = windowList[i]->windowTitle().remove("[*]");
if ( j < 10 ) title += QString(" (&%1)").arg( j );
QAction * action = menu->addAction( title );
action->setCheckable( true );
action->setChecked( windowList[i]==activeWindow );
connect( action, SIGNAL(triggered()),
&m_windowMapper, SLOT(map()) );
m_windowMapper.setMapping( action, (QWidget*)windowList[i] );
}
}
void AniLaMdi::removeSubWindowListTail()
{
QMenu * menu = senderMenu();
if ( !menu ) return;
bool isWindowList = false;
QString flagText = FLAG_WLT;
foreach ( QAction * action, menu->actions() ){
if ( isWindowList ){
if ( !action->isSeparator() ){
m_windowMapper.removeMappings( action );
disconnect( action, SIGNAL(triggered()),
&m_windowMapper, SLOT(map()) );
}
menu->removeAction( action );
} else {
if ( action->text() == flagText ){
menu->removeAction( action );
isWindowList = true;
}
}
}
}
#define FLAG_PLH_START "$$pain_list_head_start$$"
#define FLAG_PLH_END "$$pain_list_head_end$$"
void AniLaMdi::appendPainListHead()
{
removePainListHead();
QMenu * menu = senderMenu();
if ( !menu ) return;
QMenu * viewPainMenu = createPopupMenu();
if ( !viewPainMenu ) return;
QList<QAction*> pains = viewPainMenu->actions();
if ( !pains.isEmpty() ){
QList<QAction*> list = menu->actions();
QAction * before = list.isEmpty() ? 0 : list[0];
QAction * act = new QAction( FLAG_PLH_START, menu );
act->setVisible( false );
menu->insertAction( before, act );
foreach ( QAction * action, pains ){
if ( action->isSeparator() )
menu->insertSeparator( before );
else menu->insertAction( before, action );
}
if ( before ) menu->insertSeparator( before );
act = new QAction( FLAG_PLH_END, menu );
act->setVisible( false );
menu->insertAction( before, act );
}
delete viewPainMenu;
}
void AniLaMdi::removePainListHead()
{
QMenu * menu = senderMenu();
if ( !menu ) return;
QList<QAction*> list = menu->actions();
QString flagStart( FLAG_PLH_START );
QString flagEnd( FLAG_PLH_END );
bool isRemove = false;
foreach( QAction * action, list ){
QString text = action->text();
if ( text == flagStart ) isRemove = true;
if ( isRemove ) menu->removeAction( action );
if ( text == flagEnd ) break;
}
}
これらのソースは、まだ作りかけのソフトの一部分なので欠陥なども色々とあると思います。参考程度にとどめてください。
また、より分かりやすい解説などを目的にブログ等で活用されたら嬉しいです。
なお、ここに載っていないファイルは以下のzipにあります。
anilamdi-bata01.zip (パブリックドメイン・ライセンス)
※上記のファイルには一切try catch節が一切ありません。まだ書いていないだけですが…。
このままだと例外セーフじゃないので、その辺のところは自己責任でよろしくです。
このソースには、Qtソリューションの中からつぎの2つのプロジェクトで作られたdllを外部リンクで使用しています。
若干改造して使用していますので、次のコードもダウンロードしてみてください。
qttoolbardialog-2.2-opensource-kaizou01.zip (LGPL/GPL)
qtdotnetstyle-2.3-opensource-kaizou01.zip (LGPL/GPL)
この記事の続きは何時になるかわかりませんが、いずれ、MyWidgetに当たる部分の雛形も作って公開してみたいと思います。
それでは、ごきげんよう(^_^)/~