카테고리 없음

PYQT에 대한 질문 사항

김영수 2024. 11. 10. 15:59

 

self.line4가 init에 있고, update함수 실행될때 line4의 자식을 없애고, 다시 생성하는 방법으로 하려했는데 안돼서 레이아웃이라도 넣어봤는데 이렇게했더니 또 위치도 이상하고.. 분명 tkinter에서는 잘됐는데 잘안되네요..

 

def update_ui(self, *Args):
    """선택된 옵션에 따라 다른 UI를 동적으로 표시"""

    # 삭제할 위젯들을 저장할 리스트 초기화
    widgets_to_delete = []

    # line4에 있는 모든 위젯을 리스트에 저장
    for widget in self.line4.winfo_children():
        widgets_to_delete.append(widget)

    # 현재 선택된 옵션 확인
    selected_option = self.option_var.get()

    # 업데이트 옵션 선택 시
    if selected_option == "업데이트":
        version_frame = ctk.CTkFrame(self.line4, corner_radius=12, width=158, height=66, bg_color="#ffffff", fg_color="#EAF3FA")
        version_frame.place(x=0, y=0)

        ctk.CTkLabel(version_frame, text="VERSION", bg_color="#EAF3FA", text_color="#8CB2E1", font=("Lato", 12)).place(x=24, y=8)

        self.version_entry = ctk.CTkEntry(
            version_frame,
            placeholder_text="1.0",
            placeholder_text_color="#6D9FC7",
            width=140,
            fg_color="transparent",
            border_color="#EAF3FA",
            font=("Lato", 16)
        )
        self.version_entry.place(x=17, y=30)

        if self.saved_version != "":
            self.version_entry.insert(0, self.saved_version)

        # 업데이트 옵션 프레임
        update_option_frame = ctk.CTkFrame(self.line4, corner_radius=12, width=158, height=66, bg_color="#ffffff", fg_color="#EAF3FA")
        update_option_frame.place(x=169, y=0)

        ctk.CTkLabel(update_option_frame, text="UPDATE ITEM", bg_color="#EAF3FA", text_color="#8CB2E1", font=("Lato", 12)).place(x=24, y=8)

        self.update_option_box = ctk.CTkComboBox(
            update_option_frame,
            values=['기본', '고급', '보안', '개발자', '최신'],
            width=130,
            fg_color="#EAF3FA",
            dropdown_fg_color="#EAF3FA",
            border_color="#EAF3FA",
            button_color="#EAF3FA",
            dropdown_hover_color="#8CB2E1",
            button_hover_color="#8CB2E1",
            font=("Noto Sans CJK KR Medium", 16),
            dropdown_font=("Noto Sans CJK KR Medium", 16)
        )
        self.update_option_box.place(x=17, y=30)

        if self.saved_update_option != "":
            self.update_option_box.set(self.saved_update_option)

    # 등록 옵션 선택 시
    elif selected_option == "등록":
        username_frame = ctk.CTkFrame(self.line4, corner_radius=12, width=158, height=66, bg_color="#ffffff", fg_color="#EAF3FA")
        username_frame.place(x=0, y=0)

        ctk.CTkLabel(username_frame, text="USER NAME", bg_color="#EAF3FA", text_color="#8CB2E1", font=("Lato", 12)).place(x=24, y=8)

        self.username_entry = ctk.CTkEntry(
            username_frame,
            placeholder_text="사용자",
            placeholder_text_color="#6D9FC7",
            width=140,
            fg_color="transparent",
            border_color="#EAF3FA",
            font=("Noto Sans CJK KR Medium", 16)
        )
        self.username_entry.place(x=17, y=30)

        if self.saved_username != "":
            self.username_entry.insert(0, self.saved_username)

        device_frame = ctk.CTkFrame(self.line4, corner_radius=12, width=158, height=66, bg_color="#ffffff", fg_color="#EAF3FA")
        device_frame.place(x=169, y=0)

        ctk.CTkLabel(device_frame, text="DEVICE", bg_color="#EAF3FA", text_color="#8CB2E1", font=("Lato", 12)).place(x=24, y=8)

        self.device_box = ctk.CTkComboBox(
            device_frame,
            values=['모바일', '데스크탑', '태블릿'],
            width=130,
            fg_color="#EAF3FA",
            dropdown_fg_color="#EAF3FA",
            border_color="#EAF3FA",
            button_color="#EAF3FA",
            dropdown_hover_color="#8CB2E1",
            button_hover_color="#8CB2E1",
            font=("Noto Sans CJK KR Medium", 16),
            dropdown_font=("Noto Sans CJK KR Medium", 16)
        )
        self.device_box.place(x=17, y=30)

        if self.saved_device_box != "":
            self.device_box.set(self.saved_device_box)

    # 보안 설정 옵션 선택 시
    elif selected_option == "보안 설정":
        security_frame = ctk.CTkFrame(self.line4, corner_radius=12, width=327, height=66, bg_color="#ffffff", fg_color="#EAF3FA")
        security_frame.place(x=0, y=0)

        ctk.CTkLabel(security_frame, text="SECURITY LEVEL", bg_color="#EAF3FA", text_color="#8CB2E1", font=("Lato", 12)).place(x=24, y=8)

        self.security_box = ctk.CTkComboBox(
            security_frame,
            values=[
                '기본 보안 | 사용자 인증',
                '고급 보안 | 관리자 인증',
                '최상위 보안 | 이중 인증',
                '개발자 모드 | 실험 보안',
                '암호화 테스트 모드'
            ],
            width=294,
            fg_color="#EAF3FA",
            dropdown_fg_color="#EAF3FA",
            border_color="#EAF3FA",
            button_color="#EAF3FA",
            dropdown_hover_color="#8CB2E1",
            button_hover_color="#8CB2E1",
            font=("Noto Sans CJK KR Medium", 16),
            dropdown_font=("Noto Sans CJK KR Medium", 16)
        )
        self.security_box.place(x=17, y=30)

        security_levels = [
            '기본 보안 | 사용자 인증',
            '고급 보안 | 관리자 인증',
            '최상위 보안 | 이중 인증',
            '개발자 모드 | 실험 보안',
            '암호화 테스트 모드'
        ]
        self.security_box.set(security_levels[datetime.datetime.today().weekday()])

    # line4에 있는 모든 위젯 삭제
    for widget in widgets_to_delete:
        widget.destroy()

 

 

