python Tkinter GUI 프로그램에서 lambda를 이용한 버튼 이벤트 처리


코드에서 막바로 lambda를 이용한 버튼 클릭 이벤트에 대해서 살펴보자.

아래는 코드이다.

프로그램 실행하면 다음과 같은 윈도우 창이 뜨게 된다.




#-*- coding:utf-8 -*-


# 파이썬 GUI용 툴킷 Tkinter를 import

from Tkinter import *


# Tkinter 윈도우 객체 생성

root = Tk()


# (가로 x 세로 + x위치좌표 + y위치좌표)

root.geometry("500x300+300+200")


def callback(number):

    print "Button-", number


print 'b1'

# btn1 버튼 클릭시 실행할 메소드는 callback()이고

# 이 메소드로 넘길 paramter 값은 111이다.

# 따라서 btn1 버튼 클릭시 아래 내용 출력된다.

# Button- 111

btn1 = Button(text="One", command=lambda: callback(111))

btn1.configure(font=("Consolas", 15), width=20)

btn1.pack(pady=7)


print 'b2'

btn2 = Button(text="Two", command=lambda: callback(222))

btn2.configure(font=("Consolas", 15), width=20)

btn2.pack(pady=7)


print 'b3'

btn3 = Button(text="Three", command=lambda: callback(333))

btn3.configure(font=("Consolas", 15), width=20)

btn3.pack(pady=7)


# Tkinter 윈도우 화면에 표시

root.mainloop()



Kivy를 이용해서 python에서 GUI 프로그래밍을 할 때 Kivy만이 가진 특성 중 하나인 Kv language를 사용하는 방법에 대한 간단한 개념이다.

kv code를 python 코드에 포함(load)시키는 방법에는 2가지 방법이 있다.


1. by name convention(이름으로 지정하는 방법)

python의 클래스 이름과 동일한 kv 파일명을 가진 kv 파일을 만들면 자동으로 이 파일을 load한다.


2. Builder 클래스를 이용하여 직접 python 코드에 load하는 방법

  -. Builder.load_file('some/path/somefile.kv')

  -. Builder.load_string(my_kv_string) 

     이 경우는 python 코드 안에서 string 형태로 kv 코드를 만들고 이를 Build.load_string()을 이용해서 사용하는 방석이다.

     (구체적 예제코드는 여기를 참조)


아래의 코드는 by name convention 방식으로 kv 코드를 python 코드에 load하는 방법이다.


  • exkvtest.kv의 내용이다

<Label>

    text: 'Hello'+' World'

    font_size: 50



  • exkvtest.py의 내용이다.

#-*- coding: utf-8 -*-

from kivy.app import App

from kivy.uix.label import Label


'''

kv의 원리

-. kv 파일명과 python 파일명이 같아야 함. 단 모두 소문자라야 함. ExKvTest.kv, ExKvTest.py식이면 안됨.

-. exkvtest.kv, exkvtest.py식이어야 한다

-. python 소스 코드의 클래스 이름도 kv 파일과 동일해야 한다. 단 소스 코드에서의 class 이름은 소문자로만 하지 

-. 않아도 된다. class ExKvTest(App)과 같이 해도 된다. 또한 소스 코드상에서의 class이름 끝에 App이라는 문자는 상관없다.


There are two ways to load Kv code into your application:

By name convention:

   Kivy looks for a Kv file with the same name as your App class in lowercase, minus “App” if it ends with ‘App’ e.g:

      MyApp -> my.kv

'''


# 안됨

# class MyKvTest(App):

#     def build(self):

#         # return Label(text='Hi~')

#         return Label()


# 잘 됨

class ExKvTestApp(App):

    def build(self):

        # return Label(text='Hi~')

        return Label()



if __name__ == '__main__':

    # MyKvTest().run()  # 안됨

    ExKvTestApp().run()  # 잘됨


python을 이용해서 Linux 상에서 구동되는 GUI 프로그램을 개발할 일이 있어서 QT, Tkinter, kivy들을 테스트 하게되었다.

PyCharm을 이용해서 kivy 관련 코드들이 정상적으로 잘 실행이 되었다.

근데 terminal 창에서 kivy관련 코드를 실행하면(python test.py) 


ImportError: No module named 'kivy'


