青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 319, comments - 22, trackbacks - 0, articles - 11
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

cmake vs qmake

  • qmake 是為 Qt 量身打造的,使用起來非常方便
  • cmake 使用上不如qmake簡單直接,但復雜換來的是強大的功能
    • 內置的 out-of source 構建。(目前QtCreator為qmake也默認啟用了該功能,稱:shadow build)

    • 為各種平臺和場景提供條件編譯
    • 可處理多個可執行文件情況,和很好配合 QtTest 工作

如何選擇?

Using CMake to Build Qt Projects 一文中說:

  • 對簡單的Qt工程,采用 qmake
  • 對復雜度超過 qmake 處理能力的,采用 cmake

盡管如此,如果簡單Qt的工程都不知道怎么用 cmake 構建,復雜的工程,就更不知道如何使用 cmake 了。還是從簡單的學起吧

簡單的 Qt 程序

#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
int main(int argcchar** argv)
{
QCoreApplication app(argcargv);
qDebug()<<"hello qt!";
app.exec();
}

如果不使用構建工具,直接調用編譯器來編譯的話,只需要類似這樣的一條命令:

g++ main.cpp -Ie:/Qt/4.7.0/include -o main -Le:/Qt/4.7.0/lib -lQtCore4

指定頭文件目錄,以及需要鏈接的庫

qmake

qmake 需要一個 .pro 文件:

CONFIG += qt
QT -= gui
SOURCES += main.cpp
  • 因為我們需要 Qt的庫和頭文件,所以需要 CONFIG += qt 

    • 這是默認項,可直接去掉該行
  • 啟用qt后,可以通過 QT -= gui 來進一步細調我們需要的模塊
    • 默認是 core gui。我們不需要gui模塊,故去掉。

cmake

cmake 需要一個 CMakeLists.txt 文件:

PROJECT(example)
FIND_PACKAGE(Qt4 REQUIRED)
SET(QT_DONT_USE_QTGUI TRUE)
INCLUDE(${QT_USE_FILE})
ADD_EXECUTABLE(example main.cpp)
TARGET_LINK_LIBRARIES(example ${QT_LIBRARIES})
  • FIND_PACKAGE 來啟用 Qt4
  • 默認使用了core 和 gui,故手動禁用 QTGUI
    • 這兩行可以直接使用 FIND_PACKAGE(Qt4 COMPONENTS QtCore REQUIRED),未指定的模塊將被禁用

  • 包含一個CMake為Qt提供的配置文件,${QT_USE_FILE}變量是一個文件名
  • 添加可執行程序目標
  • 鏈接到 Qt 的庫

復雜一點

考慮一個常規Qt程序:

  • main.cpp
  • mainwindows.ui
  • mainwindows.h
  • mainwindows.cpp

如果手動編譯的話:

  • mainwindow.ui 需要使用 uic 預處理

 

uic mainwindow.ui -o ui_mainwindow.h
  • mainwindow.h 需要 moc 預處理

 

moc mainwindow.h -o moc_mainwindow.cpp
  • 調用編譯器進行編譯

 

g++ main.cpp mainwindow.cpp moc_mainwindow.cpp -Ie:/Qt/4.7.0/include -o main -Le:/Qt/4.7.0/lib -lQtCore4 -lQtGui4

qmake

使用 qmake 的的話,一個簡單的 pro 文件

TARGET = example
TEMPLATE = app
SOURCES += main.cpp mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui

HEADERS 中的文件是否需要 moc 進行預處理,qmake 運行時會根據其是否含有Q_OBJECT自動判斷。

這也是為什么 很多人添加Q_OBJECT宏后不重新運行qmake會出錯誤的原因。

cmake

看看相應的 cmake 的 CMakeLists.txt 文件

PROJECT(example)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
FIND_PACKAGE(Qt4 REQUIRED)
INCLUDE(${QT_USE_FILE})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
QT4_WRAP_CPP(example_MOCS mainwindow.h)
QT4_WRAP_UI(example_UIS mainwindow.ui)
ADD_EXECUTABLE(example main.cpp mainwindow.cpp ${example_MOCS})
TARGET_LINK_LIBRARIES(example ${QT_LIBRARIES})
  • 需要 moc 的文件,用 QT4_WRAP_CPP 處理
    • 生成的文件放入變量 example_MOCS 中,最后一塊鏈接到可執行程序
  • 需要 uic 的文件,用 QT4_WRAP_UI 處理

Windows

因為windows下鏈接時分為 console 和 windows 兩個子系統,所以windows下有些問題需要特殊處理。

用 qmake 時:

  • 默認是 windows 子系統
  • 可以通過 CONFIG += console 使用 console 子系統

用 cmake 是:

  • 默認是 console 子系統
  • 使用 windows 子系統需要

 

SET(QT_USE_QTMAIN TRUE)
ADD_EXECUTABLE(example WIN32 main.cpp mainwindow.cpp ${example_MOCS})

前者啟用 qtmain.lib 庫來提供windows下的 WinMain 入口函數。后者鏈接 windows 子系統

再復雜一點

  • main.cpp
  • mainwindows.ui
  • mainwindows.h
  • mainwindows.cpp
  • main.qrc
  • main.rc

前面已經用到了Qt的 moc 和 uic,這次增加了資源系統 需要用 rcc

rcc main.qrc -o qrc_main.cpp

同時,使用了windows下的資源文件 .rc (比如給程序添加圖標)

  • MVSC 中使用 rc.exe 對 .rc 文件進行處理
  • MinGW 中使用 windres.exe 處理 .rc 文件

qmake

 

TARGET = example
TEMPLATE = lib
HEADERS = mainwindow.h widget.h
SOURCES = main.cpp widget.cpp mainwindow.cpp
RESOURCES = main.qrc
RC_FILE = main.rc

cmake

PROJECT(example)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
FIND_PACKAGE(Qt4 REQUIRED)
SET(QT_USE_QTMAIN TRUE)
INCLUDE(${QT_USE_FILE})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})

