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
相关产品推荐
相关产品推荐

