プロジェクトの問題解決記録 (C++&Qt)

プロジェクトの問題解決記録 (C++&Qt)


私は新人です。
このブログは主にプロジェクトで発生した C++ と Qt の問題を記録するために使用され、
随時更新されます。


一般知識のポイント

  • クラス定義で定義された関数は、インライン指定子が使用されていない場合でも、すべて **インライン関数** です。

長所: 関数本体が小さい場合、関数をインライン化するとオブジェクト コードがより効率的になります。アクセサー関数や、短い関数本体を持つその他のパフォーマンスが重要な関数については、インライン化が推奨されます。
短所: インライン化を多用すると、プログラムの速度が低下します。インライン化すると、インライン化された関数のサイズに応じて、オブジェクト コードのサイズが増減する場合があります。
結論: 合理的な経験則は、10 行を超える関数をインライン化しないことです。

  • 継承には、パブリック、プロテクト、プライベートの 3 つの方法があります。
  1. パブリック継承: 基本クラスのパブリック メンバー、保護されたメンバー、プライベート メンバーのアクセス属性は、派生クラスではそれぞれ public、protected、private になります。
  2. protected 継承: 基本クラスの public メンバー、protected メンバー、および private メンバーのアクセス属性は、派生クラスではそれぞれ protected、protected、private になります。
  3. プライベート継承: 基本クラスのパブリック メンバー、保護されたメンバー、プライベート メンバーのアクセス属性は、派生クラスではそれぞれプライベート、プライベート、プライベートになります。

宣言がプライベート、プロテクト、またはパブリック継承であることが継承によって示されない場合、デフォルトはプライベート継承であり、構造体のデフォルトのパブリック継承です。

  • 仮想関数は、基本クラスでキーワード virtual を使用して宣言された関数です。基本クラスで定義された仮想関数を派生クラスで再定義するときは、その関数に静的にリンクしないようにコンパイラーに指示します。
    私たちが望んでいるのは、プログラムのどの時点でも、呼び出されるオブジェクトのタイプに基づいてどの関数を呼び出すかを選択できることです。この操作は動的リンクまたは遅延バインディングと呼ばれます。(公式の声明は少し抽象的であり、よりよく理解するために後で例を示します)

関数の後にconstとstatementブロックを追加します。

これは関数全体を const に変更するもので、「関数本体内のメンバーデータは変更できない」ことを意味します。このクラスの const インスタンスを宣言すると、const で装飾された関数のみを呼び出すことができます。

    QColor textColor() const { return myTextColor; }                    // 把整个函数修饰为const,后面的花括号是函数实现
    QColor itemColor() const { return myItemColor; }
    QColor lineColor() const { return myLineColor; }

コンストラクタ

クラス コンストラクターは、クラスの新しいオブジェクトが作成されるたびに実行されるクラスの特別なメンバー関数です。

以下のような特徴を持っています

  • コンストラクターの名前はクラスの名前とまったく同じです
  • 型も返さず、void も返さない
  • コンストラクターを使用して一部のメンバー変数の初期値を設定できます

** 例: **
この例は、新人チュートリアルからのものです:
https://www.runoob.com/cplusplus/cpp-constructor-destructor.html

#include <iostream>
 
using namespace std;
 
class Line
{
   public:
      void setLength( double len );
      double getLength( void );
      Line();  // 这是构造函数
 
   private:
      double length;
};
 
// 成员函数定义,包括构造函数
Line::Line(void)
{
    cout << "Object is being created" << endl;
}
 
void Line::setLength( double len )
{
    length = len;
}
 
double Line::getLength( void )
{
    return length;
}
// 程序的主函数
int main( )
{
   Line line;
 
   // 设置长度
   line.setLength(6.0); 
   cout << "Length of line : " << line.getLength() <<endl;
 
   return 0;
}

** 演算結果: **

Object is being created, length = 10
Length of line : 10
Length of line : 6

クラス デストラクターは、作成されたオブジェクトが削除されるたびに実行されるクラスの特別なメンバー関数です。

以下のような特徴を持っています

  • デストラクターの名前はクラスの名前とまったく同じですが、先頭にチルダ (~) が付いているだけです。
  • 値を返さず、パラメータを取ることもできません。
  • デストラクターは、プログラムを終了する前にリソースを解放するのに役立ちます (ファイルを閉じる、メモリを解放するなど)。

例:
この例は新人チュートリアルからのものです:
https://www.runoob.com/cplusplus/cpp-constructor-destructor.html

#include <iostream>
 
using namespace std;
 