if(MINGW)
set(CMAKE_RC_COMPILER_INIT windres)
ENABLE_LANGUAGE(RC)
SET(CMAKE_RC_COMPILE_OBJECT
"<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
endif(MINGW)

SET(example_SRCS main.cpp mainwindow.cpp widget.cpp res/main.rc)
SET(example_MOC_SRCS mainwindow.h widget.h)
QT4_WRAP_CPP(example_MOCS ${example_MOC_SRCS})
QT4_ADD_RESOURCES(example_RCC_SRCS main.qrc)
SET(example_SRCS ${example_SRCS} ${example_MOCS} ${example_RCC_SRCS})

ADD_EXECUTABLE(example WIN32 main.cpp mainwindow.cpp ${example_SRCS})
TARGET_LINK_LIBRARIES(example ${QT_LIBRARIES})
  • 對Qt的資源文件,使用 QT4_ADD_RESOURCES 來調用rcc進行預處理
  • 對 Windows 資源文件,直接和源文件一樣,添加到列表中即可。只是:
    • MinGW 下僅僅這么做還不行,上面的 MinGW 塊用來修復這個問題

Debug 與 Release

qmake

使用 qmake 時,可以在 pro 文件內分別為兩種模式設置不同的選項。

使用時,可以直接 make release 或 make debug 來編譯不同的版本

cmake

不同于 qmake,由于 cmake 采用 out-of-source 方式。故:

  • 建立debug release兩目錄,分別在其中執行cmake -DCMAKE_BUILD_TYPE=Debug(或Release)
  • 需要編譯不同版本時進入不同目錄執行make

對生成 msvc 工程的情況, CMAKE_BUILD_TYPE 不起作用。生成工程后使用IDE自帶的模式選擇。

posted @ 2011-08-05 07:24 RTY 閱讀(1872) | 評論 (0)編輯 收藏

Qt在線文檔

http://doc.qt.nokia.com/4.7/

 

Qt e-Learning

http://qt.nokia.com/developer/learning/elearning

http://wikis.in.nokia.com/QtSoftware/LearnQt

http://www.ics.com/learning/icsnetwork/

 

官方Qt移動開發社區、資源、Wiki

Getting started with Git and GitHub

Nokia Forum projects

http://forum.nokia.com

http://forum.nokia.com.cn/ 

http://wiki.forum.nokia.com/index.php/Qt_%E5%BC%80%E5%8F%91

 

官方Qt論壇

http://developer.qt.nokia.com/forums

Qt for Symbian 開發資源

http://discussion.forum.nokia.com/forum/showthread.php?162323-Qt-for-Symbian-development-resources

 

中文Qt網站

http://qt.csdn.net

諾基亞論壇上的Qt for Symbian中文論壇

http://www.qtcn.org

www.qteverywhere.com

 

 

中文文檔

http://forum.nokia.com.cn/document_1.html

http://qtdocs.sourceforge.net/index.php/%E5%88%86%E7%B1%BB:Qt_%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C


其他

 

如果在開發中遇到了技術細節上的問題,相信再下面兩個論壇搜索相關關鍵字會比直接在baidu/google上搜強很多

http://lists.trolltech.com/qt-interest/

 

 

Qt在SlideShare的幻燈片

http://www.slideshare.net/tag/qt

 

非官方的優秀Qt論壇

http://www.qtcentre.org/forum/

 

 

posted @ 2011-08-05 07:22 RTY 閱讀(424) | 評論 (1)編輯 收藏

請尊重原創作品和譯文。轉載請保持文章完整性,并以超鏈接形式注明原始作者地址http://blog.csdn.net/changsheng230,方便其他朋友提問和指正。

 

Qt/Qt Quick宏淺議一文中,我們將介紹Qt中經常使用的幾個宏: Q_OBJECT, SIGNAL與SLOT, Q_SIGNALS 與 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY。相比其他宏,Q_INVOKABLE 顯得更加神秘,但Q_INVOKABLE的理解與使用變得越來越重要。本文將圍繞Q_INVOKABLE以及相對應的invokeMethod展開討論。

Q_INVOKABLE

#define Q_INVOKABLE

重新回顧一下Q_INVOKABLE的定義,它在$QTDIR/src/corelib/kernel/qobjectdefs.h 中,簡單被define,目的在于讓moc識別。

使用Q_INVOKABLE來修飾成員函數,目的在于被修飾的成員函數能夠被元對象系統所喚起。

QMetaObject::invokeMethod

靜態方法QMetaObject::invokeMethod() 的定義如下:

     

    1. bool QMetaObject::invokeMethod ( QObject * obj, const char * member,Qt::ConnectionType type,  
    2. QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument( 0 ), …)  
     

     

     

invokeMethod的用法為,嘗試調用對象obj的方法member(注意member可以為信號或者是槽),如何member可以被調用,則返回真,否則返回假。QMetaObject::invokeMethod可以是異步調用,也可以是同步調用。這取決與它的連接方式Qt::ConnectionType type。如果type為Qt::DirectConnection,則為同步調用,若為Qt::QueuedConnection,則為異步調用。例如:

     

    1. QMetaObject::invokeMethod(object, "methodName",   
    2. Qt::QueuedConnection,   
    3. Q_ARG(type1, arg1),   
    4. Q_ARG(type2, arg2));  
     

     

上述調用為異步調用。請注意,因為上面所示的參數需要被在構建事件時進行硬拷貝,參數的自定義型別所對應的類需要提供一個共有的構造函數、析構函數以及拷貝構造函數。而且必須使用注冊Qt型別系統所提供的qRegisterMetaType() 方法來注冊這一自定義型別。

Q_INVOKABLE與QMetaObject::invokeMethod均由元對象系統喚起。這一機制在Qt C++/QML混合編程跨線程編程Qt Service Framework 以及 Qt/ HTML5混合編程以及里廣泛使用。

Qt C++/QML混合編程

QML中調用C++方法借助了Qt元對象系統。考慮在QML中使用Qt C++定義的方法,如下代碼所示:

 

  1. import Qt 4.7   
  2. import Shapes 5.0   //自定義模塊  
  3. Item {   
  4.     width: 300; height: 200  
  5.     Ellipse {   
  6.          x: 50; y: 35; width: 200; height: 100   
  7.         color: "blue"   
  8.          MouseArea {   
  9.             anchors.fill: parent  
  10.             // 調用C++中定義的randomColor方法   
  11.             onClicked: parent.color = parent.randomColor()    
  12.         }   
  13.     }  
  14. }  
 

 

為了讓上述QML代碼成功的調用下面這段代碼定義的randomColor()函數,最為關鍵的一點見randomColor方法用Q_INVOKABLE 修飾。

 

  1. #include <QDeclarativeItem >  
  2. class EllipseItem : public QDeclarativeItem   
  3. {   
  4.     Q_OBJECT   
  5. public:  
  6.       Q_INVOKABLE QColor randomColor() const;  
  7.       …  
  8. }  
 

 

更多細節,請參看我的另一篇博文:QML與C++混合編程使用

在跨線程編程中的使用

我們如何調用駐足在其他線程里的QObject方法呢?Qt提供了一種非常友好而且干凈的解決方案:向事件隊列post一個事件,事件的處理將以調用我們所感興趣的方法為主(當然這需要線程有一個正在運行的事件循環)。而觸發機制的實現是由moc提供的內省方法實現的。因此,只有信號、槽以及被標記成Q_INVOKABLE的方法才能夠被其它線程所觸發調用。如果你不想通過跨線程的信號、槽這一方法來實現調用駐足在其他線程里的QObject方法。另一選擇就是將方法聲明為Q_INVOKABLE,并且在另一線程中用invokeMethod喚起。

 

更多細節,譯文事件循環與線程

Qt Service Framework

Qt服務框架是Qt Mobility 1.0.2版本推出的,一個服務(service)是一個獨立的組件提供給客戶端(client)定義好的操作。客戶端可以通過服務的名稱,版本號和服務的對象提供的接口來查找服務。 查找到服務后,框架啟動服務并返回一個指針。

服務通過插件(plug-ins)來實現。為了避免客戶端依賴某個具體的庫,服務必須繼承自QObject。這樣QMetaObject 系統可以用來提供動態發現和喚醒服務的能力。要使QmetaObject機制充分的工作,服務必須滿足,其所有的方法都是通過 signal,slot,property 或invokable methodQ_INVOKEBLE來實現

其中,最常見的與servicer交互的方法如下:

  1. QServiceManager manager;QObject *storage ;  
  2. storage = manager.loadInterface("com.nokia.qt.examples.FileStorage"); if (storage)     QMetaObject::invokeMethod(storage, "deleteFile", Q_ARG(QString, "/tmp/readme.txt"));  
上面的代碼通過service的元對象提供的invokeMethod方法,調用文件存儲對象的deleteFile() 方法。客戶端不需要知道對象的類型,因此也沒有鏈接到具體的service庫。  當然在服務端的deleteFile方法,一定要被標記為Q_INVOKEBLE,才能夠被元對象系統識別

Qt服務框架的一個亮點是它支持跨進程通信,服務可以接受遠程進程。在服務管理器上注冊后 進程通過signal,slot,invokable method和property來通信,就像本地對象一樣。服務可以設定為在客戶端間共享,或針對一個客戶端。  請注意,在Qt服務框架推出之前,信號、槽以及invokable method僅支持跨線程。 下圖是跨進成的服務/客戶段通信示意圖(圖片來自諾基亞論壇)。這里我們可以清楚的看到,invokable methodQ_INVOKEBLE 是跨進城、跨線程對象之間通信的重要利器。

 

serivceFramework

有關Qt Service Framework的更多討論和用例,請參見Qt Service Framework文檔

posted @ 2011-08-05 07:19 RTY 閱讀(1872) | 評論 (0)編輯 收藏

Qt GPL, LGPL & Commercial License

From:

http://www.qteverywhere.com/

 

Qt 4.5中提供了三種授權協議,分別是GPL, LGPL和Commercial,可能很多人要問,為什么同樣的一個產品要提供三種授權協議,什么情況下使用什么的樣的授權協議最合適?在這里我就大致解釋一下:

 

GPL全稱是The GNU General Public License,是目前大多數的GNU程序和超過半數的自由軟件使用的許可協議。GPL的出發點是代碼的開源/免費使用和引用/修改/衍生代碼的開源/免 費使用,但不允許修改后和衍生的代碼做為閉源的商業軟件發布和銷售。
GPL協議的主要內容是只要在一個軟件中使用(”使用”指類庫引用,修改后的代碼或者衍生代碼)GPL 協議的產品,則該軟件產品必須也采用GPL協議,既必須也是開源和免費。這就是所謂的”傳染性”。GPL協議的產品作為一個單獨的產品使用沒有任何問題, 還可以享受免費的優勢。

 

回到LGPL,LGPL的全稱是 GNU Lesser General Public License,GNU 較寬松公共許可證,也是由協議是由自由軟體基金會發布的許可證,是一個主要為類庫使用設計的開源協議,和GPL要求任何使用/修改/衍生之GPL類庫的的 軟件必須采用GPL協議不同。LGPL允許商業軟件通過類庫引用(link)方式使用LGPL類庫而不需要開源商業軟件的代碼。這使得采用LGPL協議的 開源代碼可以被商業軟件作為類庫引用并發布和銷售。

 

除了GPL和LGPL兩種開源協議之外,Qt還提供了Commercial商業協議,Qt的商業協議是由Nokia定義的,由Nokia和購買方簽 訂的,具有法律效應的Qt產品授權協議。 Commercial License相教與GPL和LGPL,對于商業客戶提供了更多的靈活性,客戶可以任意的修改Qt的源代碼,開發商業軟件,而不需要公開任何源代碼。并 且,在Commercial License中,我們還提供了技術支持服務。當然,商業授權協議是需要費用的。

到底什么時候需要選擇GPL和LGPL呢?一個最顯而易見的理由就是他們都是免費的,使用LGPL和GPL版本的Qt是不需要支付任何費用的,當然 我們也相應的不會提供技術支持。如果你打算開發真正的開源軟件,并希望使用者也可以保持開源,那么GPL是更好的選擇,因為所有人,不論你自己還是將來基 于你的代碼進行再次開發都必須開源。如果你打算開發閉源(不開放源代碼)的商業軟件,那么LGPL則更適合,但必須滿足下面兩個條件:
1. 你的應用程序應該動態鏈接Qt函數庫,并使你的應用程序與未做修改的LGPL庫分開發布。同時必須確保使用者(接受者)知道應用程序使用了LGPL版本的Qt;
2. 如果你對LGPL版本的Qt進行了任何修改,并發布,則必須遵循LGPL 條款發布。任何使用者有權利得到這些修改(通常情況下是源代碼),并且確保使用者可以通過這些修改自己生成相應你修改過的Qt版本。

相信到這里大家已經對Qt提供的這三種協議有了基本的了解,通常大家還會有一個疑問,就是基于這三種授權協議的Qt產品到底由多少功能上的區別,是 不是商業版本的會更完整,性能更好一些?這里我可以負責任的說:99%的代碼都是一樣的,無論是GPL, LGPL還是Commercial,功能,性能都沒有區別,唯一的區別就在于授權協議的不同。

還有一點需要說明的就是,由于LGPL是在Qt4.5這個版本里面才引入的,所以之前的Qt版本,4.4或者3.x的版本,并不提供LGPL協議,是不可逆的。同時未來發布的Qt版本,就一直會提供三種不同的授權協議版本。

 

下面有一些鏈接,有興趣想深入了解這些授權協議的同學,可以學習學習

GPL協議原文 - http://www.gnu.org/copyleft/gpl.html
GPL協議中文譯文 - http://bergwolf.googlepages.com/gplv3_zh
LGPL協議原文 - http://www.gnu.org/copyleft/lesser.html
LGPL協議中文譯文 - http://www.thebigfly.com/gnu/lgpl/lgpl-v3.php
58種不同的開源協議 - http://www.fsf.org/licensing/licenses/
什么是動態鏈接 - http://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93
官方聲明 - http://www.qtsoftware.com/about/news/lgpl-license-option-added-to-qt
官方Q&A - http://www.qtsoftware.com/about/licensing/frequently-asked-questions

posted @ 2011-08-05 07:18 RTY 閱讀(990) | 評論 (0)編輯 收藏

請尊重原創作品和譯文。轉載請保持文章完整性,并以超鏈接形式注明原始作者地址http://blog.csdn.net/changsheng230,方便其他朋友提問和指正。

 

剛開始接觸Qt的朋友可能對Qt在使用當中需要聲明的各色各樣的宏感到神秘而又陌生,本文將介紹Qt中經常使用的幾個宏: Q_OBJECT, SIGNAL與SLOT, Q_SIGNALS 與 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY:

 

宏的頭文件出處: $QTDIR/src/corelib/kernel/qobjectdefs.h

Q_OBJECT

#define Q_OBJECT / 
public: / 
    Q_OBJECT_CHECK / 
    static const QMetaObject staticMetaObject; / 
    Q_OBJECT_GETSTATICMETAOBJECT / 
    virtual const QMetaObject *metaObject() const; / 
    virtual void *qt_metacast(const char *); / 
    QT_TR_FUNCTIONS / 
    virtual int qt_metacall(QMetaObject::Call, int, void **); /

宏Q_OBJECT是Qt所有宏中最為重要的一個,Q_OBJECT是使用信號槽機制以及其他所有元對象系統提供的服務(內省、invokeMethod,元對象property系統等等)的前提條件。有關Q_OBJECT的討論請參考Qt源碼分析之QObject。 

SIGNAL與SLOT

這兩個宏是調用connect方法時用到:

 

  1. QObject::connect(myButton, SIGNAL(clicked()),   
  2.                   label,  SLOT(showText()));  
 

 

那么宏SIGNAL和SLOT為我們做了那些事情呢,看一下源代碼:

 

  1. $QTDIR/src/corelib/kernel/qobjectdefs.h  
  2. # define SLOT(a)     qFlagLocation("1"#a QLOCATION)   
  3. # define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)  
  4. $QTDIR/src/corelib/kernel/qobject.cpp  
  5. const char *qFlagLocation(const char *method)   
  6. {   
  7.     static int idx = 0;   
  8.     flagged_locations[idx] = method;   
  9.     idx = (idx+1) % flagged_locations_count;   
  10.     return method;   
  11. }  
 

 

原來它會基于把我們定義的信號、槽的名稱返回一個字符串,比如SIGNAL(clicked()) 返回字符串 “2clicked()”, SLOT(showText())返回字符串“1showText()”

  1. Q_SIGNALS 與 Q_SLOTS  
  2. #  define slots   
  3. #  define signals protected   
  4. # define Q_SLOTS   
  5. # define Q_SIGNALS protected  
 

 

Q_SIGNALS 與 Q_SLOTS是Qt 4.1引入的,它們用來替換關鍵字signals和slots,原因是更好的與第三方信號槽機制兼容,比如boost庫。盡管Q_SIGNALS 與 Q_SLOTS看起來沒有做什么。其實不然,QT的元對象編譯器moc會識別聲明在頭文件中的宏Q_SIGNALS,Q_SLOTS。并做為依據,生成元對象模型數據,詳見文中最后所示代碼實例

Q_EMIT

#define Q_EMIT #define emit

Q_EMIT用來替換關鍵字emit,原因也是更好的與第三方信號槽機制兼容,比如boost庫。

這里要注意,我們看到Q_EMIT看起來同樣的簡單, 但它們是有區別的!表面的區別在于Q_SIGNALS 與 Q_SLOTS用在頭文件中,而Q_EMIT用在代碼視線中。 本質的區別的在于,Q_SIGNALS 與 Q_SLOTS將被moc識別,是必須使用的。而Q_EMIT或者emit是可有可無的。它不會被moc識別,它存在的唯一理由是:增加代碼的可讀性。  也就是說如下代碼都能正常工作,但2)的寫法也許會惹怒你的同事。

 

  1. void method()  
  2. {  
  3.       1) emit signalA();  
  4.       2) signalA();    
  5. }  
 

 

