Qt, Python(一)
http://antkillerfarm.github.io/
Qt主循環(huán)
這篇文章有個(gè)大概的比較和說明:
http://blog.chinaunix.net/uid-20754930-id-1877623.html
以下是我針對(duì)Qt5代碼(2015.4)的一個(gè)研究。
QApplication::exec
QGuiApplication::exec
QCoreApplication::exec
QEventLoop::exec
QEventLoop::processEvents
QEventDispatcher::processEvents
再以下就和具體的平臺(tái)相關(guān)了。
Windows平臺(tái):
QEventDispatcherWin32::processEvents
它的實(shí)現(xiàn)主要是GetMessage+WaitForMultipleObjects,如上文中對(duì)MiniGUI的主循環(huán)所述。
Unix平臺(tái):
QEventDispatcherUNIX::processEvents
QEventDispatcherUNIXPrivate::doSelect
這個(gè)函數(shù)主要使用select系統(tǒng)調(diào)用來監(jiān)聽事件源。
Android平臺(tái):
QAndroidEventDispatcher::processEvents
QUnixEventDispatcherQPA::processEvents
QEventDispatcherUNIX::processEvents
以下和Unix平臺(tái)相同。
Qt多線程中connect的使用
近日在研究OpenGL多線程處理時(shí),偶然看到了如下代碼:
http://download.csdn.net/detail/zhoukuanbin/7669187
沒有CSDN賬號(hào)的讀者,也可以在這里下載:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/Qt/MyGlTest
粗看代碼,發(fā)現(xiàn)并無特殊的OpenGL處理,理論上應(yīng)該無法達(dá)到一個(gè)線程處理渲染,另一個(gè)線程處理貼圖的目標(biāo)。但實(shí)際編譯運(yùn)行代碼,又確實(shí)可用。因此這里面一定有什么原因。
void ThreadGl::run() {connect(this, SIGNAL(SigCopy()), this, SLOT(Copy()));printf("ID 0:%x\n", currentThreadId());while(1){if(!m_bEndFlag){break;}usleep(16000);emit SigCopy();}qDebug("Copy End\n"); }void ThreadGl::Copy() {m_glWidgets -> OnTimeOut(m_pImage, m_Formal, m_pthId); }這段代碼引起了我的注意。粗一看,connect函數(shù)連接的SIGNAL和SLOT都屬于同一個(gè)對(duì)象。而connect函數(shù)的第5個(gè)參數(shù)(這是個(gè)有默認(rèn)值的可省略參數(shù))的默認(rèn)值為Qt::AutoConnection。
這是Qt官方對(duì)Qt::AutoConnection的解釋:
- If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
按照字面上的意思,既然SIGNAL和SLOT都屬于同一個(gè)對(duì)象,那么這里的Qt::AutoConnection就等同于Qt::DirectConnection。而Qt::DirectConnection與直接調(diào)用SLOT函數(shù)是一個(gè)效果。
于是這里將emit SigCopy();替換為Copy();,結(jié)果程序運(yùn)行出錯(cuò)。
再試一下,將connect函數(shù)的第5個(gè)參數(shù)設(shè)為Qt::DirectConnection,同樣有問題。
而如果將之設(shè)為Qt::QueuedConnection的話,程序運(yùn)行一切正常。
綜上,Qt在這里的處理,顯然認(rèn)為SIGNAL和SLOT屬于不同的線程。
那么判斷的依據(jù)是什么呢?
這里有必要對(duì)emit SigCopy();中emit背后的戲法做一個(gè)剖析。
眾所周知,emit并非C++關(guān)鍵字,而屬于Qt擴(kuò)展的一部分。Qt為了處理這些擴(kuò)展,引入了moc工具作為預(yù)處理工具。
而moc處理之后,emit SigCopy();就變成了QMetaObject::activate
QMetaObject::activate中使用以下代碼,判定信號(hào)接收者的線程是否和信號(hào)發(fā)送者的一致。
const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId;于是問題轉(zhuǎn)化為receiver->d_func()->threadData是怎么來的呢?
答案在QObject::QObject中:
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();從這里可以看出所謂信號(hào)接收者的線程,實(shí)際上是接收者對(duì)象創(chuàng)建時(shí)所處的線程。
回到原來的問題。ThreadGl雖然是Qt的線程對(duì)象,但它本身卻是在主線程中創(chuàng)建的,所以以它為接收者,實(shí)際上就是以主線程為接收者。
顯然這個(gè)例子代碼并沒有真正實(shí)現(xiàn)OpenGL多線程處理,所有的OpenGL操作實(shí)際上都是在主線程完成的。
Python
教程
http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
國人寫的一個(gè)中文教程。
PyPI
PyPI是一個(gè)Python語言的軟件庫管理軟件,它的官網(wǎng)是:
https://pypi.python.org/pypi
用戶可以在這里查找自己需要的Python包。
Ubuntu下的安裝方法是:
sudo apt-get install python-pip
使用方法是:
pip install <package name>
有的python包因?yàn)榘豢梢浦驳亩M(jìn)制文件,使用pip安裝的時(shí)候會(huì)出錯(cuò)。這時(shí),可在ubuntu官網(wǎng)搜索安裝相應(yīng)的python包。
對(duì)于可移植的python包,直接使用pip安裝即可,在ubuntu官網(wǎng)搜也搜不到的。
iPython
ipython是一個(gè) python 的交互式 shell,比默認(rèn)的python shell 好用得多,支持變量自動(dòng)補(bǔ)全,自動(dòng)縮進(jìn),支持 bash shell 命令,內(nèi)置了許多很有用的功能和函數(shù)。
在較新的ipython版本中,添加了ipython notebook的功能,彌補(bǔ)了ipython shell下代碼不易保存等缺點(diǎn),并且在使用 –pylab inline選項(xiàng)后,可以在代碼執(zhí)行后立即顯示運(yùn)行結(jié)果(包括圖片,數(shù)據(jù)表格等),因此在數(shù)據(jù)分析中運(yùn)用十分廣泛。
sudo apt-get install ipython ipython-notebook
軟件發(fā)布工具
distutils
distutils是python自帶的軟件發(fā)布工具。它的安裝腳本一般叫做setup.py,對(duì)應(yīng)的配置文件叫做setup.cfg。
它的文檔參見:
https://docs.python.org/2/distutils/index.html
distutils-extra
distutils-extra在distutils的基礎(chǔ)上做了擴(kuò)展,提供諸如i18n之類的支持。如果沒有安裝,會(huì)報(bào)如下錯(cuò)誤:
error: error in setup.cfg: command 'build' has no such option 'i18n'
安裝方法:
sudo apt-get install python-distutils-extra
setuptools
setuptools是一個(gè)更強(qiáng)大的distutils擴(kuò)展,它也是PyPI的基礎(chǔ)。它的安裝腳本通常以ez_setup.py的形式出現(xiàn)。
它的文檔參見:
https://pythonhosted.org/setuptools/setuptools.html
安裝方法:
sudo apt-get install python-setuptools
Easy Install
setuptools提供的一個(gè)工具,可從網(wǎng)絡(luò)下載安裝外部依賴文件。
它的文檔參見:
https://pythonhosted.org/setuptools/easy_install.html
PyGObject
談起Python調(diào)用GTK+的話題,在GTK+ 2的時(shí)代可以使用PyGTK庫。它的官網(wǎng)是:
http://www.pygtk.org/
但由于PyGTK庫本質(zhì)上來說,使用了和一般的Python調(diào)用C庫一樣的方法,因此每導(dǎo)入一個(gè)庫,都需要編寫大量的接口文件。GNOME工程有那么多項(xiàng)目,采用這種辦法顯然是不太可行的。
于是,GNOME工程發(fā)起了GObject Introspection項(xiàng)目。眾所周知,GNOME工程諸多項(xiàng)目的基石是GObject。這是一個(gè)很成功的類型系統(tǒng),使用該系統(tǒng)可以獲得遠(yuǎn)比普通C庫更強(qiáng)的支持。GObject Introspection項(xiàng)目的目標(biāo)就是創(chuàng)建一個(gè)用于跨語言綁定的中間層。這個(gè)項(xiàng)目的官網(wǎng)是:
https://wiki.gnome.org/Projects/GObjectIntrospection
隨著GObject Introspection項(xiàng)目的進(jìn)展,越來越多的語言綁定開始使用這套系統(tǒng),python也不例外。PyGObject項(xiàng)目就是這種方法的成果,目前它已經(jīng)取代了PyGTK庫,成為GTK+ 3時(shí)代Python調(diào)用GTK+的官方方案。它的官網(wǎng)是:
https://wiki.gnome.org/Projects/PyGObject
相關(guān)的API參考文檔可參見:
http://lazka.github.io/pgi-docs/
指南文檔可參見:
http://python-gtk-3-tutorial.readthedocs.org/en/latest/
安裝方法:
Ubuntu下,可以執(zhí)行:
sudo apt-get install python-gi python3-gi
Windows下,有個(gè)PyGObject for Windows項(xiàng)目,該項(xiàng)目的官網(wǎng)是:
http://sourceforge.net/projects/pygobjectwin32/files/
PyGObject的helloworld程序可參見:
https://github.com/antkillerfarm/antkillerfarm_crazy/blob/master/python/pygtk-helloworld.py
這里必須指出的是,PyGObject依賴的接口文件只有在dev包中才有。安裝相關(guān)Glib項(xiàng)目時(shí),一定要選擇名稱以-dev結(jié)尾的包。
Sqlite
Ubuntu下的安裝方法是:
sudo apt-get install sqlite
Python自帶了pysqlite包,用于調(diào)用sqlite。
pysqlite的helloworld程序可參見:
https://github.com/antkillerfarm/antkillerfarm_crazy/blob/master/python/pysqlite-helloworld.py
可以使用sqlite_bro軟件包,查看sqlite數(shù)據(jù)庫。安裝方法:
sudo pip install sqlite_bro
python調(diào)用GTK函數(shù)的一般規(guī)則
眾所周知,GTK庫是用C語言編寫的,其相關(guān)的文檔提供的也是C函數(shù)的接口,python接口的文檔相對(duì)較少,獲得也不太容易。因此有必要掌握一下這方面基本的命名規(guī)則。(這里只講方法,對(duì)深層次的調(diào)用原理不做探究。)
1)類初始化函數(shù)
C:GtkWidget * gtk_button_new (void);
python:button = Gtk.Button()
這里除了把C函數(shù)式的寫法,替換成python的類的寫法之外,并無其他差異。
2)普通類成員函數(shù)
C:void gtk_container_add (GtkContainer *container, GtkWidget *widget);
python:button.add(image)
可以看出,C函數(shù)的第一個(gè)表示self類指針的參數(shù)被省略掉了。
3)回調(diào)函數(shù)
這里以按鈕的click事件回調(diào)為例:
C:void user_function (GtkButton *button, gpointer user_data)
python:
button.connect("clicked", self.playToggled)
def playToggled(self, w):
這里的情況要復(fù)雜的多。首先在事件回調(diào)注冊(cè)的時(shí)候,由于我們并沒有給user_data賦值,因此照理說playToggled函數(shù),只有button這一個(gè)參數(shù)。但實(shí)際傳遞給playToggled函數(shù)的有兩個(gè)參數(shù),self是一個(gè)用于占位的參數(shù),w對(duì)應(yīng)button,沒有東西對(duì)應(yīng)user_data。
4)用于輸出的參數(shù)
C:void gst_message_parse_error (GstMessage *message, GError **gerror, gchar **debug);
python:err, debug = message.parse_error()
這個(gè)例子中的gerror和debug都是用于輸出的參數(shù)。如果只想得到其一,還可用以下方法:
debug = message.parse_error()[2]
5)枚舉類型
C:
enum GstSeekFlags {GST_SEEK_FLAG_FLUSH,... }python:Gst.SeekFlags.FLUSH
6)宏常量
C:#define GST_CLOCK_TIME_NONE ((GstClockTime) -1)
python:Gst.CLOCK_TIME_NONE
7)類型轉(zhuǎn)換
大多數(shù)情況下,類型轉(zhuǎn)換自動(dòng)完成,并無什么問題。這里只討論特殊的情況。
C:
gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,GST_SEEK_TYPE_SET, time_nanoseconds,GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))python:
self.player.seek(1.0, Gst.Format.TIME, Gst.SeekFlags.FLUSH, Gst.SeekType.SET,\time_nanoseconds, Gst.SeekType.NONE, Gst.CLOCK_TIME_NONE)這里首先按照一般的方法,將C代碼轉(zhuǎn)化成python代碼。但是運(yùn)行之后,產(chǎn)生如下錯(cuò)誤:
OverflowError: long too big to convert
究其原因,gst_element_seek的最后一個(gè)參數(shù)是uint64類型的。但python原生并不支持該類型,而是將之轉(zhuǎn)換成int類型(實(shí)際上是int64類型),這樣的話,GST_CLOCK_TIME_NONE的值顯然超出了int64所能表示的范圍。
解決的辦法是使用ctypes庫,將
Gst.CLOCK_TIME_NONE
改為
c_long(Gst.CLOCK_TIME_NONE).value
Python中的括號(hào)
Python主要有三種數(shù)據(jù)類型:字典、列表、元組。其分別由花括號(hào),中括號(hào),小括號(hào)表示。如:
字典:dic={‘a(chǎn)’:12,’b’:34}
列表:list=[1,2,3,4]
元組:tup=(1,2,3,4)
總結(jié)
以上是生活随笔為你收集整理的Qt, Python(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NoSQL, Clojure
- 下一篇: Kettle, Solr