本文へスキップします。

本文へ

【全Qt】
【全・Qt】SRAロゴ
H1

一問一答

Q&A:検索

カテゴリー

Q&A:表示

Qt

コア

ウィジェット

QML/Qt Quick

Qt for Python

モデルビュー

QFileSystemModel を QTreeView に設定して使っています。ツリービューが表示されたときにツリーが展開され、各列幅が表示内容に合わされた状態にするにはどのようにすればよいでしょうか。

ツリーを展開するには QTreeView::expandToDepth() を使い、各列幅を表示内容に合わせて広げるには QTreeView::resizeColumnToContents() を使います。 これらの関数はツリービューに設定するモデルにデータがロードされた後に呼び出す必要があります。QFileSystemModel のデータのロード完了を通知するシグナル QFileSystemModel::directoryLoaded を利用してこれらの関数を呼び出せば、ツリービューを展開して、項目を列幅に合わせて表示できます。


main.cpp:
#include <QApplication>
#include <QTreeView>
#include <QFileSystemModel>

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

    QTreeView tree;
    tree.resize(800, 600);

    QFileSystemModel model;

    QObject::connect(&model, &QFileSystemModel::directoryLoaded, [&]() {
        tree.expandToDepth(1);
        for (int column = 0; column < tree.model()->columnCount(); ++column) {
            tree.resizeColumnToContents(column);
        }
    });

    tree.setModel(&model);
    tree.show();

    model.setRootPath(QDir::homePath());

    return app.exec();
}

サンプルコード

treeviewdecoration.zip
QTreeView に QFileSystemModel を設定して使っています。空のディレクトリーで枝分かれの +/- 表示をしないようにするにはどのようにすればよいでしょうか。

hasChildren()を再実装できますが、QFileSystemModelは非同期で内容を読み込みます。未読込のディレクトリーと、読込済みで子項目がないディレクトリーを区別してください。未読込時のrowCount()==0だけで空と判断すると、展開できなくなることがあります。

以下はQt 6 / Qt Widgets用のmain.cpp全体です。directoryLoadedを受けたパスだけ、モデルのrowCount()で判定します。

#include <QApplication>
#include <QTreeView>
#include <QFileSystemModel>
#include <QDir>
#include <QSet>

class FileSystemModel : public QFileSystemModel
{
public:
    explicit FileSystemModel(QObject *parent = nullptr) : QFileSystemModel(parent)
    {
        connect(this, &QFileSystemModel::directoryLoaded, this,
                [this](const QString &path) {
            loaded.insert(path);
            const QModelIndex item = index(path);
            if (item.isValid())
                emit dataChanged(item, item);
        });
    }
    bool hasChildren(const QModelIndex &parent = QModelIndex()) const override
    {
        if (!parent.isValid())
            return QFileSystemModel::hasChildren(parent);
        if (parent.column() != 0 || !isDir(parent))
            return false;
        if (!loaded.contains(filePath(parent)))
            return QFileSystemModel::hasChildren(parent);
        return rowCount(parent) > 0;
    }
private:
    QSet<QString> loaded;
};

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    FileSystemModel model;
    model.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
    QTreeView tree;
    tree.setModel(&model);
    tree.setRootIndex(model.setRootPath(QDir::homePath()));
    tree.resize(800, 500);
    tree.show();
    return app.exec();
}

確認方法と制約

空のフォルダーとファイル入りのフォルダーを用意し、それぞれ一度展開して読み込みを完了させます。空の方では展開記号が消え、内容がある方では残ることを確認します。未読込のフォルダーでは記号が一時的に表示されます。「空」はモデルに表示される子項目がないことを意味します。

hasChildren()内でQDirを使って同期的に全内容を走査する方法は、ネットワークドライブや大量のファイルでGUIを止めるおそれがあります。初回表示前から空を判定する必要がある場合は、対象範囲を限定して非同期に先読みし、結果をキャッシュする設計が必要です。

