Qtウィジェットのフォーカス制御:setEditFocus()とその他の設定方法を徹底解説

2025-05-16

QtプログラミングにおけるQWidget::setEditFocus()は、特定のウィジェットに対して入力フォーカスをプログラム的に設定するための関数です。

もう少し詳しく説明します。

  • 使用例(概念)

    // myLineEdit は QLineEdit のインスタンス
    myLineEdit->setEditFocus(); // myLineEdit に入力フォーカスを設定
    
  • 注意点

    • setEditFocus()は、ウィジェットが実際にユーザーからの入力を受け付ける準備ができている場合にのみ効果があります。例えば、ウィジェットが非表示になっている場合や、無効になっている場合は効果がないか、予期せぬ動作をする可能性があります。
    • 通常、setFocus()setFocusPolicy()といったより汎用的なフォーカス制御関数も存在します。setEditFocus()は、特に編集可能なウィジェットの文脈で使われることが多いですが、多くの場合、setFocus()で代用できることもあります。
  • いつ使うか?

    • アプリケーション起動時
      特定の入力フィールドに自動的にフォーカスを当てて、ユーザーがすぐにタイピングを開始できるようにしたい場合。
    • ユーザーインタラクション後
      例えば、ユーザーがボタンをクリックした後、関連するテキスト入力フィールドにフォーカスを移動させたい場合。
    • エラー処理
      入力エラーが発生した場合に、エラーのあるフィールドにフォーカスを戻して、ユーザーに修正を促す場合。
  • setEditFocus()の機能 QWidget::setEditFocus()は、通常、テキスト入力が可能なウィジェット(QLineEditQTextEditなど)や、ユーザーが編集操作を行うことが期待されるウィジェットに対して使用されます。この関数を呼び出すと、そのウィジェットが入力フォーカスを獲得し、キーボード入力の準備ができた状態になります。

  • 入力フォーカスとは? ユーザーがキーボードで文字を入力したり、矢印キーで移動したりする際に、その入力がどのウィジェット(例えば、テキストボックス、ボタンなど)に向けられるかを決定する概念です。フォーカスを持っているウィジェットだけが、キーボードからの入力イベントを受け取ります。



