99久久全国免费观看_国产一区二区三区四区五区VM_久久www人成免费看片中文_国产高清在线a视频大全_深夜福利www_日韩一级成人av

QtQuick(Qml)制作Qml插件(自定義控件)

希望制作個自己的自定義控件庫,最好封裝成dll,這樣每次調用和使用方便,還可以不斷的積累,生成一套自己喜歡的UI,所以到處找封裝方法,雖然最后也沒有成功,但是還是記錄一下,方便后續查看,也希望幫到需要的人。

簡要介紹一下 Qt 和 QML 的插件系統,并用幾個簡單的示例介紹 QML 的幾種插件的創建方法。由于時間所限,有些地方可能講述的不是很到位,歡迎溝通指正。

1. 插件概述

1.1. 什么是插件

插件(Plug-in,又稱 addin、add-in、addon 或 add-on,又譯外掛)是一種遵循一定規范的應用程序接口編寫出來的程序。其只能運行在程序規定的系統平臺下(可能同時支持多個平臺),而不能脫離指定的系統單獨運行。

1.2. 插件系統組成

      主系統 —— 通過插件管理器加載插件,并創建插件對象。一旦插件對象被創建,主系統就會獲得插件相應的指針或引用,它可以像任何其他對象一樣使用。

      插件管理器 —— 用于管理插件的生命周期,并將其暴露給主系統使用。它負責查找并加載插件,初始化它們,并且能夠進行卸載。它還應該讓主系統迭代加載的插件或注冊的插件對象。

      插件 —— 插件本身應符合插件管理器的協議,并提供符合主系統期望的對象。

1.3. 為什么要使用插件

    為了將模塊從框架中剝離出來,降低框架和功能間的耦合度,功能的實現作為模塊單獨開發,而不是功能實現相關的復雜代碼與框架揉合在一起。

    解決需求不斷變化的軟件設計場景。

    面向未來,可以通過插件來擴展應用程序的功能(例如 vscode、qtcreator 的主流 IDE 的插件)。

2. 插件和動態庫區別

2.1. 使用場景

    動態庫:解決靜態庫編譯時鏈接符號表導致的程序占用空間大,庫升級時相關可執行程序需要重新編譯等問題。

    插件:對于軟件使用的不同場景,功能有所區別時,有選擇定制和加載不同的插件,另外插件能降低模塊和主功能間的耦合關系。

2.2. 生命周期

    動態庫:程序啟動時加載,程序運行時必須保證 .dll/.so 存在,否則無法正常啟動。

    插件:程序運行時到需要的時候加載,程序運行時如果 .dll/.so 不存在,也可以正常啟動,只是相應插件的功能無法正常加載和使用而已。

2.3. 耦合度

     動態庫:編譯時必須指定動態庫依賴關系。

     插件:編譯時主程序不知道插件的存在。

3. Qt 中插件的分類

3.1. 開源的純 QML 插件(qmldir)

3.1.1. 創建不帶 url 前綴的 QML 插件

創建目錄 MyPlugins(本例中我們在完整目錄 /home/LiuPC/TestQMLPlugin/ 下創建),此目錄是自己定義的,名稱也可以隨意定義,但是這個目錄名稱會作為模塊名稱。

在 MyPlugins 目錄中創建和功能相關的 qml 文件(MyRect.qml):

import QtQuick 2.12
import QtQuick.Controls 2.12

Item {
    anchors.centerIn: parent
    Rectangle{
        width: 100
        height: 100
        color: "teal"
        Label {
            width: 50
            height: 20
            text: qsTr("TestRect")
        }
    }
}

在 qml 同級目錄下創建一個名為 qmldir 的文件,并添加如下內容:

module MyExamplePlugins
TestRect 1.0 MyRect.qml

3.1.2. 創建帶 url 前綴的 QML 插件