Chat GTP답변:

To address the issue of dynamic UI updates and widget management in PyQt, let's refine your update_ui method in PyQt to ensure proper widget deletion, layout handling, and positioning.

Key Adjustments

  1. Ensure Widgets are Deleted Properly: Instead of iterating through self.line4.children(), you may use self.line4.layout().takeAt(i) to remove each widget from the layout before deletion. This approach gives PyQt a clear instruction to remove the widget from the layout system, which can help avoid positioning issues.
  2. Avoid deleteLater() on Widgets Directly: Call deleteLater() only on items removed from the layout. This prevents layout inconsistencies.
  3. Handle Layout Initialization Carefully: Check if the layout exists, and clear it if necessary. Create new frames and labels only after confirming the layout is clean.
  4. Use QVBoxLayout or QHBoxLayout Consistently: If customtkinter uses place for positioning, ensure frames and labels are set in a similar structure in PyQt with specific spacing or margins if needed.

Here’s an optimized version of your update_ui function:

 

파이큐트에서 동적 UI 업데이트 및 위젯 관리 문제를 해결하기 위해, 적절한 위젯 삭제, 레이아웃 처리 및 위치 지정을 보장하기 위해 파이큐트에서 update_ui 메서드를 개선해 보겠습니다.

주요 조정 사항
위젯이 제대로 삭제되었는지 확인합니다: self.line4.children()를 반복하는 대신 self.line4.layout().takeAt(i)를 사용하여 삭제하기 전에 레이아웃에서 각 위젯을 제거할 수 있습니다. 이 접근 방식은 레이아웃 시스템에서 위젯을 제거하라는 명확한 지침을 파이큐트에게 제공하므로 위치 지정 문제를 피하는 데 도움이 될 수 있습니다.

위젯에서 deleteLater()를 직접 호출하지 마세요: 레이아웃에서 제거된 항목에 대해서만 deleteLater()를 호출하세요. 이렇게 하면 레이아웃 불일치를 방지할 수 있습니다.

레이아웃 초기화를 신중하게 처리하세요: 레이아웃이 존재하는지 확인하고 필요한 경우 레이아웃을 지웁니다. 레이아웃이 깨끗한지 확인한 후에만 새 프레임과 레이블을 만드세요.

QVBoxLayout 또는 QHBoxLayout을 일관되게 사용하세요: customtkinter가 위치 지정에 장소를 사용하는 경우, 필요한 경우 특정 간격이나 여백을 사용하여 PyQt에서 프레임과 레이블이 비슷한 구조로 설정되어 있는지 확인하세요.

다음은 업데이트_ui 함수의 최적화된 버전입니다:

