はじめに
Ctrl+Tabでタブを切り替える操作はWindowsではおなじみですが、Qtでは邪道(?)扱いされているようです。
Qt treats Ctrl+Tab as Tab and Ctrl+Shift+Tab as Shift+Tab, ... 《途中省略》
However, since some systems use Ctrl+Tab for other purposes, and many users aren't aware of Ctrl+Tab anyway, this isn't a complete solution.
[Google翻訳]
Qt は Ctrl+Tab を Tab として扱い、Ctrl+Shift+Tab を Shift+Tab として扱います。 《途中省略》
ただし、一部のシステムでは Ctrl+Tab を他の目的に使用しており、いずれにしても多くのユーザーは Ctrl+Tab を認識していないため、これは完全な解決策ではありません。
(あれ?そうなの?)そういう割に、QTabWidgetではCtrl+Tabでタブを切り替えられる場合もあって気持ちが悪いです。
冒頭の例では、QPushButtonやQCheckBoxにフォーカスがあたっている場合はタブが切り替わります。一方で、QComboBoxやQTableWidgetにフォーカスがあたっていると切り替わらないです。
そこで常にCtrl+Tabが効くようにする方策を考えてみました。
まず、カスタムウィジットを作成してイベントフィルタを組み込み、Ctrl+Tabのキーイベントを横取りして親のQTabWidgetへ転送するようにしてみました。
ところが、状態によってはサブクラスにイベントを吸い込まれてしまいました。
例1:QComboBoxのアイテム選択中 →QComboBoxListViewにイベントを吸われる
例2:QTableWidgetのアイテム編集中 →QExpandingLineEditにイベントを吸われる
main関数にイベントフィルタを組み込めばQComboBoxListViewやQExpandingLineEditのようなサブクラスのイベントを横取りできます。これでCtrl+Tabが常に効くようになり、すっきりしました。
ただし、組み込んだイベントフィルタは高頻度で呼ばれ、すっきりするだけのためにコストかかりすぎかもしれないです。
いちおう実装例:
#include "mainwindow.h"
#include <QApplication>
#include <QKeyEvent>
class MyFilter : public QObject
{
protected:
bool eventFilter(QObject *object, QEvent *event)
{
if(event->type() != QEvent::KeyPress)
return false;
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(!(keyEvent->modifiers() & Qt::ControlModifier) ||
!(keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Backtab))
return false;
const char *p = object->metaObject()->className();
if(!strcmp(p, "QTableWidget") || !strcmp(p, "QExpandingLineEdit") ||
!strcmp(p, "QComboBox") || !strcmp(p, "QComboBoxListView")){ // 必要な場合、追加する
QWidget *w = qobject_cast<QWidget *>(object->parent());
while(w){
if(!strcmp(w->metaObject()->className(), "QTabWidget")){
qApp->sendEvent(w, event); // QTabWidgetにキーイベントを転送する
return true; // イベントを破棄
}
w = qobject_cast<QWidget *>(w->parent());
}
}
return false;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyFilter filter;
a.installEventFilter(&filter);
MainWindow w;
w.show();
return a.exec();
}
参考