Profile picture

[Python / GUI] PySide6로 지역 선택 기능 구현해보기: 시/도, 시/군/구, 읍/면/동

JaehyoJJAng2024년 09월 11일

개요

오늘은 PySide6를 활용하여 시/도 -> 시/군/구 -> 읍/면/동 단계별로 연동되는 지역 선택 기능을 구현해볼거다.
example


목표

  • 1. 시/도 선택: 첫 번째 QComboBox에서 시/도를 선택한다.
  • 2. 시/군/구 선택: 선택한 시/도에서 해당하는 시/군/구가 두 번째 QComboBox에 표시된다.
  • 3. 읍/면/동 선택: 선택한 시/군/구에 해당하는 읍/면/동이 세 번째 QComboBox에 표시된다.
  • 4. 각 항목에는 고유한 ID(sidoID)가 포함되어 있으며, 이를 기반으로 데이터를 관리한다.

구현

1. 기본 데이터 설계

지역 데이터를 계층적으로 저장하며, 각 항목은 고유한 ID를 가지도록 작성하자.

테스트를 위해 아래와 같은 테스트용 계층 데이터를 임의로 작성하였다.

region_data = {
    "서울특별시": {
        "sidoID": 1,
        "children": {
            "강남구": {
                "sidoID": 90,
                "children": {
                    "삼성동": 900,
                    "역삼동": 901,
                    "논현동": 902
                }
            },
            "송파구": {
                "sidoID": 91,
                "children": {
                    "잠실동": 910,
                    "문정동": 911,
                    "가락동": 912
                }
            }
        }
    },
    "경기도": {
        "sidoID": 2,
        "children": {
            "수원시": {
                "sidoID": 100,
                "children": {
                    "장안구": 1000,
                    "권선구": 1001,
                    "영통구": 1002
                }
            },
            "고양시": {
                "sidoID": 101,
                "children": {
                    "일산동구": 1010,
                    "일산서구": 1011,
                    "덕양구": 1012
                }
            }
        }
    }
}

2. PySide6 UI 구성

QComboBox를 활용하여 세 개의 콤보박스를 생성한다.

각 콤보박스는 선택 이벤트에 따라 연동될거다.
image



3. 메인 윈도우 클래스

QMainWindow를 상속하여 UI를 구성하고 데이터 연동 로직을 추가한다.

class RegionSelector(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("지역 선택")
        self.setGeometry(100, 100, 400, 200)

        # 메인 위젯 및 레이아웃 설정
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        layout = QVBoxLayout()
        main_widget.setLayout(layout)

        # 콤보박스 생성
        self.combo_sido = QComboBox()
        self.combo_sigungu = QComboBox()
        self.combo_eupmyeon = QComboBox()

        # 콤보박스 초기화
        self.combo_sido.addItem("시/도 선택", -1)
        for sido, data in region_data.items():
            self.combo_sido.addItem(sido, data["sidoID"])
        
        self.combo_sigungu.addItem("시/군/구 선택", -1)
        self.combo_eupmyeon.addItem("읍/면/동 선택", -1)

        # 콤보박스를 레이아웃에 추가
        layout.addWidget(self.combo_sido)
        layout.addWidget(self.combo_sigungu)
        layout.addWidget(self.combo_eupmyeon)

        # 시그널 연결
        self.combo_sido.currentIndexChanged.connect(self.update_sigungu)
        self.combo_sigungu.currentIndexChanged.connect(self.update_eupmyeon)

4. 시/군/구 및 읍/면/동 연동

선택 이벤트에 따라 콤보박스를 동적으로 업데이트한다.

    def update_sigungu(self):
        self.combo_sigungu.clear()
        self.combo_eupmyeon.clear()
        self.combo_sigungu.addItem("시/군/구 선택", -1)
        self.combo_eupmyeon.addItem("읍/면/동 선택", -1)

        selected_sido = self.combo_sido.currentText()
        if selected_sido in region_data:
            for sigungu, data in region_data[selected_sido]["children"].items():
                self.combo_sigungu.addItem(sigungu, data["sidoID"])

    def update_eupmyeon(self):
        self.combo_eupmyeon.clear()
        self.combo_eupmyeon.addItem("읍/면/동 선택", -1)

        selected_sido = self.combo_sido.currentText()
        selected_sigungu = self.combo_sigungu.currentText()

        if selected_sido in region_data:
            sigungu_data = region_data[selected_sido]["children"].get(selected_sigungu, {})
            if "children" in sigungu_data:
                for eupmyeon, sidoID in sigungu_data["children"].items():
                    self.combo_eupmyeon.addItem(eupmyeon, sidoID)

실행 결과

아래는 실행 화면을 캡쳐한 것이다.
example

  • 시/도 선택: "서울특별시" 선택 시, 강남구, 송파구 ..가 표시된다.
  • 시/군/구 선택: "강남구" 선택시 삼성동, 역삼동 ..가 표시된다.

또한 선택된 항목의 ID는 QComboBOx.currentData()로 가져올 수도 있다.

예를 들어:

selected_sido_id = self.combo_sido.currentData()
selected_sigungu_id = self.combo_sigungu.currentData()
selected_eupmyeon_id = self.combo_eupmyeon.currentData()

print(f"시/도 ID: {selected_sido_id}, 시/군/구 ID: {selected_sigungu_id}, 읍/면/동 ID: {selected_eupmyeon_id}")

Loading script...