와 같은 에러를 계속 뿜어 낸다.

분명히 kiviy 공식 사이트가 지정해 주는대로 kivy를 정상적으로 잘 설치했고 따라서 PyCharm에서 잘 실행이 되었다.

그런데 유독 터미널 창에서만 실행이 되지를 않았다.

결국 문제는 path상에서 인식으로 하지 못한 문제였다. 원인은 anaconda를 설치했다가 삭제를 했는데 path상에는 여전히 그 놈이 살아있어서 path를 읽어가는 중에 문제를 일으킨것 같다.


root@joe-VirtualBox:/usr/lib/python2.7/dist-packages/kivy/uix# echo $PATH

/root/anaconda2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games


위와 같이 이미 삭제된 anaconda가 살이있어서의 문제였다.

/root/.bashrc에 있는 


export PATH="/root/anaconda2/bin:$PATH"


이 놈을 주석으로 묶어 버렸더니 터니널 창에서도 정상적으로 kivy가 잘 동작했다.

리눅스는 아무튼 복잡한 동물이라서... 쩝




Python의 list를 다룰 때 특히 list의 특정 항목을 다른 항목으로 치환하고자 할 때 사용하는 slice에서 자칫 잘못하면

원래의 list 항목을 날려 먹거나 원치 않는 value가 끼워넣어지는 문제가 발생한다.

그래서 list의 length가 원치 않게 변해 버리는 문제가 발생한다.

아래 코드가 전형적으로 이런 문제를 유발하는 예제이다.


#-*- coding: utf-8 -*-

a = []

b = [101, 102, 103, 104, 105]

for i in range(10):

   a.insert(i, i)


print("원본", a)

print('길이', len(a))


#아래 코드는 index 2~4까지를 바꾼다. 총3개를 바꾼다.

#그런데 list b에 있는 값은 5개이다. 따라서 b의 앞 3개는

#치환이 되지만 나머지 2개(104, 105)는 끼워넣기가 되어 버린다.

#따라서 list a가 원래 10개였는데 아래 코드 실행 후 len()은 12개가 된다

#a[2:5] = b[0:] 

#print(a)

#print("길이", len(a)) #12가 나온다


#아래 코드는 index 1~7까지 총 7개를 바꾸는데 바꿀 내용인 

#list b에는 값이 5개 뿐이다(101 ~ 105). 이럴 경우 발생하는 현상은

#list a의 index 1~5까지는 101~105로 각각 치환이 되고 

#list a에서 나머지 index 6~7에 해당하는 값은 사라져 버린다.

#그래서 아래 코드 실행후 list a의 len()은 8이 되어져 버린다.

#a[1:8] = b[0:] #이 코드를 실행하고자 하면 위 a[2:5] = b[0:]를 주석 처리 할 것

#print(a)

#print("길이", len(a)) #8이 나온다.


#이러한 문제를 해결하기 위해서는 다음과 같이 처리해 주어야 안전하다.

a[1:len(b)+1] = b[0:]

print(a)

print("길이", len(a))




Python은 좀 특이한 언어이다. 들여쓰기가 그렇게 의미 있는 행동이다.

또 공백이 있고 없고가 큰 차이를 만들어내는 경우도 있다.

대표적으로 Python 코드는 기본적으로 ASCII 문자로 처리해서 해석을 한다.

따라서 소스 코드 상에서 한글을 사용하면 컴파일 단계에서 에러 발산한다.

심지어는 #로 시작하는 주석에서 한글을 사용해도 컴파일 에러 발생한다.

에러 메시지는 다음과 같은 걸 뿜는다.


SyntaxError: Non-ASCII character '\xec' in file test.py on line 16, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details



따라서 파이썬에서 한글을 사용할려면 다음의 코드를 소스 맨 첫줄에 삽입해 주어야 한다.


#-*- coding: utf-8 -*-


그런데 다음과 같이 하면 여전히 한글을 사용할수 없는 상황이 변하지 않는다.


#-*- coding : utf-8 -*-


coding과 콜론(:) 사이에 있는 공백 때문이다. 


참고로 이 글은 Python 버전 2.7에서 실행했을 때의 상황이다.

Python 버전 3에서는 이상의 문제 발생하지 않는다.




+ Recent posts