よくあるエラーと原因

    • ウィジェットがまだ表示されていない、または非表示になっている
      setEditFocus()を呼び出す時点で、対象のウィジェットがまだ画面に表示されていない(show()が呼ばれていない)場合や、hide()によって非表示になっている場合、フォーカスは設定されません。Qtのフォーカスシステムは、表示されているウィジェットにのみ有効です。
    • ウィジェットが無効になっている (setEnabled(false))
      無効化されたウィジェットは、入力イベントを受け付けないため、フォーカスも設定できません。
    • フォーカスポリシーが正しくない (setFocusPolicy())
      各ウィジェットにはフォーカスを受け入れるかどうかのポリシーが設定されています。例えば、NoFocusに設定されているウィジェットは、基本的にフォーカスを受け入れません。
    • 他のウィジェットがすぐにフォーカスを奪ってしまう
      複数のウィジェットが同時にフォーカスを要求したり、何らかのイベント(例えば、ウィンドウの表示直後)で別のウィジェットに自動的にフォーカスが移ってしまう場合があります。
    • ウィジェットが削除済み、または無効なポインタ
      setEditFocus()を呼び出す対象のウィジェットが、すでにメモリから解放されている場合や、無効なポインタを指している場合、クラッシュや未定義動作の原因となります。
    • QApplication::exec() がまだ呼ばれていない
      Qtアプリケーションのイベントループが開始されていない場合(つまり、QApplication::exec()が呼ばれる前)、UIの要素は完全に初期化されておらず、フォーカス設定が機能しないことがあります。
  1. 目的のウィジェットではなく、別のウィジェットにフォーカスが設定される

    • レイアウトによる自動フォーカス管理
      Qtのレイアウト(QHBoxLayout, QVBoxLayoutなど)は、内部的にフォーカス順を管理しています。意図しないウィジェットにフォーカスが当たるのは、レイアウトが構築された順序や、フォーカスポリシーの設定によるものです。
    • タブ順序 (setTabOrder())
      明示的にタブ順序を設定している場合、それが原因で期待通りのフォーカス順にならないことがあります。
  2. setEditFocus()がコンパイルエラーになる

    • Qt 5.15以降の非推奨化
      Qt 5.15以降のバージョンでは、QWidget::setEditFocus()は非推奨 (deprecated) となっています。代わりに、より汎用的なQWidget::setFocus()を使用することが推奨されます。setEditFocus()はQt Embedded Linux向けの機能で、通常のデスクトップアプリケーションではsetFocus()と同じ動作をします。
    • ヘッダファイルのインクルード不足
      setEditFocus()が定義されているヘッダファイル(通常は <QtWidgets/QWidget> または <QtWidgets/QLineEdit> など)がインクルードされていない場合、コンパイルエラーになります。
  1. ウィジェットの表示状態と有効状態を確認する

    • qDebug() << myWidget->isVisible();
    • qDebug() << myWidget->isEnabled();
    • setEditFocus()を呼び出す前に、これらのプロパティがtrueであることを確認してください。
  2. フォーカスポリシーを確認する

    • qDebug() << myWidget->focusPolicy();
    • デフォルトのQt::StrongFocusまたはQt::WheelFocusが設定されているか確認してください。もしQt::NoFocusになっている場合は、myWidget->setFocusPolicy(Qt::StrongFocus);などと設定し直す必要があります。
  3. setFocus()を試す

    • setEditFocus()の代わりにmyWidget->setFocus();を使ってみてください。特にQt 5.15以降を使用している場合は、こちらが推奨されます。
  4. フォーカス設定のタイミングを調整する

    • show()の直後や、他のUI操作が完了した後にsetEditFocus()(またはsetFocus())を呼び出すようにタイミングを調整します。
    • イベントループが完全に開始された後にフォーカスを設定したい場合、QTimer::singleShot()を使って遅延実行を試すことも有効です。
      QTimer::singleShot(0, myWidget, &QWidget::setFocus);
      // または
      QTimer::singleShot(0, this, [this]() {
          myWidget->setFocus();
      });
      
      singleShot(0, ...)は、現在のイベント処理が完了した直後に指定されたスロットを実行します。これにより、ウィジェットが完全に準備できた状態でフォーカスが設定されます。
  5. 親ウィジェットの表示状態を確認する

    • 対象のウィジェットが親ウィジェットの中に配置されている場合、親ウィジェットも表示されている必要があります。
  6. タブ順序を確認・調整する

    • Qt Designerを使用している場合は、フォームエディタでタブ順序を視覚的に確認・調整できます。
    • コードで明示的にsetTabOrder()を呼び出している場合は、その順序が正しいか確認してください。
  7. デバッガを使用する

    • setEditFocus()が呼び出されているかどうか、どの時点で呼び出されているかをデバッガでステップ実行して確認します。
    • QApplication::focusWidget()を使って、現在どのウィジェットがフォーカスを持っているかを動的に確認することもできます。
      qDebug() << "Current focus widget:" << QApplication::focusWidget();
      
  8. 単純なテストケースで再現を試みる

    • 問題が複雑なUIの一部で発生している場合、最小限のコードで問題が再現するかどうかを試すことで、原因の特定が容易になります。


基本的な使用例:アプリケーション起動時に特定のQLineEditにフォーカスを当てる

これは最も一般的なケースです。

