K01-02:Kivy的Widget組件

基本上Kivy中的UI組件都是繼承Widget素邪,掌握好Widget就基本上掌握了UI組件的使用妻顶。

  1. Widget的設(shè)計(jì)理念捆等;
  2. Widget的基本使用氓皱;

一路召、Widget組件的默認(rèn)值與一些默認(rèn)行為

(1)Widget不是布局,Widget不會(huì)改變其包含的子組件的位置與大小波材。
(2)Widget的默認(rèn)大小是100*100股淡。
(3)Widget的size_hint默認(rèn)是1*1,如果其父組件是一個(gè)布局組件各聘,則其大小是父組件中的布局需要的大小揣非。
(4)on_touch_down(), on_touch_move(), on_touch_up() 等函數(shù)不進(jìn)行組件邊界范圍判定(碰撞判定),需要調(diào)用collide_point()
來(lái)判定躲因。
下面使用例子說(shuō)明:【 UI01_Widget_default.py

#coding=utf-8
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color
from kivy.graphics import Rectangle
from kivy.core.window import Window

class MyWidget(Widget):
    # 3. on_touch_down(), on_touch_move(), on_touch_up() 不檢測(cè)Widget的觸發(fā)邊界
    # 點(diǎn)擊Widget區(qū)域之外,事件照樣觸發(fā)忌傻。
    def on_touch_up(self, touch):
        print(touch)

class WidgetApp(App):
    def build(self):
        widget=MyWidget()

        #1. size與size_hint的默認(rèn)值大脉。
        print("大小:(%d,%d)"%(widget.width,widget.height))         #(100,100)
        print("大小提示(%d,%d)"%(widget.size_hint[0],widget.size_hint[1]))                #(1,1)

        widget.size = (Window.size[0] / 2, Window.size[1] / 2,)     #是窗體一般大小水孩。

        with widget.canvas:
            Color(0,255,255)
            Rectangle(pos=widget.pos, size=widget.size)

        #2. 不改變子組件的位置與大小
        widget2=Widget()
        widget.add_widget(widget2)

        with widget2.canvas:
            Color(255,0,255)
            Rectangle(pos=widget2.pos, size=widget2.size)

        return widget

app=WidgetApp()
app.run()

運(yùn)行控制臺(tái)輸出:

控制臺(tái)輸出說(shuō)明Widget的大小默認(rèn)值

運(yùn)行界面

說(shuō)明Widget不是布局镰矿,不會(huì)改變子組件大小位置(紫色為子組件Widget,父組件大小設(shè)置得與窗體一樣大蟹帧),點(diǎn)擊組件以外的區(qū)域也會(huì)觸發(fā)事件

二秤标、Widget的設(shè)計(jì)理念

1. 事件驅(qū)動(dòng)的屬性設(shè)計(jì)

??所謂事件驅(qū)動(dòng)的屬性設(shè)計(jì)是指每個(gè)屬性都可以綁定一個(gè)事件,當(dāng)屬性改變宙刘,可以觸發(fā)一個(gè)事件苍姜。
??屬性的事件是通過(guò)回調(diào)函數(shù)(on_屬性名)實(shí)現(xiàn)。
代碼如下:【 UI01_Widget_eventdriven.py

#coding=utf-8
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color
from kivy.graphics import Rectangle
from kivy.core.window import Window

class WidgetApp(App):
    def build(self):
        widget=Widget()
        #2. 使用on_<屬性名>綁定一個(gè)事件方法悬包。
        widget.on_size=self.changeSize()
        #3.改變size會(huì)觸發(fā)change方法的調(diào)用衙猪。
        widget.size=(Window.size[0]/2,Window.size[1]/2,)
        with widget.canvas:
            Color(0,255,255)
            Rectangle(pos=widget.pos, size=widget.size)
        return widget

    #1.實(shí)現(xiàn)一個(gè)事件方法
    def changeSize(self):
        print("Size Change")

app=WidgetApp()
app.run()

當(dāng)程序啟動(dòng),會(huì)改變size屬性布近,導(dǎo)致幫定的事件方法被調(diào)用垫释。

當(dāng)size屬性改變,屬性綁定的事件函數(shù)被調(diào)用的輸出

2. 組件與圖形分離的設(shè)計(jì)