この例は起動中にrootPathやフィルターを切り替えない小さな例です。実アプリでは、モデルのリセット、ディレクトリーの名前変更、監視結果の反映に応じてキャッシュを無効化します。権限不足や読込エラーを空フォルダーと断定しないでください。

参考資料

従来の同期走査を使う参考サンプル: treeviewemptydirectory.zip(上の例とは実装が異なります)。

ビューに表示される数値を編集可能にしたとき、スピンボックスに表示される数値を右寄せにするにはどのようにすればよいでしょうか。

QSpinBoxやQDoubleSpinBoxには、共通基底クラスQAbstractSpinBoxのsetAlignment()があります。内部のQLineEditを非公開のオブジェクト名で検索する必要はありません。

以下はQt 6 / Qt Widgets用のmain.cpp全体です。デリゲートが作ったエディターがスピンボックスの場合だけ右寄せにします。

#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QAbstractSpinBox>

class RightAlignedDelegate : public QStyledItemDelegate
{
public:
    using QStyledItemDelegate::QStyledItemDelegate;
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                          const QModelIndex &index) const override
    {
        QWidget *editor = QStyledItemDelegate::createEditor(parent, option, index);
        if (auto *spin = qobject_cast<QAbstractSpinBox *>(editor))
            spin->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
        return editor;
    }
};

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QStandardItemModel model(3, 1);
    for (int row = 0; row < 3; ++row) {
        const QModelIndex index = model.index(row, 0);
        model.setData(index, (row + 1) * 100, Qt::EditRole);
        model.setData(index, int(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
    }
    QTableView view;
    view.setModel(&model);
    view.setItemDelegate(new RightAlignedDelegate(&view));
    view.show();
    return app.exec();
}

コードの説明と確認

セルをダブルクリックして編集し、数値が右寄せになることを確認します。モデルには文字列ではなくint値を設定しているため、標準デリゲートが数値エディターを作成します。

編集していないセルの配置はQt::TextAlignmentRole、編集中の配置はエディターのsetAlignment()で指定します。独自デリゲートが別のエディターを返す場合は、その部品のAPIを使ってください。特定列だけに適用する場合はcreateEditor()内でindex.column()を確認します。

参考資料

画像

画像を青や赤などに色付けするにはどのようにすればよいでしょうか。

公開APIの QGraphicsColorizeEffect を使うと、画像の明暗を生かして指定色を付けられます。プライベートヘッダーや widgets-private は不要です。すべての不透明画素を単一色へ置換する処理とは異なります。

以下はQt 6 Widgets用の main.cpp 全体です。C++17以上でQt Widgetsをリンクしてください。実行例は colorize input.png red output.png です。色は "#ff0000" の形式でも指定できます。

#include <QApplication>
#include <QColor>
#include <QDebug>
#include <QGraphicsColorizeEffect>
#include <QGraphicsPixmapItem>
#include <QGraphicsScene>
#include <QImage>
#include <QPainter>
#include <QPixmap>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    const auto args = app.arguments();
    if (args.size() != 4) {
        qWarning() << "Usage: colorize input.png red output.png";
        return 1;
    }
    QPixmap source(args[1]);
    const QColor color(args[2]);
    if (source.isNull() || !color.isValid()) {
        qWarning() << "Invalid image or color";
        return 2;
    }
    source.setDevicePixelRatio(1.0);
    QGraphicsScene scene;
    auto *item = scene.addPixmap(source);
    auto *effect = new QGraphicsColorizeEffect;
    effect->setColor(color);
    effect->setStrength(1.0);
    item->setGraphicsEffect(effect);

    QImage result(source.size(), QImage::Format_ARGB32_Premultiplied);
    result.fill(Qt::transparent);
    QPainter painter(&result);
    scene.render(&painter, QRectF(result.rect()), item->boundingRect());
    painter.end();
    if (!result.save(args[3])) {
        qWarning() << "Cannot save" << args[3];
        return 3;
    }
    return 0;
}