創建目錄 NewPlugins (本例中我們在完整目錄 /home/dongshuang/TestQMLPlugin/com/mycompany/test/ 下創建),此目錄是自己定義的,名稱也可以隨意定義,但是這個目錄名稱會作為模塊名稱。

在 NewPlugins 目錄中創建和功能相關的 qml 文件(NewRect.qml):

import QtQuick 2.12
import QtQuick.Controls 2.12

Item {
    Rectangle{
        width: 100
        height: 100
        color: "teal"
        Label {
            width: 50
            height: 20
            text: qsTr("NewRect")
        }
    }
}

在 qml 同級目錄下創建一個名為 qmldir 的文件,并添加如下內容:

module NewExamplePlugins
NewRect 1.0 NewRect.qml

3.1.3. 使用 QML 插件

在 pro 文件中添加:

# 環境變量的設置只是為了讓 ide 能夠找到插件位置,進行高亮,自動補全等
QML_IMPORT_PATH += /home/dongshuang/TestQMLPlugin

在 main 函數中添加如下代碼即可:

// 此處才是真正告訴程序去哪里加載插件 
engine.addImportPath("/home/dongshuang/TestQMLPlugin");

在 main.qml 中的使用實例:

import QtQuick 2.12
import QtQuick.Window 2.12

import MyPlugins 1.0
import com.mycompany.test.NewPlugins 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    TestRect {
    }

    NewRect {
    }
}

以上插件實際上是將源碼目錄直接打包發布的過程。

3.2. 隱藏源碼的 QML 插件

在實際開發中,我們更多的需要將源碼封裝打包,而不對外提供源碼。那又應該如何處理呢?

此時就需要借助 QQmlExtensionPlugin 這個類,以及 Qt 的資源管理系統了。下面我們用一個簡單的實例來講解如何實現。

3.2.1. 創建插件工程

首先,我們使用 Qt Creator 的新建一工程向導,創建一個 “Library > Qt Quick 2 Extension Plugin”插件工程。工程名字,我們可以叫 qrcmoduleplugin,Object class-name 可以隨便填,因為后面我們要去掉它。 URI 的名稱我們定為:com.mycompany.mymodule

3.2.2. 添加 qml 文件

之后我們在 qrcmoduleplugin.pro 文件所在的目錄創建三個 qml 文件:

ButtonBase.qml 文件的內容如下:

import QtQuick 2.12

MouseArea {
    property alias border: bgObj.border
    property alias color: bgObj.color
    property alias font: txtObj.font
    property alias text: txtObj.text
    property alias textAnchors: txtObj.anchors
    implicitWidth: 100
    implicitHeight: 100
    objectName: "ButtonBase"

    Rectangle {
        id: bgObj
        anchors.fill: parent
        color: "honeydew"
    }

    Text {
        id: txtObj
        text: qsTr("ButtonBase")
    }
}
ButtonQrc.qml 文件的內容如下:
import QtQuick 2.12

ButtonBase {
    color: "lightcoral"
    text: qsTr("ButtonQrc")
}

ButtonQrc2.qml 文件的內容如下:

import QtQuick 2.12

ButtonBase {
    color: "slateblue"
    text: qsTr("ButtonQrc2")
}

3.3.3. 創建資源文件

之后我們在 qrcmoduleplugin.pro 文件所在的目錄創建一個名為 qrcmoduleplugin.qrc 的資源文件,其內容如下:

<RCC>
    <qresource prefix="/component">
        <file>ButtonQrc.qml</file>
        <file>ButtonQrc2.qml</file>
        <file>ButtonBase.qml</file>
    </qresource>
</RCC>

3.2.4. 修改工程文件的內容

之后我們修改 qrcmoduleplugin.pro 文件,主要涉及到其中用數字標記的 5 處:

TEMPLATE = lib
TARGET = qrcmoduleplugin
QT += qml quick
CONFIG += plugin c++11

TARGET = $$qtLibraryTarget($$TARGET)
uri = com.mycompany.mymodule