Q_INVOKABLE

#define Q_INVOKABLE

 

使用Q_INVOKABLE來修飾成員函數,目的在于被修飾的成員函數能夠被元對象系統所喚起。這一機制在Qt C++/QML混合編程,Qt service framework, 以及Qt/ HTML5混合編里廣泛使用。我會隨后另撰寫一文做深入探討。

 

 

Q_PROPERTY

 

#define Q_PROPERTY(text)   

 

使用Q_PROPERTY用以聲明屬性,屬性類似于成員變量,但它能夠被元對象系統所訪問。QML的屬性便是利用該機制得以實現的。 Q_PROPERTY的用法如下:

 

Q_PROPERTY(QString title READ title WRITE setTitle USER true)

 


 

接下來,讓我們結合代碼來看一下上述宏的使用以及元對象編譯器是如何利用這些宏的。

 

 

  1. #include <QDeclarativeItem >  
  2. class EllipseItem : public QDeclarativeItem   
  3. {   
  4.     Q_OBJECT   
  5.     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)  
  6. public:   
  7.     EllipseItem(QDeclarativeItem *parent = 0);   
  8.     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,   
  9.                QWidget *widget = 0);  
  10.     const QColor &color() const;   
  11.     void setColor(const QColor &newColor);  
  12.     Q_INVOKABLE QColor randomColor() const;  
  13. public Q_SLOTS:   
  14.     void try1();   
  15.     void try2() {}  
  16. Q_SIGNALS:   
  17.     void colorChanged();   
  18.     void ready();  
  19. private:   
  20.     QColor m_color;   
  21. };  
 

 

 

