1. 程式人生 > >《快速掌握PyQt5》第十八章 拖放與剪貼簿

《快速掌握PyQt5》第十八章 拖放與剪貼簿

第十八章 拖放與剪貼簿

拖放和剪貼簿的功能原理基礎都是QMimeData類,所以這裡我們將這兩種放在一起講。QMimeData當然與MIME相關:MIME是描述訊息內容型別的因特網標準,可以簡單理解為對副檔名的詳細解釋,通過該解釋,程式就可以知道應該以何種方式處理該資料。每個MIME型別由兩部分組成,前面是資料的大類別,後面定義具體的種類,例如副檔名為.png的MIME型別為image/png;而QMimeData則給記錄自身MIME型別的資料提供了一個容器,用於專門處理MIME型別資料。

詳細的MIME型別請參考:MIME參考手冊

針對常見的MIME型別,QMimeData類提供了很方便的函式用於處理MIME型別資料:

18.1 拖放

拖放分為拖動和放下兩個動作,它們涉及到以下事件:

  • DragEnterEvent: 所拖動目標進入接收該事件的視窗或控制元件時觸發;
  • DragMoveEvent: 所拖動目標進入視窗或控制元件後,繼續被拖動時觸發;
  • DragLeaveEvent: 所拖動目標離開視窗或控制元件時觸發;
  • DropEvent: 所拖動目標被放下時觸發。

下面我們完成一個可以實現拖放txt檔案並讀取的小程式:

import sys
from PyQt5.QtWidgets import QApplication, QTextBrowser


class Demo(QTextBrowser):                                           # 1
    def __init__(self):
        super(Demo, self).__init__()
        self.setAcceptDrops(True)                                   # 2

    def dragEnterEvent(self, QDragEnterEvent):                      # 3
        print('Drag Enter')
        if QDragEnterEvent.mimeData().hasText():
            QDragEnterEvent.acceptProposedAction()

    def dragMoveEvent(self, QDragMoveEvent):                        # 4
        print('Drag Move')

    def dragLeaveEvent(self, QDragLeaveEvent):                      # 5
        print('Drag Leave')

    def dropEvent(self, QDropEvent):                                # 6
        print('Drag Drop')
        # MacOS
        txt_path = QDropEvent.mimeData().text().replace('file:///', '/')

        # Linux
        # txt_path = QDropEvent.mimeData().text().replace('file:///', '/').strip()

        # Windows
        # txt_path = QDropEvent.mimeData().text().replace('file:///', '')

        with open(txt_path, 'r') as f:
            self.setText(f.read())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

1. 繼承QTextBrowser,也就是說下面來實現該控制元件的拖放事件響應函式;

2. setAcceptDrops(True)方法可以讓該控制元件接收放下(Drop)事件;

3. 當拖動目標進入QTextBrowser的那一剎那,觸發dragEnterEvent事件,在該響應函式中,我們先判斷所拖動目標的MIME型別是否為text/plain,若是的話則呼叫acceptProposedAction()方法來表明可以在QTextBrowser上進行拖放動作;

4. 當目標進入窗體後,如果不放下而是繼續移動的話,則會觸發dragMoveEvent事件;

5. 將進入控制元件後的目標再次拖動到控制元件之外時,就會觸發dragLeaveEvent()事件;

6. 將目標在QTextBrowser中放下後,我們先通過QDropEvent.mimeData().text()方法獲取到該檔案的URI路徑,replace()方法將其中的file:///替換為/,這樣得到的值才是我們想要的本地檔案路徑。最後開啟my.txt檔案進行讀取,並用setText()方法將QTextBrowser的文字設為該my.txt的內容。

注:不同系統使用的路徑寫法也不同,請注意區分。在Linux上獲取的路徑中存在'\r\n'所以用strip()去除。

執行截圖如下,筆者將放在桌面的my.txt檔案拖到程式中,程式顯示my.txt檔案的內容:

18.2 剪貼簿

