반응형

이전 포스팅의 투명한 배경에 이어, 둥근 버튼 구현하기를 알아보겠습니다.

요즘 tkinter와 kivy를 번갈아가며 사용해보고 있는데, 서로 장단점이 존재하네요. 어느것도 완벽한게 없는듯 합니다.

tkinter는 둥근버튼이 없어서 별도로 구현해야 하는 반면 투명한 배경처리가 가능하고,

kivy는 투명한 배경은 안되도 둥근버튼은 쉽게 구현이 되네요. 

import tkinter as tk

root = tk.Tk()
# root.attributes('-alpha', 0.3)  # 앱 전체가 투명해짐
root.wm_attributes("-transparentcolor", "white")

canvas = tk.Canvas(root, width=600, height=300, bg='white')
canvas.grid(columnspan=3, rowspan=3)
hello = tk.Label(root, text="Hello World", font="Raleway", bg='white')
hello.grid(columnspan=3, column=0, row=0)

# 이미지의 사이즈 변경. x방향 1/2, y방향 1/2
btn_img = tk.PhotoImage(file="button.png").subsample(2, 2)
# compound='center'로 이미지의 위치 설정하고 반대편에 텍스트 배치
# (left,right,top,bottom등 가능)
button = tk.Button(root, text="click", image=btn_img, compound='center', borderwidth=0, bg='white')
button.grid(column=1, row=1)

root.mainloop()

 

반응형
반응형

한참 좋다고 다른 GUI라이브러리 공부할 땐 언제고, 투명 기능이 어려워서 다시 tkinter를 손대게 되네요.

아래는 Tkinter로 구현하는 투명 배경 예제입니다. 

import tkinter as tk

root = tk.Tk()
# root.attributes('-alpha', 0.3)  # 앱 전체가 투명해짐
root.wm_attributes("-transparentcolor", "white")	# 흰색을 투명하도록 지정

canvas = tk.Canvas(root, width=600, height=300, bg='white')	# 배경을 흰색으로 지정
canvas.grid(columnspan=3, rowspan=3)
instructions = tk.Label(root, text="Hello World", font="Raleway")
instructions.grid(columnspan=3, column=0, row=0)

root.mainloop()

 

반응형
반응형

파일관리 프로그램 예제입니다.

 

<main.py>

## File Chooser

from kivy.app import App
from kivy.uix.gridlayout import GridLayout

class TopGridLayout(GridLayout):
    def selected(self, directory, filename):
        try:
            self.ids.image.source = filename[0]
        except:
            pass

class TreeApp(App):
    def build(self):
        return TopGridLayout()

if __name__ == '__main__':
    TreeApp().run()

 

<tree.kv>

<TopGridLayout>:
    cols:2
    id:my_widget

    #FileChooserIconView:
    FileChooserListView:
        id:filechooser
        path:'D:\\'
        dirselect: True
        on_selection:my_widget.selected(filechooser.path, filechooser.selection)

    Image:
        id:image
        source:""

 

<결과>

 

한글 지원이 아직 부족하네요.

반응형
반응형

행성들이 가운데 태양을 중심으로 공전하는 모습을 구현해보겠습니다.

 

<main.py>

import math

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.clock import Clock
import math

Window.size = (900, 900)
center_w = Window.size[0]/2
center_h = Window.size[1]/2

class Sun(Widget):
    pass

class Mercury(Widget):
    pass

class Vinus(Widget):
    pass

class Earth(Widget):
    pass

class Mars(Widget):
    pass

class Solar(Widget):
    sw_seconds = 0
    def update(self, nap):  # nap: 증분, dt delta time
        self.sw_seconds += nap

        ## Earth
        E_dis = 300   # 태양으로부터의 거리
        E_r = self.ids.earth.size[0]      # 지구 직경
        E_rv = 45 # 각도도
        self.ids.earth.pos = self.calc_pos(E_dis, E_r, E_rv)

        ## Mercury
        M_dis = 80  # 태양으로부터의 거리
        M_r = self.ids.mercury.size[0]    # 수성 직경
        M_rv = 60  # 시간에 따른 각도
        self.ids.mercury.pos = self.calc_pos(M_dis, M_r, M_rv)

        ## Vinus
        V_dis = 120  # 태양으로부터의 거리
        V_r = self.ids.vinus.size[0]  # 금성 직경
        V_rv = 50  # 시간에 따른 각도
        self.ids.vinus.pos = self.calc_pos(V_dis, V_r, V_rv)

        ## Mars
        MS_dis = 350  # 태양으로부터의 거리
        MS_r = self.ids.mars.size[0]  # 화성 직경
        MS_rv = 30  # 시간에 따른 각도
        self.ids.mars.pos = self.calc_pos(MS_dis, MS_r, MS_rv)



    def calc_pos(self, dis, radius, radial_v):
        degree = radial_v * self.sw_seconds
        pos_x = dis * math.cos(math.pi * degree / 180) + center_w
        pos_y = dis * math.sin(math.pi * degree / 180) + center_h
        pos = (pos_x, pos_y)
        return pos

