首頁 > 軟體

Qt實現拖動單個控制元件移動的範例程式碼

2022-06-21 14:10:04

做慣了靜態圖,今天來搞一搞動態圖吧,首先來個最基礎的功能:如果讓一個控制元件拖動起來。

展示效果:

按照以往簡單的做法,使用mouseMoveEvent、mousePressEvent、mouseReleaseEvent也是可以實現的。這是最基礎的移動做法。

今天,不使用那種簡單的做法,採用Qt一種特有的拖動方法來實現!

使用QDropEvent實現拖拽事件。

實現控制元件拖拽的流程,如下:

1:建立一個控制元件,這裡使用QLabel控制元件。

2:選中需要拖拽的控制元件

3:重寫拖拽事件。

根據上述操作流程,來實現一個控制元件的拖拽吧!

1.設定視窗拖拽屬性

在Qt中,預設是不響應拖拽訊息的,這跟mouseMoveEvent訊息預設不響應是一樣的,必須明確呼叫,告訴視窗,需要響應此訊息。

this->setAcceptDrops(true);

2.建立初始控制元件

建立一個初始控制元件,用於初始拖動使用。

QLabel *labIcon = new QLabel(this);
labIcon->setText("");
labIcon->setPixmap(QPixmap(":/QDragSingleLabel/image/boat.png"));
labIcon->move(10, 10);
labIcon->show();
labIcon->setAttribute(Qt::WA_DeleteOnClose);

偷懶起見,對QLabel控制元件設定了視窗關閉銷燬的功能,很是方便。

3.選中控制元件進行拖動

滑鼠在控制元件上按下,開始做拖動操作;當滑鼠擡起時,不進行拖動操作。

3.1響應mousePressEvent事件

需要知道滑鼠是否點選到控制元件上

這裡需要特殊注意的是:QLabel是一個靜態控制元件,正常情況下是不會響應滑鼠選中效果的。

此時,需要響應QWidget滑鼠按下的事件,將滑鼠點選的點轉換成是否選中QLabel控制元件,側面實現資料點選控制元件效果。

QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
if(!child)
{
    //不是QLabel控制元件,不進行處理
    return;
}

QWidget::childAt(const QPoint& p)const;說明:返回視窗小部件自身座標系統中p點處的可見子視窗小部件。

查詢到有效QLabel指標後,建立一個可儲存在剪貼簿中的資訊,通過拖放機制進行傳輸的。這裡採用:QMimeData類實現。

優勢該類可以確保資訊在應用程式之間安全傳輸,並且可以在相同的應用程式內複製。

建立該類並將QLabel中的資料傳入到類中,用於做拖拽使用。

QMimeData *mimeData = new QMimeData;
mimeData->setData(qsEnum, itemData);

設定資料。

qsEnum:型別:QString。

在這裡可以設定任意字串,只要保證在拖拽訊息時用的一個字串就可以。為了方便統一,將該字串做了統一設定。

const QString qsEnum = "zhongGuoHaoGongMin";//自定義資料型別

itemData:型別:QByteArray。

對QMimeData傳入的資料,這裡存放了QLabel的圖片以及顯示位置。

QPixmap pixmap = *child->pixmap();
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
dataStream << pixmap << QPoint(event->pos() - child->pos());

上述內容準備就緒後,建立拖拽類,用於資料拖拽。

QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setPixmap(pixmap);
drag->setHotSpot(event->pos() - child->pos());

將資料傳遞給拖動物件,設定將在操作期間與遊標一起顯示的畫素圖,並定義一個熱點的位置,該熱點將畫素圖的位置置於遊標之下。

繪製拖動的位置,這裡採用了QPainter繪製機制

QPixmap tempPixmap = pixmap;
QPainter painter;
painter.begin(&tempPixmap);
painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127));
painter.end();
	
child->setPixmap(tempPixmap);

開始拖動操作,呼叫QDrag::exec();

3.2判斷控制元件拖動

目前只有一個控制元件可以拖動,那麼,當建立多個拖動控制元件時,該如何判斷要拖動哪個呢?

這時候,在建立QMimeData傳入的自定義資料型別就起到作用了。

當資料型別是qsEnum時,進行判斷,如果不是,不進行判斷。

if (event->mimeData()->hasFormat(qsEnum))
{
    //進行判斷
}
else
{
    event->ingnore(); //忽略判斷
}

事件:dragEnterEvent、dragMoveEvent、dropEvent都需要這樣判斷。

3.3事件處理

當前是匹配的自定義資料型別時,並且是該資源是,接受拖動進入事件,並設定當前為拖動事件。

if (event->source() == this)
{
	event->setDropAction(Qt::MoveAction);
	event->accept();
}

否則設定執行操作並接收該事件

else
{
    event->acceptProposedAction();
}

3.4結束拖動

結束拖動,響應事件:virtual void dropEvent(QDropEvent *event)override;

除了處理操作3中的事件處理,還需要當滑鼠結束操作時,需要在新的位置上重新建立QLabel控制元件。並將滑鼠按下時建立的QMimeData資料獲取出來,顯示到新建立的QLabel控制元件上。

QByteArray itemData = event->mimeData()->data(qsEnum);
QDataStream dataStream(&itemData, QIODevice::ReadOnly);
QPixmap pixmap;
QPoint offset;
dataStream >> pixmap >> offset;

QLabel *newIcon = new QLabel(this);
newIcon->setPixmap(pixmap);
newIcon->move(event->pos() - offset);
newIcon->show();
newIcon->setAttribute(Qt::WA_DeleteOnClose);

dropEvent訊息是什麼時候被觸發呢?

當滑鼠左鍵彈起時,說明結束了控制元件拖動事件,需要呼叫dropEvent並重新建立控制元件,顯示新位置。

Qt::DropAction n = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
if (n == Qt::MoveAction)
{
    //結束操作
    child->close();
}
else
{
    //繼續拖動控制元件,實時顯示新位置
    child->show();
    child->setPixmap(pixmap);
}

到此這篇關於Qt實現拖動單個控制元件移動的範例程式碼的文章就介紹到這了,更多相關Qt拖動控制元件移動內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com