QTableViewテーブルの行を追加および削除するためのQtウィジェット



この記事では、単一のウィジェット(GUI要素)を開発した経験を共有したいのですが、Qtの技術とテクニックのいくつかを強調したいと思います。

多くの場合、ユーザーが表に行と列を挿入したり、表から削除したりできるようにする必要があります。 原則として、これは次のように実装されます:ヘッダーをクリックして行を選択し、メニューで項目を選択する必要があります:select> menu> insert | 削除する これは、行が現在の行の前ではなく、たとえば後ではなく挿入されるという事実と同様に、完全に明白で直感的ではありません。 そのため、この問題を解決するウィジェットを作成しました。

ウィジェットは、テーブルの境界に沿ってカーソルに続く4つのボタンのように見えます(笑、web 1.0の時代のサイトでカーソルを追いかけたミツバチのようです!)。 QTableViewをオーバーロードすることは可能ですが、すべてのインスタンスを変更する必要があります。 代わりに、既存のQTableViewに接続する一種のソケットである別のウィジェットを作成しました。

このプロジェクトは、 InsertRemove :: ButtonInsertRemove :: Panel、および2つの補助的なデモンストレーションの4つのクラスで構成されます。 。

ボタンは、現在の座標と現在のポリシー値( InsertRemove :: Policy )に適切なウィジェット上の位置を計算し、列幅と行高から計算します。 1つの座標はこれらの寸法の合計であり、もう1つは境界線または線の中央に最も近い値です。

int coord1; int coord2 = 0; int sizes[m]; if (_orientation == Qt::Horizontal) { for (int i=0;i<m;i++) sizes[i] = table->columnWidth(i); for (int i=0;i<n;i++) coord2 += table->rowHeight(i); } else { for (int i=0;i<m;i++) sizes[i] = table->rowHeight(i); for (int i=0;i<n;i++) coord2 += table->columnWidth(i); } if (_type == InsertRemove::Insert) nearestBorder(_policy,point1+offset1,sizes,m,&_modelIndex,&coord1); else // _type == InsertRemove::Remove nearestMiddle(_policy,point1+offset1,sizes,m,&_modelIndex,&coord1);
      
      





ポリシーは次のとおりです。すべてのモデルがこれらすべての操作を許可するわけではないため、挿入、削除、先頭にのみ挿入、最後にのみ挿入。

ボタンには、Qtで広く使用されている親の概念をオブジェクトに使用しました。これは、親が削除されると、すべてのメモリオブジェクトが削除されることを意味し、ウィジェットの場合、子ウィジェットが親内に表示されることも意味します(ダイアログボックスではありません)およびその座標系です。

スタイルを記述するのにcssよりも優れているものはありません。データを格納するためにQtリソースシステムを使用すると、バイナリにリソースを埋め込み、ルートディレクトリとして「:」を使用してファイルとしてアクセスできます。

  QString plus_css = "* {image: url(':/plus-icon.png'); border: 0;}" "*:hover {image: url(':/plus-icon-hover.png');}" "*:pressed {image: url(':/plus-icon-pressed.png');} "; QString minus_css = "* {image: url(':/minus-icon.png'); border: 0;}" "*:hover {image: url(':/minus-icon-hover.png');}" "*:pressed {image: url(':/minus-icon-pressed.png');} "; if (_type == Insert) setStyleSheet(plus_css); else setStyleSheet(minus_css);
      
      





ボタンが押されると、モデルへの実際の挿入または削除が呼び出されます。

 void Button::on_clicked() { QTableView* table = dynamic_cast<QTableView*>(this->parent()); if (!table) return; QAbstractItemModel* model = table->model(); if (!model) return; if (_type == InsertRemove::Insert) { if (_orientation == Qt::Horizontal) model->insertColumn(_modelIndex); else model->insertRow(_modelIndex); } else // _type == InsertRemove::Remove { if (_orientation == Qt::Horizontal) model->removeColumn(_modelIndex); else model->removeRow(_modelIndex); } }
      
      





ボタンですべてが明確になったので、パネルに移動します。 彼女はこれらのボタンを作成して保存し、それらに座標とポリシーを渡し、ボタンをテーブルに適用する責任があります。

 void Panel::attach(QTableView* table) { for (int i=0;i<4;i++) _buttons[i]->setParent(table); _table = table; table->setMouseTracking(true); table->viewport()->installEventFilter(this); connect(table->horizontalHeader(),SIGNAL(sectionResized(int,int,int)),this,SLOT(placeButtons())); connect(table->verticalHeader(),SIGNAL(sectionResized(int,int,int)),this,SLOT(placeButtons())); placeButtons(); }
      
      





私のお気に入りのQtの機能はイベントフィルター(QEventFilter)で、これを使用すると、オブジェクトの内部生活を祈って侵入することができ、カプセル化に違反します。 考えてみると、デスクトッププログラマになるのがより困難だった、裸のWinApi、クリッピーなマクロ、構造、およびlpcwstrのような呪いの時代に精神的に戻ります。 このようなフィルターの助けを借りて、パネルはQTableView上のマウスの動きを監視します。 私の場合のフィルターはパネルそのものです。 最初はフィルターを別のクラスにして、イベントをシグナルに入れたいと思っていましたが、イベントがイベントであり、シグナルがシグナルであり、すべてが積み上げられない正当な理由があるべきだと思いました(メモリがうまく機能していれば、 .Netで)。 第一に、イベントはウィジェットの内部ライフであり、シグナルはそのインターフェースです。第二に、イベントが毎秒数百回呼び出される場合、重要な場合がある相互作用の層が少ないため、イベントが高速であることは明らかです。 私はこれらの計算を100%確信していませんが。 したがって、必要なのは、マウスの移動イベントを追跡し、ボタンに座標を渡すことだけです。

 bool Panel::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::MouseMove && object == _table->viewport()) { QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event); if (!mouseEvent) return false; for (int i=0;i<4;i++) _buttons[i]->setPoint(mouseEvent->pos()); } return false; }
      
      





コンテナとデモンストレーションモデルは自明であるように見えるため、すぐにアプリケーションに進みます。モデルの作成、テーブルの作成、パネルの作成、テーブルへのパネルの添付。

  QTableView view; view.setModel(&model); Panel panel(EverythingAllowed,EverythingAllowed); panel.setPolicy(Qt::Horizontal, (PolicyFlags) RemoveAllowed | AppendAllowed ); panel.attach(&view);
      
      





このウィジェットの欠点の1つは、QTableViewに結び付けられていることです(これは、このために必要だったためです)。ただし、他のタイプのビューにも使用できます。 時間と欲求があれば、この問題を解決します。

おそらく私の仕事はあなたにとって役に立つかもしれません。それはgithubまたは私のサーバーから取得できます。 必要なものはすべて、InsertRemove名前空間のinsertremoveフォルダーにあり、プロファイルに含まれています。 ライブラリーではまだ十分ではなく、湿気があります。 自由に使用して貢献してください。

リンク:

 git clone git://github.com/overloop/insertremovepanel.git git clone git://mugiseyebrows.ru/insertremovepanel.git
      
      





ビュー: github.com | mugiseyebrows.ru

ダウンロード: github.com | mugiseyebrows.ru



All Articles