??組件與圖形分離撑瞧,就是不按照傳統(tǒng)的圖形圖像繪制實(shí)現(xiàn)套路棵譬,提供一個(gè)draw或者paint類(lèi)似的方法,并提供一個(gè)圖像繪制對(duì)象來(lái)集中實(shí)現(xiàn)圖形圖像的繪制(這個(gè)在Java Swing或者JavaFX预伺,C++的Qt都是這個(gè)套路)订咸,傳統(tǒng)的套路下琅束,實(shí)現(xiàn)圖像繪制一般會(huì)override繪制函數(shù),并重新實(shí)現(xiàn)繪制過(guò)程算谈。這樣的缺點(diǎn)是必須要繼承Widget涩禀,Override繪制函數(shù)。
??組件與圖形分離的技術(shù)實(shí)際上C中慣用模式然眼,通過(guò)開(kāi)啟一個(gè)繪制環(huán)境艾船,在環(huán)境開(kāi)始后,任何獨(dú)立的繪制都影響繪制效果高每,繪制完畢后關(guān)閉繪制環(huán)境屿岂,之后的繪制就沒(méi)有效果。在Kivy中這個(gè)繪制環(huán)境就是Canvas鲸匿,在Widget中有這個(gè)成員爷怀。而繪制的函數(shù)與Canvas沒(méi)有任何代碼上的設(shè)計(jì)關(guān)聯(lián)關(guān)系,這樣實(shí)現(xiàn)繪制與Widget組件的寬?cǎi)詈显O(shè)計(jì)模式带欢。
??組件與圖形分離的編程模式在Python語(yǔ)言中特別容易實(shí)現(xiàn)运授,利用with語(yǔ)句塊自動(dòng)開(kāi)啟與自動(dòng)關(guān)閉一個(gè)環(huán)境,編程模式如下:

  with  widget組件.canvas:                    #繪制環(huán)境開(kāi)始
        繪制的相關(guān)操作
  pass                                       #繪制環(huán)境結(jié)束

下面使用簡(jiǎn)單代碼說(shuō)明這種繪制模式(代碼繪制了一個(gè)白色矩形用來(lái)做背景乔煞,繪制了一個(gè)黃色線(xiàn)條):【 UI01_Widget_graphics.py

#coding=utf-8
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color
from kivy.graphics import Rectangle
from kivy.graphics import *
from kivy.core.window import Window

class WidgetApp(App):
    def build(self):
        widget=Widget()
        widget.size=Window.size
        #Kivy不提供專(zhuān)門(mén)的圖形繪制函數(shù)吁朦,而是采用組件與繪制分離模式,這樣渡贾,可以在任何地方實(shí)現(xiàn)圖形繪制逗宜。
        with widget.canvas:
            #設(shè)置顏色
            Color(255,255,255)
            #繪制一個(gè)與Widget一樣大小的矩形
            Rectangle(pos=widget.pos, size=widget.size)
            Color(255, 255, 0)
            Line(points=[0,0,widget.size[0],widget.size[1]],width=5)
            print(widget.size)
        return widget

app=WidgetApp()
app.run()

運(yùn)行結(jié)果如下:

在Widget中繪制圖形

3. 組件邊界檢測(cè)設(shè)計(jì)

??Widget的事件處理,需要檢測(cè)Widget的范圍空骚,否則在Widget組件外也會(huì)觸發(fā)事件纺讲。為了保障只有在點(diǎn)擊Widget材觸發(fā),需要做碰撞模式的邊界判定囤屹,Widget組件中邊界檢測(cè)函數(shù)聲明如下:

#判定(x熬甚,y)是否在Widget框內(nèi),在就返回True牺丙,否則返回False则涯。
Widget.collide_point(x, y)

下面是測(cè)試代碼:【 UI01_Widget_collide.py

#coding=utf-8
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color
from kivy.graphics import Rectangle
from kivy.core.window import Window

class TheWidget(Widget):
    def on_touch_down(self, touch):
        print(self.size,self.pos)
        print(self.collide_point(*touch.pos))


class TheApp(App):
    def build(self):
        parent_widget=Widget()
        with parent_widget.canvas:
            Color(255,0,0)
            Rectangle(pos=parent_widget.pos,size=Window.size)
        child_widget = TheWidget()
        with child_widget.canvas:
            Color(0,255,0)
            Rectangle(pos=child_widget.pos,size=child_widget.size)
        parent_widget.add_widget(child_widget)
        return parent_widget
    

TheApp().run()

??在綠色Widget區(qū)域點(diǎn)擊返回True,在區(qū)域外返回False冲簿。不管在區(qū)域內(nèi)外粟判,事件都會(huì)觸發(fā),需要自己處理點(diǎn)擊是否在Widget組件內(nèi)還是組件外峦剔。
??在上面例子中档礁,我們使用了兩個(gè)Widget,原因是直接放在Window中的Widget盡管設(shè)置了size屬性吝沫,但是在Widget添加在Window中的時(shí)候呻澜,Widget的size會(huì)設(shè)置成與Window的size一樣大小递礼。但是在Widget中的Widget不會(huì)。
運(yùn)行界面如下:

