چطور می شود در کیوت (Qt) اشیاء با قابلیت جابجایی را در صفحه ایجاد کرد و آنها را با یک خط اتصال داد؟ - هفت خط کد انجمن پرسش و پاسخ برنامه نویسی

چطور می شود در کیوت (Qt) اشیاء با قابلیت جابجایی را در صفحه ایجاد کرد و آنها را با یک خط اتصال داد؟

0 امتیاز
با سلام،

لطفا راهنمایی بفرمایید که چطور می شود در Qt (کیوت) دوتا شی ء مثلا ماشین را روی صفحه درگ کرد ( بشود  جابجا کنیم)  و سپس  با یک خط آنها را بهم متصل کنیم.

چیزی شبیه کاری که در نرم افزارهای نقشه کشی و یا رسم مدار الکتریکی انجام می شود.

 

با تشکر از توجهی که می نمایید.
سوال شده بهمن 10, 1397  بوسیله ی mousavi (امتیاز 14)   1 2

2 پاسخ

+1 امتیاز
 
بهترین پاسخ

سلام

اگر به دنبال مثال جامعی می گردید سایت خود Qt این مثال1  و مثال2 را قرار داده و با جزئیات کلیه موارد بخش ها توضیح داده شده.

من خودم هم یه پیاده سازی انجام دادم  که کلاس QAbstractGraphicsShapeItem کلاس پایه ای بر این کار هستش در ابتدا باید graphItem ی بسازید که resizeable و هم movable باشه بعدش هر شکلی که خواستید رو می تونید توش رسم کنید مدیریت با خودتون.

#ifndef ECV_RESIZABLE_GRAPHICS_ITEM
#define ECV_RESIZABLE_GRAPHICS_ITEM

#include "viewlib_global.h"

#include <QGraphicsItem>
#include "EcvObjectData.h"

#include <array>
#include <QPointF>
#include <QRectF>
#include <QFont>
#include <QCursor>
#include <qdebug.h>
#include <QObject>
#include <QAbstractGraphicsShapeItem>

#include <opencv2/core/core.hpp>

namespace ecv {
	//QGraphicsRectItem

	const int HANDLE_SIZE = 3;

	using HandlePoints = std::array<QPointF, 8>;
	using HandleRects = std::array<QRectF, 8>;

	enum class RectDirect { left_top, top, right_top, right, bottom_right, bottom, bottom_left, left, move, hover };



	class VIEWLIB_EXPORT EcvResizableGraphicsItem : public QAbstractGraphicsShapeItem
	{
		
	public:

		explicit EcvResizableGraphicsItem(const EcvObjectData& data, int handel_size = HANDLE_SIZE,  QGraphicsItem *parent = 0);
		~EcvResizableGraphicsItem();

		QRectF boundingRect() const;
		virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)override;

		void setRect();

		bool titleVisiable()const;
		void setTitleVisiable(const bool &value);


		int titleBorderSize()const;
		void setTitleBorderSize(int value);

		void setHandleSize(int size);
		int handleSize()const;

		QFont font()const;
		void setFont(const QFont& value);

		QString title()const;
		void setTitle(const QString &value);

		QCursor cursor()const;

		bool isSelectable()const;
		void setIsSelectable(bool value);

		EcvObjectData& data();
	protected:
		EcvObjectData object_data_;
		bool is_selectable_;
		QRectF bounding_rect_;
		HandleRects handle_rects_;
		HandlePoints handle_points_;
		int handle_size_;
		RectDirect mouse_state_;
		bool pressed_;
		int title_border_size_;
		QFont font_;
		QSizeF title_size_;
		bool title_visiable_;
		QString title_;
		QRectF handels_br_;
		QRectF title_br_;
		QCursor cursor_;

		void setCursor(const QCursor& value);

		QRectF getSqure(const QPointF& center)const;
		void setHandlesRects();
		void setHandlesPoints(const QRectF& rct);
		void drawHandlesRect(QPainter *painter);
		QLineF getLine(const QPointF &p1, const QPointF &p2, int size);
		void setCurrentCursor();
		QPointF getRectCoordinate(const QRectF& rct, const RectDirect& rect_direct);


