Qt 勉強会 @ Tokyo #63 参加報告 | Qt Widgetsでのタブページの実装に挑戦

概要

イベント情報
項目 内容
イベント名 Qt 勉強会 @ Tokyo #63
URL https://qt-users.connpass.com/event/101062/
ハッシュタグ #qtjp
主催者 日本Qtユーザー会
開催地 東京都新宿区新宿1-23-1 新宿マルネビル9F
開催日時 2018-09-15 13:00~18:00
参加人数 6
SNS

今回の勉強会は名古屋と同じ開催日だった。また,いつもは10人くらいの参加者だったが,今回は6人とこじんまりとした集まりになった。

作業

前回前々回の勉強会でQt Quickでのタブページの実装に挑戦し,Qt Quickだと実装が困難なことがわかった。

そこで,今回からはQt Widgetsでのタブページの実装に挑戦した。具体的には,以下のページを参考に,QTabWidgetsの使い方を調べ,今回行き詰まった[タブの追加]ボタンの実装した。

その他,当日Atsuhi4さんに相談したところ,サンプルコードを教えてもらった。自分の実装と違う方法なので,参考になった。

Atsushi4/qt_users_tabwidget

成果

当日Qt 5.11で作成したQt Widgetsでのタブページの実装動作例は以下のとおりとなった。

タブページのデモ

ソースコード一式を「QtExample/TabPage at b7f30aecc9b20fa71d144cd74db1f86e20e0d4d7 · senooken/QtExample」に格納している。長くないので,全文を以下にも掲載する。

Qt Widgetsでのタブページの実装コード
///////////////////////////////////////////////////////////////////////////////
/// \file main.cpp
/// \author SENOO, Ken
///////////////////////////////////////////////////////////////////////////////

#include <QApplication>
#include <QLabel>
#include <QTabBar>
#include <QTabWidget>
#include <QTextEdit>
#include <QToolButton>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    // 1. Create QTabWidget instance.
    QTabWidget widget;
    // 2. Create page widget instance.
    QTextEdit editor1{"EDITOR1", &widget};
    QTextEdit editor2{"EDITOR2", &widget};
    // 3. Insert page widget into tab widget by addTab() or insertTab().
    widget.insertTab(0, &editor1, "TAB1");
    widget.addTab(&editor2, "TAB2");
    // Enable close and drag.c
    widget.setTabsClosable(true);
    widget.setMovable(true);
    // Handle tab close.
    widget.connect(&widget, &QTabWidget::tabCloseRequested, 
        [&](int index) {widget.removeTab(index);}
    );

    // Add new tab button.
    QToolButton tb;
    tb.setText("+");
    tb.setAutoRaise(true);
    tb.connect(&tb, &QToolButton::clicked,
        [&]() {widget.insertTab(widget.count()-1, new QTextEdit(), "New Tab");}
    );
    widget.addTab(new QLabel("You can add tabs by pressing +"), QString());
    widget.setTabEnabled(widget.count()-1, false);
    widget.tabBar()->setTabButton(widget.count()-1, QTabBar::RightSide, &tb);

    widget.show();

    return app.exec();
}

QTabWidgetには,tabsClosableとmovableのプロパティがあり,これらを有効にすることで,Qt Quickでは自分で実装が必要だったタブのクローズと,ドラッグを実装できる。タブのクローズは,SetTabsClosable()で有効にするだけでは不十分で,このシグナルを捕捉して,removeTab()で削除する。

どちらにしても,たった数行のコードでQt Quickで1か月かけても実装しきれなかった,タブのクローズとドラッグを実装できた。いったい自分は何をやっていたんだと拍子抜けしてしまった。

しかし,QTabWidgetにも課題はあった。それは,タブ追加ボタンの実装だ。

今回の実装では,StackOverFlowでの回答を参考にして,ダミーのタブを用意し,それをQToolButtonに差し替えて実装している。これにより,タブバーと同じように配置がされる。ただし,タブバーと同じように扱われるため,ドラッグで移動できてしまう (デモ動画の最後参照)。

Atsushi4さんの実装では,setCornerWidget()でタブの角にQPushButtonを配置して実装している。この実装だと,ドラッグの対象にはならないが,代わりに常に端にボタンが配置されるため,画面を最大化したときに,現在のタブとタブの追加ボタンの位置が大きく離れてしまう

解決方法はいくつか考えれる。今のところ以下の3点を考えている。

タブ追加ボタンの実装方法
  1. Chromium系のWebブラウザーでは,ドラッグ中はタブ追加ボタンは無効になっている。これを参考にして,ドラッグ中は一番端のタブを非表示にして無効にする。
  2. StackOverFlowでは,「QTabBarのmousePressEventをオーバーライドして独自のTabBarで上書きする」という回答があった。この方法だと,いちいち自分でオーバーライドしないといけないので手間だと感じた。
  3. Qtで作られたWebブラウザーであるfalkonのソースコードを参考にする。

Webブラウザーでのタブページの実装が一つのお手本だと思っている。この中の方法を検討して,うまく実装していきたい。

また,今回の勉強会では,「タブバーをダブルクリックで編集」機能も実装していない。この機能自体がおまけみたいなものだが,こちらも挑戦していきたい。

結論

今回の勉強会では,Qt Widgetsでのタブページの実装に挑戦した。今まではQt QuickでのQMLでのアプリ開発しかほぼ勉強していなかったので,またいろいろ発見があった。感触としては,Qt自体がC++で作られているのもあり,Qt Widgetsはデスクトップアプリで長い実績もあり安定していて,QMLよりも応用が効くように感じた。

前回の勉強会で,Qt Quickでのタブページの実装について発表したように,この1か月でQt Widgetsでのタブページを完成させて,また成果を発表したい。

なお,今回は4月から勉強会に参加し始めて,初めて懇親会に参加した。今月で半年,6回目の勉強会参加であり,今回は参加人数が少ないのもあり,一つの区切りとしていいかと思って参加した。話の内容はあまりよくわからなかったが,一つの経験になった。また常連が少ないときに参加してみたいと思う。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です