運(yùn)行界面

下面是在綠色Widget中點(diǎn)擊一次羹幸,在外面點(diǎn)擊一次的輸出:

三脊髓、Widget的基本使用

??有些屬性在后面使用說(shuō)明,比如id與ids栅受,cls(在kv語(yǔ)言的時(shí)候說(shuō)明)将硝,size_hint(在布局的時(shí)候說(shuō)明)屬性。

1. Widget構(gòu)造

  class kivy.uix.widget.Widget(**kwargs)

其中**kwargs可是是Widget任何有效的屬性屏镊,參數(shù)設(shè)置方式:

屬性名=屬性值

下面是Widget常用的屬性:
基本屬性

屬性名 屬性說(shuō)明
cls Class of the widget, used for styling.
id Identifier of the widget in the tree.
ids This is a dictionary of ids defined in your kv language.

畫(huà)布依疼,透明與失效屬性

屬性名 屬性說(shuō)明
canvas = None Canvas of the widget.
opacity Opacity of the widget and all its children.
disabled Indicates whether this widget can interact with input or not.

集合屬性

屬性名 屬性說(shuō)明
height Height of the widget.
width Width of the widget.
center,center_x而芥,center_y Center position of the widget.
x X position of the widget.
y Y position of the widget.
size Size of the widget
pos Position of the widget.
right Right position of the widget.
top Top position of the widget.

布局幾何屬性

屬性名 屬性說(shuō)明
pos_hint Position hint. This property allows you to set the position of the widget inside its parent layout, in percent (similar to size_hint)
size_hint Size hint.size_hint
size_hint_max Maximum size when using size_hint
size_hint_max_x When not None, the x-direction maximum size (in pixels, like width) when size_hint_x is also not None.
size_hint_max_y When not None, the y-direction maximum size (in pixels, like height) when size_hint_y is also not None.
size_hint_min Minimum size when using size_hint.
size_hint_min_x When not None, the x-direction minimum size (in pixels, like width) when size_hint_x is also not None.
size_hint_min_y When not None, the y-direction minimum size (in pixels, like height) when size_hint_y is also not None.
size_hint_x x size hint. Represents how much space the widget should use in the direction of the x axis relative to its parent’s width. Only the Layout and Window classes make use of the hint.
size_hint_y y size hint.

下面是通過(guò)構(gòu)造器使用屬性的例子:【 UI01_Widget_property.py

#coding=utf-8
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color
from kivy.graphics import Rectangle
from kivy.graphics import *
from kivy.core.window import Window

class WidgetApp(App):
    def build(self):
        widget=Widget(opacity=0.5,size=Window.size)
        with widget.canvas:
            #設(shè)置顏色
            Color(255,255,255)
            #繪制一個(gè)與Widget一樣大小的矩形
            Rectangle(pos=widget.pos, size=widget.size)

        return widget

app=WidgetApp()
app.run()

因?yàn)榇绑w背景是黑色律罢,Widget是白色,設(shè)置為半透明后棍丐,顯式效果是灰色误辑。

通過(guò)構(gòu)造器設(shè)置Widget的opacity屬性

2. 事件使用

事件 事件描述
on_touch_down: Fired when a new touch event occurs
on_touch_move: Fired when an existing touch moves
on_touch_up: Fired when an existing touch disappears

3. addWidget與remove_widget方法

add_widget(widget, index=0, canvas=None)
    widget:被添加的組件
    index:添加的索引位置,默認(rèn)是0骄酗,就是插入到組件列表的第一個(gè)稀余,但是最后繪制并顯式。
    canvas:字符串參數(shù)趋翻,畫(huà)布處理。取值'befoe','after',或者None盒蟆。

remove_widget(widget)

4. 碰撞判定方法

方法名 方法說(shuō)明
collide_point(x, y) Check if a point (x, y) is inside the widget’s axis aligned bounding box.
collide_widget(wid) Check if another widget collides with this widget. This function performs an axis-aligned bounding box intersection test by default.

5. export_to_png把組件導(dǎo)出為圖像方法

export_to_png(filename, *args)

args參數(shù)沒(méi)有使用踏烙。

6. Widget樹(shù)訪(fǎng)問(wèn)

方法名 方法說(shuō)明
get_parent_window() Instance of the parent window. Can be a WindowBase or Widget.
get_root_window() Instance of the root window. Can be a WindowBase or Widget.

7. 容器與組件坐標(biāo)變換

