Table of Contents 2 1. タブページ 2. Qt での 4 通りの開発方法 3. Qt Quick Controls 2 での開発 1. タブページ外観と追加 ([+]) ボタン 2. 追加 ([+]) の実装 3. 閉じるボタン ([ ]) の実装 4. 削除の実装 5. タブ

Similar documents
10th Developer Camp - B5

_責)Wordトレ1_斉木

PowerPoint プレゼンテーション

Calendar Plus JavaScript API リファレンス ラジカルブリッジ Ver

PowerPoint プレゼンテーション

第 8 回の内容 クライアントサイド処理 JavaScript の基礎

Microsoft PowerPoint - Tutorial_2_upd.ppt

更新履歴 変更履歴 版数 リリース日 更新内容 第 1 版 2017/5/15 第 1 版発行 第 2 版 2017/7/13 更新履歴 変更内容を追加 (2ページ) 編集の前に を追加(8 ページ ) ブロックエディタ スマートモード エディタモード の説明を追加 (10~12 ページ ) ブロッ

目次 DjVu Viewer インストールガイド 信頼済みサイトへの登録 ポップアップブロックの解除 GSPc_Web 用インストーラのダウンロード方法 GSPc_Web 用インストーラのインストール... 8 GSPc_WEB 操作説

目次 P. ログイン P. TOPページ P3. 物件概要の更新 P4. ページの編集 P6. 項目の編集 全体概要 登録本告 先着本告 予告 の編集 P7. 項目の編集 フリーエリア の編集 P8. 編集エディターのご使用方法 P. 項目の編集 更新日 の編集 P3. 次回更新予定日アラートメール