# 1. 去掉其他的實現文件
SOURCES += \
        qrcmoduleplugin_plugin.cpp
# 2. 去掉其他的頭文件
HEADERS += \
        qrcmoduleplugin_plugin.h

DISTFILES = qmldir

!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
    copy_qmldir.target = $$OUT_PWD/qmldir
    copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
    copy_qmldir.commands = $(COPY_FILE) "$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)" "$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)"
    QMAKE_EXTRA_TARGETS += copy_qmldir
    PRE_TARGETDEPS += $$copy_qmldir.target
}

qmldir.files = qmldir
# 3. 增加安裝資源文件
qrc.files = qrcmoduleplugin.qrc
unix {
    installPath = $$[QT_INSTALL_QML]/$$replace(uri, \., /)
    qmldir.path = $$installPath
    target.path = $$installPath
    # 4.指定安裝資源文件位置
    qrc.path = $$installPath
    INSTALLS += target qmldir qrc
}

# 5. 添加資源文件到工程
RESOURCES += \
    qrcmoduleplugin.qrc

3.2.5. 修改插件類的實現

在這之后,我們修改 qrcmoduleplugin_plugin.cpp 文件,這里我們注冊了兩個 qml 文件,給外部使用,我們的 ButtonBase.qml 不會被暴露:

#include "qrcmoduleplugin_plugin.h"

#include <qqml.h>

void QrcmodulepluginPlugin::registerTypes(const char *uri)
{
    // @uri com.mycompany.mymodule
    qmlRegisterType(QUrl("qrc:/component/ButtonQrc.qml"), uri, 1, 0, "ButtonQrc");
    qmlRegisterType(QUrl("qrc:/component/ButtonQrc2.qml"), uri, 2, 0, "ButtonQrc");
}

3.2.6. 拷貝插件資源到指定目錄

之后,我們構建工程,完成之后,就可以在構建目錄下生成一系列的文件,我們只要拷貝 libqrcmoduleplugin.so  qmldir 這兩個文件到目錄 /home/dongshuang/TestQMLPlugin/com/mycompany/mymodule 中即可,我們可以看到這個目錄結構其實是和我們之前定義的 URI (我們的定義為:com.mycompany.mymodule)有一定的關聯的。而 /home/dongshuang/TestQMLPlugin/ 這個目錄是上節中我們用到的目錄,沒錯,我們之后還會使用上節介紹的例子進行測試。

3.2.7. 生成 .qmltypes 文件

在命令行運行如下兩條命令:

$ cd /home/dongshuang/TestQMLPlugin
$ qmlplugindump com.mycompany.mymodule 1.0 /home/dongshuang/TestQMLPlugin > /home/dongshuang/TestQMLPlugin/com/mycompany/mymodule/mymodule.qmltypes

注:如果 qmlplugindump 找不到,需要添加 Qt 的環境變量。

之后,我們就可以在 /home/dongshuang/TestQMLPlugin/com/mycompany/mymodule 目錄中生成 mymodule.qmltypes 文件:

import QtQuick.tooling 1.2

// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
// 'qmlplugindump com.mycompany.mymodule 1.0 /home/dongshuang/TestQMLPlugin'

Module {
    dependencies: ["QtQuick 2.12"]
    Component {
        prototype: "QQuickMouseArea"
        name: "ButtonQrc 1.0"
        exports: ["ButtonQrc 1.0"]
        exportMetaObjectRevisions: [0]
        isComposite: true
        defaultProperty: "data"
        Property { name: "border"; type: "QQuickPen"; isReadonly: true; isPointer: true }
        Property { name: "color"; type: "QColor" }
        Property { name: "font"; type: "QFont" }
        Property { name: "text"; type: "string" }
        Property { name: "textAnchors"; type: "QQuickAnchors"; isReadonly: true; isPointer: true }
    }
    Component {
        prototype: "QQuickMouseArea"
        name: "ButtonQrc 2.0"
        exports: ["ButtonQrc 2.0"]
        exportMetaObjectRevisions: [0]
        isComposite: true
        defaultProperty: "data"
        Property { name: "border"; type: "QQuickPen"; isReadonly: true; isPointer: true }
        Property { name: "color"; type: "QColor" }
        Property { name: "font"; type: "QFont" }
        Property { name: "text"; type: "string" }
        Property { name: "textAnchors"; type: "QQuickAnchors"; isReadonly: true; isPointer: true }
    }
}