コードの説明

  1. 画像と色を検証し、読み込めない場合は終了コード2で終了します。
  2. 画像をシーンに置き、色付け効果を設定します。強度は0.0が効果なし、1.0が最大です。効果はアイテムが所有します。
  3. デバイスピクセル比を1にそろえ、元画像と同じ画素数の透過画像へ描画します。画面への表示やスクリーンショットは不要です。
  4. 保存結果を確認し、失敗時は終了コード3を返します。出力先には書き込み可能な別ファイルを指定してください。

確認時は、入力と出力の画素数、透明部分、明暗が保たれた色付けを比較してください。入力のDPIメタデータなどをすべて引き継ぐ例ではありません。

旧版の colorize.zip はプライベートAPIを使う参考資料です。このページの公開API版とは実装が異なります。

参考資料

アイコン画像ファイルから無効化画像を作成する方法はありますか。

Qt でアイコン画像ファイルから無効化 (グレーアウト) 画像を作成するには、QPixmap と QIcon クラスを利用する方法があります。まず、アイコン画像ファイルを QPixmap に読み込み、その後、QIcon の機能を使用して、このピクスマップの無効化ピックスマップを生成します。

画像を読み込み、元の画像と無効化画像を並べて表示する例です。

main.cpp:

#include <QApplication>
#include <QWidget>
#include <QHBoxLayout>
#include <QLabel>
#include <QPixmap>
#include <QIcon>
#include <QDebug>

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

    if (app.arguments().count() != 2) {
        qWarning() << "Usage: disabledicon file.";
        return -1;
    }

    // The orignal image file
    const QString iconFileName = app.arguments()[1];

    QWidget window;
    const auto topLayout = new QHBoxLayout(&window);

    // Load the original pixmap
    const QPixmap originalPixmap(iconFileName);
    if (originalPixmap.isNull()) {
        qWarning() << "Bad image file";
        return -1;
    }

    // Create a QIcon from the pixmap
    const QIcon icon(originalPixmap);

    // Generate the disabled pixmap
    const QSize pixmapSize = originalPixmap.size();
    const QPixmap disabledPixmap = icon.pixmap(pixmapSize, QIcon::Disabled);

    // Display both pixmaps
    const auto originalLabel = new QLabel;
    originalLabel->setPixmap(originalPixmap);
    topLayout->addWidget(originalLabel);

    const auto disabledLabel = new QLabel;
    disabledLabel->setPixmap(disabledPixmap);
    topLayout->addWidget(disabledLabel);

    window.show();

    return app.exec();
}

コードの説明

アイコン画像ファイルを QPixmap に読み込みます。ファイルパスが正しいこと、そして画像ファイルにアクセスできることを確認してください。


次に、QPixmap から QIcon オブジェクトを作成します。QIcon クラスは、無効状態を含む様々なモードと状態で、元の画像を変換して描画できます。


アイコンに無効状態で描画されたピクスマップを要求できます。このとき必要なピクスマップのサイズを指定しなければなりません。通常は、元のピクスマップのサイズを使用しますが、必要に応じて異なるサイズを指定することもできます。


この disabledPixmap は、元の画像をグレーアウトしたものとなり、QLabel やカスタムウィジェットの一部としてなど、QPixmap が受け入れられる場所であればどこでも使用できます。


この例では、QWidget と水平レイアウト (QHBoxLayout) を使用して、QLabel ウィジェットを使い、元の画像のピクスマップと無効化画像を並べて表示しています。

参考資料

QIcon Class

ネットワーク

QLocalServer に置き換えるとアドレスが重複してしまいます。どのようにすれば重複を避けられるでしょうか。

QLocalServer はアドレス解放を必ずするとは限りません。アドレスの重複を避けるには以下のようにして QLocalServer::listen() を再呼び出しをします。


main.cpp:
if (!listen(SERVER_NAME)) {
    if (serverError() == QAbstractSocket::AddressInUseError) {
        removeServer(SERVER_NAME);
        if (!listen(SERVER_NAME)) {
            qDebug() << errorString();
        }
    }
}

