You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5实现无边框可拖拽窗口内UI切换的技术问题

PyQt5 无新窗口切换UI的问题

我希望在PyQt5中无需打开新窗口即可切换UI,但遇到以下问题:

  • 使用QStackedWidget实现UI切换时,无法将窗口设置为无边框样式,也无法实现点击拖拽功能;
  • 不使用QStackedWidget时,已实现无边框可拖拽窗口,但不知道如何进行UI切换。

尝试的代码

不使用QStackedWidget的实现

import sys, time, os

from PyQt5 import uic
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPixmap

import sqlite3

class LoginMenu(QWidget):

    def __init__(self):
        super(LoginMenu, self).__init__()
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        uic.loadUi("LoginMenu.ui",self)
        self.clicked = False

    def mousePressEvent(self, event):
        self.old_pos = event.screenPos()

    def mouseMoveEvent(self, event):
        if self.clicked:
            dx = self.old_pos.x() - event.screenPos().x()
            dy = self.old_pos.y() - event.screenPos().y()
            self.move(self.pos().x() - dx, self.pos().y() - dy)
        self.old_pos = event.screenPos()
        self.clicked = True

        return QWidget.mouseMoveEvent(self, event)

app = QApplication(sys.argv)
log = LoginMenu()
log.show()
sys.exit(app.exec())

使用QStackedWidget的实现

import sys, time, os

from PyQt5 import uic
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPixmap

class LogMenu(QWidget):
    def __init__(self):
        super(LogMenu, self).__init__()
        uic.loadUi("LoginMenu.ui",self)
        self.SignUp.clicked.connect(self.gotoReg)

    def gotoReg(self):
        reg=Register()
        widget.addWidget(reg)
        widget.setCurrentIndex(widget.currentIndex()+1)

class Register(QWidget):
    def __init__(self):
        super(Register, self).__init__()
        uic.loadUi("SignUp.ui",self)

#main
app = QApplication(sys.argv)
widget = QtWidgets.QStackedWidget()
log=LogMenu()
reg=Register()
widget.addWidget(log)
widget.addWidget(reg)
widget.show()

try:
    sys.exit(app.exec())
except:
    print("Exiting")

解决方案

一、修复QStackedWidget的无边框与拖拽功能

问题核心是不能直接把QStackedWidget作为主窗口,需要将它嵌套在一个无边框的主窗口内,拖拽逻辑统一放在主窗口实现。

修改后代码:

import sys
from PyQt5 import uic
from PyQt5 import QtWidgets, QtCore

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        # 设置无边框窗口
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        # 创建QStackedWidget作为中心部件
        self.stacked_widget = QtWidgets.QStackedWidget()
        self.setCentralWidget(self.stacked_widget)
        
        # 添加UI页面
        self.log_menu = LogMenu()
        self.register_page = Register()
        self.stacked_widget.addWidget(self.log_menu)
        self.stacked_widget.addWidget(self.register_page)
        
        # 绑定页面切换事件
        self.log_menu.SignUp.clicked.connect(lambda: self.stacked_widget.setCurrentWidget(self.register_page))
        
        # 拖拽状态变量
        self.drag_start_pos = None
        self.is_dragging = False

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.is_dragging = True
            self.drag_start_pos = event.globalPos()

    def mouseMoveEvent(self, event):
        if self.is_dragging:
            delta = event.globalPos() - self.drag_start_pos
            self.move(self.pos() + delta)
            self.drag_start_pos = event.globalPos()

    def mouseReleaseEvent(self, event):
        self.is_dragging = False

class LogMenu(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi("LoginMenu.ui", self)

class Register(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi("SignUp.ui", self)

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

说明

  • 用QMainWindow作为顶层容器,设置无边框属性,QStackedWidget作为其中心部件负责页面切换
  • 拖拽逻辑集中在主窗口,避免每个UI页面重复编写
  • 通过setCurrentWidget直接切换到目标页面,比索引切换更直观

二、不使用QStackedWidget时的UI切换方法

可以通过动态替换主窗口的中心部件实现页面切换,拖拽逻辑同样放在主窗口统一处理。

修改后代码:

import sys
from PyQt5 import uic
from PyQt5 import QtWidgets, QtCore

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        # 初始加载登录页面
        self.load_login_page()
        
        # 拖拽状态变量
        self.drag_start_pos = None
        self.is_dragging = False

    def load_login_page(self):
        self.login_page = LoginMenu()
        self.setCentralWidget(self.login_page)
        self.login_page.SignUp.clicked.connect(self.load_register_page)

    def load_register_page(self):
        self.register_page = Register()
        self.setCentralWidget(self.register_page)
        # 可给Register页面添加返回按钮,绑定self.load_login_page实现回退

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.is_dragging = True
            self.drag_start_pos = event.globalPos()

    def mouseMoveEvent(self, event):
        if self.is_dragging:
            delta = event.globalPos() - self.drag_start_pos
            self.move(self.pos() + delta)
            self.drag_start_pos = event.globalPos()

    def mouseReleaseEvent(self, event):
        self.is_dragging = False

class LoginMenu(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi("LoginMenu.ui", self)

class Register(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi("SignUp.ui", self)

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

说明

  • 主窗口负责加载不同的UI页面,通过setCentralWidget替换当前显示内容
  • 每个UI页面的按钮事件触发主窗口加载新页面,实现无窗口切换
  • 拖拽逻辑统一在主窗口实现,无需在每个UI类中重复编写

内容的提问来源于stack exchange,提问作者Sawik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:35:15