3.2.8. 修改 qmldir 文件

之后我們修改 /home/dongshuang/TestQMLPlugin/com/mycompany/mymodule 目錄中的 qmldir 文件為如下內容:

module com.mycompany.mymodule
plugin qrcmoduleplugin
typeinfo mymodule.qmltypes

3.2.9. 使用示例

之后,我們修改上節中的示例,將 main.qml 改成如下:

import QtQuick 2.12
import QtQuick.Window 2.12

import MyPlugins 1.0
import com.mycompany.mymodule 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    TestRect {
    }

    ButtonQrc {
        anchors.centerIn: parent
    }
}

上面的代碼我們可以再試下不改變別的內容,而只是把 import com.mycompany.mymodule 1.0 這一句中的 1.0 改成 2.0,再運行試試效果。這也是 QML 插件處理不同版本的插件的測試。

3.3. 包含 C++ 的 QML 插件

現實開發中我們的 QML 插件,可能需要 C++ 的功能的支持,因此包含 C++ 的 QML 插件也是需要我們學習和掌握的。有了上面的兩節示例的基礎,其實 C++ 的部分看起來就很簡單了,這部分大家可以直接參考 QML Plugin Example 這個示例。

3.3.1. 創建 MinuteTimer 類

MinuteTimer 類主要作用是創建 QBasicTimer 對象,并啟動 QBasicTimer 的 start 方法,之后監聽 QBasicTimer 在 time out 之后發出的 timerEvent 事件來產生時間變化的信號,同時計算和更新當前的 hour 和 minute 值。

class MinuteTimer : public QObject
{
    Q_OBJECT
public:
    MinuteTimer(QObject *parent) : QObject(parent)
    {
    }

    void start()
    {
        if (!timer.isActive()) {
            time = QTime::currentTime();
            timer.start(60000-time.second()*1000, this);
        }
    }

    void stop()
    {
        timer.stop();
    }

    int hour() const { return time.hour(); }
    int minute() const { return time.minute(); }

signals:
    void timeChanged();

protected:
    void timerEvent(QTimerEvent *) override
    {
        QTime now = QTime::currentTime();
        if (now.second() == 59 && now.minute() == time.minute() && now.hour() == time.hour()) {
            // just missed time tick over, force it, wait extra 0.5 seconds
            time = time.addSecs(60);
            timer.start(60500, this);
        } else {
            time = now;
            timer.start(60000-time.second()*1000, this);
        }
        emit timeChanged();
    }

private:
    QTime time;
    QBasicTimer timer;
};

上述代碼使用了 QBasicTimer 這個類,該類是 Qt 在內部使用的一個快速、輕量級的低級類。如果希望在應用程序中使用計時器,我們建議使用更高級別的 QTimer 類而不是這個類。注意,這個計時器是一個重復計時器,除非調用 stop() 函數,否則它將發送后續計時器事件。

3.3.2. 創建 TimeModel 類

下面是創建用于暴露給 QML 使用的 TimeModel 類,它主要是對 MinuteTimer 類進行單利化的管理和封裝,畢竟時間應該是一樣的,對吧。其代碼如下:

class TimeModel : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int hour READ hour NOTIFY timeChanged)
    Q_PROPERTY(int minute READ minute NOTIFY timeChanged)

