The QSpinBox and QComboBox Widgets
QSpinBox는 텍스트 상자와 유사한 객체를 생성하지만 사용자가 위젯에 값을 입력하거나 위쪽 및 아래쪽 화살표를 클릭하여 정수 값을 선택할 수 있도록 합니다. 값의 범위를 편집하거나, 화살표를 클릭할 때 단계 크기를 설정하거나, 시작 값을 설정하거나, 상자에 접두사 또는 접미사를 추가할 수도 있습니다.
QSpinBox와 유사한 클래스가 있어 다양한 상황에 대해 유사한 기능을 제공합니다.
QDoubleSpinBox는 부동 소수점 숫자를 선택하는 데 사용됩니다.
QDateTimeEdit 또는 그 변형 중 하나는 날짜 및 시간 값을 선택하는 데 유용합니다.
QComboBox 위젯은 사용자가 위젯의 화살표 버튼을 클릭할 때 사용자가 선택할 수 있는 옵션의 드롭다운 목록을 표시합니다. 콤보 상자는 최소한의 공간에 많은 양의 옵션을 표시하는 데 편리합니다.
# nested.py
# Import necessary modules
import sys
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel,
QComboBox, QSpinBox, QHBoxLayout, QVBoxLayout)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QFont
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initializeUI()
def initializeUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(400, 160)
self.setWindowTitle('Nested Layout Example')
self.setUpMainWindow()
self.show()
def setUpMainWindow(self):
"""Create and arrange widgets in the main window."""
info_label = QLabel(
"Select 2 items for lunch and their prices.")
info_label.setFont(QFont("Arial", 16))
info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Create a list of food items and two separate
# QComboBox widgets to display all of the items
food_list = ["egg", "turkey sandwich", "ham sandwich",
"cheese", "hummus", "yogurt", "apple", "banana",
"orange", "waffle", "carrots", "bread", "pasta",
"crackers", "pretzels", "coffee", "soda", "water"]
food_combo1 = QComboBox()
food_combo1.addItems(food_list)
food_combo2 = QComboBox()
food_combo2.addItems(food_list)
# Create two QSpinBox widgets to display prices
self.price_sb1 = QSpinBox()
self.price_sb1.setRange(0, 100)
self.price_sb1.setPrefix("$")
self.price_sb1.valueChanged.connect(self.calculateTotal)
self.price_sb2 = QSpinBox()
self.price_sb2.setRange(0, 100)
self.price_sb2.setPrefix("$")
self.price_sb2.valueChanged.connect(self.calculateTotal)
# Create two horizontal layouts for the QComboBox
# and QSpinBox widgets
item1_h_box = QHBoxLayout()
item1_h_box.addWidget(food_combo1)
item1_h_box.addWidget(self.price_sb1)
item2_h_box = QHBoxLayout()
item2_h_box.addWidget(food_combo2)
item2_h_box.addWidget(self.price_sb2)
self.totals_label = QLabel("Total Spent: $")
self.totals_label.setFont(QFont("Arial", 16))
self.totals_label.setAlignment(Qt.AlignmentFlag.AlignRight)
# Organize widgets and layouts in the main window
main_v_box = QVBoxLayout()
main_v_box.addWidget(info_label)
main_v_box.addLayout(item1_h_box)
main_v_box.addLayout(item2_h_box)
main_v_box.addWidget(self.totals_label)
# Set the layout for the main window
self.setLayout(main_v_box)
def calculateTotal(self, value):
"""Calculate the total price and update
totals_label."""
total = self.price_sb1.value() + \
self.price_sb2.value()
self.totals_label.setText(f"Total Spent: ${total}")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
Arranging Widgets in Grids with QGridLayout
QGridLayout의 addWidget() 메서드에는 두 가지 형태가 있습니다.
지정된 행과 열에 추가
addWidget(widget, row, column, alignment)
여러 행, 열 ,행열로 확장
addWidget(widget, fromRow, fromColumn, rowSpan, columnSpan, alignment)
# grid.py
# Import necessary modules
import sys, json
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel,
QLineEdit, QCheckBox, QTextEdit, QGridLayout)
from PyQt6.QtCore import Qt, QDate
from PyQt6.QtGui import QFont
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initializeUI()
def initializeUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(500, 300)
self.setWindowTitle("QGridLayout Example")
self.setUpMainWindow()
self.loadWidgetValuesFromFile()
self.show()
def setUpMainWindow(self):
"""Create and arrange widgets in the main window."""
name_label = QLabel("Simple Daily Planner")
name_label.setFont(QFont("Arial", 20))
name_label.setAlignment(Qt.AlignmentFlag.AlignLeft)
# Create widgets for the left side of the window
today_label = QLabel("• Today's Focus")
today_label.setFont(QFont("Arial", 14))
self.today_tedit = QTextEdit()
notes_label = QLabel("• Notes")
notes_label.setFont(QFont("Arial", 14))
self.notes_tedit = QTextEdit()
# Organize the left side widgets into a column 0
# of the QGridLayout
self.main_grid = QGridLayout()
self.main_grid.addWidget(name_label, 0, 0)
self.main_grid.addWidget(today_label, 1, 0)
self.main_grid.addWidget(self.today_tedit, 2, 0, 3, 1)
self.main_grid.addWidget(notes_label, 5, 0)
self.main_grid.addWidget(self.notes_tedit, 6, 0, 3, 1)
# Create widgets for the right side of the window
today = QDate.currentDate().toString(Qt.DateFormat.ISODate)
date_label = QLabel(today)
date_label.setFont(QFont("Arial", 18))
date_label.setAlignment(Qt.AlignmentFlag.AlignRight)
todo_label = QLabel("• To Do")
todo_label.setFont(QFont("Arial", 14))
# Organize the right side widgets into columns 1 and 2
# of the QGridLayout
self.main_grid.addWidget(date_label, 0, 2)
self.main_grid.addWidget(todo_label, 1, 1, 1, 2)
# Create 7 rows, from indexes 2-8
for row in range(2, 9):
item_cb = QCheckBox()
item_edit = QLineEdit()
self.main_grid.addWidget(item_cb, row, 1)
self.main_grid.addWidget(item_edit, row, 2)
# Set the layout for the main window
self.setLayout(self.main_grid)
def saveWidgetValues(self):
"""Collect and save the values for the different widgets."""
details = {"focus": self.today_tedit.toPlainText(),
"notes": self.notes_tedit.toPlainText()}
remaining_todo = []
# Check the values of the QCheckBox widgets
for row in range(2, 9):
# Retrieve the QLayoutItem object
item = self.main_grid.itemAtPosition(row, 1)
# Retrieve the widget (QCheckBox)
widget = item.widget()
if widget.isChecked() == False:
# Retrieve the QLayoutItem object
item = self.main_grid.itemAtPosition(row, 2)
# Retrieve the widget (QLineEdit)
widget = item.widget()
text = widget.text()
if text != "":
remaining_todo.append(text)
# Save text from QLineEdit widgets
details["todo"] = remaining_todo
with open("details.txt", "w") as f:
f.write(json.dumps(details))
def loadWidgetValuesFromFile(self):
"""Retrieve the user's previous values from the last session."""
# Check if file exists first
try:
with open("details.txt", "r") as f:
details = json.load(f)
# Retrieve and set values for the widgets
self.today_tedit.setText(details["focus"])
self.notes_tedit.setText(details["notes"])
# Set the text for QLineEdit widgets
for row in range(len(details["todo"])):
# Retrieve the QLayoutItem object
item = self.main_grid.itemAtPosition(row + 2, 2)
# Retrieve the widget (QLineEdit)
widget = item.widget()
widget.setText(details["todo"][row])
except FileNotFoundError as error:
# Create the file since it doesn't exist
f = open("details.txt", "w")
def closeEvent(self, event):
"""Save widget values when closing the window."""
self.saveWidgetValues()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
Building Forms with QFormLayout
• addRow(QWidget(), QWidget())
– Adds two widgets to a row, where the first widget is a label and the second is a field widget.
The first QWidget is typically a QLabel, but it is possible to add other widget types.
• addRow(QWidget(), QLayout()) – Adds a label widget and a layout to a row.
• addRow(string, QWidget()) – Adds a string and a field to a row.
• addRow(string, QLayout()) – Adds a string and a layout to a row.
• addRow(QWidget()) – Adds a single widget to a layout.
• addRow(QLayout()) – Nests a single layout to the form.
# form.py
# Import necessary modules
import sys
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel,
QPushButton, QDateEdit, QLineEdit, QTextEdit, QComboBox,
QFormLayout, QHBoxLayout)
from PyQt6.QtCore import Qt, QRegularExpression, QDate
from PyQt6.QtGui import QFont, QRegularExpressionValidator
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initializeUI()
def initializeUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(500, 400)
self.setWindowTitle("QFormLayout Example")
self.setUpMainWindow()
self.show()
def setUpMainWindow(self):
"""Create and arrange widgets in the main window."""
header_label = QLabel("Appointment Form")
header_label.setFont(QFont("Arial", 18))
header_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.first_name_edit = QLineEdit()
self.first_name_edit.setPlaceholderText("First")
self.first_name_edit.textEdited.connect(self.clearText)
self.last_name_edit = QLineEdit()
self.last_name_edit.setPlaceholderText("Last")
self.last_name_edit.textEdited.connect(self.clearText)
# Create horizontal layout for names
name_h_box = QHBoxLayout()
name_h_box.addWidget(self.first_name_edit)
name_h_box.addWidget(self.last_name_edit)
# Create additional widgets to be added in the window
gender_combo = QComboBox()
gender_combo.addItems(["Male", "Female"])
self.phone_edit = QLineEdit()
self.phone_edit.setInputMask("(999) 999-9999;_")
self.phone_edit.textEdited.connect(self.clearText)
self.birthdate_edit = QDateEdit()
self.birthdate_edit.setDisplayFormat("MM/dd/yyyy")
self.birthdate_edit.setMaximumDate(QDate.currentDate())
self.birthdate_edit.setCalendarPopup(True)
self.birthdate_edit.setDate(QDate.currentDate())
self.email_edit = QLineEdit()
self.email_edit.setPlaceholderText("<username>@<domain>.com")
reg_opt = QRegularExpression()
regex = QRegularExpression(
"\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[com]{3}\\b",
reg_opt.PatternOption.CaseInsensitiveOption)
self.email_edit.setValidator(QRegularExpressionValidator(regex))
self.email_edit.textEdited.connect(self.clearText)
extra_info_tedit = QTextEdit()
self.feedback_label = QLabel()
submit_button = QPushButton("SUBMIT")
submit_button.setMaximumWidth(140)
submit_button.clicked.connect(self.checkFormInformation)
# Create horizontal layout for last row of widgets
submit_h_box = QHBoxLayout()
submit_h_box.addWidget(self.feedback_label)
submit_h_box.addWidget(submit_button)
# Organize widgets and layouts in QFormLayout
main_form = QFormLayout()
main_form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
main_form.setFormAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop)
main_form.setLabelAlignment(Qt.AlignmentFlag.AlignLeft)
main_form.addRow(header_label)
main_form.addRow("Name", name_h_box)
main_form.addRow("Gender", gender_combo)
main_form.addRow("Date of Birth", self.birthdate_edit)
main_form.addRow("Phone", self.phone_edit)
main_form.addRow("Email", self.email_edit)
main_form.addRow(QLabel("Comments or Messages"))
main_form.addRow(extra_info_tedit)
main_form.addRow(submit_h_box)
# Set the layout for the main window
self.setLayout(main_form)
def clearText(self, text):
"""Clear the text for the QLabel that provides feedback."""
self.feedback_label.clear()
def checkFormInformation(self):
"""Demonstrates a few cases for validating user input."""
if self.first_name_edit.text() == "" or self.last_name_edit.text() == "":
self.feedback_label.setText("[INFO] Missing names.")
elif self.phone_edit.hasAcceptableInput() == False:
self.feedback_label.setText("[INFO] Phone number entered incorrectly.")
elif self.email_edit.hasAcceptableInput() == False:
self.feedback_label.setText("[INFO] Email entered incorrectly.")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
Managing Pages with QStackedLayout
QStackedLayout과 동일한 기능을 제공하는 편의 클래스 인 QStackedWidget이 있습니다. 또 다른 위젯인 QTabWidget은 탭을 제공합니다.
각 페이지는 addWidget()을 사용하여 QStackedLayout에 추가됩니다. 추가된 페이지는 내부 위젯 목록에 의해 관리되며 각 페이지 또는 위젯에 액세스하는 작업은 다음 방법으로 수행할 수 있습니다.
• currentIndex() – 표시되는 페이지의 인덱스를 반환합니다. 페이지에는 인덱스 값이 있고 시작 인덱스는 0입니다.
• currentWidget() – Retrieves the widget of the visible page.
페이지에 여러 위젯이 포함되어 있는 경우 currentWidget()이 반환하는 위젯을 통해 해당 자식 위젯에 액세스할 수 있습니다. 마지막으로 페이지가 insertWidget (인덱스, 위젯)으로 삽입되거나 removeWidget (위젯)으로 제거되는 동적 스택 레이아웃을 만들 수 있습니다.
![]() |
![]() |
![]() |
# stacked.py
# Import necessary modules
import sys
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel,
QLineEdit, QTextEdit, QComboBox, QSpinBox, QDoubleSpinBox,
QStackedLayout, QFormLayout, QVBoxLayout)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPixmap
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initializeUI()
def initializeUI(self):
"""Set up the application's GUI."""
self.setFixedSize(300, 340)
self.setWindowTitle("QStackedLayout Example")
self.setUpMainWindow()
self.show()
def setUpMainWindow(self):
"""Create and arrange widgets in the main window."""
# Create and connect the combo box to switch between pages
page_combo = QComboBox()
page_combo.addItems(["Image", "Description",
"Additional Info"])
page_combo.activated.connect(self.switchPage)
# Create the Image page (Page 1)
profile_image = QLabel()
pixmap = QPixmap("images/norwegian.jpg")
profile_image.setPixmap(pixmap)
profile_image.setScaledContents(True)
# Create the Profile page (Page 2)
pg2_form = QFormLayout()
pg2_form.setFieldGrowthPolicy(
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
pg2_form.setFormAlignment(
Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop)
pg2_form.setLabelAlignment(Qt.AlignmentFlag.AlignLeft)
pg2_form.addRow("Breed:", QLabel("Norwegian Forest cat"))
pg2_form.addRow("Origin:", QLabel("Norway"))
pg2_form.addRow(QLabel("Description:"))
default_text = """Have a long, sturdy body, long legs
and a bushy tail. They are friendly, intelligent,
and generally good with people."""
pg2_form.addRow(QTextEdit(default_text))
pg2_container = QWidget()
pg2_container.setLayout(pg2_form)
# Create the About page (Page 3)
pg3_form = QFormLayout()
pg3_form.setFieldGrowthPolicy(
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
pg3_form.setFormAlignment(
Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop)
pg3_form.setLabelAlignment(Qt.AlignmentFlag.AlignLeft)
pg3_form.addRow(QLabel("Enter your cat's info."))
pg3_form.addRow("Name:", QLineEdit())
pg3_form.addRow("Color:", QLineEdit())
age_sb = QSpinBox()
age_sb.setRange(0, 30)
pg3_form.addRow("Age:", age_sb)
weight_dsb = QDoubleSpinBox()
weight_dsb.setRange(0.0, 30.0)
pg3_form.addRow("Weight (kg):", weight_dsb)
pg3_container = QWidget()
pg3_container.setLayout(pg3_form)
# Create the stacked layout and add pages
self.stacked_layout = QStackedLayout()
self.stacked_layout.addWidget(profile_image)
self.stacked_layout.addWidget(pg2_container)
self.stacked_layout.addWidget(pg3_container)
# Add widgets and the stacked layout to the main layout
main_v_box = QVBoxLayout()
main_v_box.addWidget(page_combo)
main_v_box.addLayout(self.stacked_layout)
# Set the layout for the main window
self.setLayout(main_v_box)
def switchPage(self, index):
"""Slot for switching between tabs."""
self.stacked_layout.setCurrentIndex(index)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
Additional Tips for Managing Space
• addSpacing(int) – Creates blank space between widgets specified by int (in pixels)
• addStretch(int)
– Adds a stretchable area of value int between widgets that is proportional to the stretch factors of other widgets
• setHorizontalSpacing(int) –Sets the horizontal spacing between widgets (in pixels)
• setVerticalSpacing(int) – Sets the vertical spacing between widgets (in pixels)
• setSpacing(int) – Sets the horizontal and vertical spacing between widgets (in pixels)
# spacing.py
# Import necessary modules
import sys
from PyQt6.QtWidgets import (QApplication, QWidget,
QLabel, QPushButton, QLineEdit, QVBoxLayout)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initializeUI()
def initializeUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(300, 200)
self.setWindowTitle("Spacing Example")
label = QLabel("Enter text")
line_edit = QLineEdit()
button = QPushButton("End")
main_v_box = QVBoxLayout()
main_v_box.addWidget(label)
main_v_box.addSpacing(20)
main_v_box.addWidget(line_edit)
main_v_box.addStretch()
main_v_box.addWidget(button)
# setContentsMargins(left, top, right, bottom)
# main_v_box.setContentsMargins(40, 30, 40, 30)
self.setLayout(main_v_box)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
'Beginning PyQt' 카테고리의 다른 글
QIcon Class (0) | 2022.05.21 |
---|---|
Menus, Toolbars, and More (0) | 2022.05.21 |
QButtonGroup (0) | 2022.05.14 |
Layout Management (0) | 2022.05.14 |
Handling Events in PyQt (0) | 2022.05.14 |