以下代碼由元對象編譯器moc根據上述頭文件自動生成:

 

 

  1. static const uint qt_meta_data_EllipseItem[] = {  
  2. // content:   
  3.        5,       // revision   
  4.        0,       // classname   
  5.        0,    0, // classinfo   
  6.        5,   14, // methods   
  7.        1,   39, // properties   
  8.        0,    0, // enums/sets   
  9.        0,    0, // constructors   
  10.        0,       // flags   
  11.        2,       // signalCount  
  12. // signals: signature, parameters, type, tag, flags   
  13.       13,   12,   12,   12, 0x05,   
  14.       28,   12,   12,   12, 0x05,  
  15. // slots: signature, parameters, type, tag, flags   
  16.       36,   12,   12,   12, 0x0a,   
  17.       43,   12,   12,   12, 0x0a,  
  18. // methods: signature, parameters, type, tag, flags   
  19.       57,   12,   50,   12, 0x02,  
  20. // properties: name, type, flags   
  21.       71,   50, 0x43495103,  
  22. // properties: notify_signal_id   
  23.        0,  
  24.        0        // eod   
  25. };  
  26. static const char qt_meta_stringdata_EllipseItem[] = {   
  27.     "EllipseItem/0/0colorChanged()/0ready()/0"   
  28.     "try1()/0try2()/0QColor/0randomColor()/0"   
  29.     "color/0"   
  30. };  
 

 

 