public:
    TimeModel(QObject *parent=nullptr) : QObject(parent)
    {
        if (++instances == 1) {
            if (!timer)
                timer = new MinuteTimer(QCoreApplication::instance());
            connect(timer, &MinuteTimer::timeChanged, this, &TimeModel::timeChanged);
            timer->start();
        }
    }

    ~TimeModel() override
    {
        if (--instances == 0) {
            timer->stop();
        }
    }

    int minute() const { return timer->minute(); }
    int hour() const { return timer->hour(); }

signals:
    void timeChanged();

private:
    QTime t;
    static MinuteTimer *timer;
    static int instances;
};

int TimeModel::instances=0;
MinuteTimer *TimeModel::timer=nullptr;

3.3.3. 注冊 TimeModel 類到 QML 插件

在接下來,就是將 TimeModel 類注冊給 QML 插件:

class QExampleQmlPlugin : public QQmlExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)

public:
    void registerTypes(const char *uri) override
    {
        Q_ASSERT(uri == QLatin1String("TimeExample"));
        qmlRegisterType<TimeModel>(uri, 1, 0, "Time");
    }
};

這段代碼中,作者沒有使用 C++ 中的類名,而是給暴露到 QML 插件中的類另起了一個簡單和一目了然的名字 Time。

3.3.4. 改造示例內容

接下來我們像上節一樣改造一下這個示例,使其 qml 文件和圖片資源都能一起發布到 libqmlqtimeexampleplugin.so 文件中,而不是獨立的文件。

3.3.4.1. 添加 res.qrc 文件在 pro 目錄

res.qrc 的內容如下:

<RCC>
    <qresource prefix="/">
        <file>imports/TimeExample/center.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20</file>
        <file>imports/TimeExample/clock.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20</file>
        <file>imports/TimeExample/Clock.qml</file>
        <file>imports/TimeExample/hour.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20</file>
        <file>imports/TimeExample/minute.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20</file>
    </qresource>
</RCC>

3.3.4.2. 修改 qmlextensionplugins.pro 文件的內容

將其改成如下的樣子:

TEMPLATE = lib
CONFIG += plugin
QT += qml

DESTDIR = imports/TimeExample
TARGET  = qmlqtimeexampleplugin

SOURCES += plugin.cpp

qrc.files = qrcmoduleplugin.qrc

qml.files = plugins.qml \
    imports/TimeExample/qmldir
qml.path += $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins
target.path += $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins/imports/TimeExample
qrc.path += $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins/res.qrc

INSTALLS += target qml qrc

CONFIG += install_ok  # Do not cargo-cult this!

RESOURCES += \
    res.qrc

3.3.4.3. 修改 plugin.cpp 文件中的 QExampleQmlPlugin 實現

將其改成如下形式:

class QExampleQmlPlugin : public QQmlExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)

public:
    void registerTypes(const char *uri) override
    {
        Q_ASSERT(uri == QLatin1String("TimeExample"));
        qmlRegisterType<TimeModel>(uri, 1, 0, "Time");
        qmlRegisterType(QUrl("qrc:/imports/TimeExample/Clock.qml"), uri, 1, 0, "Clock");
    }
};

3.3.4.4 修改 Clock.qml 文件的內容

接下來我們修改名叫 Clock.qml 的 QML 文件,它主要用于時間顯示,其內部主要是使用 SpringAnimation 實現的時鐘,我們的修改點主要是圖片的資源改為使用 qrc 文件中的資源:

import QtQuick 2.12