class SolarApp(App):
    def build(self):
        SolarSystem = Solar()
        Clock.schedule_interval(SolarSystem.update, 1.0 / 60.0)
        return SolarSystem

if __name__ == '__main__':
    SolarApp().run()

 

<solar.kv>

<Sun>:
    size: 50, 50
    canvas:
        Color:
            rgb: 1,0,0
        Ellipse:
            size: self.size
            pos: self.pos

<Mercury>:
    size: 15, 15
    canvas:
        Color:
            rgb: 0,0,1
        Ellipse:
            size: self.size
            pos: self.pos
<Vinus>:
    size: 20, 20
    canvas:
        Color:
            rgb: 1,1,0
        Ellipse:
            size: self.size
            pos: self.pos

<Earth>:
    size: 20, 20
    canvas:
        Color:
            rgb: 0,1,1
        Ellipse:
            size: self.size
            pos: self.pos
<Mars>:
    size: 18, 18
    canvas:
        Color:
            rgb: 1,0.3,0
        Ellipse:
            size: self.size
            pos: self.pos

<Solar>:
    Sun:
        id:sun
        pos: self.parent.center
    Mercury:
        id:mercury
        pos: self.parent.center
    Vinus:
        id:vinus
        pos: self.parent.center
    Earth:
        id:earth
        pos: self.parent.center
    Mars:
        id:mars
        pos: self.parent.center

<결과>

반응형
반응형

1. main.py

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty

class MyGridLayout(Widget):
    name = ObjectProperty(None) # 변수에 아무것도 할당하지 않도록 함
    pizza = ObjectProperty(None)
    color = ObjectProperty(None)

    def press(self):
        name = self.name.text
        pizza = self.pizza.text
        color = self.color.text

        #self.add_widget(Label(text=f'Hello {name} pizza {pizza} color {color}'))
        print(f'Hello {name} pizza {pizza} color {color}')
        self.name.text = ""
        self.pizza.text = ""
        self.color.text = ""

class MyApp(App):
    def build(self):
        return MyGridLayout()

if __name__ == '__main__':
    MyApp().run()

 

2. my.kv

<MyGridLayout>

    name:name
    pizza:pizza
    color: color

    GridLayout:
        cols:1
        size: root.width, root.height
        GridLayout:
            cols:2

            Label:
                text: "Name"
            TextInput:
                id:name
                multiline:False
            Label:
                text: "Favorite Pizza"
            TextInput:
                id:pizza
                multiline:False
            Label:
                text: "Favorite Color"
            TextInput:
                id:color
                multiline:False

        Button:
            text: "Submit"
            font_size: 32
            on_press: root.press()

 

<결과>

반응형
반응형

파이썬에는 tkinter, pyqt(pyside2), wxpython외에 Kivy라는 라이브러리도 있습니다.

Kivy는 크로스 플랫폼 사용자 인터페이스의 신속한 개발을 위한 오픈 소스 파이썬 라이브러리다. 키비 응용 프로그램을 사용하면 리눅스, 윈도우에 사용하는 GUI 프로그램뿐 아니라 안드로이드, IOS 용 GUI도 개발할 수 있다고 합니다. PC에서는 SDL2와 OpenGL 을 사용해서 그래픽 API를 사용할 수 있고 모바일 환경에서 OpenGL ES (임베디드 시스템용 OpenGL)를 사용하여 균일하고 안정적인 그래픽을 표현할 수 있습니다. 그리고 MIT 라이센스이므로 무료로 사용하는데 제한은 없습니다.

Kivy는 특이하게도 화면을 구성하는 kv파일과 로직을 구성하는 일반 py파일이 구분되어있습니다. JavaFX나 C#의 WPF를 생각하시면 이해될 거라고 생각됩니다. 
 
간단한 예제를 만들어보겠습니다.

 

1. 라이브러리 설치

pip install kivy

# 의존성 문제가 발생할 경우 (먼저 설치 필요)
pip install docutils pygments pypiwin32 kivy_deps.sdl2 kivy_deps.glew kivy_deps.gstreamer

 

2. main.py

from kivy.app import App
from kivy.uix.gridlayout import GridLayout  # 그리드 레이아웃
from kivy.uix.label import Label            # 라벨
from kivy.uix.textinput import TextInput    # 텍스트 인풋
from kivy.uix.button import Button
import os

class LoginScreen(GridLayout):
    def __init__(self, **kwargs):
        super(LoginScreen, self).__init__(**kwargs) # 오버로드되는 원래 클래스의 기능을 구현
        # fontName = '/'.join([os.getenv('SystemRoot'), '/fonts/NanumGothic.ttf'])
        fontName = 'NanumGothic.ttf'
        self.cols = 1

        self.upper = GridLayout()
        self.upper.cols = 2

        self.upper.add_widget(Label(text='이름',font_name=fontName))

        self.username = TextInput(multiline=False)
        self.upper.add_widget(self.username)

        self.upper.add_widget(Label(text='비밀번호',font_name=fontName))

        self.password = TextInput(password=True, multiline=False)
        self.upper.add_widget(self.password)

        self.add_widget(self.upper)

        self.lower = Button(text="Submit", font_size=40)
        self.lower.bind(on_press=self.pressed)  # on_press, on_release, on_state
        self.add_widget(self.lower)

    def pressed(self, instance):
        # print(instance, "is pressed")
        print("user name:", self.username.text, "password:", self.password.text)
        self.username.text = ""
        self.password.text = ""