#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // メインウィンドウとなるQWidgetを作成
    QWidget *window = new QWidget();
    window->setWindowTitle("Focus Example");

    // テキスト入力フィールドを3つ作成
    QLineEdit *lineEdit1 = new QLineEdit();
    lineEdit1->setPlaceholderText("氏名を入力");

    QLineEdit *lineEdit2 = new QLineEdit();
    lineEdit2->setPlaceholderText("メールアドレスを入力");

    QLineEdit *lineEdit3 = new QLineEdit();
    lineEdit3->setPlaceholderText("電話番号を入力");

    QPushButton *submitButton = new QPushButton("送信");

    // レイアウトを作成し、ウィジェットを追加
    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(lineEdit1);
    layout->addWidget(lineEdit2);
    layout->addWidget(lineEdit3);
    layout->addWidget(submitButton);

    window->setLayout(layout);

    // ここがポイント!アプリケーション起動時にlineEdit2にフォーカスを設定
    // QWidget::setEditFocus() は Qt 5.15 以降では非推奨のため、QWidget::setFocus() を使用します
    lineEdit2->setFocus(); 
    // または (Qt Embedded Linuxなど、特定の環境向け)
    // lineEdit2->setEditFocus(); 

    window->show();

    return app.exec();
}

解説
この例では、アプリケーションが起動すると同時に lineEdit2 にカーソルが移動し、ユーザーがすぐにメールアドレスを入力できる状態になります。

ボタンクリック時に別のQLineEditにフォーカスを移動させる

ユーザーのアクションに応じてフォーカスを移動させる例です。

#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QLabel> // エラー表示用

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget *window = new QWidget();
    window->setWindowTitle("Dynamic Focus Example");

    QLineEdit *usernameEdit = new QLineEdit();
    usernameEdit->setPlaceholderText("ユーザー名");

    QLineEdit *passwordEdit = new QLineEdit();
    passwordEdit->setPlaceholderText("パスワード");
    passwordEdit->setEchoMode(QLineEdit::Password); // パスワードとして表示

    QPushButton *loginButton = new QPushButton("ログイン");

    QLabel *statusLabel = new QLabel("ステータス: 待機中");

    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(new QLabel("ログインフォーム"));
    layout->addWidget(usernameEdit);
    layout->addWidget(passwordEdit);
    layout->addWidget(loginButton);
    layout->addWidget(statusLabel);
    window->setLayout(layout);

    // ログインボタンがクリックされたときの処理
    QObject::connect(loginButton, &QPushButton::clicked, [&]() {
        if (usernameEdit->text().isEmpty()) {
            statusLabel->setText("エラー: ユーザー名を入力してください");
            usernameEdit->setFocus(); // ユーザー名フィールドにフォーカスを戻す
        } else if (passwordEdit->text().isEmpty()) {
            statusLabel->setText("エラー: パスワードを入力してください");
            passwordEdit->setFocus(); // パスワードフィールドにフォーカスを戻す
        } else {
            statusLabel->setText("ログイン処理中...");
            // 実際にはここで認証処理を行う
        }
    });

    usernameEdit->setFocus(); // 起動時はユーザー名フィールドにフォーカス

    window->show();

    return app.exec();
}

解説
この例では、ログインボタンがクリックされた際に、入力が空のフィールドがあればそのフィールドにフォーカスを戻し、ユーザーに修正を促します。

遅延してフォーカスを設定する (QTimer::singleShot)

ウィジェットが完全に表示され、イベントループが開始された後にフォーカスを設定したい場合、または複雑な初期化処理の後にフォーカスを設定したい場合に便利です。

#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QVBoxLayout>
#include <QTimer> // QTimer を使うために必要

class MyWindow : public QWidget
{
    Q_OBJECT // シグナル/スロットを使用する場合に必要

public:
    MyWindow(QWidget *parent = nullptr) : QWidget(parent)
    {
        setWindowTitle("Delayed Focus Example");

        lineEdit1 = new QLineEdit();
        lineEdit1->setPlaceholderText("最初のフィールド");

        lineEdit2 = new QLineEdit();
        lineEdit2->setPlaceholderText("ここにフォーカスを設定");

        QVBoxLayout *layout = new QVBoxLayout();
        layout->addWidget(lineEdit1);
        layout->addWidget(lineEdit2);
        setLayout(layout);

        // ウィジェットが完全に構築され、イベントループが開始された直後に
        // lineEdit2 にフォーカスを設定するための遅延実行
        // 0ミリ秒の遅延は「現在のイベント処理が完了したらすぐに」を意味します
        QTimer::singleShot(0, this, &MyWindow::setInitialFocus);
    }

private slots:
    void setInitialFocus()
    {
        lineEdit2->setFocus(); // lineEdit2 にフォーカスを設定
        // または lineEdit2->setEditFocus();
    }

private:
    QLineEdit *lineEdit1;
    QLineEdit *lineEdit2;
};