		void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
		void mousePressEvent(QGraphicsSceneMouseEvent * event);
		void mouseReleaseEvent(QGraphicsSceneMouseEvent * event);
		void hoverMoveEvent(QGraphicsSceneHoverEvent * event);
		//void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
		//void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);

		void moveEvent(const QPointF &pos);
		void setMouseState(const QPointF &point);
		void changeHandlePosition(const QPointF& pos);
		void setTitleSize();
		void setHandelsRect();
		void setTitleRect();

		void drawHandles(QPainter *painter);
		void drawTitle(QPainter *painter);
	private:
		QRectF getNormRect(const QPointF& pnt1, const QPointF& pnt2);
	//private slots:
	    void onRectChanged();
	};


}//ecv
#endif //ECV_RESIZABLE_GRAPHICS_ITEM

 

 

 

#include <stdafx.h>

#include "EcvResizableGraphicsItem.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>

namespace ecv {
	

	EcvResizableGraphicsItem::EcvResizableGraphicsItem(const EcvObjectData& data, int handel_size, QGraphicsItem *parent /*= 0*/) :
		object_data_(data),
		handle_size_(HANDLE_SIZE),
		title_border_size_(1),
		font_(QFont("tahoma",8)),
		title_visiable_(false),
		title_(""),
		is_selectable_(true)

	{
		setZValue(1000);
		setAcceptHoverEvents(true);
		setFlags(QGraphicsItem::ItemIsSelectable);

//--		QObject::connect(&object_data_, &EcvObjectData::rectChanged, this, &onRectChanged);
		setRect();
		
		
	}

	

	EcvResizableGraphicsItem::~EcvResizableGraphicsItem()
	{
		qDebug() << "end" << endl;
	}


	QRectF EcvResizableGraphicsItem::boundingRect() const
	{
		return bounding_rect_;
	}

