[Python] Window Resizing Issues with Custom Title Bar

Discussão em 'Python' iniciado por Stack, Dezembro 20, 2024.

  1. Stack

    Stack Membro Participativo

    I'm developing a custom media player application using PySide6. I've successfully implemented a custom title bar with buttons for minimizing, maximizing, and closing the window. However, after adding the custom title bar, the window has become unresponsive to resizing attempts.

    Here's the relevant code snippet:

    import sys
    from PySide6.QtCore import Qt, QSize, QRect
    from PySide6.QtGui import QIcon, QPixmap
    from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QHBoxLayout, QVBoxLayout, QLabel, QWidget, QSizePolicy, QFileDialog, QLineEdit, QTreeView, QFileSystemModel

    class NordMediaPlayer(QMainWindow):
    def __init__(self):
    super().__init__()

    # Initialize the dragging state
    self._dragging = False
    self._drag_position = None

    self.setWindowTitle("shax0")
    self.setWindowFlags(Qt.FramelessWindowHint) # Remove original title bar
    self.resize(250, 250) # Set default window size to 250x250
    self.setStyleSheet("background-color: #ECEFF4; color: #2E3440;") # Light Nord theme

    self.centralWidget = QWidget()
    self.setCentralWidget(self.centralWidget)

    # Main layout with control bar, cover art, and command bar
    mainLayout = QVBoxLayout(self.centralWidget)
    mainLayout.setContentsMargins(0, 0, 0, 0)
    mainLayout.setSpacing(0)

    # Create the layout container for the title bar, cover art, and control bar
    self.mainContainer = QWidget(self)
    self.mainLayout = QVBoxLayout(self.mainContainer)
    self.mainLayout.setContentsMargins(0, 0, 0, 0)

    # Title bar
    self.titleBar = self.createTitleBar()
    self.mainLayout.addWidget(self.titleBar)

    # Cover art area
    self.coverArt = self.createCoverArt()
    self.mainLayout.addWidget(self.coverArt)

    # Control bar
    self.controlBar = self.createControlBar()
    self.mainLayout.addWidget(self.controlBar)

    # Create terminal command bar (text pad for command input)
    self.commandBar = QLineEdit(self)
    self.commandBar.setStyleSheet("background-color: #2E3440; color: #ECEFF4; font-family: Mononoki; font-size: 14px; border: none;")
    self.commandBar.setPlaceholderText("Enter command...")
    self.commandBar.setFixedHeight(30) # Height of the command bar
    self.commandBar.setVisible(False) # Initially hidden
    self.mainLayout.addWidget(self.commandBar)

    # Create file explorer widget to be shown when "f" command is pressed
    self.fileExplorerWidget = QWidget(self)
    self.fileExplorerWidget.setVisible(False) # Start with file explorer hidden
    self.mainLayout.addWidget(self.fileExplorerWidget)

    # Create a QFileSystemModel and QTreeView for file explorer
    self.fileSystemModel = QFileSystemModel()
    self.fileSystemModel.setRootPath('')

    self.fileExplorerView = QTreeView(self)
    self.fileExplorerView.setModel(self.fileSystemModel)
    self.fileExplorerView.setRootIndex(self.fileSystemModel.index('')) # Show the root directory
    self.fileExplorerView.setColumnWidth(0, 250) # Adjust column width
    self.fileExplorerView.setStyleSheet("background-color: #ECEFF4; color: #2E3440; font-family: Mononoki; font-size: 12px;")
    self.fileExplorerWidget.setLayout(QVBoxLayout())
    self.fileExplorerWidget.layout().addWidget(self.fileExplorerView)

    # Set main layout
    mainLayout.addWidget(self.mainContainer)

    # Connect Enter key press to process the command
    self.commandBar.returnPressed.connect(self.processCommand)

    def createTitleBar(self):
    """Create a custom title bar with the original Nord theme colors in right-to-left direction."""
    titleBarWidget = QWidget(self)
    titleBarLayout = QHBoxLayout(titleBarWidget)
    titleBarLayout.setContentsMargins(0, 0, 0, 0)
    titleBarLayout.setSpacing(1) # Reduced horizontal space between buttons to 1 pixel

    # Set layout direction to Right-To-Left (RTL)
    titleBarLayout.setDirection(QHBoxLayout.RightToLeft) # Corrected this line

    # Title bar height
    buttonHeight = 35
    buttonWidth = 40 # Reduced width of buttons

    titleBarWidget.setFixedHeight(buttonHeight)

    # App icon (Ensure you have a valid path for this image)
    appIcon = QLabel()
    appIcon.setPixmap(QPixmap("playback/sine.png").scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation)) # Replace with valid path
    titleBarLayout.addWidget(appIcon)

    # App title
    appTitle = QLabel("shax0")
    appTitle.setStyleSheet("font-size: 14px; font-weight: bold; color: #2E3440; font-family: Mononoki;")
    titleBarLayout.addWidget(appTitle)

    titleBarLayout.addStretch()

    # Minimize button
    minimizeButton = self.createTitleBarButton("playback/min.png", "Minimize", buttonHeight, buttonWidth) # Ensure valid image path
    minimizeButton.clicked.connect(self.showMinimized)
    titleBarLayout.addWidget(minimizeButton)

    # Maximize button
    maximizeButton = self.createTitleBarButton("playback/max.png", "Maximize", buttonHeight, buttonWidth) # Ensure valid image path
    maximizeButton.clicked.connect(self.toggleMaximizeRestore)
    titleBarLayout.addWidget(maximizeButton)

    # Close button (positioned to the far left in RTL)
    closeButton = self.createTitleBarButton("playback/close.png", "Close", buttonHeight, buttonWidth) # Ensure valid image path
    closeButton.clicked.connect(self.close)
    titleBarLayout.addWidget(closeButton)

    titleBarWidget.setStyleSheet("background-color: #D8DEE9; border: none;")

    return titleBarWidget

    def createTitleBarButton(self, iconPath, tooltip, buttonHeight, buttonWidth):
    """Create a button for the title bar."""
    button = QPushButton()
    button.setIcon(QIcon(iconPath))
    button.setToolTip(tooltip)
    button.setFixedSize(buttonWidth, buttonHeight)
    button.setStyleSheet("""
    QPushButton {
    background-color: transparent;
    border: none;
    }
    QPushButton:hover {
    background-color: #BF616A;
    }
    """)

    # Set icon size to 30% of the button height
    button.setIconSize(QSize(buttonHeight * 0.3, buttonHeight * 0.3)) # Reduced size (30% of button height)

    return button

    def createCoverArt(self):
    """Create a placeholder for the cover art with Light Nord theme."""
    coverArtWidget = QLabel()
    coverArtWidget.setPixmap(
    QPixmap("playback/cover_art_placeholder.png").scaled(200, 200, Qt.KeepAspectRatio, Qt.SmoothTransformation)) # Replace with valid path
    coverArtWidget.setAlignment(Qt.AlignCenter)
    coverArtWidget.setStyleSheet("""
    background-color: #ECEFF4;
    border: none;
    font-family: Mononoki;
    color: #2E3440;
    font-size: 12px;
    """)
    coverArtWidget.setText("shax0")
    return coverArtWidget

    def createControlBar(self):
    """Create the control bar with evenly distributed icons."""
    controlBarWidget = QWidget(self)
    controlBarLayout = QHBoxLayout(controlBarWidget)
    controlBarLayout.setContentsMargins(0, 0, 0, 0)
    controlBarLayout.setSpacing(0)

    buttonHeight = 35

    # Control buttons
    controls = [
    ("playback/play.png", "Play"),
    ("playback/rwd.png", "Rewind"),
    ("playback/stop.png", "Stop"),
    ("playback/fwd.png", "Fast Forward"),
    ("playback/shuffle.png", "Shuffle"),
    ("playback/wave.png", "Wave"),
    ("playback/terminal.png", "Terminal"),
    ]

    for iconPath, tooltip in controls:
    button = self.createControlButton(iconPath, tooltip, buttonHeight)
    controlBarLayout.addWidget(button)

    controlBarWidget.setFixedHeight(buttonHeight)
    controlBarWidget.setStyleSheet("background-color: #D8DEE9; border: none;")
    return controlBarWidget

    def createControlButton(self, iconPath, tooltip, buttonHeight):
    """Create a control button."""
    button = QPushButton()
    button.setIcon(QIcon(iconPath))
    button.setToolTip(tooltip)
    button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
    button.setStyleSheet("""
    QPushButton {
    background-color: transparent;
    border: none;
    }
    QPushButton:hover {
    background-color: #E5E9F0;
    }
    """)
    button.setIconSize(QSize(buttonHeight * 0.6, buttonHeight * 0.6))
    if tooltip == "Terminal":
    button.clicked.connect(self.toggleCommandBar) # Connect Terminal button to toggle visibility
    return button

    def mousePressEvent(self, event):
    """Track mouse press to enable dragging the window."""
    if event.button() == Qt.LeftButton and self.titleBar.geometry().contains(event.pos()):
    self._dragging = True
    self._drag_position = event.globalPos() - self.frameGeometry().topLeft()
    event.accept()

    def mouseMoveEvent(self, event):
    """Drag window based on mouse movement."""
    if self._dragging:
    self.move(event.globalPos() - self._drag_position)
    event.accept()

    def mouseReleaseEvent(self, event):
    """Stop dragging the window."""
    self._dragging = False

    def toggleMaximizeRestore(self):
    """Toggle between maximizing and restoring the window."""
    if self.isMaximized():
    self.showNormal() # Restore the window to its previous size
    else:
    self.showMaximized() # Maximize the window

    def toggleCommandBar(self):
    """Toggle command bar visibility."""
    self.commandBar.setVisible(not self.commandBar.isVisible())

    def processCommand(self):
    """Process the command entered in the command bar."""
    command = self.commandBar.text().strip()
    if command == 'f':
    self.openFileExplorer()
    elif command == 't':
    self.commandBar.clear()
    self.commandBar.setVisible(False)
    elif command == 'p':
    self.commandBar.clear()
    self.commandBar.setVisible(False)

    def openFileExplorer(self):
    """Open the file explorer when the 'f' command is entered."""
    self.fileExplorerWidget.setVisible(True)
    self.commandBar.clear()
    self.commandBar.setVisible(False)

    if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = NordMediaPlayer()
    window.show()
    sys.exit(app.exec())



    I've tried the following approaches to enable resizing, but none have worked:

    Setting QSizeGrip: I attempted to add QSizeGrip widgets to the window corners, but they had no effect. Overriding window resize events: I tried overriding resizeEvent, but it didn't seem to be called when attempting to resize the window. I suspect that the way I'm handling mouse events for dragging the window might be interfering with the window's resizing behavior.

    Could anyone please provide guidance on how to make the window resizable again while maintaining the custom title bar?

    Additional Notes:

    I'm using PySide6 on a Linux system. I've searched for similar issues online, but haven't found a solution that works for my specific case. I appreciate any help or suggestions you can offer. I believe its also the last button blocking the edge and also causing a problem where the cursor can change and affect because its using resources for the hover detection.

    Continue reading...

Compartilhe esta Página