class Line
{
   public:
      void setLength( double len );
      double getLength( void );
      Line();   // 这是构造函数声明
      ~Line();  // 这是析构函数声明
 
   private:
      double length;
};
 
// 成员函数定义,包括构造函数
Line::Line(void)
{
    cout << "Object is being created" << endl;
}
Line::~Line(void)
{
    cout << "Object is being deleted" << endl;
}
 
void Line::setLength( double len )
{
    length = len;
}
 
double Line::getLength( void )
{
    return length;
}
// 程序的主函数
int main( )
{
   Line line;
 
   // 设置长度
   line.setLength(6.0); 
   cout << "Length of line : " << line.getLength() <<endl;

   return 0;	 // 自动调用析构函数
}

** 演算結果: **

Object is being created
Length of line : 6
Object is being deleted

オーバーライド

override 予約語は、現在の関数が基本クラス
**Purpose** の仮想関数をオーバーライドすることを示します。

  1. 多くの関数の場合、特定の関数が基本クラスの仮想関数を書き換えることを読者に促すことができます (これは、仮想関数が派生クラス自体によって定義されているのではなく、基本クラスから継承されていることを示します)。
  2. 関数が基本クラスの仮想関数をオーバーライドするかどうかをコンパイラーに強制的にチェックさせ、オーバーライドしない場合はエラーを報告します。

仮想関数

仮想関数の役割: 技術用語で説明することはポリモーフィズム (Polymorphism) を実現すること、ポリモーフィズムはインターフェースを実装から分離すること、ビジュアル言語で説明することは共通の手法を実現することだが、個体差により異なる手法を採用すること戦略。
例:
この例は Baidu Know からのものです:
https://zhidao.baidu.com/question/1797274966344020227.html

#include<iostream>
usingnamespacestd;
classA
{
public:
	voidprint()
	{
		cout<<"ThisisA"<<endl;
	}
};
classB:publicA
{
public:
	voidprint()
	{
		cout<<"ThisisB"<<endl;
	}
};
int main()
{
	//为了在以后便于区分,我这段main()代码叫做main1
	Aa;
	Bb;
	a.print();
	b.print();
	return0;
}

出力結果はそれぞれ「ThisisA」「ThisisB」となります。クラス A とクラス B の print() インターフェイスを通して、これら 2 つのクラスが個体差により異なる戦略を採用していることがわかりますが、これは本当にポリモーフィズムを実現しているのでしょうか? いいえ、ポリモーフィズムのもう 1 つの重要な点は、すべてのオブジェクトが基本クラスへのポインターまたは参照を使用して操作されることです。次に、main() のコードを変更します。

intmain()
{
	//main2
	Aa;
	Bb;
	A*p1=&a;
	A*p2=&b;
	p1->print();
	p2->print();
	return0;
}

実行して結果を確認してください。よー、ふと振り返ると、結果は 2 つです。これは A です。ここで問題が発生します。p2 は明らかにクラス B のオブジェクトを指していますが、クラス A の print() 関数を呼び出しています。これは期待した結果ではないため、この問題を解決するには仮想関数を使用する必要があります。

classA
{
	public:
	virtualvoidprint(){cout<<"ThisisA"<<endl;}
	};
classB:publicA
	{
	public:
	voidprint(){cout<<"ThisisB"<<endl;}
};

クラス A のメンバー関数 print() が仮想関数になっているのは間違いないので、クラス B のメンバー関数 print() も仮想関数になっているでしょうか。答えは「はい」です。基本クラスのメンバー関数を仮想に設定するだけで、派生クラスの対応する関数が自動的に仮想関数になります。したがって、クラス B の print() も仮想関数になります。次に、派生クラスの対応する関数を変更するために virtual キーワードを使用する必要があるかどうかは、あなた自身の問題です。
ここで main2 のコードを再実行すると、出力結果は This is A と This is B になります。
概要: 基本クラスへのポインタがその多態性クラス オブジェクトを操作するとき、異なるクラス オブジェクトに従って対応する関数を呼び出します。この関数は仮想関数です。

QGraphicsScene と QGraphicsview およびアイテム

QGraphics グラフィックス ビュー フレームワークは 3 つの部分で構成されます。

  • Qグラフィックスシーン
  • グラフィックアイテム
  • グラフィックビュー

Scene は、キャンバスに相当するグラフィック ビュー フレームワークのシーンを提供する役割を果たし、すべてのアイテムを管理し、次の機能を持ちます。

  1. 多数のグラフィック項目を管理するための迅速なインターフェイス。
  2. イベントを各グラフィックアイテムに伝播する
  3. 選択、フォーカス処理などのグラフィック項目の状態を管理します。
  4. 主に印刷用に、変換せずにレンダリングを提供します