参考資料

QLocalServer Class

Qt Creator

Windows

Windows のコンソールにデバッグメッセージを表示するにはどのようにすればよいですか。

Qt Creator などの IDE を使うとデバッグメッセージが IDE のアプリケーション出力領域に表示されます。しかし、コンソールから実行すると、コンソールにデバッグメッセージが表示されません。デバッグメッセージをコンソールに表示するには、コンソールアプリケーションとしてビルドする必要があります。

qmake でビルドする場合

qmake の CONFIG 変数に cmdline を追加すれば、Windows でコンソールにデバッグメッセージを表示できます。

CONFIG += cmdline

CMake でビルドする場合

CMakeLists.txt で WIN32_EXECUTABLE を FALSE に設定するとコンソールアプリケーションとしてビルドされコンソールにデバッグメッセージを表示できます。

set_target_properties(YourAppName PROPERTIES
    WIN32_EXECUTABLE FALSE
    MACOSX_BUNDLE TRUE
)

コンソールアプリケーションとしてビルドしない方法

Qt 6.5 で追加された QT_WIN_DEBUG_CONSOLE 環境変数を使う方法です。GUI アプリケーションのままで、環境変数設定だけで、コンソール出力できます。new に設定するとコンソールを別に開きそこにデバッグ出力し、attach に設定すると起動したコンソールにデバッグメッセージをします。コンソールアプリケーションにビルとしなおさなくてよいので便利です。

参考資料

Debugging Techniques

Linux

macOS

Qt の macOS 版で Apple Silicon (M シリーズ) に対応しているバージョンを教えてください。

はい。Qt 6.2からApple Silicon(arm64)の正式サポートが導入されました。新規開発では、現在保守されているQt 6系列のうち、使用するmacOSとXcodeがサポート対象となる版を選んでください。「6.2以降なら、どのOS・Xcodeでもよい」という意味ではありません。

ネイティブ動作とRosettaの違い

  • arm64ビルド:Apple Silicon上でネイティブ動作します。Qt本体だけでなく、リンクする外部ライブラリもarm64対応が必要です。
  • x86_64ビルド:Apple Silicon上ではRosettaによる実行となります。ネイティブ対応の確認とは分けて扱ってください。
  • Universalビルド:arm64とx86_64を含む実行ファイルです。両方を配布対象にする場合は、Qt・プラグイン・外部ライブラリの対応アーキテクチャも確認します。

作成したアプリの確認には、ターミナルで file MyApp.app/Contents/MacOS/MyApp を実行し、arm64が含まれることを確かめます。実行ファイル名は実際の名前に置き換えてください。配布前には対象macOSで起動と主要機能も確認します。

Qt 5.15を継続する場合

2021年の公式記事では、Qt 5.15.4をApple Silicon向けにソースからビルドする方法と、その時点でのサポート対象外という扱いが説明されています。この歴史的な情報を、すべての5.15パッチ版や現在の契約条件に一般化しないでください。

既存製品では、利用中の正確なQtパッチ版、入手元、対象CPU、保守契約の期間・範囲を確認します。ソースからビルドできることと、ベンダーの正式サポートを受けられることは別です。

参考資料

macOS の Qt Creator で設定やヘルプでキー入力をするときに `^H` を Backspace として 認識させる方法を教えてください。

Qt Creator 20.0.0 のソースツリーに、macOS の Control-H キー入力を Backspace キー入力へ変換するパッチを適用してから Qt Creator をビルドします。

このパッチは、Qt Creator 本体の src/app/main.cpp と src/app/main_mac.mm を変更します。 macOS 側では NSEvent のローカルモニターで Control-H を Backspace 相当のキーイベントに 変換し、Qt 側ではアプリケーション全体のイベントフィルターで QLineEdit などに届く Control-H / Control 付き Backspace / 文字コード 0x08 を Backspace として処理します。

適用例は次のとおりです。