#include "main.moc" // Q_OBJECT を使用する場合に必要 (mocが生成)

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MyWindow window;
    window.show();

    return app.exec();
}

解説
QTimer::singleShot(0, this, &MyWindow::setInitialFocus); の行が重要です。これは、現在のイベントキューにあるすべてのイベント(ウィンドウの表示など)が処理された後、すぐに setInitialFocus() スロットを実行するようにスケジュールします。これにより、ウィジェットが完全に「描画可能な」状態になってからフォーカスが設定されるため、より確実に動作します。

setFocusPolicy() の使用例

ウィジェットがどのようにフォーカスを受け入れるかを制御します。

#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget *window = new QWidget();
    window->setWindowTitle("Focus Policy Example");

    QLineEdit *lineEditNormal = new QLineEdit();
    lineEditNormal->setPlaceholderText("通常フォーカス (デフォルト)");
    // デフォルトは Qt::StrongFocus や Qt::WheelFocus のため、明示的な設定は不要な場合が多い

    QLineEdit *lineEditNoFocus = new QLineEdit();
    lineEditNoFocus->setPlaceholderText("フォーカスなし");
    lineEditNoFocus->setFocusPolicy(Qt::NoFocus); // このウィジェットはフォーカスを受け入れない

    QLineEdit *lineEditClickFocus = new QLineEdit();
    lineEditClickFocus->setPlaceholderText("クリックのみでフォーカス");
    lineEditClickFocus->setFocusPolicy(Qt::ClickFocus); // クリックでのみフォーカスを受け入れる

    QPushButton *button = new QPushButton("ボタン");
    // QPushButton は通常、Qt::TabFocus を持っています(Tabキーでフォーカス可能)

    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(lineEditNormal);
    layout->addWidget(lineEditNoFocus);
    layout->addWidget(lineEditClickFocus);
    layout->addWidget(button);
    window->setLayout(layout);

    window->show();

    return app.exec();
}

解説
この例では、lineEditNoFocus にはフォーカスが設定されません(Tabキーを押してもスキップされます)。lineEditClickFocus はTabキーではフォーカスされず、マウスでクリックしたときにのみフォーカスされます。これは、特定のウィジェットのフォーカス動作を細かく制御したい場合に役立ちます。

これらの例は、Qtで setFocus() (または setEditFocus()) をどのように使用するか、そして関連する QTimer::singleShotsetFocusPolicy() といった便利な機能と組み合わせてどのように応用できるかを示しています。 QtプログラミングにおけるQWidget::setEditFocus()(または推奨されるQWidget::setFocus())の具体的な使用例をいくつか紹介します。

アプリケーション起動時に特定の入力フィールドにフォーカスを設定する

これは最も一般的な使用例です。ユーザーがアプリケーションを起動した際に、すぐにテキスト入力を開始できるようにします。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLineEdit> // QLineEditを使用するために必要
#include <QPushButton> // QPushButtonを使用するために必要
#include <QVBoxLayout> // レイアウトのために必要
#include <QWidget> // 中央ウィジェットのために必要

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    QLineEdit *lineEdit1;
    QLineEdit *lineEdit2;
    QPushButton *button;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include <QApplication> // QApplicationを使用するために必要

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // ウィジェットの作成
    lineEdit1 = new QLineEdit("最初の入力", this);
    lineEdit2 = new QLineEdit("二番目の入力", this);
    button = new QPushButton("フォーカスを切り替える", this);

    // レイアウトの設定
    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(lineEdit1);
    layout->addWidget(lineEdit2);
    layout->addWidget(button);

    QWidget *centralWidget = new QWidget(this);
    centralWidget->setLayout(layout);
    setCentralWidget(centralWidget);

    // シグナルとスロットの接続
    connect(button, &QPushButton::clicked, this, [this]() {
        // ボタンがクリックされたら、lineEdit2にフォーカスを移す
        lineEdit2->setFocus();
        // Qt 5.15以前では setEditFocus() でも同じ動作をする
        // lineEdit2->setEditFocus();
        qDebug() << "Current focus widget after button click:" << QApplication::focusWidget()->objectName();
    });

    // アプリケーション起動時に lineEdit1 にフォーカスを設定
    // 注意: ウィジェットが完全に表示されてからフォーカスを設定する必要がある
    // 最も確実な方法は、QTimer::singleShot(0, ...) を使うことです。
    QTimer::singleShot(0, this, [this]() {
        lineEdit1->setFocus();
        // Qt 5.15以前では setEditFocus() でも同じ動作をする
        // lineEdit1->setEditFocus();
        qDebug() << "Initial focus widget:" << QApplication::focusWidget()->objectName();
    });

    // ウィジェットの名前を設定(デバッグ出力用)
    lineEdit1->setObjectName("LineEdit1");
    lineEdit2->setObjectName("LineEdit2");
    button->setObjectName("Button");

    setWindowTitle("Focus Example");
}