從上面代碼實例我們可以看到, QT的元對象編譯器moc會識別聲明在頭文件中的宏Q_SIGNALS,Q_SLOTS, Q_PROPERTY, Q_PROPERTY。并以此做為依據,生成了元對象數據表。在這張元對象數據表中,我們已可以看到,moc根據頭文件所聲明的宏定義,識別出:

  • 兩個信號:colorChanged(), ready();      (Q_SIGNALS)
  • 兩個槽:    try1(), try2()                          (Q_SLOTS)
  • 五個方法,其中被標記為Q_INVOKABLE的方法randomColor()被記錄在元對象字符串數組qt_meta_stringdata_EllipseItem中。  
  • 一個屬性:color   (Q_PROPERTY)

posted @ 2011-08-05 07:16 RTY 閱讀(850) | 評論 (0)編輯 收藏

請尊重原創作品和譯文。轉載請保持文章完整性,并以超鏈接形式注明原始作者地址http://blog.csdn.net/changsheng230,方便其他朋友提問和指正。

將QML整合到基于QWidget UI程序的方法有很多種,而具體采用哪種方法取決于現有UI代碼的特性。

與基于QWidget的UI整合

如果你已經有了一個基于QWidget的UI,QML widgets可以使用QDeclarativeView來進行集成。QDeclarativeView是QWidget的一個子類,所以你可以像加載其他QWidget一樣把它加載進你的UI。 具體方法是使用QDeclarativeView::setSource()方法加載一個QML文件到視圖中,然后將這個視圖(即QDeclarativeView)加到你的UI中。

  1. QDeclarativeView *qmlView = new QDeclarativeView;  
  2. qmlView->setSource(QUrl::fromLocalFile("myqml.qml"));  
  3.   
  4. QWidget *widget = myExistingWidget();  
  5. QVBoxLayout *layout = new QVBoxLayout(widget);  
  6. widget->addWidget(qmlView);  

這種方法的缺點在于與QWidget相比,QDelarativeVeiw的初始化過程更慢,而且使用更多的內存。如果創建大量的QDelarativeVeiw對象可能會導致性能的下降。在這種情況下,更好的選擇是用QML重寫你的widgets,使用main QML widget來加載widget, 從而替代QDelarativeVeiw的濫用。

請注意,QWidgets的UI設計理念與QML并不相同,所以將基于QWidget的應用移植到QML并不總是一個好主意。如果你的UI是由少數幾個復雜、靜態的元素的組成,使用QWidgets是一個更好的選擇。而如果你的UI是由大量簡單、動態的元素組成,那么QML則是你的最佳選擇。

與基于QGraphicsView的UI整合

將QML widgets加入到QGraphicsScene

如果你已經有了一個基于Graphics View Framework的UI,你可以直接將QML widgets集成到你的QGraphicsScene中。具體方法是使用QDeclarativeComponent 從QML文件中創建一個QGraphicsObject,并通過使用QGraphicsScene::addItem(), 方法把這個圖形對象加到你的scene中,或者將其父化到已經存在與QGraphicsScene的組件中。舉例說明:

>

  1. QGraphicsScene* scene = myExistingGraphicsScene();  
  2. QDeclarativeEngine *engine = new QDeclarativeEngine;  
  3. QDeclarativeComponent component(engine, QUrl::fromLocalFile("myqml.qml"));  
  4. QGraphicsObject *object =  
  5.     qobject_cast(component.create());  
  6. scene->addItem(object);  

推薦使用下面的一些QGraphicsView選項來優化QML UIs的性能:

在QML中加載QGraphicsWidget 對象

另一個可供選擇的方法是將你現有的QGraphicsWidget 對象暴露給QML,并且在QML中構建你的scene。請參見圖形布局示例,它展示了如何結合QGraphicsWidget 、QGraphicsLinearLayout 以及QGraphicsGridLayout的使用,將Qt圖形布局類暴露給QML。

為了將現有的QGraphicsWidget類暴露給QML,需使用qmlRegisterType()。在QML中使用C++型別的進一步信息,請參見在C++中拓展QML。 (譯者注:也看參閱QML與C++混合編程使用)

英文原文出處:integrating QML with existing Qt UI code

posted @ 2011-08-04 22:38 RTY 閱讀(2745) | 評論 (0)編輯 收藏

本文介紹的是Qt 內省機制,關于內省,新手的原因,我們一塊學習,所謂內省是指面向對象語言的一種在運行期間查詢對象信息的能力, 比如如果該語具有運行期間檢查對象型別的能力,那么我們稱它是型別內省(type intropection)的,型別內省可以用來實施多態。

c++內省比較有限,它僅支持上面所說的型別內省, C++的型別內省是通過運行時類型識別(RTTI)(Run-Time Type Information)中的typeid 以及 dynamic_case關鍵字來實現的,舉例說明:

  1. // rabbit 派生于 Animal, jump為虛函數
  2. if ( rabbit *p = dynamic_case<Animal*>(obj))
  3. {
  4. p->jump();
  5. }
  6. //我們還可以通過typeid萃取到對象的型別信息,比如對象的名稱
  7. std::cout << typeid(obj).name() << std::endl

Qt拓展了C++的內省機制,(實際上,它并沒有采用c++的RTTI),而是提供了更為強大的元對象(meta object)機制,來實現內省。接下來,就讓我們看看,Qt是如何擴展c++內省機制的。

