라즈베리파이 Python 프로그래밍 13: TTK 메뉴, 레이아웃 관리, 이벤트 및 멀티스레딩
이전의 튜토리얼에서 Tkinter와 TTK 위젯에 대해 알아보았습니다. 이러한 위젯의 도움으로 임베디드 전자 장치를 제어하기 위한 사용자 인터페이스를 만들 것입니다. 우리는 이미 Raspberry Pi(RPi) 임베디드 전자 제어 앱을 위한 빈 GUI 창을 만들었습니다.
이 자습서에서는 TTK 메뉴에 대해 배우고 RPi 앱용 메뉴를 만듭니다. 또한 Tkinter/TTK의 레이아웃 관리 및 이벤트와 멀티스레딩에 대해서도 논의할 것입니다.
이것은 GUI 인터페이스에서 실행되고 임베디드 작업의 구현을 위해 스레드를 사용할 RPi 레시피에 대한 충분한 기반을 제공해야 합니다.
Tkinter/TTK 메뉴
메뉴 모음과 팝업 메뉴는 그래픽 인터페이스에서 일반적이며 응용 프로그램의 다른 섹션을 탐색하는 데 사용됩니다. 메뉴는 다양한 기능이나 사용자 옵션에 대한 체계적인 액세스를 제공합니다. 일반적으로 다른 중첩 메뉴(하위 메뉴 또는 계단식 메뉴)를 항목으로 포함할 수 있는 항목의 드롭다운 목록입니다. 하위 메뉴는 일반적으로 중첩된 드롭다운 목록으로 채워집니다.
메뉴의 항목을 클릭하면 콜러블이 실행될 수 있습니다. 일반적으로 콜러블은 일부 기능에 대한 인터페이스를 채우거나 현재 인터페이스 내에서 추가 사용자 옵션을 제공하는 데 사용됩니다.
예를 들어 RPi 앱에서 다양한 프로그램을 개발할 것이며 그 중 일부는 다음을 처리합니다.
- 디스플레이 장치
- 센서
- 애플리케이션별 모듈
- 통신 인터페이스
- 그리고 아마도 더
앱의 다른 프로그램에 액세스하려면 각 카테고리에 대한 메뉴를 만드는 것이 가장 좋습니다.
Tk GUI 툴킷에서 메뉴는 위젯으로 구현됩니다. 메뉴는 메뉴 개체를 인스턴스화하여 생성되는 클래스이기도 합니다. 메뉴 개체의 부모는 창(메인 창 또는 자식 창), 프레임 또는 다른 메뉴가 될 수 있습니다. 창을 부모로 사용하여 메뉴 개체를 인스턴스화하면 메뉴 모음이 자동으로 생성됩니다.
창에는 둘 이상의 메뉴 모음이 있을 수 없습니다. 표시될 때 메뉴 표시줄은 창의 제목 표시줄 아래에 있습니다.
상위 메뉴가 다른 메뉴인 메뉴 개체를 인스턴스화하면 하위 메뉴(계단식 메뉴)가 됩니다. 따라서 창에는 메뉴 모음이 있어야 하고 메뉴 모음에는 다른 항목이 포함되어야 합니다.
모든 메뉴의 항목은 명령 항목, 기타 메뉴(하위 메뉴), 구분 기호, 라디오 버튼 항목 또는 체크 버튼 항목이 될 수 있습니다. 메뉴 모음에는 명령 항목, 기타 메뉴(하위 메뉴), 라디오 버튼 항목 또는 체크 버튼 항목이 포함될 수 있습니다. 하위 메뉴의 항목은 다른 항목(command, Radiobutton, Checkbutton), 중첩 메뉴 또는 구분 기호일 수 있습니다. 각 메뉴 항목에는 항목에 대한 텍스트/이미지, 키보드 가속기 및 호출할 명령(연관된 호출 가능)과 같은 몇 가지 속성이 있습니다.
메뉴바는 부모가 창(메인 창 또는 자식 창)인 메뉴 개체를 인스턴스화하여 만들 수 있습니다. 메뉴 객체는 Tkinter/TTK 클래스의 Menu 메서드를 사용하여 인스턴스화됩니다.
다음은 기본 창에 대한 메뉴 표시줄을 만드는 코드입니다.
root = Tk()
root.title(“RPi Embedded Electronics Control APP”)
root.minsize(480, 480)
root.resizable(0, 0)
main_menu = Menu(root)
명령 항목은 메뉴 모음(그 자체가 메뉴임)이나 Menu 클래스의 add_command() 메서드를 사용하여 모든 메뉴에 추가할 수 있습니다. Menu 클래스의 add_cascade() 메서드를 사용하여 메뉴 모음이나 메뉴에 하위 메뉴(메뉴 항목)를 추가할 수 있습니다.
그러나 하위 메뉴는 상위 메뉴 개체가 상위 메뉴 개체인 메뉴 개체로 인스턴스화되어야 합니다. (그리고 부모 메뉴는 이미 생성되어 있어야 합니다.)
add_cascade() 메서드는 자식 메뉴를 인수 중 하나로 사용하고 해당 자식 메뉴의 레이블을 다른 인수로 사용합니다. 기본적으로 tkinter/ttk는 점선으로 나타나는 구분 기호로 각 하위 메뉴를 시작합니다. 이 시작 구분 기호를 제거하려면 하위 메뉴 정의에서 "tearoff" 속성을 False로 설정해야 합니다.
다음은 위의 코드 조각을 사용하여 메뉴 모음의 항목으로 하위 메뉴를 만드는 코드입니다.
displays_menu = Menu(main_menu, tearoff=0)
main_menu.add_cascade(label=”Displays”, menu=displays_menu)
sensors_menu = Menu(main_menu, tearoff=0)
main_menu.add_cascade(label=”Sensors”, menu=sensors_menu)
modules_menu = Menu(main_menu, tearoff=0)
main_menu.add_cascade(label=”Modules”, menu=modules_menu)
motors_menu = Menu(main_menu, tearoff=0)
main_menu.add_cascade(label=”Motors”, menu=motors_menu)
comm_menu = Menu(main_menu, tearoff=0)
main_menu.add_cascade(label=”Communication”, menu=comm_menu)
help_menu = Menu(main_menu, tearoff=0)
main_menu.add_cascade(label=”Help”, menu=help_menu)
add_command() 메서드는 메뉴(메뉴 모음, 메뉴 또는 하위 메뉴)에 명령 항목을 추가하는 데 사용됩니다. 항목의 레이블을 하나의 인수로 사용하고 명령을 사용하여 다른 인수를 호출합니다. 명령 인수는 메뉴 항목을 클릭할 때 실행되어야 하는 호출 가능(함수 또는 클래스 메서드)을 할당할 수 있습니다. 이것은 위의 코드를 사용하여 하위 메뉴에 명령 항목을 추가하는 유효한 예입니다.
displays_menu.add_command(label=”LEDs”, command=donothing)
displays_menu.add_command(label=”SSDs”, command=donothing)
displays_menu.add_command(label=”Character LCD”, command=donothing)
displays_menu.add_command(label=”Graphic LCD”, command=donothing)
displays_menu.add_separator()
displays_menu.add_command(label=”Touch Screen”, command=donothing)
sensors_menu.add_command(label=”LDR”, command=donothing)
sensors_menu.add_command(label=”IR”, command=donothing)
sensors_menu.add_command(label=”HC-SR04 Ultrasonic”, command=donothing)
sensors_menu.add_command(label=”LM35″, command=donothing)
sensors_menu.add_command(label=”DHT-11″, command=donothing)
sensors_menu.add_command(label=”Motion Sensor”, command=donothing)
sensors_menu.add_command(label=”Moisture Sensor”, command=donothing)
sensors_menu.add_command(label=”Accelerometer”, command=donothing)
sensors_menu.add_command(label=”Accelero + Gyro”, command=donothing)
modules_menu.add_command(label=”GPS”, command=donothing)
modules_menu.add_command(label=”GSM”, command=donothing)
modules_menu.add_command(label=”Fingerprint”, command=donothing)
modules_menu.add_command(label=”RFID”, command=donothing)
modules_menu.add_command(label=”RTC”, command=donothing)
motors_menu.add_command(label=”DC”, command=donothing)
motors_menu.add_command(label=”Stepper”, command=donothing)
motors_menu.add_command(label=”Servo”, command=donothing)
comm_menu.add_command(label=”RF”, command=donothing)
comm_menu.add_command(label=”USB”, command=donothing)
comm_menu.add_command(label=”Ethernet”, command=donothing)
comm_menu.add_command(label=”Bluetooth”, command=donothing)
comm_menu.add_command(label=”Wi-Fi”, command=donothing)
help_menu.add_command(label=”Index”, command=donothing)
help_menu.add_command(label=”About…”, command=donothing)
help_menu.add_command(label=”Exit”, command=root.quit)
명령 항목 및 메뉴 유형 항목과 함께 구분 기호, 라디오 버튼 항목, 체크 버튼 항목을 메뉴에 추가할 수 있습니다. add_separator() 메서드를 사용하여 메뉴에 구분 기호를 추가할 수 있습니다. 이 메서드에는 인수가 필요하지 않습니다. 구분 기호는 다른 메뉴 항목 사이에 수평선으로 나타납니다.
다음은 메뉴에 구분 기호를 추가하는 유효한 예입니다.
displays_menu.add_separator()
메뉴 클래스의 add_checkbutton() 메서드를 사용하여 메뉴에 Checkbutton 항목을 추가할 수 있습니다. 이 메서드는 제어 변수인 Checkbutton에 대한 레이블과 onvalue 및 offvalue를 인수로 사용합니다.
체크 버튼 항목을 클릭하면 연결된 제어 변수의 값이 onvalue 또는 offvalue로 설정됩니다. 이 변수는 코드의 어딘가에서 사용할 수 있습니다. Checkbutton을 클릭할 때마다 콜러블을 실행하는 Checkbutton에 대한 명령 인수를 할당하는 것도 가능합니다.
다음은 메뉴에 Checkbutton 항목을 추가하는 유효한 예입니다.
any_menu.add_checkbutton(label=’Check’, variable=check, onvalue=1, offvalue=0)
메뉴 클래스의 add_radiobutton() 메서드를 사용하여 라디오 버튼 항목을 메뉴에 추가할 수 있습니다. 이 메서드는 라디오 버튼, 변수 및 값에 대한 레이블을 인수로 사용합니다.
라디오 버튼을 클릭하면 해당 라디오 버튼과 연결된 값이 연결된 변수에 할당됩니다. 이 변수는 코드의 어딘가에서 사용할 수 있습니다. 라디오 버튼이 토글될 때마다 호출 가능 항목을 실행하는 라디오 버튼에 대한 명령 인수를 할당하는 것도 가능합니다.
다음은 메뉴에 라디오 버튼 항목을 추가하는 유효한 예입니다.
any_menu.add_radiobutton(label=’Option1′, variable=variable, value=”Option1″)
any_menu.add_radiobutton(label=’Option1′, variable=variable, value=”Option1″)
any_menu.add_radiobutton(label=’Option1′, variable=variable, value=”Option1″)
any_menu.add_radiobutton(label=’Option1′, variable=variable, value=”Option1″)
메뉴 모음은 창 개체에 대한 메뉴 옵션으로 구성될 때까지 부모 창에 표시되지 않습니다. 메뉴 옵션은 창 개체의 config() 메서드를 사용하여 설정할 수 있습니다.
다음은 위의 코드를 사용하여 메뉴를 주 창의 메뉴 표시줄로 설정하는 유효한 예입니다.
root.config(menu = main_menu)
root.mainloop()
항목 정의에서 액셀러레이터 인수를 사용하여 메뉴 항목에 액셀러레이터 키(단축키)를 할당할 수도 있습니다. 이 인수에는 (키보드) 키 조합이 할당되어야 합니다.
메뉴 항목의 레이블 텍스트에서 문자에 밑줄을 긋려면 underline 인수를 사용하십시오. 이미지 및 복합 인수를 사용하여 메뉴 항목의 레이블 텍스트 대신 이미지를 사용할 수도 있습니다. 이러한 인수에는 이미지 개체가 할당되어야 합니다. 또한 state 인수를 사용하여 메뉴의 상태를 "normal" 또는 "disabled"로 설정할 수 있습니다.
위의 예에서 메뉴의 명령 항목에 대한 명령 인수에는 donothing() 함수가 할당되었습니다.
이 함수는 다음과 같은 몸체만 가지고 있습니다.
def do-nothing():
pass
위의 코드 예제를 통해 앱에 대한 메뉴를 만들었습니다. 앱을 개발할 때 donothing() 함수를 callable(s)로 대체하여 다양한 전자 부품, 인터페이스 및 작업에 대한 임베디드 시스템 프로그램을 적절하게 구현합니다.
호출 가능 항목은 함수 또는 클래스 메서드일 수 있습니다. 클래스 메서드보다 항상 빠르기 때문에 함수를 사용하는 것을 선호합니다.
다음은 앱용으로 방금 만든 메뉴 모음의 스크린샷입니다.
Tkinter/TTK 레이아웃 관리
위젯은 효율적이고 조직적인 방식으로 발생해야 하는 사용자와의 상호 작용을 제공합니다. 그렇게 하려면 위젯을 순서대로 상위 창에 배치해야 합니다. 이 순서를 창의 레이아웃이라고 합니다.
Tkinter/TTK는 절대 위치 지정, 팩 및 그리드의 세 가지 유형의 레이아웃을 제공합니다.
위젯의 절대 위치 지정을 위해 place() 메서드가 사용됩니다. 이 메서드는 각 위젯에 대해 호출해야 합니다. 절대 위치 지정은 각 위젯이 픽셀 단위로 위치를 지정하여 창을 기준으로 배치됨을 의미합니다. 위젯의 높이와 너비는 place() 메서드에서 인수로 설정할 수도 있습니다.
위치 지정을 위해 "x" 및 "y" 인수는 픽셀 값으로 전달되어야 합니다. 높이와 너비를 지정하려면 relheight 및 relwidth 인수를 각각 픽셀 값으로 전달해야 합니다. relheight 및 relwidth 인수는 픽셀 값을 위반으로 사용합니다.
창 크기를 조정하거나 글꼴을 변경하거나 창을 다른 플랫폼(Mac OS, Microsoft Windows 또는 X11)에서 볼 때 위젯의 크기와 위치는 절대 변경되지 않습니다. 절대 위치는 가장 기본적인 레이아웃이지만 더 나은 사용자 경험을 위해 피해야 합니다.
팩 레이아웃의 경우 pack() 메서드가 사용됩니다. 이 레이아웃에서 위젯은 창에 수직 또는 수평 상자로 배치됩니다. pack() 메서드는 측면, 채우기 및 확장의 세 가지 인수를 사용합니다.
side 인수는 위젯이 배치되어야 하는 상위 위젯의 측면을 결정합니다. TOP, BOTTOM, LEFT 또는 RIGHT와 같은 값을 할당할 수 있습니다.
채우기 인수는 위젯이 상위 위젯에서 사용 가능한 추가 공간을 채우는 방법을 결정합니다. 다음과 같은 값을 가질 수 있습니다.
- NONE(참고: 기본값을 사용하면 위젯이 추가 공간을 채우기 위해 확장되지 않음)
- X – 가로로 채우기
- Y – 세로로만 채우기
- BOTH – 가로 및 세로 모두 채우기
expand 인수가 True로 설정되면 위젯은 상위 위젯에서 사용 가능한 모든 추가 공간을 차지합니다. 팩 레이아웃은 절대 위치 지정보다 낫지만 여전히 단순한 인터페이스에만 적합합니다.
그리드 레이아웃의 경우 grid() 메서드가 사용되며 위젯은 동일한 간격의 행과 열로 구성됩니다. 각각 rowspan 및 columnspan 인수를 사용하여 여러 행 및/또는 열에 걸쳐 위젯을 설정할 수 있습니다.
위젯의 위치는 지정된 행-열 위치에 위젯을 배치하는 행 및 열 인수를 사용하여 지정됩니다. 이것은 위젯을 배치하는 가장 체계적인 방법이며 복잡한 인터페이스를 디자인하는 데 사용할 수 있습니다.
위젯에서 패커 메소드(place, pack 또는 grid)가 호출될 때까지는 창에 나타나지 않는다는 점에 유의해야 합니다. 우리는 모든 RPi 레시피의 GUI에 그리드 레이아웃을 사용할 것입니다.
Tkinter/TTK Event
위젯은 여러 키보드 또는 마우스 이벤트에 바인딩할 수 있습니다. 해당 이벤트가 위젯에서 발생할 때 호출 가능 항목을 실행할 수 있습니다. 예를 들어, 커서가 위젯 위에 놓이거나 사용자가 위젯을 클릭하거나 더블 클릭할 때 호출 가능이 실행될 수 있습니다. 아래에 Tkinter/TTK에서 지원하는 이벤트를 나열합니다.
이벤트 수정자
Event Modifier | Meaning |
Alt | The Alt key is held |
Control | The Ctrl key is held |
Shift | The Shift key is held |
Any | This modifier makes an event type general. For example, the event pattern <Any-KeyPress> applies to the keypress of any key. |
이벤트 타입
Type | Name | Description |
36 | Activate | The state option of a widget changes from inactive to active. |
4 | Button | One mouse button is pressed |
5 | ButtonRelease | One mouse button is released |
22 | Configure | The size of the widget is changed |
37 | Deactivate | The state option of a widget change from active to inactive. |
17 | Destroy | A widget is being destroyed. |
7 | Enter | The mouse pointer is moved into a visible part of a widget. |
12 | Expose | Some part of the widget or application is visible after having been covered up by another window. |
9 | FocusIn | The input focus was moved into a widget. |
10 | FocusOut | The input focus was moved out of a widget. |
2 | KeyPress | A key is pressed. |
3 | KeyRelease | A key is released |
8 | Leave | The mouse pointer is moved out of a widget. |
19 | Map | A widget is being placed on a container e.g., calling the pack() or grid() method. |
6 | Motion | The mouse pointer is moved entirely within a widget. |
38 | MouseWheel | The user moved the mouse wheel up or down. |
18 | Unmap | A widget is being unmapped and is no longer visible, for example when calling the grid_remove() method on the widget. |
15 | Visibility | At least some part of the application window becomes visible on the screen. |
Event Detail
.keysym | .keycode | .keysym_num | Key |
Alt_L | 64 | 65513 | The left-hand alt key |
Alt_R | 113 | 65514 | The right-hand alt key |
BackSpace | 22 | 65288 | backspace |
Cancel | 110 | 65387 | break |
Caps_Lock | 66 | 65549 | CapsLock |
Control_L | 37 | 65507 | The left-hand control key |
Control_R | 109 | 65508 | The right-hand control key |
Delete | 107 | 65535 | Delete |
Down | 104 | 65364 | ↓ |
End | 103 | 65367 | end |
Escape | 9 | 65307 | esc |
Execute | 111 | 65378 | SysReq |
F1 | 67 | 65470 | Function key F1 |
F2 | 68 | 65471 | Function key F2 |
Fi | 66+i | 65469+i | Function key Fi |
F12 | 96 | 65481 | Function key F12 |
Home | 97 | 65360 | home |
Insert | 106 | 65379 | insert |
Left | 100 | 65361 | ← |
Linefeed | 54 | 106 | Linefeed (control-J) |
KP_0 | 90 | 65438 | 0 on the keypad |
KP_1 | 87 | 65436 | 1 on the keypad |
KP_2 | 88 | 65433 | 2 on the keypad |
KP_3 | 89 | 65435 | 3 on the keypad |
KP_4 | 83 | 65430 | 4 on the keypad |
KP_5 | 84 | 65437 | 5 on the keypad |
KP_6 | 85 | 65432 | 6 on the keypad |
KP_7 | 79 | 65429 | 7 on the keypad |
KP_8 | 80 | 65431 | 8 on the keypad |
KP_9 | 81 | 65434 | 9 on the keypad |
KP_Add | 86 | 65451 | + on the keypad |
KP_Begin | 84 | 65437 | The center key (same key as 5) on the keypad |
KP_Decimal | 91 | 65439 | Decimal (.) on the keypad |
KP_Delete | 91 | 65439 | delete on the keypad |
KP_Divide | 112 | 65455 | / on the keypad |
KP_Down | 88 | 65433 | ↓ on the keypad |
KP_End | 87 | 65436 | end on the keypad |
KP_Enter | 108 | 65421 | enter on the keypad |
KP_Home | 79 | 65429 | home on the keypad |
KP_Insert | 90 | 65438 | insert on the keypad |
KP_Left | 83 | 65430 | ← on the keypad |
KP_Multiply | 63 | 65450 | × on the keypad |
KP_Next | 89 | 65435 | PageDown on the keypad |
KP_Prior | 81 | 65434 | PageUp on the keypad |
KP_Right | 85 | 65432 | → on the keypad |
KP_Subtract | 82 | 65453 | - on the keypad |
KP_Up | 80 | 65431 | ↑ on the keypad |
Next | 105 | 65366 | PageDown |
Num_Lock | 77 | 65407 | NumLock |
Pause | 110 | 65299 | pause |
111 | 65377 | PrintScrn | |
Prior | 99 | 65365 | PageUp |
Return | 36 | 65293 | Enter key |
Right | 102 | 65363 | → |
Scroll_Lock | 78 | 65300 | ScrollLock |
Shift_L | 50 | 65505 | The left-hand shift key |
Shift_R | 62 | 65506 | The right-hand shift key |
Tab | 23 | 65289 | The tab key |
위젯의 이벤트에 콜러블을 바인딩하기 위해 bind() 메소드가 사용됩니다. 다음과 같은 구문이 있습니다.
widget_name.bind(event, callable)
다음은 이벤트 바인딩의 코드 예입니다.
label_LED_ON.bind(<Enter>, changeColor) #changeColor is a function/method
키보드 및 마우스 이벤트 외에도 일부 위젯은 가상 이벤트를 지원합니다. 위젯의 상태 또는 내용 변경을 트리거하는 위젯별 이벤트입니다. 예를 들어 Combobox는 사용자가 Combobox에서 값을 선택할 때 트리거되는 <<ComboboxSelected> 가상 이벤트를 지원합니다.
다음은 가상 이벤트를 사용한 바인딩의 유효한 예입니다.
combo_LED_op.bind(‘<<ComboboxSelected>>’, active_blink) # active_blink is callable
다중 스레딩 Multi-threading
무한 루프는 임베디드 시나리오에서 매우 일반적입니다. 예를 들어, 센서에서 지속적으로 데이터를 가져오거나 디스플레이에 메시지를 계속 채워야 하거나 일부 외부 인터럽트 또는 조건이 일치할 때까지 액추에이터를 실행해야 할 수 있습니다.
그러나 GUI에서 무한 루프를 실행하려고 하면 정지됩니다. GUI가 프로세스로 실행되고 있기 때문입니다.
따라서 솔루션은 GUI를 중단하지 않고 이러한 루프를 실행하는 것이며 이를 다중 스레딩이라고 합니다. 즉, 별도의 스레드에서 전자 제품용 코드를 실행할 수 있습니다. 이러한 스레드는 GUI와 병렬로 실행되며 제어 응용 프로그램을 중단하거나 중단하지 않습니다. 기본적으로 우리는 모든 RPi 레시피, 마이크로컨트롤러 방식 및 제어 애플리케이션을 독립적으로 실행할 것입니다.
멀티 스레딩은 여러 임베디드 작업을 동시에 수행할 수 있는 좋은 방법이며, 이는 어떤 마이크로컨트롤러에서도 불가능합니다. 마이크로컨트롤러는 코드를 순차적으로 실행하며 다중 스레딩 기능이 있습니다.
다중 스레딩의 경우 먼저 다음과 같이 스레딩 및 sys 모듈을 가져와야 합니다.
import threading
import sys
또한 스레드를 GUI 앱의 모든 위치에서 사용할 수 있도록 전역 개체로 만들어야 합니다. 이것은 정의된 전역 변수이며 나중에 스레딩 개체에 할당됩니다.
thread_LED_driver = None
불행히도 Python의 스레딩 모듈에는 스레드를 종료하는 방법이 없습니다. 하지만 약간의 코딩 트릭으로 이 문제를 해결할 수 있습니다. 스레딩 모듈을 재정의하고 사용자 정의 kill 이벤트를 작성할 수 있습니다.
이를 위해 다음과 같이 재정의 메서드를 사용하여 클래스를 작성합니다.
class MyThread(threading.Thread):
def __init__(self, *args, **kwargs):
super(MyThread, self).__init__(*args, **kwargs)
self._stop = threading.Event(
def stop(self):
self._stop.set()
def stopped(self):
self._stop.isSet()
def run(self):
while 1:
if self.stopped():
print(“Thread Closed”)
x = 1
return
else:
self._target(*self._args, **self._kwargs)
나중에 이 클래스를 사용하여 다양한 내장 함수에 대한 스레드를 정의할 수 있습니다. 예를 들어 다음 함수는 스레드 개체에 할당되도록 정의된 전역 변수를 사용하여 스레드를 시작합니다. 스레드는 호출 가능 항목을 실행하고 원하는 임베디드 작업을 차례로 실행합니다.
def thread_generate_LED_signal():
global thread_LED_driver
thread_LED_driver = MyThread(target = func_gen_LED_signal)
thread_LED_driver.start()
스레딩 모듈의 메서드를 재정의하는 클래스를 이미 생성했으므로 이 클래스에는 스레드를 중지/종료하는 이벤트가 정의되어 있습니다. 이 사용자 정의 방법을 사용하여 스레드를 가상으로 중지할 수 있습니다.
이 함수는 위의 함수에서 생성된 스레드를 종료합니다.
def shutdown_LED_signal():
global thread_LED_driver
thread_LED_driver.stop()
언급했듯이 함수는 클래스 메서드보다 빠르므로 대부분의 경우 내장된 모든 응용 프로그램 코드를 함수에 래핑합니다. Python은 함수 내부의 함수 정의를 허용합니다.
따라서 우리는 이 기능을 사용하여 모든 임베디드 코드를 각 임베디드 작업에 대한 단일 기능으로 마무리합니다. 예를 들어 LCD가 RPi와 인터페이스되는 경우 단일 기능으로 LCD에 대한 메시지를 제어하고 채우도록 모든 임베디드 코드를 제한합니다. 그런 다음 해당 함수를 별도의 스레드에서 실행합니다. 이렇게 하면 각 구성 요소를 독립적으로 동시에 동시에 제어할 수 있습니다.
GUI 도구로서의 Tkinter/TTK 제한
Tk GUI 도구 키트는 복잡한 그래픽 인터페이스를 만드는 데 탁월합니다. 또한 레이아웃 관리를 단순화하고 대부분의 컨트롤 및 사용자 상호 작용을 생성하기에 충분한 위젯이 있습니다. 그러나 이 툴킷의 한 가지 주요 제한 사항은 정적 인터페이스만 생성한다는 것입니다. 위젯은 런타임에 동적으로 생성 및 채울 수 없습니다.
이상적으로 Tk 툴킷은 동적 인터페이스를 지원했지만 그렇지 않습니다. 그렇다면 RPi 시스템과 인터페이스하는 새 하드웨어 구성 요소에 대한 컨트롤을 동적으로 추가할 수 있었고 가변 배열을 사용하여 해당 구성 요소를 운영할 수 있었습니다.
첫 번째 Raspberry Pi 레시피인 LED 드라이버를 소개하는 다음 자습서에서 이 제한 사항을 경험하게 될 것입니다.
연결 유지
다음 튜토리얼부터는 하드웨어 구성 요소에 대한 다양한 레시피를 구현할 것입니다. 마이크로컨트롤러에서 동일한 구성요소를 제어할 때의 차이점을 비교할 것입니다. 또한 SBC-Vs-Microcontroller, Python 또는 Linux 요인으로 인해 부과되는 제한 사항, 장점 및 단점에 대해서도 논의합니다.
'개발자 > 라즈베리파이4' 카테고리의 다른 글
라즈베리파이 4 IoT(사물인터넷) 1강 IoT와 웨어러블 디바이스 (0) | 2021.11.20 |
---|---|
라즈베리파이 Python 프로그래밍 15: 푸시 버튼 및 디지털 입력 인터페이스 (0) | 2021.11.19 |
라즈베리파이 Python 프로그래밍 14: GUI 제어 LED 드라이버 (0) | 2021.11.18 |
라즈베리파이 4 기반 IoT(사물인터넷) 설계 5강 스마트 IoT 설계 시스템 (0) | 2021.11.17 |
라즈베리파이 Python 프로그래밍 12: Tkinter 및 TTK 위젯 (0) | 2021.11.16 |
라즈베리파이 Python 프로그래밍 11: Tkinter를 사용한 Python GUI (0) | 2021.11.15 |
라즈베리파이 4 Adafruit DHT11 DHT22 온도 습도 센서 문제 (0) | 2021.11.11 |
라즈베리파이 4에서 VNC 접속하여 사용하기 Raspberry Pi4 VNC Connect (2) | 2021.11.10 |
더욱 좋은 정보를 제공하겠습니다.~ ^^