cd <qt-creator-source>
git checkout v20.0.0-beta1
git submodule update --init --recursive
git apply <patch-file>

ここで <patch-file> は、後述のパッチ内容を保存したファイルのパスに置き換えてください。

その後、Qt Creator を通常どおりビルドします。

cmake -S <qt-creator-source> -B <qt-creator-build> \
  -DCMAKE_PREFIX_PATH=<qt-install>/6.11.0/macos \
  -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build <qt-creator-build> --parallel

既存のビルドディレクトリがあり、Qt Creator 本体だけを更新したい場合は、 環境に合わせて Qt Creator のアプリケーションターゲットを再ビルドしてください。

パッチの内容は次のとおりです。

diff --git a/src/app/main.cpp b/src/app/main.cpp
index 9cd2be7f4bb..06d9006083c 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -36,6 +36,7 @@
 #include <QFontDatabase>
 #include <QHBoxLayout>
 #include <QLibraryInfo>
+#include <QLineEdit>
 #include <QMessageBox>
 #include <QCryptographicHash>
 #include <QNetworkProxyFactory>
@@ -564,6 +565,80 @@ FilePath userResourcePath(const QString &settingsPath, const QString &appId)
     return urp;
 }
 
+class ControlHBackspaceFilter : public QObject
+{
+public:
+    explicit ControlHBackspaceFilter(QObject *parentObject = nullptr)
+        : QObject(parentObject)
+    {
+    }
+
+protected:
+    bool eventFilter(QObject *watchedObject, QEvent *event) override
+    {
+        if (event->type() != QEvent::KeyPress && event->type() != QEvent::ShortcutOverride) {
+            return QObject::eventFilter(watchedObject, event);
+        }
+
+        auto *keyEvent = static_cast<QKeyEvent *>(event);
+        const bool hasControl = keyEvent->modifiers() & Qt::ControlModifier;
+        if (hasControl) {
+            qWarning().noquote()
+                << "ControlHBackspaceFilter"
+                << "type=" << int(event->type())
+                << "object=" << watchedObject->metaObject()->className()
+                << "key=" << keyEvent->key()
+                << "modifiers=" << int(keyEvent->modifiers())
+                << "textUcs4=" << [&] {
+                       QStringList values;
+                       for (const QChar c : keyEvent->text())
+                           values << QString::number(c.unicode(), 16);
+                       return values.join(QLatin1Char(','));
+                   }();
+        }
+
+        const bool isControlH =
+            keyEvent->key() == Qt::Key_H &&
+            (keyEvent->modifiers() & Qt::ControlModifier) &&
+            !(keyEvent->modifiers() & Qt::AltModifier) &&
+            !(keyEvent->modifiers() & Qt::MetaModifier);
+        const bool isControlBackspace =
+            keyEvent->key() == Qt::Key_Backspace &&
+            (keyEvent->modifiers() & Qt::ControlModifier) &&
+            !(keyEvent->modifiers() & Qt::AltModifier) &&
+            !(keyEvent->modifiers() & Qt::MetaModifier);
+
+        if (event->type() == QEvent::ShortcutOverride) {
+            if (isControlH || isControlBackspace) {
+                keyEvent->accept();
+                return false;
+            }
+            return QObject::eventFilter(watchedObject, event);
+        }
+
+        const bool isBackspaceControlCharacter =
+            keyEvent->text() == QString(QChar(0x08));
+
+        if (!isControlH && !isControlBackspace && !isBackspaceControlCharacter) {
+            return QObject::eventFilter(watchedObject, event);
+        }
+
+        if (auto lineEdit = qobject_cast<QLineEdit *>(watchedObject)) {
+            lineEdit->backspace();
+            return true;
+        }
+
+        QKeyEvent backspaceEvent(
+            QEvent::KeyPress,
+            Qt::Key_Backspace,
+            Qt::NoModifier
+        );
+
+        QApplication::sendEvent(watchedObject, &backspaceEvent);
+        return true;
+    }
+};
+
 int main(int argc, char **argv)
 {
     Restarter restarter(argc, argv);
@@ -741,6 +816,9 @@ int main(int argc, char **argv)
     QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR));
     QGuiApplication::setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME);
 