	void EcvResizableGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /*= 0*/)
	{
		//QGraphicsItem::paint(painter, option, widget);
		setRect();
		drawTitle(painter);
		drawHandles(painter);


		painter->setPen(this->pen());

		//setHandlesPoints(bounding_rect_);
		//setHandlesRects();

		//drawHandlesRect(painter);
	}

	void EcvResizableGraphicsItem::setRect()
	{
		
		setHandelsRect();
		setTitleRect();



		bounding_rect_ = handels_br_;
		if (title_br_.width() > bounding_rect_.width())
			bounding_rect_.setWidth(title_br_.width());

		//if (handels_br_.width() > bounding_rect_.width())
		//	bounding_rect_.setWidth(handels_br_.width());

		if (title_br_.height() > bounding_rect_.height())
			bounding_rect_.setHeight(title_br_.height());

		//if (handels_br_.height() > bounding_rect_.height())
		//	bounding_rect_.setHeight(handels_br_.height());


		update();
		//	QApplication::processEvents();
		//qDebug() << bounding_rect_ << endl;


	}

	bool EcvResizableGraphicsItem::titleVisiable() const
	{
		return title_visiable_;
	}

	void EcvResizableGraphicsItem::setTitleVisiable(const bool &value)
	{
		title_visiable_ = value;
	}

	int EcvResizableGraphicsItem::titleBorderSize() const
	{
		return title_border_size_;
	}

	void EcvResizableGraphicsItem::setTitleBorderSize(int value)
	{
		title_border_size_ = value;
	}

	void EcvResizableGraphicsItem::setHandleSize(int size)
	{
		handle_size_ = size;
	}

	int EcvResizableGraphicsItem::handleSize() const
	{
		return handle_size_;
	}

	QFont EcvResizableGraphicsItem::font() const
	{
		return font_;
	}

	void EcvResizableGraphicsItem::setFont(const QFont& value)
	{
		if (font_ != value) {
			font_ = value;
			//	setTitleSize();
		}
	}

	QString EcvResizableGraphicsItem::title() const
	{
		return title_;
	}

	void EcvResizableGraphicsItem::setTitle(const QString &value)
	{
		if (title_ != value) {
			title_ = value;
			setTitleSize();
		}

	}

	QCursor EcvResizableGraphicsItem::cursor() const
	{
		return cursor_;
	}

	bool EcvResizableGraphicsItem::isSelectable() const
	{
		return is_selectable_;
	}

	void EcvResizableGraphicsItem::setIsSelectable(bool value)
	{
		is_selectable_ = value;
	}

	EcvObjectData & EcvResizableGraphicsItem::data()
	{
		return object_data_;
	}

	void EcvResizableGraphicsItem::setCursor(const QCursor& value)
	{
		cursor_ = value;
	}

	::QRectF EcvResizableGraphicsItem::getSqure(const QPointF& center) const
	{
		return QRectF(center.x() - handle_size_, center.y() - handle_size_, handle_size_ * 2, handle_size_ * 2);

	}

	void EcvResizableGraphicsItem::setHandlesRects()
	{
		for (size_t i = 0; i < 8; i++)
			handle_rects_[i] = getSqure(handle_points_[i]);

	}

	void EcvResizableGraphicsItem::setHandlesPoints(const QRectF& rct)
	{
		handle_points_[0] = rct.topLeft();// +QPointF(-handle_size_, -handle_size_);
		handle_points_[1] = getRectCoordinate(rct, RectDirect::top);// +QPointF(0, handle_size_);
		handle_points_[2] = rct.topRight();// +QPointF(-handle_size_, handle_size_);
		handle_points_[3] = getRectCoordinate(rct, RectDirect::right);// +QPointF(-handle_size_, 0);
		handle_points_[4] = rct.bottomRight();// +QPointF(-handle_size_, -handle_size_);
		handle_points_[5] = getRectCoordinate(rct, RectDirect::bottom);// +QPointF(0, -handle_size_);
		handle_points_[6] = rct.bottomLeft();// +QPointF(handle_size_, -handle_size_);
		handle_points_[7] = getRectCoordinate(rct, RectDirect::left);// +QPointF(handle_size_, 0);


	}

	void EcvResizableGraphicsItem::drawHandlesRect(QPainter *painter)
	{
		for (size_t i = 0; i < 8; i++) {
			painter->drawRect(getSqure(handle_points_[i]));
			int next_i = (i + 1) % 8;

			//auto line = getLine(handle_points_[i], handle_points_[next_i], handle_size_);
			//painter->drawLine(line);
		}

	}

	QLineF EcvResizableGraphicsItem::getLine(const QPointF &p1, const QPointF &p2, int size)
	{
		size++;
		QLineF result;
		QPointF offset(0, 0);

		if (p1.x() < p2.x())
			offset.setX(size);
		else if (p1.y() < p2.y())
			offset.setY(size);
		else if (p1.x() > p2.x())
			offset.setX(-size);
		else if (p1.y() > p2.y())
			offset.setY(-size);

		result.setP1(p1 + offset);
		result.setP2(p2 - offset);
		return result;
	}

	void EcvResizableGraphicsItem::setCurrentCursor()
	{

		switch (mouse_state_)
		{
		case RectDirect::left_top:
		case RectDirect::bottom_right:
			setCursor(Qt::SizeFDiagCursor);
			break;
		case RectDirect::right_top:
		case RectDirect::bottom_left:
			setCursor(Qt::SizeBDiagCursor);
			break;
		case RectDirect::top:
		case RectDirect::bottom:
			setCursor(Qt::SizeVerCursor);
			break;
		case RectDirect::left:
		case RectDirect::right:
			setCursor(Qt::SizeHorCursor);
			break;
		case RectDirect::move:
			setCursor(Qt::SizeAllCursor);
			break;
		case RectDirect::hover:
			setCursor(Qt::ArrowCursor);
			break;

		}
	}

	QPointF EcvResizableGraphicsItem::getRectCoordinate(const QRectF& rct, const RectDirect& rect_direct)
	{
		QPointF result;
		switch (rect_direct)
		{
		case RectDirect::left:
			result = rct.topLeft() + QPointF(0, rct.height() / 2);
			break;
		case RectDirect::top:
			result = rct.topLeft() + QPointF(rct.width() / 2, 0);
			break;
		case RectDirect::right:
			result = rct.topRight() + QPointF(0, rct.height() / 2);
			break;
		case RectDirect::bottom:
			result = rct.bottomLeft() + QPointF(rct.width() / 2, 0);
			break;

		}
		return result;

	}

	void EcvResizableGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
	{
		//qDebug() << "mouseMoveEvent" << endl;
		moveEvent(event->pos());
		QGraphicsItem::mouseMoveEvent(event);
	}

	void EcvResizableGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
	{
		//qDebug() << "mouseMoveEvent" << endl;
		event->accept();
		pressed_ = true;
		update();
		//qDebug() << "press:" << pressed_ << endl;
		prepareGeometryChange();
		QGraphicsItem::mousePressEvent(event);

	}

	void EcvResizableGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
	{
		//qDebug() << "mouseReleaseEvent" << endl;
		pressed_ = false;

		QGraphicsItem::mouseReleaseEvent(event);
	}

	void EcvResizableGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent * event)
	{
		static int count = 1;

		//qDebug() << "hoverMoveEvent:" << count++ << endl;
		moveEvent(event->pos());
		QGraphicsItem::hoverMoveEvent(event);
	}

	//void EcvResizableGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
	//{
	//	parent_cursor_ = cursor();
	//}
	//
	//void EcvResizableGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
	//{
	//	setCursor(Qt::ArrowCursor);
	//}

	void EcvResizableGraphicsItem::moveEvent(const QPointF &pos)
	{

		if (!(mouse_state_ < RectDirect::move && pressed_)) {
			setMouseState(pos);
			setCurrentCursor();
		}
		if (mouse_state_ == RectDirect::move) {
			setFlag(QGraphicsItem::ItemIsMovable, true);
		}
		else {
			setFlag(QGraphicsItem::ItemIsMovable, false);
			if (pressed_) {
				changeHandlePosition(pos);
			}
		}
		prepareGeometryChange();

	}

	void EcvResizableGraphicsItem::setMouseState(const QPointF &point)
	{
		mouse_state_ = RectDirect::hover;
		for (size_t i = 0; i < 8; i++)
			if (handle_rects_[i].contains(point))
				mouse_state_ = static_cast<RectDirect>(i);

		if (mouse_state_ == RectDirect::hover) {
			if (pressed_)
				mouse_state_ = RectDirect::move;
		}

	}

	void EcvResizableGraphicsItem::changeHandlePosition(const QPointF& pos)
	{
		switch (mouse_state_)
		{
		case RectDirect::left_top:
			data().rect().setTopLeft(pos);
			break;
		case RectDirect::top:
			data().rect().setTop(pos.y());
			break;
		case RectDirect::right_top:
			data().rect().setTopRight(pos);
			break;
		case RectDirect::right:
			data().rect().setRight(pos.x());
			break;
		case RectDirect::bottom_right:
			data().rect().setBottomRight(pos);
			break;
		case RectDirect::bottom:
			data().rect().setBottom(pos.y());
			break;
		case RectDirect::bottom_left:
			data().rect().setBottomLeft(pos);
			break;
		case RectDirect::left:
			data().rect().setLeft(pos.x());
			break;
		}
		setRect();

	}

	void EcvResizableGraphicsItem::setTitleSize()
	{
		QFontMetrics metrics(font_);
		title_size_.setWidth(metrics.width(title_) + 2 * title_border_size_ + 10);
		title_size_.setHeight(metrics.height() + 2 * title_border_size_);

	}

	void EcvResizableGraphicsItem::setHandelsRect()
	{

		handels_br_.setRect(data().rect().x() - handle_size_,data().rect().y() - handle_size_,data().rect().width() + handle_size_ * 2, 
			data().rect().height() + handle_size_ * 2);
	}

	void EcvResizableGraphicsItem::setTitleRect()
	{
		title_br_ = data().rect();
		if (title_visiable_) {
			title_br_.setWidth(title_size_.width());
			title_br_.setHeight(std::max(title_size_.height(), (qreal)handle_size_) + data().rect().height() + handle_size_);
		}

	}

	void EcvResizableGraphicsItem::drawHandles(QPainter *painter)
	{
		if (is_selectable_ && isSelected()) {
			//	painter->setCompositionMode(QPainter::RasterOp_SourceXorDestination);

			QPen temp_pen(pen());
			temp_pen.setWidth(1);
			painter->setPen(temp_pen);

			setHandlesPoints(data().rect());
			setHandlesRects();
			drawHandlesRect(painter);
		}

	}

	void EcvResizableGraphicsItem::drawTitle(QPainter *painter)
	{
		if (title_visiable_) {

			auto cur_brush = painter->brush();
			auto br = bounding_rect_;


			QBrush title_brush_(pen().color().dark(200));
			painter->setBrush(title_brush_);
			painter->setPen(pen());

			QRectF title_rect(br.x() + handle_size_, br.y() + br.height() - title_size_.height(), title_size_.width() - pen().width() * 2, title_size_.height() - pen().width() * 2);
			painter->drawRoundedRect(title_rect,1, 1);
			painter->drawText(QPointF(br.x() + handle_size_ * 2 + title_border_size_, br.y() + br.height() - (title_size_.height() / 4)), title_);
			painter->setBrush(cur_brush);

		}


	}

	QRectF EcvResizableGraphicsItem::getNormRect(const QPointF& pnt1, const QPointF& pnt2)
	{
		int x1 = pnt1.x();
		int y1 = pnt1.y();
		int x2 = pnt2.x();
		int y2 = pnt2.y();

		if (x2 < x1)
			std::swap(x1, x2);
		if (y2 < y1)
			std::swap(y1, y2);

		return QRectF(QPointF(x1, y1), QPointF(x2, y2));

	}

	void EcvResizableGraphicsItem::onRectChanged()
	{
		setRect();
	}


}//ecv

 