class MyApp(App):
    def build(self):
        return LoginScreen()

if __name__ == '__main__':
    MyApp().run()

 

<결과>

반응형
반응형

 

우선 PyPDF2 라이브러리 설치가 필요합니다.

pip install pypdf2

 

app.py 파일을 하나 생성하여 아래와 같이 입력합니다. 여기에 로고로 쓸 images.png파일이 필요한데, 인터넷에서 적당한 파일을 다운받으시거나 첨부 파일을 사용하시기 바랍니다.

images.png
0.01MB

import tkinter as tk
import PyPDF2
from PIL import Image, ImageTk
from tkinter.filedialog import askopenfile

root = tk.Tk()

canvas = tk.Canvas(root, width=600, height=300)
canvas.grid(columnspan=3, rowspan=3)

# logo
image = Image.open('images.png')
logo = ImageTk.PhotoImage(image)
logo_label = tk.Label(root, image=logo)
# logo_label.image = logo
logo_label.grid(column=1, row=0)

# instructions
instructions = tk.Label(root, text="Select a PDF file on your computer to extract all its text", font="Raleway")
instructions.grid(columnspan=3, column=0, row=1)

def open_file():
    # print("is this working??")
    browse_text.set("loading...")
    file = askopenfile(parent=root, mode='rb', title="Choose a file", filetype=[("Pdf file", "*.pdf")])
    if file:
        read_pdf = PyPDF2.PdfFileReader(file)
        page = read_pdf.getPage(0)
        page_content = page.extractText()

        #text box
        text_box = tk.Text(root, height=10, width=50, padx=15, pady=15)
        text_box.insert(1.0, page_content)
        text_box.tag_configure("center", justify="center")
        text_box.tag_add("center", 1.0, "end")
        text_box.grid(column=1, row=3)

        browse_text.set("Browse")

# browse button
browse_text = tk.StringVar()
browse_btn = tk.Button(root, textvariable=browse_text, command=lambda:open_file(), font="Raleway", bg="#20bebe", fg="white", height=2, width=15)
browse_text.set("Browse")
browse_btn.grid(column=1, row=2)

# 하단 갭 생성
canvas = tk.Canvas(root, width=600, height=250)
canvas.grid(columnspan=3)

root.mainloop()

 

<결과>

Browse 버튼을 누르면 파일탐색기가 실행되고, pdf 파일을 누르면 내용을 불러옵니다. 단, 아직은 텍스트로 작성된 pdf만 불러와집니다.

반응형
반응형

1. hello_world.py

import PySimpleGUI as sg

sg.Window(title="Hello World", layout=[[]], margins=(100,50)).read()

 

2. hello_psg.py

import PySimpleGUI as sg

layout = [
    [sg.Text("Hello from PySimpleGUI")],
    [sg.Button("OK")]
]

window = sg.Window("Demo", layout)

while True:
    event, values = window.read()
    if event =="OK" or event == sg.WIN_CLOSED:
        break

window.close()

3. Image_Viewer.py

import PySimpleGUI as sg
import os.path
file_list_column = [
    [
        sg.Text("Image Folder"),
        sg.In(size=(25,1), enable_events=True, key="-FOLDER-"),
        sg.FolderBrowse(),
    ],
    [
        sg.Listbox(
            values=[], enable_events=True, size=(40, 20),
            key="-FILE LIST-"
        )
    ],
]
image_viewer_column = [
    [sg.Text("Choose an image from the list on the left:")],
    [sg.Text(size=(40,1), key="-TOUT-")],
    [sg.Image(key="-IMAGE-")],
]

layout = [
    [
        sg.Column(file_list_column),
        sg.VSeperator(),
        sg.Column(image_viewer_column),
    ]
]

window = sg.Window("Image Viewer", layout)

while True:
    event, values = window.read()
    if event =="Exit" or event == sg.WINDOW_CLOSED:
        break
    if event == "-FOLDER-":
        folder = values["-FOLDER-"]
        try:
            file_list = os.listdir(folder)
        except:
            file_list = []

        fnames = [
            f
            for f in file_list
            if os.path.isfile(os.path.join(folder, f))
            and f.lower().endswith((".png", ".gif"))
        ]
        window["-FILE LIST-"].update(fnames)
    elif event == "-FILE LIST-":
        try:
            filename = os.path.join(
                values["-FOLDER-"], values["-FILE LIST-"][0]
            )
            window["-TOUT-"].update(filename)
            window["-IMAGE-"].update(filename=filename)
        except:
            pass


window.close()

 

<결과>

반응형

+ Recent posts