+    auto *controlHBackspaceFilter = new ControlHBackspaceFilter(&app);
+    app.installEventFilter(controlHBackspaceFilter);
+
     const QScopeGuard cleanup([] { ProcessReaper::deleteAll(); });
 
     const QStringList pluginArguments = app.arguments();
diff --git a/src/app/main_mac.mm b/src/app/main_mac.mm
index 8e1fa5fe253..9d9fb513d25 100644
--- a/src/app/main_mac.mm
+++ b/src/app/main_mac.mm
@@ -3,6 +3,7 @@
 
 #include <qglobal.h>
 
+#include <AppKit/NSEvent.h>
 #include <Foundation/NSNumberFormatter.h>
 #include <Foundation/NSUserDefaults.h>
 
@@ -14,3 +15,38 @@ static void initializeCreatorDefaults()
     [NSUserDefaults.standardUserDefaults registerDefaults:@{@"ApplePressAndHoldEnabled": @NO}];
 }
 Q_CONSTRUCTOR_FUNCTION(initializeCreatorDefaults);
+
+static bool isControlHEvent(NSEvent *event)
+{
+    const NSEventModifierFlags flags = event.modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask;
+    return event.type == NSEventTypeKeyDown
+           && (flags & NSEventModifierFlagControl)
+           && !(flags & NSEventModifierFlagOption)
+           && !(flags & NSEventModifierFlagCommand)
+           && [[event.charactersIgnoringModifiers lowercaseString] isEqualToString:@"h"];
+}
+
+static NSEvent *backspaceEventFromControlHEvent(NSEvent *event)
+{
+    return [NSEvent keyEventWithType:event.type
+                            location:event.locationInWindow
+                       modifierFlags:0
+                           timestamp:event.timestamp
+                        windowNumber:event.windowNumber
+                             context:nil
+                          characters:@"\b"
+         charactersIgnoringModifiers:@"\b"
+                           isARepeat:event.isARepeat
+                             keyCode:51];
+}
+
+static void initializeControlHBackspaceMonitor()
+{
+    [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
+                                         handler:^NSEvent *(NSEvent *event) {
+        if (isControlHEvent(event))
+            return backspaceEventFromControlHEvent(event);
+        return event;
+    }];
+}
+Q_CONSTRUCTOR_FUNCTION(initializeControlHBackspaceMonitor);

起動後、Qt Creator の設定ダイアログやヘルプの検索欄など、QLineEdit を使っている入力欄で Control-H を押し、カーソル左側の文字が削除されれば反映されています。

参考資料

Qt Creator: ソースからのビルド
Building Qt Creator from Git
Qt Creator source repository
Qt Creator ドキュメント
macOS 用 Qt
macOS で端末から Qt アプリを起動すると端末がアクティブでなくなりキー入力できなくなります。端末でキー入力し続けられるようにするにはどうすればよいですか。

Qt には QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM という環境変数があります。この環境変数を設定すると、Qt アプリを起動したときにアプリをフォアグラウンドアプリケーションへ変換する処理を抑制できます。

macOS 13 では、この環境変数を設定することで端末がアクティブでなくなる問題を解消できます。たとえば、次のようにアプリを起動します。

起動例:
QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM=1 ./MyQtApp

ただし、この方法は macOS のバージョンによって挙動が異なります。macOS 15 では、この環境変数を設定すると Qt アプリが常に非アクティブになり、アプリを操作できなくなってしまいます。

そのため、この環境変数をシェルの初期化ファイルで常に設定することは避けてください。macOS 13 で必要な場合に限り、確認した環境で一時的に設定して起動するのが安全です。

また、この環境変数をプログラム内で qputenv() などを使って設定するのは避けてください。利用者の macOS バージョンによってはアプリを操作できなくなるため、アプリケーション側で一律に設定するべきではありません。