پاسخ داده شده بهمن 11, 1397 بوسیله ی مصطفی ساتکی (امتیاز 21,998)   24 34 75
انتخاب شد خرداد 22, 1399 بوسیله ی مصطفی ساتکی
+1 امتیاز

حالا از اون کلاس resizable ی که ایجاد کردیم میام shape مورد نظر خودمونو می سازیم من به طور مثال rectagle را به شما نشان میدم بقیه موارد را بر طبق همین بسازید.

#ifndef ECV_RESIZABLE_GRAPHICS_RECT
#define ECV_RESIZABLE_GRAPHICS_RECT

#include "viewlib_global.h"
#include "EcvResizableGraphicsItem.h"


namespace ecv {
	extern const int HANDLE_SIZE ;
	class VIEWLIB_EXPORT EcvResizableGraphicsRect : public EcvResizableGraphicsItem {
		
	public:
		
		EcvResizableGraphicsRect(const EcvObjectData& data, int handel_size = HANDLE_SIZE, QGraphicsItem *parent = 0);
		virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
		
	private:
		
	};

}//ecv
#endif //ECV_RESIZABLE_GRAPHICS_RECT

 

 


#include "EcvResizableGraphicsRect.h"
#include <QPainter>
namespace ecv {

	EcvResizableGraphicsRect::EcvResizableGraphicsRect(const EcvObjectData & data, int handel_size, QGraphicsItem * parent):
		EcvResizableGraphicsItem(data,handel_size,parent)
	{
	}
	void EcvResizableGraphicsRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /*= 0*/)
	{
		if (widget) {
			EcvResizableGraphicsItem::paint(painter, option, widget);

				
				painter->drawRect(data().rect());

			

			//for (size_t i = 0; i < 8; i++) {
			//	//painter->drawRect(getSqure(handle_points_[i]));
			//	int next_i = (i + 1) % 8;

			//	auto line = getLine(handle_points_[i], handle_points_[next_i], handle_size_);
			//	painter->drawLine(line);
			//}

			
		}
	

	}
}//ecv

 

پاسخ داده شده بهمن 11, 1397 بوسیله ی مصطفی ساتکی (امتیاز 21,998)   24 34 75
با تشکر از آقای ساتکی
اگر اجازه بدهید کدهای شما را بررسی کنم و اگر سوالی بود ( و شما هم محبت کنید) مجددا از شما کمک بگیرم.
با تشکر مجدد
...