坐標(biāo)轉(zhuǎn)換函數(shù) 函數(shù)說(shuō)明
to_local(x, y, relative=False) Transform parent coordinates to local coordinates.
to_parent(x, y, relative=False) Transform local coordinates to parent coordinates.
to_widget(x, y, relative=False) Convert the given coordinate from window to local widget coordinates.
to_window(x, y, initial=True, relative=False) Transform local coordinates to window coordinates.
get_window_matrix(x=0, y=0) Calculate the transformation matrix to convert between window and widget coordinates.

下面是方法使用的例子代碼:【 UI01_Widget_method.py

#coding=utf-8
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
from kivy.core.window import Window

class MyWidget(Widget):
    def on_touch_down(self, touch):
        print("點(diǎn)擊位置:",touch.pos)
        print("local:",self.to_local(*touch.pos,relative=True))
        print("parent:", self.to_parent(*touch.pos,relative=True))
        print("widget:", self.to_widget(*touch.pos,relative=True))
        print("window:", self.to_window(*touch.pos,relative=True))

class WidgetApp(App):
    def build(self):
        widget=Widget(size=Window.size)
        with widget.canvas:
            #設(shè)置顏色
            Color(255,0,255)
            #繪制一個(gè)與Widget一樣大小的矩形
            Rectangle(pos=widget.pos, size=widget.size)

        mywidget=MyWidget(size=(400,400),pos=(200,200))
        with mywidget.canvas:
            #設(shè)置顏色
            Color(0,0,255)
            #繪制一個(gè)與Widget一樣大小的矩形
            Rectangle(pos=mywidget.pos, size=mywidget.size)

        widget.add_widget(mywidget)

        widget.export_to_png("img.png")

        return widget

app=WidgetApp()
app.run()

其中運(yùn)行效果:

帶窗體的界面效果

控制臺(tái)輸出效果:

坐標(biāo)轉(zhuǎn)換的輸出效果

注意:其中relative參數(shù)設(shè)置為T(mén)rue,從中可以看出觸摸事件返回的觸摸點(diǎn)历等,實(shí)際是window坐標(biāo)系下的坐標(biāo)點(diǎn)讨惩。

export_to_png函數(shù)的保存的圖像效果:

export_to_png保存的圖像效果

資源

  1. 本文使用的資源同統(tǒng)一下載路徑: https://github.com/QiangAI/PythonSkill/tree/master/KivyUI
  2. Kivy的官方參考路徑:https://kivy.org/doc/stable/api-kivy.uix.widget.html
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市寒屯,隨后出現(xiàn)的幾起案子荐捻,更是在濱河造成了極大的恐慌,老刑警劉巖寡夹,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件处面,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡菩掏,警方通過(guò)查閱死者的電腦和手機(jī)魂角,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)智绸,“玉大人野揪,你說(shuō)我怎么就攤上這事访忿。” “怎么了斯稳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵海铆,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我挣惰,道長(zhǎng)卧斟,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任通熄,我火速辦了婚禮唆涝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唇辨。我一直安慰自己廊酣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布赏枚。 她就那樣靜靜地躺著亡驰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饿幅。 梳的紋絲不亂的頭發(fā)上凡辱,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音栗恩,去河邊找鬼透乾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛磕秤,可吹牛的內(nèi)容都是我干的乳乌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼市咆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼汉操!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蒙兰,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤磷瘤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后搜变,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體采缚,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年痹雅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仰担。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖摔蓝,靈堂內(nèi)的尸體忽然破棺而出赂苗,到底是詐尸還是另有隱情,我是刑警寧澤贮尉,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布拌滋,位于F島的核電站,受9級(jí)特大地震影響猜谚,放射性物質(zhì)發(fā)生泄漏败砂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一魏铅、第九天 我趴在偏房一處隱蔽的房頂上張望昌犹。 院中可真熱鬧,春花似錦览芳、人聲如沸斜姥。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)铸敏。三九已至,卻和暖如春悟泵,著一層夾襖步出監(jiān)牢的瞬間杈笔,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工糕非, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蒙具,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓朽肥,卻偏偏與公主長(zhǎng)得像店量,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鞠呈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱(chēng)項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,988評(píng)論 3 119
  • 愿你有高跟鞋也有跑鞋 喝茶也喝酒 愿你有勇敢的朋友 有厲害的對(duì)手 愿你對(duì)過(guò)往的一切情深意重 但從不回頭 愿你美麗右钾、...
    丶問(wèn)君知否閱讀 720評(píng)論 0 0
  • 感恩這本書(shū)的到來(lái)蚁吝,喚醒了我內(nèi)心沉睡的愛(ài),用感恩的心看世界舀射,真實(shí)窘茁,溫暖,寬恕脆烟,接觸山林,歸屬感,信任邢羔,專(zhuān)心驼抹,同理心桑孩,謙虛...
    龔晶晶閱讀 286評(píng)論 0 1