目次 1. アニメーションの仕組み 3 2. ワードアートでムービーのタイトルを作成 7 3. まとめ 課題にチャレンジ 19 [ アニメーション ] 機能 PowerPoint に搭載されている [ アニメーション ] 機能を使用すると 文字や図形にアニメーション ( さまざまな動きや

コンテンツメディアプログラミング実習2

はじめに - マニュアルエディター機能の概要 - Dojoの種類とマニュアルエディター機能解除について マニュアルレイアウトの生成 - マニュアルレイアウトの生成 基本編集 4 - 表紙の挿入 4 - 目次の挿入 5 - 一括変換 6 4 マニュアルビルド 9 4- MS Word 9

Consuming a simple Web Service

SAMBA Stunnel(Mac) 編 1. インストール 1 セキュア SAMBA の URL にアクセスし ログインを行います xxxxx 部分は会社様によって異なります xxxxx 2 Mac OS 版ダウンロー

JavaScript演習

Prog2_6th

(Microsoft Word - Word\216\300\217K\212\356\221b1.doc)

2 / 25 複数ソフトの組み合わせ テキストファイルを Excel で開く テキスト形式 (.txt) で保存したファイルを Excel で利用しましょう 第 14 講で保存した west.txt を Excel で開きます 1. Excel を起動します 2. [Office ボタ

Java言語 第1回


Local variable x y i paint public class Sample extends Applet { public void paint( Graphics gc ) { int x, y;... int i=10 ; while ( i < 100 ) {... i +=

JavaScript 演習 2 1

JavaScript の使い方

AWS Client VPN - ユーザーガイド

目次 第 1 章はじめに 取扱いについて 記載内容について... 6 第 2 章基本操作 OneNote Online を開く ノートブックを開く ノート ( セクション ) を作成する... 11

1-2. 文字の編集について (1) 文字入力する ページ編集フィールド 上では キーボードからの文字入力 または コピーした文章の貼り付け操作に より 文章を入力します 以降 文字入力に関する操作について説明します ページ編集フィールド (1) 改行の扱いについて [Enter キー ] を押下し

Autodesk Revit Building 基礎コース

設定をクリックしてください 初期設定をクリックします

brieart変換設定画面マニュアル

<91808DEC90E096BE8F91322E786C73>

SILAND.JP テンプレート集

目次 ページ 1. 本マニュアルについて 3 2. 動作環境 4 3. ( 前準備 ) ライブラリの解凍と保存 5 4. モデルのインポート 6 5. インポートしたモデルのインピーダンス計算例 8 6. 補足 単シリーズ 単モデルのインポート お問い合わせ先 21 2

クイックスタートマニュアル目次 スマホサイトビルダーモビークとは? モビークの特徴 ドラッグ& ドロップで簡単編集 スタイリッシュなデザイン部品 PC サイトと自動連動 最高のSEO 対策導入までの流れ STEP1 初期デザイン設定 STEP2 ページの登録 STEP3 スマホページの編集 STEP

目次 1. ログイン ログアウト デスクトップ ( 例 :Word Excel 起動中 ) Dock( 例 :Word Excel 起動中 ) Finder ウィンドウ メニューバー ( 例 :Word 起動中 )...

Oracle BI Publisherを利用したレポートの作成

スライド 1

目次 1. PDF 変換サービスの設定について )Internet Explorer をご利用の場合 )Microsoft Edge をご利用の場合 )Google Chrome をご利用の場合 )Mozilla Firefox をご利

Microsoft Word - Word1.doc

Eclipse 操作方法 (Servlet/JSP 入門補助テキスト)

Sharing the Development Database

Microsoft Word - 205MSPowerpoint2010

StarBoard Software ユーザーズガイド 目次 1. 教育用端末 (imac) の起動と,StarBoard Software の起動 電子黒板の起動 電子黒板の終了 StarBoard Software の使い方..

Microsoft Word - 操作マニュアル(PowerPoint2010).doc

1.WebClass( ウェブクラス ) とは WebClass を利用される前に 学生の立場で WebClass を利用してみましょう... 4 開始方法... 4 資料を閲覧する 先生の立場で WebClass を利用してみましょう... 8 資料を

ProVisionaire Control V3.0セットアップガイド

JavaScript プログラミング 4.Web ブラウザのオブジェクト 4-4 window オブジェクト 4-5 location オブジェクトと history オブジェクト 4-6 link オブジェクト 08T4082A 野太樹

AppsWF ワークフロー設定ガイド Ver.1.1 株式会社オプロ

IBM Business Process Manager CSS による Coach レイアウト制御ガイド WebSphere 2014 IBM Corporation

Microsoft Word - macマニュアル【 】.doc

ACD/1D NMR Processor:基本トレーニング

Windowsユーザでも 手軽に作れるiPhoneアプリ

PowerPoint プレゼンテーション

FutureWeb3 Web Presence Builderマニュアル

Microsoft PowerPoint - SKYMENUの使い方.ppt

住所録を整理しましょう

Microsoft Word - VB.doc

Microsoft Word - P doc

エンドポイント濁度測定装置 LT-16 取扱説明書

MMC Unity講座

Microsoft Word - ws-0001.doc

TestDesign for Web

Microsoft Word - tutorial3-dbreverse.docx

サイボウズ ツールバー βマニュアル

Acrobat Reader DCのインストール・操作方法―Windows 10/8.1/7

HP Primeバーチャル電卓

<4D F736F F D C815B835E838B837D836A B5F92A18A4F94C55F2E646F63>

Transcription:

Qt Quick でのタブページの実装に 手こずった話 妹尾賢 (SENOO, Ken) contact@senooken.jp https://social.senooken.jp/senooken 2018-08-18 Qt 勉強会 @ Tokyo #62 <https://qt-users.connpass.com/event/97166/> URL: https://senooken.jp/public/20180818/ This work is licensed under the CC0 1.0 Universal Lincense. To the extent possible under law, I have waived all copyright and related or neighboring rights to this work.

Table of Contents 2 1. タブページ 2. Qt での 4 通りの開発方法 3. Qt Quick Controls 2 での開発 1. タブページ外観と追加 ([+]) ボタン 2. 追加 ([+]) の実装 3. 閉じるボタン ([ ]) の実装 4. 削除の実装 5. タブボタンのドラッグ 6. タブタイトルの編集機能 4. 問題点 1. タブページの削除 移動時に座標がおかしくなる 2. 起動直後のタブボタン編集時にフォーカスあわない 3. Qt 5.11 ではタブボタン編集時に文字が被る

1. タブページとは 3

1. タブページとは 4 タブ ( tab ) とはドキュメントを切り替えて表示する ための GUI ウィジェットである 一般的には長方形のボックス中にテキストラベルを表示する形で画面上部に表示され タブの選択により管理するドキュメントを切り替えて表示させる仕組みとなっている --Wikipedia タブ (GUI) < https://ja.wikipedia.org/wiki/ タブ _(GUI)> 水平タブ (U+0009) と区別するため, タブページとよぶ タブの見出し部分をタブボタンとよぶ

多数のソフトで採用されている GUI 部品 1. タブページとは Web Browser (Firefox) Text Editor (Vim) 5 File Manager (Nautilus) PDF Viewer (Foxit)

逆にタブページがないと不便 1. タブページとは シェル (cmd.exe) Text Editor (notepad) 6 File Manager (Explorer) Word Processor (MS Word)

1. タブページの機能イメージ 7

1. タブページの機能 8 1. ボタン ([+]) でタブページ追加 2. マウスホバーで [ ] ボタン表示 3.[ ] ボタン押下でタブページ削除 4. タブボタンをドラッグで移動 5. タブボタンをドロップで別ウィンドウへ移動 GUI に必須のタブページを Qt で実装

2. Qt での 4 通りの開発方法 9

2. Qt での 4 通りの開発方法 10 1.Qt Widgets C++ 2.Qt Quick 3.Qt Quick Controls 1 QML 4.Qt Quick Controls 2

2. Qt での 4 通りの開発方法 11 1.Qt Widgets 2.Qt Quick 3.Qt Quick Controls 1 4.Qt Quick Controls 2 Qt Widgets or Qt Quick Controls 2 の 2 択 今回は Qt Quick Controls 2 を選択

2. Qt での 4 通りの開発方法 12 1. Qt Widgets C++ で作る 昔から存在する Qt のベース 2. Qt Quick Qt 5.0 から存在 QML で作る 矩形描画など原始的機能提供 必要な部品は自作 ( 非効率 ) 3. Qt Quick Controls 1 Qt 5.1 から存在 ダイアログなど GUI に必要な機能を提供 モバイル環境での性能が悪いため, Qt 5.11 から廃止予定扱い Qt Wiki: https://wiki.qt.io/new_features_in_qt_5.11 ML: http://lists.qt-project.org/pipermail/development/2018-february/032073.html 4. Qt Quick Controls 2 Qt 5.7 から存在 1 系での性能を改善 モバイルフレンドリー?

3. Qt Quick Controls 2 での開発 13

3. Qt Quick Controls 2 での実装動作イメージ 14

3. Qt Quick Controls 2 での開発 15 Qt 5.10.0 で開発 開発期間 : 2018-07-14~08-15 ソースコード : https://github.com/senooken/qtexample/tree/master/tabpageqml main.qml の 1 ファイルでのシンプル実装 ドロップで別画面への移動は未実装 タブボタンのダブルクリックでリネームを実装 こちらを主に参考にした Adding TabButton dynamically to TabBar Qt Forum https://forum.qt.io/topic/81768/adding-tabbutton-dynamically-to-tabbar/1 0

1. タブページ外観と追加 ([+]) ボタンタブページの実装のための TabBar と TabButton QML Type を利用 https://doc.qt.io/qt-5/qml-qtquick-controls2-tabbar.html https://doc.qt.io/qt-5/qml-qtquick-controls2-tabbutton.html import QtQuick 2.10 import QtQuick.Controls 2.0 16 ApplicationWindow { id: window visible: true title: "Tab Page" width: 300 height: 300 header: TabBar { id: tabbar currentindex: view.currentindex TabButton { id: addbutton [+] ボタン部 text: "+" onclicked: addtab() ヘッダーとコンテントを連動 後でイベントハンドラー定義 SwipeView { id: view anchors.fill: parent currentindex: tabbar.currentindex interactive: false TextArea {placeholdertext: "Input here" サンプルでは Repeater を多用 しかし, タブページ削除機能の都合断念 同種の StackView と ScrollView は Control 型 View で唯一 Container 型 の SwipeView が都合いい ( 後述 )

2. タブページ追加の実装 17 QML でのオブジェクトの動的生成 削除の一般的方法 Dynamic QML Object Creation from JavaScript http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html Qt Quick Controls 2 の Container 型 (TabBar と SwipeView) は動的生 成 削除のメソッド (additem, insertitem, removeitem) があり簡単 https://doc.qt.io/qt-5/qml-qtquick-controls2-container.html [+] の直前にタブボタンとコンテンツを挿入 ApplicationWindow { function addtab() { tabbar.insertitem(tabbar.currentindex, tabbutton.createobject(tabbar, {text: "Tab"+(tabBar.currentIndex+1))) tabbar.setcurrentindex(tabbar.currentindex-1) view.insertitem(tabbar.currentindex, tabcontent.createobject(view, {text: "Text"+ (tabbar.currentindex+1))) view.setcurrentindex(view.currentindex-1) Component.onCompleted: addtab() // header: TabBar {... // SwipeView {... Component { id: tabcontent TextArea {placeholdertext: "Input here" 先頭の Tab1 を最初に生成 動的生成用コンテンツを用意 Component { id: tabbutton TabButton { /* ここが長い */

3. 閉じるボタン ([ ]) の実装 マウスホバーで閉じるボタン ([ ]) を表示 ( 非標準機能のため自作 ) MouseArea 内にホバーしたときだけ Button を表示 Component { id: tabbutton TabButton { // Avoid moving right focus to add tab button. Keys.onRightPressed: { if ( tabbar.currentindex+2 < tabbar.count ) tabbar.incrementcurrentindex() 18 MouseArea { id: mousearea anchors.fill: parent visible: true hoverenabled: true ホバー中だけ [ ] を表示 onentered: closebutton.visible = true onexited: closebutton.visible = false Button { id: closebutton anchors.right: parent.right anchors.verticalcenter: parent.verticalcenter visible: false FontMetrics {id: fm width: fm.height * closebutton.text.length height: fm.height text: " " onclicked: {parent.closetab(parent) [ ] のフォントサイズ 配置調整 後でイベントハンドラー定義

4. 削除の実装 MouseArea {... hoverenabled: true property int nowindex: 0 property int hoveredindex : 0 property int newindex : 0 function closetab(parent) { view.removeitem(view.itemat(mousearea.hoveredindex)) tabbar.removeitem(tabbar.itemat(mousearea.hoveredindex)) if (hoveredindex == 0) tabbar.setcurrentindex(0) // updatetabx() // タブページ削除時の座標更新 function updatetabposition() { newindex = tabbar.currentindex if ((mousex < 0) && (tabbar.currentindex > 0)) { newindex = tabbar.currentindex - 1; else if ((mousex > width-1) && (tabbar.currentindex+2 < tabbar.count)) { newindex = tabbar.currentindex + 1; // Save current hovered tab index var windowposition = maptoitem(tabbar, mousex, mousey) for (var i in tabbar.contentchildren) { var tab = tabbar.contentchildren[i] if ((tab.x <= windowposition.x) && (windowposition.x <= (tab.x+tab.width))) { hoveredindex = i; ここから急に難易度上昇 現在のタブページ以外でも 19 [ ] 押下時に削除するため, マウスホバー時のタブボタ ンの ( 添字 ) 取得が必要 マウス座標とタブボタンの座標を比較してマウスがタブボタン上か判定 onpressed: { tabbar.setcurrentindex(hoveredindex) nowindex = hoveredindex // Show close button onentered: { updatetabposition() closebutton.visible = true マウスホバー時のタブボタンの取得 onexited: closebutton.visible = false Button {...

5. タブボタンのドラッグ function updatetabposition() {... // Save current hovered tab index var windowposition = maptoitem(tabbar, mousex, mousey) for (var i in tabbar.contentchildren) { var tab = tabbar.contentchildren[i] if ((tab.x <= windowposition.x) && (windowposition.x <= (tab.x+tab.width))) { hoveredindex = i; if (drag.active) { // Tab position switching condition if ((nowindex > 0) && (tabbar.contentchildren[nowindex].x <= tabbar.contentchildren[nowindex-1].x)) { newindex = nowindex - 1 else if ((nowindex < tabbar.count-2) && (tabbar.contentchildren[nowindex].x >= tabbar.contentchildren[nowindex+1].x)) { newindex = nowindex + 1 タブドラッグ中に隣のタブを 超えたら移動 ドラッグ解放時に位置を固定 20 drag.target: parent drag.axis: Drag.XAxis // Update tab position if (nowindex!= newindex) { tabbar.moveitem(nowindex, newindex) view.moveitem(nowindex, newindex) tabbar.setcurrentindex(newindex) view.setcurrentindex(newindex) nowindex = newindex // Drag and move tab onpositionchanged: { updatetabposition() // When released drag, fixing tab position. onreleased: { if (!drag.active) return var rightitem = tabbar.itemat(currentindex+1) tabbar.currentitem.x = rightitem.x - tabbar.currentitem.width // updatetabx() // タブ位置更新時座標異常対応... // Show close button onentered: {...... x 方向ドラッグ有効化ドラッグ中のタブの交換 ドラッグ解放時位置固定本来なら直前の 2 行 ( 右隣のタブの隣に固定 ) で済むはずだが, クリックの位置がおかしくなるので updatex() を使う

6. タブタイトルの編集機能 タブボタンをダブルクリックでタイトルを編集可能にする 21 TabButton に TextField を重ねてダブルクリック時だけ有効化 TabButton { // Avoid moving right focus to add tab button. Keys.onRightPressed: { if ( tabbar.currentindex+2 < tabbar.count ) tabbar.incrementcurrentindex() // Rename tab page title TextField { id: textfield anchors.fill: parent horizontalalignment: TextInput.AlignHCenter visible: false text: parent.text oneditingfinished: { parent.text = text textfield.visible = false mousearea.visible = true... MouseArea {... onpressed: { tabbar.setcurrentindex(hoveredindex) nowindex = hoveredindex タイトル編集後 TextField 非表示 MouseArea 表示 // Change focus ondoubleclicked: { tabbar.setcurrentindex(hoveredindex) mousearea.visible = false textfield.visible = true textfield.focus = true ダブルクリック時 MouseArea 非表示 TextField 表示 // Show close button onentered: {...

4. 問題点 22

23 4.1. タブページの削除 移動時に座標がおかしくなる 以下の操作後, タブボタンをクリックしたときの位置がずれる [ ] で削除時 タブボタンをドラッグで移動時 > 対策として updatex() で無理やり TabButton の座標を固定 また, タブを高速でドラッグして移動させるとタブの配置がおかしくなる > 対策として幅を更新 MouseArea {... // After drag, update position is wrong function updatetabx() { for (var i = 0, len = tabbar.contentchildren.length, width = tabbar.width/len; i < len; ++i) { tabbar.contentchildren[i].x = i * width // Updating window size for alignment tab button. window.width += 1 var start = new Date().getTime() var stop = new Date().getTime() while (stop < start + 20) { stop = new Date().getTime() window.width -= 1 幅更新 早いと反映されないので 20 ms 待機

24 4.2. 起動直後のタブボタン編集時にフォーカスあわない 起動直後, 最初のタブボタンをダブルクリックして も, フォーカスされず TextField の編集に入らない ( カーソルが表示されない ) もう一度クリックすると編集できる タブページを追加した場合などは問題ない

4.3. Qt 5.11 でタブボタン編集時に文字が被る 25 タブボタンをダブルクリックすると, 一番上の TextField が表示されて, TabButton は隠れるはず Qt 5.11 だとなぜか下の TabButton のテキストが隠れずに表示され, 座標が微妙にずれて二重に表示される

まとめ 26 Qt Quick Controls 2 でのタブページの実装を検討 複雑なこと ( 以下 2 点 ) をしない場合, 簡単に実装可能 タブの移動を不許可 タブの削除は現在タブのみ 標準外の実装は困難 動的生成 削除, 移動などはバグらしき挙動 Controls 2 は新しい (Qt 5.7 から ) ので不安定? 割り切って, 設計で複雑な実装をしないようにする? 今後, Qt Widgets で同じ機能を実装し, Qt Quick Controls 2 と比較検討したい

Q & A 27 1.Qt Quick Controls 2 でのタブページの実装例がほぼない Qt Quick Controls 1 だとネット上に情報があった気がする ただし, ドラッグはできなかった 2.Controls 2 はまだ安定していないのか? だいぶ安定してきているとは思うが, 不具合なのか, なんだろうね? 3. ドラッグさせない, 現在タブだけ閉じるとか機能を限定し たら, たしかに Controls 2 はスマートにできると感じた しかし, ちょっと凝ったことをすると急に難しい 提供されていない機能を実装するのはたしかに難しい

Q & A 28 4. 今回の実装は Android などで動くか試したか? いいえ 不具合があるので, デスクトップ環境でちゃ んと動作するものを作ってから, Android などでの動作を検証する 今後, Qt Quick と Qt Widgets のどちらメインに使うか検討中なので, それらが落ち着いてからになる