LoginSignup
11
4

More than 5 years have passed since last update.

QWidgetの階層構造を可視化するデバッグ支援ツール

Posted at

Qt Advent Calendar 2016 14日目の記事です。

QWidgetの階層構造を可視化するデバッグ支援ツールWidgetBrowserを作りました。

はじめに

大規模なアプリケーションの開発では、画面上に見えているウィジェットがどこで実装されているのかわからないということがしばしばあります。表示されている文字列で検索することもできますが、クラス名が分かればもっと効率よく該当ソースコードを探すことができます。

Qtでは、宣言中にQ_OBJECTマクロを含むクラスであればクラス名を知ることができるので、例えばカーソル下にあるウィジェットのクラス名を調べるということが可能です。

そこで、ウィジェットの階層構造を辿ってクラス名を調べられるツールWidgetBrowserを開発しました。

image

インストール

基本的にアプリケーションに組み込んで使います。

WidgetBrowsergit cloneしてsrc/wbディレクトリをアプリケーション内にコピーし、ビルド対象に含めます。

起動するにはwb::WbDialog::exec()を呼ぶだけでOKです。WbDialogクラスが自動的にQApplicationオブジェクトから情報を集めて表示します。

example
#include <wb/dialog.h>

wb::WbDialog dialog;
dialog.exec();

また、イベントフィルター WbOpenListenerQApplicationにインストールすることでショートカットキーで起動できます。

example
#include <QApplication>
#include <QKeySequence>
#include <wb/listener.h>

WbOpenListener listener;
listener.setKeySequenceToOpen(QKeySequence("Meta+F2"));
qApp->installEventfilter(&listener);

アプリケーションのソースコードを変更できない場合、WidgetBrowserを組み込んだQtのDLLを
ビルドして差し替えるという方法が使えます(対象がLGPL版Qtを使っていれば)。

使い方

起動すると、その時点のウィジェットの階層構造がキャプチャーされ、左側のツリーに表示されます。

トップレベルの要素は以下の5つです。

  • Active Modal Widget
    アクティブなモーダルウィジェット(QApplication::activeModalWidget()の値)
  • Active Popup Widget アクティブなポップアップウィジェット(QApplication::activePopupWidget()の値)
  • Focus Widget フォーカスを持つウィジェット(QApplication::focusWidget()の値)
  • Widget at Cursor カーソル下のウィジェット(QApplication::widgetAt(QCursor::pos())の値)
  • Top Level Widgets トップレベルウィジェット(QApplication::topLevelWidgets()の値)

これらは起動した瞬間の値であり、更新されません。

image

ツリー上でウィジェットを選択すると右側にウィジェットのスクリーンショットが表示されます。

ツリー上ではコンテキストメニューからウィジェットのクラス名をコピーできます。
スクリーンショット上では画像を保存できます。

ダイアログを閉じるとアプリケーションに処理を返します。

作り方

ツリービューは、ウィジェットの階層構造を表すアイテムモデルを作成して使っています。

スクリーンショットは、QWidget::renderを呼ぶことで画像を取得しているため副作用があります。また、一度もshow()されていないウィジェットは正しくない画像になることがあります。

QWidget* widget;
QLabel* label;

const QRect rectangle(QPoint(), widget->size());
QPixmap pixmap(rectangle.size());
widget->render(&pixmap, QPoint(), QRegion(rectangle));

label->setPixmap(pixmap);

クラス名をコピーする機能は以下のように実装しています。
cpp
void copyClassName(QWidget* widget) {
QApplication::clipboard()->setText(widget->metaObject()->className());
}

欲しい機能

週末にハッカソンで作ったツールなので現時点での機能は少ないです。

QtDesignerのプロパティエディタ的な機能を付けたい。

image

まとめ

大きなプロジェクトでは検索のキーワードとしてクラス名を知りたいことがあるのでツールを作りました(おまけでスクリーンショットも付けてみました)。

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4