Rectangle {
    id: clock
    width: 200; height: 200; color: "gray"

    property alias city: cityLabel.text
    property variant hours
    property variant minutes
    property variant shift : 0

    Image { id: background; source: "qrc:/imports/TimeExample/clock.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20" }

    Image {
        x: 92.5; y: 27
        source: "qrc:/imports/TimeExample/hour.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20"
        transform: Rotation {
            id: hourRotation
            origin.x: 7.5; origin.y: 73;
            angle: (clock.hours * 30) + (clock.minutes * 0.5)
            Behavior on angle {
                SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 }
            }
        }
    }

    Image {
        x: 93.5; y: 17
        source: "qrc:/imports/TimeExample/minute.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20"
        transform: Rotation {
            id: minuteRotation
            origin.x: 6.5; origin.y: 83;
            angle: clock.minutes * 6
            Behavior on angle {
                SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 }
            }
        }
    }

    Image {
        anchors.centerIn: background; source: "qrc:/imports/TimeExample/center.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20"
    }

    Text {
        id: cityLabel; font.bold: true; font.pixelSize: 14; y:200; color: "white"
        anchors.horizontalCenter: parent.horizontalCenter
    }
}

3.3.4.5 修改 qmldir 文件的內容

修改工程目錄中的 qmldir 文件的內容為:

module TimeExample
plugin qmlqtimeexampleplugin

3.3.5. 構建并拷貝資源到指定目錄

接下來構建項目,然后找到構建目錄,將其中的 libqmlqtimeexampleplugin.so 文件。以及工程目錄中的 qmldir 文件拷貝。然后復制到 /home/dongshuang/TestQMLPlugin/TimeExample 這個目錄。

3.3.6. 接著使用 3.2 節中的項目中 main.qml 進行測試

修改 main.qml 的內容,其內容其實是參考示例代碼中的 plugins.qml 文件的內容:

import TimeExample 1.0 // import types from the plugin

Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)

    Time { // this class is defined in C++ (plugin.cpp)
        id: time
    }

    hours: time.hour
    minutes: time.minute

}

我們將 main.qml 的內容改為:

import QtQuick 2.12
import QtQuick.Window 2.12

import MyPlugins 1.0
import TimeExample 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    TestRect {
    }

    Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
        anchors.centerIn: parent
        Time { // this class is defined in C++ (plugin.cpp)
            id: time
        }

        hours: time.hour
        minutes: time.minute
    }
}

至此,我們完成了在 QML 插件中注冊 C++ 類插件的功能,以及將 qml 文件和圖片資源文件一起打包發布的示例。

聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 5
收藏 3
關注 19
成為作者 賺取收益
全部留言
0/200
  • 十三貓 2021-06-16 18:28
    學到了很多,感謝大神分享
    回復
主站蜘蛛池模板: 中国美女a级毛片 | 91视频九色欧美 | 国产av无码一区二区二三区j | 人与禽性视频7777 | 国产欧美一区二区三区国产幕精品 | 成人vagaa免费观看视频 | 综合久久国产 | 欧美少妇在线观看 | 中文字幕一区在线观看视频 | 日本一区高清 | 成人免费在线网站 | 91久久精品国产91久久性色也 | av高清在线观看 | 免费AV一区二区三区3ATV | 中文人妻无码一区二区三区 | 亚洲а∨天堂久久精品2021 | 18禁止导深夜福利备好纸巾 | 少妇被粗大的猛烈进出动态图片 | 成人做爰69片免网站 | 国产一区二区精品久 | 在线A亚洲老鸭窝天堂 | Chinese国产HD精品实拍 | 精品国产青草久久久久96 | 欧美三级视频日日操 | 在线看免费无码av天堂的 | 亚洲精品97久久中文字幕无码 | av免费在线播放网址 | 蜜臀人妻精品一区二区免费 | 日本高清视频一区二区三区四区 | 精品乱码久久久久久中文字幕 | 性做久久 | 国产精品99久久久久久久 | 澳门黄色网 | 国产成人无遮挡在线视频 | 久久精品亚洲精品无码金尊 | 国产农村妇女毛片精品久久 | 视频一区视频二区视频三区视频四区国产 | 日日噜狠狠噜天天噜AV | 黄色A级国产免费大片 | 欧美精品亚洲一区 | 神马久久精品综合 |