要深刻理解Qt的內省機制,首先理解QObject,QObject類是整個Qt對象模型的心臟,Qt對象模型最為核心的功能是提供一種無縫的對象通訊機制,即就是我們所熟知的信號和槽。QObject主要有三大職責: 內存管理、內省(intropection)與事件處理。本文將集中在在內省的討論。以下代碼介紹了QObject類提供的內省方法:

  1. //每個對象可以通過QObject::setObjectName()和QObject::objectName()設置、取得類的實例的名字
  2. FirstQtApp obj;
  3. obj.setObjectName("instanceName");
  4. QString name1 = obj.objectName(); // return instanceName
  5. //每個對象還可以通過它的元對象className方法得到類的名字
  6. QString name2 = obj.metaObject()->className(); // return FirtstQtApp
  7. //每個對象可以通過QObject::inherits方法來查詢是否對前對象類派生于量一個類
  8. bool isherited = obj.inherits("QObject"); // returns true
  9. isherited = obj.inherits("QWideget"); // returns true

讓我們再來一下QObject::inherits方法的底層實現:

  1. inline bool inherits(const char *classname) const
  2. { return const_cast<QObject *>(this)->qt_metacast(classname) != 0; }

原來,QObject::inherits是通過qt_metacast()這個虛函數實現的, 事實上每個QObject的派生類都必須實現metaObject()以及其他qt_metacall()方法,從而滿足自省方法className, inherits等方法的調用(當然還有其他用途)。

而所有有關派生從QObject的子類中的內省方法無須有用戶實現,用戶只要在類中聲明宏Q_OBJECT即可,Qt的元對象編譯器(moc)負責實現派生從QObject的子類中的內省方法。

  1. // defined at ..\Qt\src\corelib\kernel\qobjectdefs.h
  2. /* tmake ignore Q_OBJECT */
  3. #define Q_OBJECT \
  4. public: \
  5. Q_OBJECT_CHECK \
  6. static const QMetaObject staticMetaObject; \
  7. Q_OBJECT_GETSTATICMETAOBJECT \
  8. virtual const QMetaObject *metaObject() const; \
  9. virtual void *qt_metacast(const char *); \
  10. QT_TR_FUNCTIONS \
  11. virtual int qt_metacall(QMetaObject::Call, int, void **); \

此外,所有的Qt widgets類均繼承自QObject, QObject所提供的isWidgetType自省方法可以很方便讓QObject子對象查詢自己是否是wideget, 而且它會比 qobject_cast<QWidget *>(obj) 或者 obj->inherits快很多。原因qobject_cast()t和inherits()都是借助元對象系統來實現其功能的,isWidgetType()是QObject本身的標志位得以實現。

更多自省方法定義在QMetaObject,以下是QMetaObject聲明的源代碼:

  1. struct Q_CORE_EXPORT QMetaObject
  2. {
  3. const char *className() const;
  4. const QMetaObject *superClass() const;
  5. QObject *cast(QObject *obj) const;
  6. ....
  7. int methodOffset() const;
  8. int enumeratorOffset() const;
  9. int propertyOffset() const;
  10. int classInfoOffset() const;
  11. int constructorCount() const;
  12. int methodCount() const;
  13. int enumeratorCount() const;
  14. int propertyCount() const;
  15. int classInfoCount() const;
  16. int indexOfConstructor(const char *constructor) const;
  17. int indexOfMethod(const char *method) const;
  18. int indexOfSignal(const char *signal) const;
  19. int indexOfSlot(const char *slot) const;
  20. int indexOfEnumerator(const char *name) const;
  21. int indexOfProperty(const char *name) const;
  22. int indexOfClassInfo(const char *name) const;
  23. ...
  24. }

上述方法主要是實現對元對象表的訪問及其操作,對元對象表(由moc實現)實例如下所示:

  1. // defined at ..\Qt\src\corelib\kernel\qobjectdefs.h
  2. /* tmake ignore Q_OBJECT */
  3. #define Q_OBJECT \
  4. public: \
  5. Q_OBJECT_CHECK \
  6. static const QMetaObject staticMetaObject; \
  7. Q_OBJECT_GETSTATICMETAOBJECT \
  8. virtual const QMetaObject *metaObject() const; \
  9. virtual void *qt_metacast(const char *); \
  10. QT_TR_FUNCTIONS \
  11. virtual int qt_metacall(QMetaObject::Call, int, void **); \

總結:

1、Qt是通過QObject、QMetaObject類實現其內省機制,

2、QObject暴露給用戶的共有自省方法有objectName(), inherits(), isWidgetType()等

3、大多數自省方法是QObject派發給QMetaObject實現 (e.g. QMetaObject::className,),元對象模型編譯器moc負責自省方法的實現

4、更多自省方法定義在QMetaObject,而是為了等信號槽通訊、事件派發等機制,

小結:關于解析 Qt 內省機制剖析的內容介紹完了,希望本文對你有所幫助!

posted @ 2011-08-04 22:33 RTY 閱讀(753) | 評論 (0)編輯 收藏

本文適合于對Qt Quick有基本了解的讀者。首先回答一個比較常會被問到的問題:什么是QML,它與Quick的關系是什么?

Qt QuickQt User Interface Creation Kit的縮寫,而QMLQt Quick最重要的組成部分,Qt Quick結合了如下技術:

組件集合,其中大部分是關于圖形界面的

基于JavaScript陳述性語言:QML (Qt Meta-Object Language的縮寫)

用于管理組件并與組件交互的C++ API - QtDeclarative模塊

言歸正傳:通過Qt Creator,我們可以輕松生成一個Qt Quick的應用工程,從而為QML生成應用程序框架。具體操作詳見:創建qt quick (qml) 應用程序。

C++與QML的交互是通過注冊C++對象給QML環境得以實現的:

C++實現中,非可視化的型別均為QObject的子類,可視化的類型均為QDeclarativeItem的子類。注意:QDeclarativeItem等同于QML的Item類。

如果用戶想要定義自己的型別,做法如下:

在C++中,實現派生于QObject或QDeclarativeItem的子類,它是新定義item的實體對象;

在C++中,將1中實現的新item類型注冊給QML;

在QML中,導入含有1中定義的新item的模塊;

在QML中,向使用標準的item一樣使用新定義的item