macOS 13 / macOS 15 の違いは外部記事の引用ではなく、確認した環境での挙動です。

参考資料

Qt for macOS - 特定の問題

QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM を参照している Qt のソース

Apple Developer Documentation: LSUIElement

ライセンスモデルに関する FAQ

QtのLGPL版を利用するとソースコードを開示しないといけないのでしょうか。
開発したアプリケーション部分のソースコードを開示する必要はありません。
Qt自身に手を加えるような使い方をした場合に、改変部分のソースコードの開示義務が発生します。
Qtのライブラリにスタティックリンクした場合も改変とみなされ、該当部分が開示対象となります。
その他のLGPLの留意点は以下のページをご覧ください。
LGPL詳細
QtのLGPL版を利用しているのですが、技術的な問合せなどは可能でしょうか。
SRAでは、LGPL版ユーザ様向けのサポートを提供しています。詳細は以下のページをご覧ください。
LGPLサポート詳細

Qtの商用版とLGPL版を併用することは可能でしょうか。

同じプロジェクト/製品の開発で、Qtの商用ライセンスとオープンソースライセンスを自由に混在させることはできません。Qtの公式商用ライセンスFAQも、同じプロジェクト/製品で両者を混在させないよう説明しています。

例えば、同じ製品を共同開発するチームで、一部の開発者だけ商用ライセンスを購入し、残りの開発者がLGPL版を使えばよい、とは判断しないでください。商用ライセンスの対象となる開発者や組織の範囲は、適用される契約の定義・条件を確認する必要があります。

確認すべき事項

  • 開発する製品とプロジェクトの範囲、共通コードや共通ライブラリの利用関係
  • 参加する社内・委託先の開発者と、それぞれのライセンス
  • 利用するQtの版、モジュール、開発ツール、および配布方法
  • 適用する商用契約と、オープンソース部品のライセンス条件

別製品でそれぞれ異なるライセンスを採用したい場合も、「リポジトリーが別なら別プロジェクト」「コードが一部共通なら必ず同一」といった単一の基準では断定できません。構成と利用関係を整理し、Qtの窓口に契約上の扱いを確認してください。

この回答は一般的な判断の入口です。個別製品への適用は、実際の契約・ライセンス本文を優先して確認してください。

参考資料

商用版からLGPL版、またはLGPL版から商用版への移行は可能でしょうか。

移行の方向によって条件が異なります。単にQtのインストール先を切り替えたり、商用ライセンスを後から購入したりするだけで、過去の開発や配布に適用される条件が自動的に置き換わるわけではありません。

オープンソース版から商用版へ

Qtの公式商用ライセンスFAQでは、オープンソース版で開発を始めたコードを商用ライセンスへ移すには、The Qt Companyの書面による同意が必要と説明されています。自動的に移行できると考えず、購入・移行を決定する前に相談してください。

相談時には、開発開始時期、利用したQtの版・モジュール、参加した開発者、既存コードの範囲、配布実績、今後の配布方法を整理すると、対象と条件を確認しやすくなります。商用版への移行によって、過去のオープンソースライセンス上の義務が当然に消えるわけではありません。

商用版からオープンソース版へ

移行先の版と全モジュールについて、利用可能なオープンソースライセンスの条件を満たせるかを確認します。Qtのすべてのモジュール・版がLGPLで提供されるわけではなく、GPLのみのものや商用限定の機能・部品は別に確認が必要です。

利用する部品、リンク方法、改変の有無、配布先に応じて、ライセンス表示、必要なソースコードの提供、ライブラリ差し替え等の要件を検討してください。また、商用契約に基づく既存の義務や権利は、その契約条件に従います。

判断手順:構成と開発・配布履歴を整理し、各部品のライセンスと適用契約を確認したうえで、Qtの窓口と移行条件を合意してください。この回答だけで個別製品の移行可否を確定するものではありません。

参考資料

お問い合わせリンク(FAQ)