Qt學習之路 54 自定義拖放資料物件

2021-09-30 06:01:12 字數 3924 閱讀 1024

前面的例子都是使用的系統提供的拖放物件 qmimedata 進行拖放資料的儲存,比如使用 qmimedata::settext() 建立文字,使用 qmimedata::urls() 建立 url 物件。但是,如果你希望使用一些自定義的物件作為拖放資料,比如自定義類等等,單純使用 qmimedata 可能就沒有那麼容易了。為了實現這種操作,我們可以從下面三種實現方式中選擇乙個:

將自定義資料作為 qbytearray 物件,使用 qmimedata::setdata() 函式作為二進位制資料儲存到 qmimedata 中,然後使用 qmimedata::data() 讀取;

繼承 qmimedata,重寫其中的 formats() 和 retrievedata() 函式操作自定義資料;

如果拖放操作僅僅發生在同乙個應用程式,可以直接繼承 qmimedata,然後使用任意合適的資料結構進行儲存。

第一種方法不需要繼承任何類,但是有一些侷限:即是拖放不會發生,我們也必須將自定義的資料物件轉換成 qbytearray 物件;如果你希望支援很多種拖放的資料,那麼每種型別的資料都必須使用乙個 qmimedata 類,這可能會導致類**;如果資料很大的話,這種方式可能會降低系統的可維護性。然而,後兩種實現方式就不會有這些問題,或者說是能夠減小這種問題,並且能夠讓我們有完全控制權。

我們先來看乙個應用,使用 qtablewidget 來進行拖放操作,拖放的型別包括 plain/text,plain/html 和 plain/csv。如果使用第一種實現方法,我們的**將會如下所示:

void mytablewidget::mousemoveevent(qmouseevent *event)  

qtablewidget::mousemoveevent(event);  

}  void mytablewidget::performdrag()  

對於這段**,我們應該已經很容易的理解:在 performdrag() 函式中,我們呼叫 qmimedata 的 settext() 和 sethtml() 函式儲存 plain/text 和 plain/html 資料,使用 setdata() 將 text/csv 型別的資料作為二進位制 qbytearray 型別儲存。

qstring mytablewidget::tocsv(const qstring &plaintext)  

qstring mytablewidget::tohtml(const qstring &plaintext)  

tocsv() 和 tohtml() 函式將資料取出並轉換成我們需要的 csv 和 html型別的資料。例如,下面的資料

red   green   blue

cyan yellow magenta

轉換成 csv 格式為:

"red", "green", "blue"

"cyan", "yellow", "magenta"

轉換成 html 格式為:

redgreenblue

cyanyellowmagenta

在放置的函式中我們像以前一樣使用:

void mytablewidget::dropevent(qdropevent *event)  

else

if (event->mimedata()->hasformat("text/plain"))   

}

雖然我們接受三種資料型別,但是在這個函式中我們只接受兩種型別。至於 html 型別,我們希望如果使用者將 qtablewidget 的資料拖到乙個 html 編輯器,那麼它就會自動轉換成 html **,但是我們不計畫支援將外部的 html **拖放到 qtablewidget 上。為了讓這段**能夠工作,我們需要在建構函式中設定 setacceptdrops(true) 和 setselectionmode(contiguousselection)。

好了,上面就是我們所說的第一種方式的實現。這裡並沒有給出完整的實現**,大家可以根據需要自己實現一下試試。下面我們將按照第二種方法重新實現這個需求。

class tablemimedata : public qmimedata  

qtablewidgetselectionrange range() const   

qstringlist formats() const;  

protected:  

qvariant retrievedata(const qstring &format,  

qvariant::type preferredtype) const;  

private:  

static qstring tohtml(const qstring &plaintext);  

static qstring tocsv(const qstring &plaintext);  

qstring text(int row, int column) const;  

qstring rangeasplaintext() const;  

const qtablewidget *mytablewidget;  

qtablewidgetselectionrange myrange;  

qstringlist myformats;  

};  

為了避免儲存具體的資料,我們儲存 table 和選擇區域的座標的指標。

tablemimedata::tablemimedata(const qtablewidget *tablewidget,  

const qtablewidgetselectionrange &range)  

qstringlist tablemimedata::formats() const

建構函式中,我們對私有變數進行初始化。formats() 函式返回的是被 mime 資料物件支援的資料型別列表。這個列表是沒有先後順序的,但是最佳實踐是將「最適合」的型別放在第一位。對於支援多種型別的應用程式而言,有時候會直接選用第乙個符合的型別儲存。

qvariant tablemimedata::retrievedata(const qstring &format,  

qvariant::type preferredtype) const

else

if (format == "text/csv")  else

if (format == "text/html")  else   

}

函式 retrievedata() 將給出的 mime 型別作為 qvariant 返回。引數 format 的值通常是 formats() 函式返回值之一,但是我們並不能假定一定是這個值之一,因為並不是所有的應用程式都會通過 formats() 函式檢查 mime 型別。一些返回函式,比如 text(), html(), urls(), imagedata(), colordata() 和 data() 實際上都是在 qmimedata 的 retrievedata() 函式中實現的。第二個引數 preferredtype 給出我們應該在 qvariant 中儲存哪種型別的資料。在這裡,我們簡單的將其忽略了,並且在 else 語句中,我們假定 qmimedata 會自動將其轉換成所需要的型別。

void mytablewidget::dropevent(qdropevent *event)  

else

if (event->mimedata()->hasformat("text/csv"))  else

if (event->mimedata()->hasformat("text/plain"))   

qtablewidget::mousemoveevent(event);  

}

在放置的函式中,我們需要按照我們自己定義的資料型別進行選擇。我們使用 qobject_cast 巨集進行型別轉換。如果成功,說明資料來自同一應用程式,因此我們直接設定 qtablewidget 相關 資料,如果轉換失敗,我們則使用一般的處理方式。

Qt學習之路之自定義訊息框

qt自己也有很多的訊息框,這時,如果這些訊息框都不能滿足開發的需求,qt還允許自定義訊息框。包括訊息框的圖示,按鈕和訊息框顯示的內容都可以根據需求設定。不廢話了,下面給出個簡單的例子 custmsg widget.h ifndef custmsgwidget h define custmsgwidg...

QT學習之自定義訊號

我們先建立乙個msignal工程專案,並在ui介面拖入乙個按鈕 然後轉到槽函式選擇clicked 如圖 在類中定義乙個訊號 signals void msignal 在類中定義乙個print的槽函式,並實現 void msignal print connect this,msignal msigna...

Qt自定義資料型別

qt框架下開發時,建立乙個自定義型別,需要確保建立的這個自定義型別符合qmetatype規定的所有要求,即它必須滿足以下幾個條件 下面的message類的定義滿足這些條件,可以定義成乙個新的資料型別 class message q declare metatype message 這個類還提供了乙個...