現舉例說明,我們現嘗試使用用Qt C++實現的MyButton對象(如下qml代碼),它有自己的屬性、方法以及信號的handler。用法如下(它與使用其它標準的QML item一樣),所需要做的是 需要導入包含MyButton的對應模塊名稱及其版本“MyItems 1.0 ”。

  1. //main.qml
  2. import Qt 4.7
  3. import MyItems 1.0
  4. Item {
  5. width: 300; height: 200
  6. MyButton {
  7. //注意:x, y, width, height是繼承自item的屬性,無需再自定義的item中實現
  8. x: 50; y: 50
  9. width: 200; height: 100
  10. color: "gray" //自定義屬性
  11. onMySignals: dosth //自定義信號mySignals
  12. MouseArea {
  13. anchors.fill: parent
  14. onClicked: parent.myColor() // 調用C++定義的方法myColor
  15. }
  16. }
  17. }
  18. //main.qml
  19. import Qt 4.7
  20. import MyItems 1.0
  21. Item {
  22. width: 300; height: 200
  23. MyButton {
  24. //注意:x, y, width, height是繼承自item的屬性,無需再自定義的item中實現
  25. x: 50; y: 50
  26. width: 200; height: 100
  27. color: "gray" //自定義屬性
  28. onMySignals: dosth //自定義信號mySignals
  29. MouseArea {
  30. anchors.fill: parent
  31. onClicked: parent.myColor() // 調用C++定義的方法myColor
  32. }
  33. }
  34. }

為了能夠上述qml代碼工作,需要為在Qt C++代碼中注冊MyButton及其所屬的模塊,對應的main.cpp代碼如下:

  1. #include <QtGui/QApplication>
  2. #include "qmlapplicationviewer.h"
  3. int main(int argc, char *argv[])
  4. {
  5. QApplication app(argc, argv);
  6. QmlApplicationViewer viewer;
  7. // MyButtonItem是與QML中MyButton相對應的C++實現的類名稱
  8. // 1,0是版本信息;MyItems是MyButton所屬的模塊名稱
  9. qmlRegisterType<MyButtonItem>("MyItems", 1, 0, "MyButton ");
  10. viewer.setOrientation(QmlApplicationViewer::Auto);
  11. viewer.setMainQmlFile(QLatin1String("qml/untitled/main.qml"));
  12. viewer.show();
  13. return app.exec();
  14. }
  15. #include <QtGui/QApplication>
  16. #include "qmlapplicationviewer.h"
  17. int main(int argc, char *argv[])
  18. {
  19. QApplication app(argc, argv);
  20. QmlApplicationViewer viewer;
  21. // MyButtonItem是與QML中MyButton相對應的C++實現的類名稱
  22. // 1,0是版本信息;MyItems是MyButton所屬的模塊名稱
  23. qmlRegisterType<MyButtonItem>("MyItems", 1, 0, "MyButton ");
  24. viewer.setOrientation(QmlApplicationViewer::Auto);
  25. viewer.setMainQmlFile(QLatin1String("qml/untitled/main.qml"));
  26. viewer.show();
  27. return app.exec();
  28. }

上面我們在QML中MyButton對象,有自己的屬性、方法以及信號的handler,其實現均來自Qt C++。Qt C++需要作以下工作:首先要定義 QML中MyButton相對應的C++實現MyButtonItem,它必須繼承自QDeclarativeItem

為了讓MyButton對象能夠使用其Color屬性,MyButtonItem類需要利用QT的PROPERTY系統,為Moc聲明其屬性

為了讓MyButton對象能夠使用其myColor方法,MyButtonItem類需要聲明該方法,并標記為Q_INVOKABLE (另外一種解決方案是將myColor聲明為槽。

為了讓MyButton對象能夠接受到C++所emit的信號,并在onMySignals,MyButtonItem類需要聲明mySignals信號

  1. class MyButtonItem : public QDeclarativeItem
  2. {
  3. Q_OBJECT
  4. Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
  5. signals:
  6. void colorChanged();
  7. void mySignals();
  8. public:
  9. MyButtonItem(QDeclarativeItem *parent = 0);
  10. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
  11. QWidget *widget = 0);
  12. public:
  13. const QColor &color() const;
  14. void setColor(const QColor &newColor);
  15. Q_INVOKABLE QColor myColor() const;
  16. // Alternatives for myColor to be called from QML
  17. //public slots
  18. //QColor myColor() const;
  19. private:
  20. QColor m_color;
  21. };

原始作者地址http://blog.csdn.net/changsheng230

小結:關于詳解QMLC++混合編程使用的內容介紹完了,希望本文對你有所幫助!

posted @ 2011-08-04 22:31 RTY 閱讀(949) | 評論 (0)編輯 收藏

posted @ 2011-08-04 22:29 RTY 閱讀(626) | 評論 (0)編輯 收藏

1.這里主要是介紹,如何在c++中調用QML中的函數和設置QML中的屬性的問題


2.具體代碼



// UICtest.qml
import Qt 4.7
Rectangle {
    id: mainWidget;
    width: 640
    height: 480
    function callbyc(v)
    {
        mainWidget.color = v;
        return "finish";
    }
    Rectangle{
        id: secondRect;
        x: 100;
        y: 20;
        width: 400;
        height: 300;
        Rectangle{
            x: 10;
            y: 20;
            width: 30;
            height: 40;
            color: "#FF035721"
            Text  {
                objectName: "NeedFindObj";
                anchors.fill: parent;
                text: "";
            }
        }
    }
}


// main.cpp
#include <QtGui/QApplication>
#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeComponent>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeItem>
#include <QMetaObject>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QDeclarativeView qmlView;
    qmlView.setSource(QUrl::fromLocalFile("../UICtest/UICtest.qml"));
    qmlView.show();
    // 獲取根節點,就是 QML idmainWidget的節點
    QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(qmlView.rootObject());
    item->setProperty("color", QVariant("blue"));
    // 查找到我們需要的節點根均objectname NeedFindObj 來獲得,并設置他的文本屬性
    QDeclarativeItem *item1 = item->findChild<QDeclarativeItem *>("NeedFindObj");
    if (item1)
    {
        item1->setProperty("text", QVariant("OK"));
    }
    // 調用QML中的函數, 分別是 函數所在的對象, 函數名,返回值, 參數
    QVariant returnVar;
    QVariant arg1 = "blue";
    QMetaObject::invokeMethod(item, "callbyc",
                              Q_RETURN_ARG(QVariant, returnVar),Q_ARG(QVariant, arg1));
    qDebug(" %s",returnVar.toString().toLocal8Bit().data());
    return a.exec();
}





說明:

這里的根節點是idmainWidget的矩形元素,那么在C++中獲取根節點后就可以,直接的設置他的屬性了。其他屬性也可以同樣,調用指定節點內的函數是通過QMetaObject中的invokeMethod 來進行調用的。


最后所有關于QMLc++交互部分就基本寫完,如果想要更多的東西,或者一些其他方法,強烈看看

