mirror of
https://github.com/KenanZhu/AutoLibrary.git
synced 2026-06-18 07:23:03 +08:00
252 lines
7.7 KiB
Python
252 lines
7.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
Copyright (c) 2025 KenanZhu.
|
|
All rights reserved.
|
|
|
|
This software is provided "as is", without any warranty of any kind.
|
|
You may use, modify, and distribute this file under the terms of the MIT License.
|
|
See the LICENSE file for details.
|
|
"""
|
|
from PySide6.QtCore import (
|
|
Qt, Slot, Signal, QEvent
|
|
)
|
|
from PySide6.QtWidgets import (
|
|
QFrame, QWidget, QLabel, QHBoxLayout, QVBoxLayout,
|
|
QGridLayout, QGraphicsView, QGraphicsScene, QGraphicsItem,
|
|
QPushButton,
|
|
)
|
|
from PySide6.QtGui import (
|
|
QPainter, QWheelEvent, QCloseEvent
|
|
)
|
|
from gui.SeatFrame import SeatFrame
|
|
|
|
|
|
class SeatMapWidget(QWidget):
|
|
|
|
seatMapWidgetClosed = Signal(list)
|
|
|
|
def __init__(
|
|
self,
|
|
parent: QWidget = None,
|
|
floor: str = "",
|
|
room: str = "",
|
|
seats_data: dict = {},
|
|
):
|
|
|
|
super().__init__(parent)
|
|
|
|
self.__floor = floor
|
|
self.__room = room
|
|
self.__seats_data = seats_data
|
|
self.__selected_seats = []
|
|
self.__seat_frames = {}
|
|
self.setUpUi()
|
|
self.connectSignals()
|
|
|
|
@staticmethod
|
|
def formatSeatNumber(
|
|
seat_number: str
|
|
) -> str:
|
|
|
|
if seat_number and not seat_number[-1].isdigit():
|
|
digits = seat_number[:-1]
|
|
letter = seat_number[-1]
|
|
return digits.zfill(3) + letter
|
|
return seat_number.zfill(3)
|
|
|
|
|
|
def setUpUi(
|
|
self
|
|
):
|
|
|
|
self.setWindowFlags(Qt.WindowType.Window)
|
|
self.setWindowModality(Qt.WindowModality.ApplicationModal)
|
|
self.setMinimumSize(800, 600)
|
|
self.resize(800, 600)
|
|
self.setWindowTitle(f"选择楼层座位 - AutoLibrary")
|
|
|
|
self.SeatMapWidgetMainLayout = QVBoxLayout(self)
|
|
self.TitleLabel = QLabel(f"楼层座位分布图: {self.__floor}-{self.__room}")
|
|
self.TitleLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
self.TitleLabel.setStyleSheet("font-size: 16px; font-weight: bold; margin: 10px;")
|
|
self.SeatMapWidgetMainLayout.addWidget(self.TitleLabel)
|
|
|
|
self.SeatMapGraphicsView = QGraphicsView(self)
|
|
self.SeatMapGraphicsScene = QGraphicsScene(self)
|
|
self.SeatMapGraphicsView.setScene(self.SeatMapGraphicsScene)
|
|
self.SeatMapGraphicsView.setRenderHint(QPainter.RenderHint.LosslessImageRendering)
|
|
self.SeatMapGraphicsView.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)
|
|
self.SeatMapGraphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
|
self.SeatMapGraphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
|
self.SeatMapGraphicsView.viewport().installEventFilter(self)
|
|
|
|
self.SeatsContainerWidget = QWidget()
|
|
self.SeatsContainerLayout = QGridLayout(self.SeatsContainerWidget)
|
|
self.createSeatMap()
|
|
|
|
self.ContainerProxy = self.SeatMapGraphicsScene.addWidget(self.SeatsContainerWidget)
|
|
self.ContainerProxy.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, False)
|
|
self.SeatMapWidgetMainLayout.addWidget(self.SeatMapGraphicsView)
|
|
|
|
self.TipsLabel = QLabel(
|
|
" 点击座位进行选择/取消选择, 最多选择1个座位 \n"
|
|
" [操作方法: Ctrl+鼠标滚轮缩放 | 滚轮/拖拽/方向键 移动]"
|
|
)
|
|
self.TipsLabel.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
|
self.TipsLabel.setStyleSheet("color: #666; margin: 5px;")
|
|
self.SeatMapWidgetMainLayout.addWidget(self.TipsLabel)
|
|
|
|
self.ConfirmButton = QPushButton("确认")
|
|
self.ConfirmButton.setFixedSize(80, 25)
|
|
self.CancelButton = QPushButton("取消")
|
|
self.CancelButton.setFixedSize(80, 25)
|
|
self.SeatMapWidgetControlLayout = QHBoxLayout()
|
|
self.SeatMapWidgetControlLayout.setAlignment(Qt.AlignmentFlag.AlignRight)
|
|
self.SeatMapWidgetControlLayout.addWidget(self.CancelButton)
|
|
self.SeatMapWidgetControlLayout.addWidget(self.ConfirmButton)
|
|
self.SeatMapWidgetMainLayout.addLayout(self.SeatMapWidgetControlLayout)
|
|
|
|
|
|
def connectSignals(
|
|
self
|
|
):
|
|
|
|
self.ConfirmButton.clicked.connect(self.onConfirmButtonClicked)
|
|
self.CancelButton.clicked.connect(self.onCancelButtonClicked)
|
|
|
|
|
|
def closeEvent(
|
|
self,
|
|
event: QCloseEvent
|
|
):
|
|
|
|
self.seatMapWidgetClosed.emit(self.__selected_seats)
|
|
super().closeEvent(event)
|
|
|
|
|
|
def eventFilter(
|
|
self,
|
|
watched,
|
|
event
|
|
):
|
|
|
|
if (watched is self.SeatMapGraphicsView.viewport() and
|
|
event.type() == QEvent.Type.Wheel and
|
|
event.modifiers() == Qt.KeyboardModifier.ControlModifier
|
|
):
|
|
self.zoomGraphicsView(event)
|
|
return True
|
|
return super().eventFilter(watched, event)
|
|
|
|
|
|
def zoomGraphicsView(
|
|
self,
|
|
event: QWheelEvent
|
|
):
|
|
|
|
delta = event.angleDelta().y()
|
|
zoom_factor = 1.2 if delta > 0 else 1/1.2
|
|
self.SeatMapGraphicsView.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
|
|
self.SeatMapGraphicsView.scale(zoom_factor, zoom_factor)
|
|
|
|
|
|
def createSeatMap(
|
|
self
|
|
):
|
|
|
|
rows = self.__seats_data.strip().split("\n")
|
|
for row_idx, row in enumerate(rows):
|
|
col_idx = 0
|
|
seats_number = [seat.strip() for seat in row.split(",")]
|
|
for seat_number in seats_number:
|
|
if seat_number:
|
|
seat_widget = SeatFrame(seat_number)
|
|
seat_widget.clicked.connect(self.onSeatClicked)
|
|
self.SeatsContainerLayout.addWidget(seat_widget, row_idx, col_idx)
|
|
self.__seat_frames[seat_number] = seat_widget
|
|
else:
|
|
spacer = QFrame()
|
|
spacer.setFixedSize(20, 30)
|
|
spacer.setStyleSheet("background-color: transparent; border: none;")
|
|
self.SeatsContainerLayout.addWidget(spacer, row_idx, col_idx)
|
|
col_idx += 1
|
|
self.SeatsContainerLayout.setSpacing(20)
|
|
self.SeatsContainerLayout.setContentsMargins(20, 20, 20, 20)
|
|
self.SeatsContainerWidget.adjustSize()
|
|
|
|
|
|
def selectSeat(
|
|
self,
|
|
seat_number: str
|
|
):
|
|
|
|
if len(self.__selected_seats) >= 1:
|
|
return
|
|
seat_number = self.formatSeatNumber(seat_number)
|
|
if seat_number not in self.__seat_frames:
|
|
return
|
|
widget = self.__seat_frames[seat_number]
|
|
if widget.isSelected():
|
|
return
|
|
widget.toggleSelection()
|
|
self.__selected_seats.append(seat_number)
|
|
|
|
|
|
def selectSeats(
|
|
self,
|
|
selected_seats: list
|
|
):
|
|
|
|
self.clearSelections()
|
|
for seat_number in selected_seats:
|
|
self.selectSeat(seat_number)
|
|
|
|
|
|
def getSelectedSeats(
|
|
self
|
|
) -> list[str]:
|
|
|
|
return self.__selected_seats
|
|
|
|
|
|
def clearSelections(
|
|
self
|
|
):
|
|
|
|
seats_to_clear = self.__selected_seats.copy()
|
|
for seat_number in seats_to_clear:
|
|
if seat_number not in self.__seat_frames:
|
|
continue
|
|
widget = self.__seat_frames[seat_number]
|
|
if widget.isSelected():
|
|
widget.toggleSelection()
|
|
self.__selected_seats = []
|
|
|
|
@Slot(str)
|
|
def onSeatClicked(
|
|
self,
|
|
seat_number: str
|
|
):
|
|
|
|
if seat_number in self.__selected_seats:
|
|
self.__selected_seats.remove(seat_number)
|
|
else:
|
|
if len(self.__selected_seats) < 1:
|
|
self.__selected_seats.append(seat_number)
|
|
else:
|
|
self.__seat_frames[seat_number].toggleSelection()
|
|
|
|
@Slot()
|
|
def onConfirmButtonClicked(
|
|
self
|
|
):
|
|
|
|
self.close()
|
|
|
|
@Slot()
|
|
def onCancelButtonClicked(
|
|
self
|
|
):
|
|
|
|
self.clearSelections()
|
|
self.close() |