Add: addItem(item) // シーンの座標
削除:removeItem(item)
背景を画像として設定: setBackgroundBrush(QPixmap(""))
シーンの境界四角形: setSceneRect(QRectF())

View は、QGraphicsScene を観察するためのインスタンス ウィンドウを提供します。ビュー ウィンドウは、大きなシーン間を移動するためのスクロール バーを提供するスクロール可能な領域です。
ズームインとズームアウト: QGraphicsView::scale(xScale, yScale); //xScale 倍と yScale 倍をそれぞれ x 方向と y 方向にスケールします。1.0倍の場合はスケーリングを行いません。
view and scene: QGraphicsView::setScene() // ビューはシーンをバインドし、ビューとシーンは中央揃えで表示されます

Item は、独自のカスタム項目を作成するための軽量の基盤を提供します。これには、アイテムのジオメトリ、衝突検出、描画実装、イベント ハンドラーを介したアイテムの相互作用の定義が含まれます。
使いやすさを考慮して、Qt には最も一般的に使用される基本的な標準プリミティブがいくつか用意されています。

  • QGraphicsEllipseItem は楕円オブジェクトを提供します
  • QGraphicsLineItemはラインオブジェクトを提供します
  • QGraphicsPathItemはパスオブジェクトを提供します
  • QGraphicsPixmapItemは画像オブジェクトを提供します
  • QGraphicsPolygonItemはポリゴンオブジェクトを提供します
  • QGraphicsRectItem は四角形オブジェクトを提供します
  • QGraphicsSimpleTextItem はテキストラベルオブジェクトを提供します
  • QGraphicsTextItem は、高度なテキスト ブラウジング オブジェクトを提供します。
    これらが要件を満たさない場合 (例: 特定の形状が必要な場合)、多くの場合、カスタマイズする必要があります。通常の方法は、QGraphicsItem (QGraphicsObject) を継承することです。

参考:
https://blog.csdn.net/Bing_Lee/article/details/106106414
https://blog.csdn.net/xiezhongyuan07/article/details/79262573

カスタムアイテム

2 つの仮想関数を書き換える必要があります
voidPaint(): 項目の内容をローカル座標で描画します
QRectFboundingRect(): 項目の外側の境界を四角形として返します どの領域を再描画する必要があるかを決定するために QGraphicsView によって呼び出され
ます次のような他の要件を添付する必要がある場合があります。

  • QPainterPath shade() 項目の形状は、衝突検出のために contains() および collidesWithPath() によって使用されます。実装されていない場合、デフォルトはboundingRect()です。
  • シグナル/スロット、属性メカニズムを使用: QObject および QGraphicsItem を継承 (または QGraphicsObject を直接継承)
  • マウスイベントの処理:mouse....Event()を再実装します。
  • キーボード イベントの処理: key の再実装....Event()
  • ドラッグ アンド ドロップ イベントの処理: ドラッグ...Event()、dropEvent() などを再実装します。

以下の図は、2 つの機能の主な設定を示しています
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-cGzESUGz-1633746670045)(D: \Downloads\shape&boundingRect.png)] 参照
:
https://www.cnblogs.com/klcf0220/p/10316510.html

QGraphicsScene内のアイテムの移動範囲を制限する

プロジェクト内ではアイテムがマウスで移動してビューウィンドウ以外の場所に移動してしまうため、アイテムの移動範囲を制限するために、QGraphicsItemが所属するQGraphicsItemの位置を通知する仮想関数ItemPositionChange関数を提供していることがデータからわかります。が変更されようとしており、
QVariant QGraphicsItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
値は QGraphicsItem の将来の位置座標です

QVariant Networkitem::itemChange(GraphicsItemChange change, const QVariant& value)
{
    if (change == ItemPositionChange && scene()) // 控件是否发生移动
    {
        for (Arrow* arrow : qAsConst(arrows))	// 更新arrow
            arrow->updatePosition();

        QPointF newPos = value.toPointF(); 		//即将要移动的位置
        QRectF rect(0, 0, scene()->width(), scene()->height()); 	// 限制的区域,scene需要提前设定好大小
        if (!rect.contains(newPos)) // 是否在区域内
        {
            newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));		// 设置限制
            newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top())));
            return newPos;
        }
    }
    return QGraphicsItem::itemChange(change, value);		// Qt图形机制,不必深究
}

参考:
https://blog.csdn.net/diaotaoning2896/article/details/102055010

おすすめ

転載: blog.csdn.net/p3116002589/article/details/120438168