http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html,或者幫助文檔,(究竟是不是我的文檔里面沒有還是怎么的)

posted @ 2011-08-04 22:05 RTY 閱讀(1707) | 評論 (2)編輯 收藏

僅列出標題
共31頁: First 9 10 11 12 13 14 15 16 17 Last 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            狂野欧美一区| 亚洲黄网站在线观看| 精品91视频| 亚洲电影在线看| 亚洲欧洲综合| 亚洲一区免费观看| 久久爱www| 欧美成人精品激情在线观看| 亚洲国产日韩一区二区| 99精品99| 久久国产精品毛片| 99re6热在线精品视频播放速度| 久久国产一区二区| 欧美成人按摩| 美女主播精品视频一二三四| 欧美精品国产精品日韩精品| 欧美三区在线| 在线成人激情视频| 亚洲网在线观看| 久久女同互慰一区二区三区| 亚洲国产欧美在线人成| 一区二区三欧美| 久久琪琪电影院| 国产精品国产三级国产a| 激情久久综合| 亚洲男人av电影| 欧美激情成人在线视频| 亚洲欧美国产精品桃花| 欧美韩日一区二区三区| 国产视频一区三区| 中文国产一区| 欧美国产日本| 久久久久国产一区二区| 国产精品系列在线播放| 亚洲精品美女免费| 老巨人导航500精品| 亚洲永久精品大片| 欧美日韩国产精品 | 欧美国产日本高清在线| 国产日韩一区二区三区在线| 亚洲天堂av图片| 亚洲国产专区校园欧美| 久久久精品tv| 国外成人在线视频| 性做久久久久久| 亚洲视频999| 欧美色偷偷大香| 一区二区三区日韩欧美| 亚洲国产小视频在线观看| 久久综合五月| 亚洲黄色小视频| 欧美肥婆在线| 麻豆精品传媒视频| 亚洲激情在线观看| 亚洲电影在线免费观看| 美国成人直播| 亚洲精品一区二区三| 欧美激情一区二区三区不卡| 久久综合九色99| 亚洲国内精品| 性感少妇一区| 欧美激情一区二区三区高清视频| 国内精品嫩模av私拍在线观看 | 欧美日在线观看| 亚洲免费观看高清完整版在线观看熊| 奶水喷射视频一区| 欧美不卡激情三级在线观看| 亚洲人午夜精品| 日韩视频免费在线| 国产精品久久影院| 午夜在线观看欧美| 欧美亚洲免费在线| 在线看片成人| 亚洲国产婷婷综合在线精品| 欧美日韩一级黄| 欧美在线观看天堂一区二区三区| 香蕉乱码成人久久天堂爱免费| 国产亚洲综合精品| 欧美电影免费| 欧美女同视频| 欧美一区二区在线免费播放| 久久久久综合| 日韩视频三区| 午夜天堂精品久久久久| 一区二区在线观看视频在线观看| 亚洲国产视频一区| 国产日韩精品一区| 久久精品毛片| 欧美精品久久一区| 欧美亚洲日本一区| 久久蜜桃精品| 亚洲少妇诱惑| 久久久福利视频| 亚洲天堂av综合网| 久久一区二区三区av| 在线视频亚洲欧美| 久久久99久久精品女同性| av成人老司机| 久久久精品2019中文字幕神马| 亚洲精品久久久久| 午夜欧美大片免费观看| 亚洲最新在线视频| 快射av在线播放一区| 小嫩嫩精品导航| 欧美日韩成人一区二区三区| 久久久天天操| 国产精品一区免费视频| 亚洲精品欧美日韩专区| 在线免费观看日本一区| 亚洲欧美不卡| 亚洲一区二区视频| 欧美精品在线视频| 美女免费视频一区| 国产女精品视频网站免费| 女人色偷偷aa久久天堂| 国产亚洲精久久久久久| 在线亚洲一区| aa日韩免费精品视频一| 欧美电影打屁股sp| 欧美成人资源| 亚洲高清资源综合久久精品| 欧美一区二区三区免费观看视频| 亚洲淫性视频| 国产精品成人一区二区网站软件| 亚洲午夜精品网| 久久国产精品久久w女人spa| 亚洲永久精品国产| 欧美日韩在线播| 最新国产精品拍自在线播放| 亚洲国产欧美一区二区三区久久 | 亚洲精品免费在线播放| 精品999在线观看| 久久精品国产96久久久香蕉| 久久久久久久网| 狠狠久久亚洲欧美专区| 欧美专区在线观看一区| 久久久久久夜| 伊人久久亚洲热| 欧美在线观看视频| 亚洲欧美日韩国产综合| 欧美日韩久久久久久| 99精品欧美一区| 亚洲在线国产日韩欧美| 国产精品白丝av嫩草影院| 在线一区二区日韩| 亚洲理伦在线| 欧美日韩dvd在线观看| 日韩亚洲欧美成人一区| 亚洲女性喷水在线观看一区| 国产精品高潮呻吟| 亚洲一区二区黄| 久久久另类综合| 国产真实乱偷精品视频免| 久久精品123| 亚洲国产精品毛片| 亚洲视频播放| 国内视频精品| 欧美精品一区二区三区久久久竹菊| 日韩午夜一区| 久久国产婷婷国产香蕉| 亚洲第一页在线| 欧美午夜a级限制福利片| 亚洲一区免费视频| 欧美超级免费视 在线| 一本一本大道香蕉久在线精品| 国产精品久久久久免费a∨| 久久www成人_看片免费不卡| 亚洲国产一二三| 欧美在线free| 日韩视频一区二区三区在线播放免费观看| 欧美视频在线观看 亚洲欧| 欧美一级成年大片在线观看| 欧美黄色视屏| 欧美中文字幕在线观看| 亚洲人成在线影院| 国产亚洲精品久| 欧美日韩国产一区二区| 欧美在线精品免播放器视频| 亚洲精品国产精品国产自| 久久精品国产一区二区三区免费看| 最新成人av在线| 国产区日韩欧美| 欧美日韩中文字幕综合视频 | 久久九九久精品国产免费直播| 亚洲精品婷婷| 免费不卡视频| 久久精品国产久精国产爱| 最新成人av在线| 国产精品久久久久9999高清| 欧美日韩精品欧美日韩精品| 在线成人性视频| 亚洲一级黄色| 亚洲福利专区| 欧美三区免费完整视频在线观看| 欧美一级午夜免费电影| 欧美一区激情| 香蕉av777xxx色综合一区| 亚洲精品女人| 欧美色大人视频| 欧美一区国产在线|