MainWindow::~MainWindow()
{
}

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show(); // ウィンドウを表示

    return a.exec();
}

解説

  • setFocus() vs setEditFocus()
    コメントにもありますが、Qt 5.15以降ではsetEditFocus()は非推奨であり、setFocus()を使用することが推奨されます。通常の編集可能なウィジェットであれば、setFocus()で同様の動作が得られます。
  • ボタンクリック時のフォーカス切り替え
    QPushButtonclicked()シグナルにラムダ式を接続し、ボタンがクリックされたときにlineEdit2->setFocus()を呼び出してフォーカスを切り替えています。
  • QTimer::singleShot(0, ...) の利用
    MainWindowのコンストラクタ内で直接lineEdit1->setFocus()を呼び出すと、ウィンドウが表示される前にフォーカスが設定され、うまく機能しない場合があります。QTimer::singleShot(0, ...)を使用すると、現在のイベントループが完了した直後(つまり、ウィンドウが完全に表示され、イベント処理が可能になった後)に指定されたスロットが実行されます。これにより、確実に対象のウィジェットにフォーカスが設定されます。

特定の条件に基づいてフォーカスを移動する

例えば、入力が完了した後に自動的に次のフィールドにフォーカスを移したい場合などに役立ちます。

mainwindow.h (変更なし)

mainwindow.cpp (一部変更)

#include "mainwindow.h"
#include <QApplication>
#include <QDebug> // qDebug() を使用するために必要

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    lineEdit1 = new QLineEdit("ユーザー名", this);
    lineEdit2 = new QLineEdit("パスワード", this);
    button = new QPushButton("ログイン", this);

    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(new QLabel("ユーザー名:", this)); // ラベルを追加
    layout->addWidget(lineEdit1);
    layout->addWidget(new QLabel("パスワード:", this)); // ラベルを追加
    layout->addWidget(lineEdit2);
    layout->addWidget(button);

    QWidget *centralWidget = new QWidget(this);
    centralWidget->setLayout(layout);
    setCentralWidget(centralWidget);

    // lineEdit1 で Enter が押されたら lineEdit2 にフォーカスを移す
    connect(lineEdit1, &QLineEdit::returnPressed, this, [this]() {
        lineEdit2->setFocus();
        qDebug() << "Focus moved to lineEdit2 after Enter in lineEdit1.";
    });

    // lineEdit2 で Enter が押されたらボタンにフォーカスを移す(またはクリックをシミュレート)
    connect(lineEdit2, &QLineEdit::returnPressed, this, [this]() {
        button->setFocus();
        qDebug() << "Focus moved to button after Enter in lineEdit2.";
        // button->click(); // Enterでボタンクリックをシミュレートすることも可能
    });

    // アプリケーション起動時に lineEdit1 にフォーカスを設定
    QTimer::singleShot(0, this, [this]() {
        lineEdit1->setFocus();
        qDebug() << "Initial focus widget:" << QApplication::focusWidget()->objectName();
    });

    // ウィジェットの名前を設定(デバッグ出力用)
    lineEdit1->setObjectName("UserNameLineEdit");
    lineEdit2->setObjectName("PasswordLineEdit");
    button->setObjectName("LoginButton");

    setWindowTitle("Conditional Focus Example");
}