def update_ui(self, *args):
    print("Clearing widgets from line4...")

    # Clear existing widgets in the layout
    layout = self.line4.layout()
    if layout is None:
        layout = QtWidgets.QVBoxLayout(self.line4)
        self.line4.setLayout(layout)
    else:
        while layout.count() > 0:
            child = layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()

    selected_option = self.option_var.currentText()
    print(f"Selected option: {selected_option}")

    if selected_option == "업데이트":
        # Create 'Update' UI elements
        update_frame = QtWidgets.QFrame(self.line4)
        update_frame.setStyleSheet("background-color: #EAF3FA; border-radius: 12px;")
        layout.addWidget(update_frame)

        version_label = QtWidgets.QLabel("버전", update_frame)
        version_label.setGeometry(24, 12, 100, 14)
        version_label.setStyleSheet("font-family: Lato; font-size: 12px; color: #8CB2E1;")

        self.version_entry = QtWidgets.QLineEdit(update_frame)
        self.version_entry.setGeometry(17, 30, 124, 26)
        self.version_entry.setPlaceholderText("1.0")
        self.version_entry.setStyleSheet("font-family: Lato; font-size: 16px; color: #6D9FC7; border: none;")

        # Similar setup for the update options dropdown
        update_option_frame = QtWidgets.QFrame(self.line4)
        update_option_frame.setStyleSheet("background-color: #EAF3FA; border-radius: 12px;")
        layout.addWidget(update_option_frame)

        update_option_label = QtWidgets.QLabel("옵션 선택", update_option_frame)
        update_option_label.setGeometry(24, 12, 100, 14)
        update_option_label.setStyleSheet("font-family: Lato; font-size: 12px; color: #8CB2E1;")

        self.update_option_box = QtWidgets.QComboBox(update_option_frame)
        self.update_option_box.setGeometry(17, 30, 124, 26)
        self.update_option_box.addItems(['일반', '보안', '프리미엄', '최신', '개발자'])
        self.update_option_box.setStyleSheet("font-family: Noto Sans CJK KR Medium; font-size: 16px; color: #6D9FC7; border: none;")

    elif selected_option == "등록":
        # 'Registration' UI elements setup here
        registration_frame = QtWidgets.QFrame(self.line4)
        registration_frame.setStyleSheet("background-color: #EAF3FA; border-radius: 12px;")
        layout.addWidget(registration_frame)  

        user_label = QtWidgets.QLabel("사용자 이름", registration_frame)
        user_label.setGeometry(24, 12, 100, 14)
        user_label.setStyleSheet("font-family: Lato; font-size: 12px; color: #8CB2E1;")

        self.username_entry = QtWidgets.QLineEdit(registration_frame)
        self.username_entry.setGeometry(17, 30, 124, 26)
        self.username_entry.setPlaceholderText("홍길동")
        self.username_entry.setStyleSheet("font-family: Lato; font-size: 16px; color: #6D9FC7; border: none;")

        # Similar setup for device selection
        device_frame = QtWidgets.QFrame(self.line4)
        device_frame.setStyleSheet("background-color: #EAF3FA; border-radius: 12px;")
        layout.addWidget(device_frame)  

        device_label = QtWidgets.QLabel("디바이스 선택", device_frame)
        device_label.setGeometry(24, 12, 100, 14)
        device_label.setStyleSheet("font-family: Lato; font-size: 12px; color: #8CB2E1;")

        self.device_box = QtWidgets.QComboBox(device_frame)
        self.device_box.setGeometry(17, 30, 124, 26)
        self.device_box.addItems(['모바일', '데스크탑', '태블릿'])
        self.device_box.setStyleSheet("font-family: Noto Sans CJK KR Medium; font-size: 16px; color: #6D9FC7; border: none;")

    elif selected_option == "보안 설정":
        # 'Security settings' UI elements setup here
        security_frame = QtWidgets.QFrame(self.line4)
        security_frame.setStyleSheet("background-color: #EAF3FA; border-radius: 12px;")
        layout.addWidget(security_frame)

        security_label = QtWidgets.QLabel("보안 패턴", security_frame)
        security_label.setGeometry(24, 12, 100, 14)
        security_label.setStyleSheet("font-family: Lato; font-size: 12px; color: #8CB2E1; background-color:rgba(0, 0, 0, 0);")

        self.security_box = QtWidgets.QComboBox(security_frame)
        self.security_box.setGeometry(0, 0, 327, 66)
        self.security_box.addItems([
            '암호화 1단계 | 사용자 인증',
            '암호화 2단계 | 관리자 인증',
            '고급 보안 | 사용자 및 관리자 인증',
            '보안 설정 | 일반 보안',
            '보안 설정 | 고급 보안',
            '테스트 모드'
        ])
        self.security_box.setStyleSheet("font-family: Noto Sans CJK KR Medium; font-size: 16px; color: #6D9FC7; border: none;")

 

 

Explanation of Key Changes

  • Widget Removal: Ensures proper deletion by clearing self.line4.layout() without lingering references.
  • Geometry Management: Sets geometry only after deleting widgets; avoids layout misalignment.
  • Alternative QVBoxLayout Setup: Initializes layout if absent and ensures items are correctly stacked.

This approach aligns with PyQt's structure while emulating customtkinter's functionality. Let me know if this improves your PyQt UI’s consistency!

 

주요 변경 사항 설명
위젯 제거: 참조를 남기지 않고 self.line4.layout()을 지워 적절한 삭제를 보장합니다.
지오메트리 관리: 위젯을 삭제한 후에만 지오메트리를 설정하여 레이아웃 정렬 불량을 방지합니다.
대체 QVBoxLayout 설정: 레이아웃이 없는 경우 레이아웃을 초기화하고 항목이 올바르게 쌓여 있는지 확인합니다.
이 접근 방식은 customtkinter의 기능을 에뮬레이트하면서 PyQt의 구조와 일치합니다. 이렇게 하면 PyQt UI의 일관성이 향상되는지 알려주세요!