通常我們在Windows或Linux上使用複製都是按ctrl+c然後按ctrl+v進行貼上(Mac上為command+c和command+v),這其中就涉及到了剪貼簿,當進行復制時,其實是將要複製的內容放到了一個無形的剪貼簿上,要貼上時,再將剪貼簿上的內容放到介面上。

當我們瀏覽CSDN部落格,在碰到程式碼想要複製的時候,右上角會出現一個複製按鈕,點選後就可以將所有程式碼複製到剪貼簿上:

我們用PyQt5來實現下類似功能,程式碼如下:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit, QTextBrowser, QPushButton, QGridLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.text_edit = QTextEdit(self)
        self.text_browser = QTextBrowser(self)
        
        self.clipboard = QApplication.clipboard()                               # 1
        self.clipboard.dataChanged.connect(lambda: print('Data Changed'))    

        self.copy_btn = QPushButton('Copy', self)                               # 2
        self.copy_btn.clicked.connect(self.copy_func)               

        self.paste_btn = QPushButton('Paste', self)                             # 3
        self.paste_btn.clicked.connect(self.paste_func)

        self.g_layout = QGridLayout()
        self.g_layout.addWidget(self.text_edit, 0, 0, 1, 1)
        self.g_layout.addWidget(self.text_browser, 0, 1, 1, 1)
        self.g_layout.addWidget(self.copy_btn, 1, 0, 1, 1)
        self.g_layout.addWidget(self.paste_btn, 1, 1, 1, 1)
        self.setLayout(self.g_layout)

    def copy_func(self):
        self.clipboard.setText(self.text_edit.toPlainText())

    def paste_func(self):
        self.text_browser.setText(self.clipboard.text())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

1. 例項化一個剪貼簿,並將其dataChanged訊號和列印函式連線起來。每當剪貼簿內容發生變化的時候,都會觸發dataChanged訊號。在這裡也就是說每當發生變化,控制檯都會打印出Data Changed;

2. 當點選copy_btn後,槽函式copy_func()就會啟動:

def copy_func(self):
    self.clipboard.setText(self.text_edit.toPlainText())

在槽函式中,我們將text_edit中的文字獲取過來並通過setText()方法將其設定為剪貼簿的文字;

3. 當點選paste_btn後,槽函式paste_func()啟動:

def paste_func(self):
    self.text_browser.setText(self.clipboard.text())

在槽函式中,我們將text_browser的文字設為剪貼簿的文字。當然該槽函式還有另一種實現方法:

def paste_func(self):
    mime = self.clipboard.mimeData()
    if mime.hasText():
        self.text_browser.setText(mime.text())

首先通過mimeData()方法獲取剪貼簿內容的MIME型別,然後判斷mime型別是否為text/plain,是的話則通過text()方法獲取,並設為text_browser文字。

當然以上只是針對文字內容,當然還可以複製圖片等檔案,而剪貼簿當然也有相應的方法,以下列出常用的:

方法 解釋
clear() 清空剪貼簿內容
mimeData() 獲取剪貼簿上的MIME型別資料
setMimeData() 將MIME型別資料放到剪貼簿中
pixmap() 獲取剪貼簿上的QPixmap型別資料
setPixmap() 將QPixmap型別資料放到剪貼簿中
image() 獲取剪貼簿上的QImage型別資料
setImage() 將QImage型別資料放到剪貼簿中
text() 獲取剪貼簿上的文字
setText() 將文字放到剪貼簿中

執行截圖如下,在左側出入文字,點選Copy,再點選Paste,右側顯示相應文字:

18.3 小結

1. 使用QMimeData類來處理MIME型別資料;

1. 拖放事件一共有四種,分別在拖動目標進入視窗或部件時、目標進入後繼續被拖動時、目標離開視窗或控制元件時以及目標被放下時;

2. 剪貼簿的內容發生變化的話,則會觸發dataChanged訊號。剪貼簿針對不同資料型別有相應獲取和設定的方法。

----------------------------------------------------------------------

喜歡的小夥伴可以加入這個Python QQ交流群一起學習:820934083