MainWindow::~MainWindow()
{
}

解説

  • QDebug を使って、現在フォーカスを持っているウィジェットの名前を出力し、フォーカスが意図通りに移動しているかを確認できます。
  • QLineEdit::returnPressed() シグナルを利用して、ユーザーがEnterキーを押したときにフォーカスを次の入力フィールドに移動させています。これは、フォーム入力などで非常に便利な機能です。

無効なウィジェットにフォーカスを設定しようとしても、通常は無視されます。

mainwindow.h (変更なし)

mainwindow.cpp (一部変更)

#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QLabel> // QLabel を使用するために必要

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    lineEdit1 = new QLineEdit("有効な入力フィールド", this);
    lineEdit2 = new QLineEdit("無効な入力フィールド", this);
    button = new QPushButton("フォーカスを試す", this);

    lineEdit2->setEnabled(false); // lineEdit2 を無効にする

    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(lineEdit1);
    layout->addWidget(lineEdit2);
    layout->addWidget(button);

    QWidget *centralWidget = new QWidget(this);
    centralWidget->setLayout(layout);
    setCentralWidget(centralWidget);

    connect(button, &QPushButton::clicked, this, [this]() {
        qDebug() << "Attempting to set focus to lineEdit2 (disabled)...";
        lineEdit2->setFocus(); // 無効なウィジェットにフォーカスを設定しようとする
        qDebug() << "Current focus widget after attempt:" << QApplication::focusWidget()->objectName();

        // 別のウィジェットにフォーカスを移すために、lineEdit1を有効化してフォーカスを設定
        // lineEdit2->setEnabled(true);
        // lineEdit2->setFocus();
        // qDebug() << "Focus moved to lineEdit2 (enabled) after button click:" << QApplication::focusWidget()->objectName();
    });

    QTimer::singleShot(0, this, [this]() {
        lineEdit1->setFocus();
        qDebug() << "Initial focus widget:" << QApplication::focusWidget()->objectName();
    });

    lineEdit1->setObjectName("EnabledLineEdit");
    lineEdit2->setObjectName("DisabledLineEdit");
    button->setObjectName("TryFocusButton");

    setWindowTitle("Disabled Focus Example");
}

MainWindow::~MainWindow()
{
}
  • コメントアウトされた部分のように、ウィジェットを有効化してからsetFocus()を呼び出すことで、無効なウィジェットにフォーカスを設定できます。
  • ボタンをクリックして無効なlineEdit2setFocus()を呼び出しても、フォーカスは移動しません。デバッグ出力を見ると、依然としてEnabledLineEditにフォーカスがあることがわかります。
  • lineEdit2->setEnabled(false); とすることで、lineEdit2は無効化されます。


タブ順序の利用 (setTabOrder())

最も一般的で、プログラムによる明示的なフォーカス設定を減らすための強力な方法です。

  • 使用例
    // コンストラクタ内やUI構築後
    QLineEdit *lineEdit1 = new QLineEdit(this);
    QLineEdit *lineEdit2 = new QLineEdit(this);
    QPushButton *button = new QPushButton(this);
    
    // lineEdit1 -> lineEdit2 -> button の順にタブ移動するように設定
    setTabOrder(lineEdit1, lineEdit2);
    setTabOrder(lineEdit2, button);
    
  • 欠点
    • 非常に複雑なUIで、特定の条件に基づいて動的にフォーカスを移動させたい場合には不向き。
    • ユーザーがTabキーを使用しない限り、自動的にフォーカスは移動しない。
  • 利点
    • ユーザーがTabキーで直感的に操作できる。
    • コードがシンプルになりやすい。
    • 多くのフォームベースのアプリケーションに適している。

フォーカスイン/アウトイベントのハンドリング

ユーザーがウィジェットにフォーカスしたり、ウィジェットからフォーカスを失ったりしたときに、カスタムロジックを実行したい場合に使用します。

  • 使用例
    // MyLineEdit.h
    class MyLineEdit : public QLineEdit
    {
        Q_OBJECT
    public:
        MyLineEdit(QWidget *parent = nullptr) : QLineEdit(parent) {}
    
    protected:
        void focusInEvent(QFocusEvent *event) override {
            qDebug() << "MyLineEdit gained focus!";
            // 基底クラスのイベントハンドラを呼び出す
            QLineEdit::focusInEvent(event);
        }
    
        void focusOutEvent(QFocusEvent *event) override {
            qDebug() << "MyLineEdit lost focus!";
            QLineEdit::focusOutEvent(event);
        }
    };
    
    // mainwindow.cpp で MyLineEdit を使用
    // ...
    // MyLineEdit *myLineEdit = new MyLineEdit(this);
    // ...
    
  • 欠点
    • フォーカスを設定するための直接的な方法ではない。
    • コードが複雑になりやすい。
  • 利点
    • フォーカスの変化に応じて、ウィジェットの状態を変更したり、関連するUI要素を更新したりできる。
    • デバッグやユーザー行動の追跡に役立つ。

イベントフィルターの利用

  • 使用例
    // MainWindow.h に QObject を継承するクラスを追加(イベントフィルター用)
    class FocusEventFilter : public QObject
    {
        Q_OBJECT
    public:
        explicit FocusEventFilter(QObject *parent = nullptr) : QObject(parent) {}
    
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override {
            if (event->type() == QEvent::FocusIn) {
                qDebug() << "FocusIn event detected for:" << obj->objectName();
            } else if (event->type() == QEvent::FocusOut) {
                qDebug() << "FocusOut event detected for:" << obj->objectName();
            }
            return QObject::eventFilter(obj, event); // イベントを通常の処理に渡す
        }
    };
    
    // mainwindow.cpp のコンストラクタ内
    // ...
    FocusEventFilter *filter = new FocusEventFilter(this);
    lineEdit1->installEventFilter(filter);
    lineEdit2->installEventFilter(filter);
    // ...
    
  • 欠点
    • イベント処理のロジックが分散する可能性がある。
    • setEditFocus()(またはsetFocus())のような直接的なフォーカス設定とは目的が異なる。
  • 利点
    • 既存のウィジェットをサブクラス化せずに、フォーカスイベントを制御できる。
    • 複数のウィジェットに対して一元的にイベント処理を適用できる。

シグナルとスロットによる連携

あるウィジェットの操作が完了したときに、別のウィジェットにフォーカスを移す場合に最もよく使われる方法です。setFocus()と組み合わせることで強力な連携が可能です。

  • 使用例
    これは前述のsetEditFocus()の例で既に示されていますが、改めて強調します。
    // lineEdit1 で Enter が押されたら lineEdit2 にフォーカスを移す
    connect(lineEdit1, &QLineEdit::returnPressed, lineEdit2, &QLineEdit::setFocus);
    
    // ボタンがクリックされたら lineEdit1 にフォーカスを移す
    connect(button, &QPushButton::clicked, lineEdit1, &QLineEdit::setFocus);
    
  • 欠点
    • ユーザーの特定の操作に依存するため、完全に自動的なフォーカス移動ではない。
  • 利点
    • ユーザー操作に応じた自然なフォーカス移動を実現できる。
    • コードの可読性が高く、イベント駆動型プログラミングの原則に則っている。
  • フォーカスの入出時のカスタム処理
    focusInEvent()/focusOutEvent()のオーバーライド、またはイベントフィルターを使用します。
  • ユーザー操作に応じた動的なフォーカス移動
    シグナルとスロットの組み合わせ(例:QLineEdit::returnPressed()setFocus()を接続)が最適です。
  • 最も推奨される一般的なケース
    QWidget::setFocus()を使い、必要に応じてQTimer::singleShot(0, ...)でタイミングを調整します。フォームのナビゲーションにはsetTabOrder()も活用します。