PyQt6实战开发之旅-代码均可运行


在这里插入图片描述

学习感悟

由于官方文档是英文的,所以学习起来不是很直观。
网上的中文教程也都有点偏重就轻,去从头学习细枝末节不是很必要。假如每个控件组件讲十分钟,几百个控件可想而知。
最关键的是有python基础,能理解类与继承,函数调用这些东西。所有教程都过分强调信号与槽这个东西,很大可能他面向的学习对象是零基础的学生,但是你有基础的话一看就明白了,无非就是某些事件发出个信号然后调用函数的过程。
所以我的学习方法就是弄清楚,PyQt6中有哪些模块,每个模块中有哪些组件,每个组件是什么功能,体现在软件上是什么样,有一个直观的认识之后。
就怼着一个目标开始我们的编程。开始设计一款自己的软件,怼着那些厉害的软件模仿功能,我这里就直接模仿者vscode来做了,过程中整理记录好笔记,等软件做出来,自己肯定收获不小。
不然你从头到尾看完教程,才开始实战,这个时候前面学的又忘光了,很消耗人的。
所以说不要一开始就在认知不清楚的时候盲目看教程,很可能看个标签,按钮什么的各种都敲一敲。其实每个细节你都不用太细究,你只需要有个清晰的整体认知,需要使用的时候直接搜索查询拿来使用就好了。

简介

PyQt6组成模块及功能

QtCore
QtGui
QtWidgets
QtDBus
QtNetwork
QtHelp
QtXml
QtSvg
QtSql
QtTest
  • QtCore:这个模块提供了一些基本的功能,如时间处理、文件和目录处理、数据类型、流、属性系统、元对象系统等。
  • QtGui:这个模块是PyQt6中的图形用户界面(GUI)工具集,它提供了一些窗口系统、事件处理、2D图形和基本的图像类等功能。
  • QtWidgets:这个模块是建立在QtGui之上的一套新的控件,它提供了一套丰富的控件集合,例如按钮、文本框、列表框、复选框等。
  • QtDBus:这个模块实现了DBus的底层访问,使得应用程序可以通过DBus进行通信。
  • QtNetwork:这个模块提供了实现网络编程的类和方法,如网络请求和响应、SSL安全连接等。
  • QtHelp:这个模块用于创建帮助文件,支持多种格式,如HTML、XML等。
  • QtXml:这个模块实现了解析和生成XML文档的功能。
  • QtSvg:这个模块提供了将SVG文件转换为QPainter绘图的命令。
  • QtSql:这个模块实现了SQL数据库的访问功能,可以执行SQL语句以及获取查询结果。
  • QtTest:这个模块包含了一些测试工具,用于单元测试和集成测试。

模块所处位置

from PyQt6.QtWidgets import QApplication, QMainWindow, QMenu
from PyQt6.QtGui import QAction,QIcon

版本信息

# QT_VERSION_STR 可以显示 Qt 的版本信息,PYQT_VERSION_STR 可以显示 PyQt 的版本信息
from PyQt6.QtCore import QT_VERSION_STR
from PyQt6.QtCore import PYQT_VERSION_STR

print(QT_VERSION_STR)
print(PYQT_VERSION_STR)

程序实战

第一个程序

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt6.QtGui import QIcon

def main():
    app = QApplication(sys.argv)
    window = QMainWindow()
    window.setGeometry(100, 100, 300, 200) 
    window.setWindowTitle("派森斗罗")
    window.setWindowIcon(QIcon('logo.png'))

    QLabel("Hello, World!", window)

    window.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()

居中显示窗口

  • self.frameGeometry() 返回一个 QRect 对象,该对象表示小组件相对于其父级的几何图形,包括任何窗口框架。
  • QGuiApplication.primaryScreen().availableGeometry().center() 返回一个 QPoint 对象,该对象表示主屏幕的可用几何图形的中心点。
  • 此线移动矩形 ( qr ) 的左上角,使其中心位于指定的中心点 ( cp )。
  • rectangle.self.move(qr.topLeft()) :此行将小组件移动到矩形 ( qr ) 的左上角。 qr.topLeft() 返回表示矩形左上角的 A QPoint 。
import sys
from PyQt6.QtWidgets import QApplication, QWidget
from PyQt6.QtGui import QScreen, QGuiApplication
from PyQt6.QtGui import QIcon

class MyApplication(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(0, 0, 300, 200)  # Set window size
        self.setWindowTitle('派森斗罗')
        self.setWindowIcon(QIcon('logo.png'))

        self.center()  # Center the window on the screen
    def center(self):
        qr=self.frameGeometry()
        cp=QGuiApplication.primaryScreen().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApplication()
    ex.show()
    sys.exit(app.exec())

PyQt6-初探QMainWindow-各模块的学习方法

QMainWindow是Qt框架中的一个类,用于创建主窗口应用程序。它提供了一个具有一般应用程序框架的主窗口,包括菜单栏、工具栏、状态栏和中央工作区域。
以下是QMainWindow的一些主要特性:

  1. 菜单栏(Menu Bar):QMainWindow允许你添加菜单栏,通过菜单栏你可以创建各种菜单,包括文件、编辑、视图等。
  2. 工具栏(Tool Bar): 你可以在主窗口上添加工具栏,工具栏通常包含一些常用的工具按钮,例如打开、保存、剪切、复制等。
  3. 状态栏(Status Bar):QMainWindow还提供了一个状态栏,用于显示应用程序的状态信息或者当前操作的相关信息。
  4. 中央工作区域(Central Widget): 主要的应用程序界面通常放置在中央工作区域,这是一个可以包含其他Qt小部件的区域,例如文本编辑器、图形视图等。
  5. Dock小部件(Dock Widgets):QMainWindow支持将一些小部件作为停靠窗口,可以通过拖拽将它们放置在主窗口的边缘。
  6. 窗口管理功能: 包括最大化、最小化、关闭等窗口管理功能。

下面是一个简单的例子,演示如何创建一个基本的QMainWindow

from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel

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

        # 设置主窗口标题
        self.setWindowTitle('My Main Window')

        # 添加标签到中央工作区域
        central_widget = QLabel("Hello, QMainWindow!")
        self.setCentralWidget(central_widget)

        # 添加菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('File')
        file_menu.addAction('Open')
        file_menu.addAction('Save')

        # 添加工具栏
        toolbar = self.addToolBar('Tools')
        toolbar.addAction('Cut')
        toolbar.addAction('Copy')
        toolbar.addAction('Paste')

        # 添加状态栏
        statusbar = self.statusBar()
        statusbar.showMessage('Ready')

if __name__ == '__main__':
    app = QApplication([])
    window = MyMainWindow()
    window.show()
    app.exec_()

这个例子创建了一个简单的主窗口,包括一个标签作为中央工作区域,一个简单的菜单栏,一个工具栏和一个状态栏。这只是一个入门示例,你可以根据你的应用程序需求自定义和扩展QMainWindow

多页面切换实例

在PyQt6中,可以使用QTabWidgetQWidget来实现多页面切换。
当然你也可以自定义组件来实现这样的功能。在这里我们使用QTabWidgetQWidget
以下是一个简单的示例:

import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QTabWidget, QVBoxLayout, QPushButton, QWidget
from PyQt6.QtGui import QIcon

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

        self.setWindowTitle("派森斗罗")
        self.setWindowIcon(QIcon('logo.png'))
        self.setGeometry(100, 100, 800, 600)

        self.tab_widget = QTabWidget()
        self.setCentralWidget(self.tab_widget)

        self.page1 = QWidget()
        self.page2 = QWidget()

        self.tab_widget.addTab(self.page1, "页面1")
        self.tab_widget.addTab(self.page2, "页面2")

        layout = QVBoxLayout()
        button1 = QPushButton("切换到页面2")
        button1.clicked.connect(lambda: self.switch_page(2))
        layout.addWidget(button1)

        button2 = QPushButton("切换到页面1")
        button2.clicked.connect(lambda: self.switch_page(1))
        layout.addWidget(button2)

        self.page1.setLayout(layout)
        self.page2.setLayout(layout)

    def switch_page(self, index):
        self.tab_widget.setCurrentIndex(index - 1)

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

在这个示例中,我们创建了一个QMainWindow,并设置了一个QTabWidget作为其中心部件。然后,我们创建了两个QWidgetpage1page2),并将它们添加到QTabWidget中。我们还添加了两个按钮,分别用于在两个页面之间切换。当点击这些按钮时,会调用switch_page方法来切换当前选中的页面。

import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QTabWidget, QVBoxLayout, QPushButton, QWidget,QStackedWidget,QLabel
from PyQt6.QtGui import QIcon

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

        self.setWindowTitle("派森斗罗")
        self.setWindowIcon(QIcon('logo.png'))
        self.setGeometry(100, 100, 800, 600)

        self.initStackWeight()
        self.initTabWeight()

    def initStackWeight(self):
        self.stacked_widget = QStackedWidget()
        page1 = QWidget()
        page2 = QWidget()
        label1 = QLabel('这是页面 1')
        label2 = QLabel('这是页面 2')
        page1.layout = QVBoxLayout(page1)
        page2.layout = QVBoxLayout(page2)
        page1.layout.addWidget(label1)
        page2.layout.addWidget(label2)
        self.stacked_widget.addWidget(page1)
        self.stacked_widget.addWidget(page2)
        button1 = QPushButton('显示页面 1')
        button1.clicked.connect(lambda: self.stacked_widget.setCurrentIndex(0))
        button2 = QPushButton('显示页面 2')
        button2.clicked.connect(lambda: self.stacked_widget.setCurrentIndex(1))

        # 显示按钮和堆栈式布局
        mainWindow=QWidget()
        layout = QVBoxLayout()
        layout.addWidget(button1)
        layout.addWidget(button2)
        layout.addWidget(self.stacked_widget)
        mainWindow.setLayout(layout)
        self.setCentralWidget(mainWindow)

    def initTabWeight(self):
        self.tab_widget = QTabWidget()
        print(self.stacked_widget.widget(1).layout.addWidget(self.tab_widget))
        self.page1 = QWidget()
        self.page2 = QWidget()
        self.tab_widget.addTab(self.page1, "页面1")
        self.tab_widget.addTab(self.page2, "页面2")

        layout1 = QVBoxLayout()
        button1 = QPushButton("切换到标签页2")
        button1.clicked.connect(lambda: self.switch_page(2))
        layout1.addWidget(button1)
        self.page1.setLayout(layout1)

        layout2 = QVBoxLayout()
        button2 = QPushButton("切换到标签页1")
        button2.clicked.connect(lambda: self.switch_page(1))
        layout2.addWidget(button2)
        self.page2.setLayout(layout2)

    def switch_page(self, index):
        self.tab_widget.setCurrentIndex(index - 1)

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

顶部菜单栏实例

from PyQt6.QtWidgets import QApplication, QMainWindow, QMenu, QMenuBar
from PyQt6.QtGui import QIcon,QAction
from PyQt6.QtCore import Qt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        menubar = self.menuBar()
        # 创建文件菜单,里面有二级菜单:打开,保存,设置
        fileMenu = menubar.addMenu('文件')
        openFile = QAction(QIcon('./assets/imgs/icons/open-file.png'),'打开文件', self)
        openFile.setShortcut('Ctrl+O')
        openFile.triggered.connect(self.openFile)
        fileMenu.addAction(openFile)
        openFolder = QAction(QIcon('./assets/imgs/icons/open-folder.png'),'打开文件夹', self)
        openFolder.triggered.connect(self.openFolder)
        fileMenu.addAction(openFolder)
        fileMenu.addSeparator()
        saveFile = QAction(QIcon('./assets/imgs/icons/save.png'),'保存', self)
        saveFile.setShortcut('Ctrl+S')
        saveFile.triggered.connect(self.saveFile)
        fileMenu.addAction(saveFile)
        setting = QAction(QIcon('./assets/imgs/icons/setting.png'),'设置', self)
        setting.triggered.connect(self.setting)
        fileMenu.addAction(setting)
        # 创建帮助菜单
        helpMenu = menubar.addMenu('帮助')
        about = QAction(QIcon('./assets/imgs/icons/about.png'),'关于', self)
        about.triggered.connect(self.about)
        helpMenu.addAction(about)
        helpMenu.addSeparator()
        donation = QAction(QIcon('./assets/imgs/icons/donation.png'),'捐赠', self)
        donation.triggered.connect(self.donation)
        helpMenu.addAction(donation)

        self.setWindowTitle("派森斗罗")
        self.setWindowIcon(QIcon('logo.png'))
        self.setGeometry(300, 300, 400, 200)
        self.show()

    def openFile(self):
        print('打开文件')
    def openFolder(self):
        print('打开文件夹')
    def setting(self):
        print('设置')
    def saveFile(self):
        print('保存文件')
    def about(self):
        print('这是一个顶部菜单栏示例程序')
    def donation(self):
        print('捐赠选项')

if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    app.exec()

多种栏示例

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow,QPushButton,QLabel, QToolBar, QStatusBar, QTabWidget, QVBoxLayout, QWidget
from PyQt6.QtGui import QAction,QIcon

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

        self.initUI()

    def initUI(self):
        # 创建一个退出动作
        exitAction = QAction('退出', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.triggered.connect(self.close)

        # 创建一个新建动作
        newAction = QAction('新建', self)

        # 创建一个打开动作
        openAction = QAction('打开', self)

        # 创建菜单栏
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('文件')
        fileMenu.addAction(newAction)
        fileMenu.addAction(openAction)
        fileMenu.addSeparator()
        fileMenu.addAction(exitAction)

        # 创建工具栏
        toolbar = QToolBar()
        toolbar.addAction(newAction)
        toolbar.addAction(openAction)
        toolbar.addAction(exitAction)
        self.addToolBar(toolbar)

        # 创建状态栏
        statusbar = QStatusBar()
        self.setStatusBar(statusbar)
        statusbar.showMessage('这是状态栏',1000)

        btn=QPushButton('显示消息',self)
        btn.move(100,0)
        # 查看定义类
        btn.clicked.connect(lambda x:statusbar.showMessage('您好~',1000))

        # 创建标签栏
        tab_widget = QTabWidget()
        tab1 = QWidget()
        tab2 = QWidget()
        tab_widget.addTab(tab1, '标签1')
        tab_widget.addTab(tab2, '标签2')
        layout = QVBoxLayout()
        tab1.setLayout(layout)
        layout.addWidget(QWidget())  # 向标签1添加内容
        self.setCentralWidget(tab_widget)

        # 创建侧栏
        sidebar = QToolBar('侧栏')
        sidebar.addWidget(QLabel('这是侧边栏'))  # 向侧栏添加内容
        self.addToolBar(sidebar)

        # 创建工具箱栏
        toolbox = QToolBar('工具箱')
        toolbox.addWidget(QLabel('这是工具箱'))  # 向工具箱添加内容
        self.addToolBar(toolbox)

        # 设置主窗口属性
        self.setGeometry(100, 100, 600, 400)
        self.setWindowTitle('派森斗罗')
        self.setWindowIcon(QIcon('logo.png'))
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApplication()
    sys.exit(app.exec())

左侧菜单控制右侧多页面切换

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QHBoxLayout, QListWidget, QWidget, QStackedWidget,QLabel,QListWidgetItem
from PyQt6.QtGui import QIcon,QAction
from PyQt6.QtCore import Qt

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

        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 800, 600)
        self.setWindowTitle('多页面切换示例')

        # 创建一个主窗口部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        # 创建左侧导航栏
        nav_list = QListWidget()

        nav_list.addItem(QListWidgetItem(QIcon('./assets/imgs/icons/game.svg'),'游戏'))
        nav_list.addItem(QListWidgetItem(QIcon('./assets/imgs/icons/login.png'),'登录'))
        nav_list.addItem(QListWidgetItem(QIcon('./assets/imgs/icons/setting.png'),'设置'))
        nav_list.setFixedWidth(100)
        # nav_list.setViewMode(QListWidget.IconMode)
        nav_list.currentItemChanged.connect(self.switchPage)

        # 创建右侧多页面容器
        page_container = QStackedWidget()
        page1 = QWidget()
        QLabel('这是页面 1',page1)
        page1.setWindowTitle('页面 1')
        page2 = QWidget()
        page2.setWindowTitle('页面 2')
        QLabel('这是页面 2',page2)
        page_container.addWidget(page1)
        page_container.addWidget(page2)
        # page_container.setFixedWidth(500)

        # 创建布局管理器
        layout = QHBoxLayout()
        layout.addWidget(nav_list)
        layout.addWidget(page_container)

        central_widget.setLayout(layout)

    def switchPage(self, current, previous):
        if current:
            selected_index = self.centralWidget().layout().itemAt(0).widget().currentRow()
            self.centralWidget().layout().itemAt(1).widget().setCurrentIndex(selected_index)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApplication()
    ex.show()
    sys.exit(app.exec())

pyqt6中如何实现多页面切换?

在 PyQt6 中实现多页面切换通常有多种方法,其中两种主要方法是使用 QStackedWidgetQTabWidget。以下是如何使用这两种方法实现多页面切换的总结:

  1. 使用 QStackedWidget
    • 创建一个 QStackedWidget 对象来托管多个页面。
    • 为每个页面创建一个独立的 QWidget 子类,包括该页面的内容和控件。
    • 使用 addWidget 方法将这些页面部件添加到 QStackedWidget 中,每个页面都有一个索引。
    • 使用 setCurrentIndex 方法切换页面,通过指定页面的索引。
    • 适用于需要程序控制多页面切换的情况。

示例代码:

stacked_widget = QStackedWidget()
page1 = QWidget()
page2 = QWidget()
stacked_widget.addWidget(page1)
stacked_widget.addWidget(page2)
stacked_widget.setCurrentIndex(0)  # 切换到第一个页面
  1. 使用 QTabWidget
    • 创建一个 QTabWidget 对象,它提供了选项卡式的多页面切换。
    • 为每个标签页创建一个独立的 QWidget 子类,包括页面的内容和控件。
    • 使用 addTab 方法将这些页面部件添加到 QTabWidget,同时指定标签页的标题。
    • 用户可以通过点击标签页来切换页面。
    • 适用于以选项卡形式显示多个页面的情况。

示例代码:

tab_widget = QTabWidget()
tab1 = QWidget()
tab2 = QWidget()
tab_widget.addTab(tab1, "页面 1")
tab_widget.addTab(tab2, "页面 2")

根据您的项目需求和个人喜好,您可以选择使用其中一种或两种方法来实现多页面切换。无论您选择哪种方法,都可以根据需要自定义和扩展页面的内容。

QTabweight与Qstackweight的区别

在 PyQt 中,QTabWidgetQStackedWidget 是用于处理多页面(或多视图)的两个不同的部件。它们有一些区别,主要在于它们的设计和用途。

QTabWidget:

  1. 标签页式布局: QTabWidget 提供了一个标签页式的用户界面,允许用户通过选项卡(标签页)来切换不同的页面。
  2. 导航和可见性: 用户可以通过点击选项卡切换页面。每个选项卡上通常有一个相关的标题,并且用户可以通过点击标题来选择相应的页面。
  3. 集成标签栏: QTabWidget 自动提供了一个标签栏,用于容纳选项卡。标签栏通常位于部件的顶部。
  4. 适用于多个页面场景: 当您有一组相关的页面,希望以标签页的形式进行切换时,QTabWidget 是一个很好的选择。
from PyQt6.QtWidgets import QApplication, QWidget, QTabWidget, QVBoxLayout, QLabel

app = QApplication([])

# 创建 QTabWidget
tab_widget = QTabWidget()

# 添加标签页
tab_page1 = QWidget()
label1 = QLabel('这是标签页 1')
tab_page1.layout = QVBoxLayout(tab_page1)
tab_page1.layout.addWidget(label1)
tab_page1.setLayout(tab_page1.layout)
tab_widget.addTab(tab_page1, '标签页 1')

tab_page2 = QWidget()
label2 = QLabel('这是标签页 2')
tab_page2.layout = QVBoxLayout(tab_page2)
tab_page2.layout.addWidget(label2)
tab_page2.setLayout(tab_page2.layout)
tab_widget.addTab(tab_page2, '标签页 2')

tab_widget.show()
app.exec()

QStackedWidget:

  1. 堆栈式布局: QStackedWidget 提供了一个堆栈式的用户界面,允许用户通过推入和弹出页面来切换。
  2. 程序控制切换: 切换页面通常是由程序控制的,而不是用户通过点击标签页来触发的。
  3. 没有集成标签栏: QStackedWidget 不提供内置的标签栏。相反,您需要使用其他部件(例如按钮、菜单)来触发页面切换。
  4. 适用于单个页面显示: 当您有多个页面,但同一时间只显示其中一个页面时,QStackedWidget 是一个很好的选择。
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QStackedWidget

app = QApplication([])

# 创建 QStackedWidget
stacked_widget = QStackedWidget()

# 添加页面
page1 = QWidget()
label1 = QLabel('这是页面 1')
page1.layout = QVBoxLayout(page1)
page1.layout.addWidget(label1)
page1.setLayout(page1.layout)
stacked_widget.addWidget(page1)

page2 = QWidget()
label2 = QLabel('这是页面 2')
page2.layout = QVBoxLayout(page2)
page2.layout.addWidget(label2)
page2.setLayout(page2.layout)
stacked_widget.addWidget(page2)

# 创建按钮用于切换页面
button1 = QPushButton('显示页面 1')
button1.clicked.connect(lambda: stacked_widget.setCurrentIndex(0))

button2 = QPushButton('显示页面 2')
button2.clicked.connect(lambda: stacked_widget.setCurrentIndex(1))

# 显示按钮和堆栈式布局
layout = QVBoxLayout()
layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(stacked_widget)

# 设置堆栈式布局为窗口布局
window = QWidget()
window.setLayout(layout)
window.show()

app.exec()

总体而言,QTabWidget 适用于标签页式导航,而 QStackedWidget 适用于以堆栈形式切换页面的场景。您可以根据具体需求选择使用哪一个。

Qframe与Qweight的区别

在 PyQt 中,QFrameQWidget 是两个不同的类,它们用于创建界面上的可视化组件,但有一些区别。

  1. **QFrame**** 类:**
    • QFrameQWidget 的子类,因此 QFrame 可以包含在其他 QWidget 内或作为 QMainWindow 的中心部件。
    • QFrame 是一个简单的容器,通常用于包含其他小部件或进行布局管理。
    • QFrame 通常用于创建矩形框架,比如创建边框、背景或者一些特殊的辅助图形元素。
from PyQt6.QtWidgets import QFrame
frame = QFrame()
  1. **QWidget**** 类:**
    • QWidget 是一个通用的用户界面对象,也是 QFrame 的基类。
    • QWidget 通常用于创建应用程序的主窗口或作为主窗口中的中心部件。
    • QFrame 相比,QWidget 是更通用的界面元素,可以包含其他小部件,并提供更多的功能。
from PyQt6.QtWidgets import QWidget
widget = QWidget()

总的来说,QFrame 更专注于创建框架和辅助图形,而 QWidget 是一个更通用的界面元素,可以包含其他小部件并提供更广泛的功能。在实际使用中,你可以根据需求选择使用 QWidgetQFrame

先显示登陆页面,登陆成功后显示主页面

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QPushButton, QLabel
from PyQt6 import QtCore
from PyQt6.QtGui import QIcon

class LoginWindow(QWidget):
    loginSuccessSignal = QtCore.pyqtSignal()  # 登录成功的信号

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        layout = QVBoxLayout(self)

        self.username_input = QLineEdit(self)
        self.password_input = QLineEdit(self)
        self.password_input.setEchoMode(QLineEdit.EchoMode.Password)

        login_button = QPushButton('Login', self)
        login_button.clicked.connect(self.login)

        layout.addWidget(QLabel('Username:'))
        layout.addWidget(self.username_input)
        layout.addWidget(QLabel('Password:'))
        layout.addWidget(self.password_input)
        layout.addWidget(login_button)

        self.setGeometry(300, 300, 400, 200)
        self.setWindowTitle('Login Window')

    def login(self):
        # 在实际应用中,这里应该有登录验证的逻辑
        # 这里简化为判断用户名和密码是否为正确
        if self.username_input.text() == '1' and self.password_input.text() == '1':
            self.loginSuccessSignal.emit()  # 发送登录成功信号
            self.close()

class YourMainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.login_window = LoginWindow()
        self.login_window.loginSuccessSignal.connect(self.showMainWindow)

    def showMainWindow(self):
        self.setGeometry(300, 300, 400, 200)
        self.setWindowTitle('派森斗罗')
        self.setWindowIcon(QIcon('logo.png'))
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)

    main_window = YourMainWindow()
    main_window.login_window.show()

    sys.exit(app.exec())

窗口渐显与渐隐

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt6.QtCore import QPropertyAnimation

class FadeWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 400, 200)
        self.setWindowTitle('派森斗罗')

        layout = QVBoxLayout(self)

        fade_out_button = QPushButton('Fade Out', self)
        fade_out_button.clicked.connect(self.fadeOut)

        fade_in_button = QPushButton('Fade In', self)
        fade_in_button.clicked.connect(self.fadeIn)

        layout.addWidget(fade_out_button)
        layout.addWidget(fade_in_button)

        # Set initial opacity to 0
        self.setWindowOpacity(0.0)
        self.fadeIn()

    def fadeIn(self):
        self.animation = QPropertyAnimation(self, b"windowOpacity")
        self.animation.setStartValue(0.0)
        self.animation.setEndValue(1.0)
        self.animation.setDuration(1000)
        self.animation.start()

    def fadeOut(self):
        self.animation = QPropertyAnimation(self, b"windowOpacity")
        self.animation.setStartValue(1.0)
        self.animation.setEndValue(0.0)
        self.animation.setDuration(1000)
        self.animation.finished.connect(self.close)
        self.animation.start()

if __name__ == '__main__':
    app = QApplication(sys.argv)

    fade_window = FadeWindow()
    fade_window.show()

    sys.exit(app.exec())

窗口居中变大出现

我最开始想的是从小变到大,绘制之后再不断调用居中函数,最后发现窗口在左上角和中间不断闪动,于是我认真思考了一下想到了其实可以计算出初始状态和末状态的位置大小信息。
如何查看QPropertyAnimation类的方法以及信号。
可以优化一下出场,免去最开始的闪烁一下。

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt6.QtCore import QPropertyAnimation, QEasingCurve,QRect
from PyQt6.QtGui import QGuiApplication

class ScaleWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        # self.setGeometry(300, 300, 200, 100)
        self.setWindowTitle('变大窗口')
        self.scaleIn()

    def scaleIn(self):
        self.animation = QPropertyAnimation(self, b"geometry")
        self.animation.setStartValue(QRect(100,100,0,0))
        self.animation.setEndValue(QRect(100,100,200,300))
        self.animation.setDuration(1000)
        self.animation.valueChanged.connect(self.center)
        self.animation.setEasingCurve(QEasingCurve.Type.OutQuad)  # Use QEasingCurve.Type.OutQuad
        self.animation.start()
    
    def center(self):
        self.hide()
        qr=self.frameGeometry()
        cp=QGuiApplication.primaryScreen().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)

    scale_window = ScaleWindow()
    scale_window.show()

    sys.exit(app.exec())
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt6.QtCore import QPropertyAnimation, QEasingCurve,QRect
from PyQt6.QtGui import QGuiApplication

class ScaleWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(0, 0, 800, 600)
        self.setWindowTitle('变大窗口')
        self.center()
        self.scaleIn()

    def scaleIn(self):
        cp=QGuiApplication.primaryScreen().availableGeometry().center()
        qr=self.frameGeometry()
        self.animation = QPropertyAnimation(self, b"geometry")
        self.animation.setStartValue(QRect(cp.x(),cp.y(),0,0))
        self.animation.setEndValue(qr)
        self.animation.setDuration(1000)
        # self.animation.setDuration(3000)
        self.animation.setEasingCurve(QEasingCurve.Type.Linear)
        # self.animation.setEasingCurve(QEasingCurve.Type.OutQuint)
        # self.animation.setEasingCurve(QEasingCurve.Type.OutBack)
        # self.animation.setEasingCurve(QEasingCurve.Type.OutElastic)
        self.animation.start()
    
    def center(self):
        qr=self.frameGeometry()
        cp=QGuiApplication.primaryScreen().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

if __name__ == '__main__':
    app = QApplication(sys.argv)

    scale_window = ScaleWindow()
    scale_window.show()

    sys.exit(app.exec())
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt6.QtCore import QPropertyAnimation, QEasingCurve,QRect
from PyQt6.QtGui import QGuiApplication

class ScaleWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setWindowTitle('变大窗口')
        self.scaleIn()

    def scaleIn(self):
        cp=QGuiApplication.primaryScreen().availableGeometry().center()
        qr=self.center()
        self.animation = QPropertyAnimation(self, b"geometry")
        self.animation.setStartValue(QRect(cp.x(),cp.y(),0,0))
        self.animation.setEndValue(qr)
        self.animation.setDuration(1000)
        # self.animation.setDuration(3000)
        self.animation.setEasingCurve(QEasingCurve.Type.Linear)
        # self.animation.setEasingCurve(QEasingCurve.Type.OutQuint)
        # self.animation.setEasingCurve(QEasingCurve.Type.OutBack)
        # self.animation.setEasingCurve(QEasingCurve.Type.OutElastic)
        self.animation.start()
    
    def center(self):
        qr=QRect(0, 0, 800, 600)
        cp=QGuiApplication.primaryScreen().availableGeometry().center()
        qr.moveCenter(cp)
        return qr

if __name__ == '__main__':
    app = QApplication(sys.argv)

    scale_window = ScaleWindow()
    scale_window.show()

    sys.exit(app.exec())

最小化窗口到托盘,右键菜单,窗口恢复

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QSystemTrayIcon, QMenu
from PyQt6.QtGui import QIcon, QAction

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

        self.initUI()

    def initUI(self):
        self.setWindowTitle('PyQt6 托盘示例')
        self.setWindowIcon(QIcon('logo.png'))
        self.setGeometry(300, 300, 300, 200)

        # 创建系统托盘图标
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon('logo.png'))
        # 创建托盘图标菜单
        tray_menu = QMenu(self)
        action1 = tray_menu.addAction('设置一')
        action2 = tray_menu.addAction('设置二')
        tray_menu.addSeparator()
        action3 = tray_menu.addAction('打开主面板(未实现)')
        tray_menu.addSeparator()
        restore_action = QAction(QIcon('./assets/imgs/icons/recover.svg'),'还原', self)
        restore_action.triggered.connect(self.showNormal)
        exit_action = QAction(QIcon('./assets/imgs/icons/quit.svg'),'退出', self)
        exit_action.triggered.connect(app.quit)

        tray_menu.addAction(restore_action)
        tray_menu.addAction(exit_action)

        self.tray_icon.setContextMenu(tray_menu)
        # 托盘图标点击事件
        self.tray_icon.activated.connect(self.tray_icon_activated)
        self.tray_icon.show()
        
        # self.tray_icon.showMessage("托盘图标示例", "程序已最小化到托盘")


    def tray_icon_activated(self, reason):
        if reason == QSystemTrayIcon.ActivationReason.Trigger:
            if self.isHidden():
                self.showNormal()
                self.raise_()


    def closeEvent(self, event):
        # 重写窗口关闭事件,实现最小化到托盘
        event.ignore()
        self.hide()

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

背景运动及模糊滤镜

Steam登陆界面复现-PyQt6-Python-运动背景图三种实现方式

最开始使用的是重写paintEvent方法,但是后来发现加上模糊的时候窗口内容也模糊了。使用QLabel堆叠实现背景就不会造成窗口内容也模糊了。

import sys
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtGui import QPainter, QPixmap
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget,QGraphicsBlurEffect,QLabel

class MovingBackgroundWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(100, 100, 800, 600)
        self.initBg()
        self.initUI()

    def initUI(self):
        label = QLabel('啊哈哈哈哈哈', self)
        label.setGeometry(100, 100, 100, 30)

    def initBg(self):
        # 设置背景图片
        self.background_pixmap = QPixmap("bg.jpg")
        # 暂存当前现实背景图片
        self.background_pixmap_tmp=QPixmap("bg.jpg")
        self.tmp_x=0
        self.tmp_y=0
        # 设置定时器,每隔一段时间触发重绘事件
        self.bg_timer = QTimer(self)
        self.bg_timer.timeout.connect(self.update_background)
        self.bg_timer.start(50)  # 调整移动速度,单位为毫秒
        # 添加毛玻璃模糊滤镜
        blur_effect = QGraphicsBlurEffect()
        blur_effect.setBlurRadius(10)
        self.setGraphicsEffect(blur_effect)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawPixmap(0, 0, self.background_pixmap_tmp)

    def update_background(self):
        self.tmp_x+=2
        self.tmp_y+=1
        self.background_pixmap_tmp = self.background_pixmap.copy(self.tmp_x, self.tmp_y,self.background_pixmap.width()-self.tmp_x, self.background_pixmap.height()-self.tmp_y)
        # 强制重绘
        self.update()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    widget = MovingBackgroundWidget()
    
    # 将 widget 设置为主窗口的中央部件
    main_window = QMainWindow()
    main_window.setCentralWidget(widget)

    main_window.setGeometry(100, 100, 800, 600)
    main_window.show()

    sys.exit(app.exec())
import sys
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtGui import QPainter, QPixmap,QFont
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget,QLabel,
    QGraphicsBlurEffect
    ,QHBoxLayout,QVBoxLayout)
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QGridLayout, QCheckBox, QGraphicsOpacityEffect
from PyQt6.QtCore import Qt, QRect, QPropertyAnimation, QParallelAnimationGroup,QSize
from PyQt6.QtGui import QPixmap, QMovie
class LoginWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.setFixedSize(880,550)
        self.setWindowFlag(Qt.WindowType.FramelessWindowHint,True)
        # self.initStyle()
        self.initBg()
        self.initUI()

    def initUI(self):
        # 创建布局和部件
        main_layout = QVBoxLayout(self)
        close_layout = QHBoxLayout()
        top_layout = QHBoxLayout()
        center_layout = QVBoxLayout()
        bottom_layout=QHBoxLayout()

        logo_label = QLabel(self)
        logo_pixmap = QPixmap("logo.png").scaled(70,70)
        logo_label.setPixmap(logo_pixmap)
        logo_label.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft)

        software_label = QLabel("派森斗罗", self)
        software_label.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
        software_label.setStyleSheet("font-size: 20px; font-weight: bold; color: white;")

        close_button = QPushButton("×", self)
        close_button.setFixedSize(50,50)
        close_button.setStyleSheet("QPushButton {background-color: rgba(0, 0, 0, 0); color: #616F77;font-size:25px;}\
                                   QPushButton:hover {background-color: #E22A27; color: white;}")
        close_button.clicked.connect(self.close)

        username_label = QLabel("账号:", self)
        password_label = QLabel("密码:", self)
        username_label.setStyleSheet("color:white;font-weight:bold;font-size:15px;")
        password_label.setStyleSheet("color:white;font-weight:bold;font-size:15px;")

        username_input = QLineEdit(self)
        password_input = QLineEdit(self)
        username_input.setFixedSize(180,30)
        password_input.setFixedSize(180,30)
        username_input.setStyleSheet("QLineEdit{border:0;background-color:rgba(0, 0, 0, 100);padding:5px;color:white;font-weight:bold;}\
                                     QLineEdit:hover{background-color:rgba(0, 0, 0, 50);}")

        password_input.setEchoMode(QLineEdit.EchoMode.Password)
        password_input.setStyleSheet("QLineEdit{border:0;background-color:rgba(0, 0, 0, 100);padding:5px;color:white;font-weight:bold;}\
                                     QLineEdit:hover{background-color:rgba(0, 0, 0, 50);}")

        remember_me_checkbox = QCheckBox("记住密码", self)
        remember_me_checkbox.setStyleSheet("color:white;")

        login_button = QPushButton("登录", self)
        login_button.setFixedSize(100,25)
        login_button.setStyleSheet("QPushButton{border:0;color:white;background-color:rgba(0, 0, 255, 150);font-weight:bold;}\
                                     QPushButton:hover{background-color:rgba(0, 0, 255, 80);}")
        login_button.clicked.connect(lambda x:print('登录'))

        register_label = QLabel("还没有账号?  ", self)
        register_label.setStyleSheet("color:white;")
        register_button = QPushButton("去注册", self)
        font=register_button.font()
        font.setUnderline(True)
        register_button.setFont(font)
        register_button.setStyleSheet("border:0;color:white;")

        register_button.clicked.connect(lambda x:print('注册'))

        # 添加部件到布局
        close_layout.addStretch(1)
        close_layout.addWidget(close_button)

        top_layout.addWidget(logo_label)
        top_layout.addWidget(software_label)
        top_layout.addStretch(1)

        center_layout.addWidget(username_label)
        center_layout.addWidget(username_input)
        center_layout.addWidget(password_label)
        center_layout.addWidget(password_input)
        center_layout.addWidget(remember_me_checkbox)
        center_layout.addWidget(login_button, alignment=Qt.AlignmentFlag.AlignCenter)
        center_layout.setAlignment(Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter)

        bottom_layout.addStretch(10)
        bottom_layout.addWidget(register_label)
        bottom_layout.addWidget(register_button)
        bottom_layout.addStretch(1)

        main_layout.addLayout(close_layout)
        main_layout.addLayout(top_layout)
        main_layout.addStretch(1)
        main_layout.addLayout(center_layout)
        main_layout.addStretch(5)
        main_layout.addLayout(bottom_layout)
        main_layout.addStretch(3)

    def mousePressEvent(self, event):
        # 鼠标按压
        if event.button() == Qt.MouseButton.LeftButton and self.geometry().contains(self.mapToGlobal(event.pos())):
            self.dis = self.mapToGlobal(event.pos()) - self.pos()
            self.dragging = True
            self.setCursor(Qt.CursorShape.ClosedHandCursor)

    def mouseMoveEvent(self, event):
        # 鼠标移动的时候判断是否是拖拽状态,如果是的话就移动窗口
        if self.dragging:
            self.move(self.mapToGlobal(event.pos()) - self.dis)

    def mouseReleaseEvent(self, event):
        # 鼠标释放的时候接触拖拽状态并且改变鼠标样式
        if event.button() == Qt.MouseButton.LeftButton and self.dragging:
            self.dragging = False
            self.setCursor(Qt.CursorShape.OpenHandCursor)
        
    def initStyle(self):
        self.font=QFont('./assets/fonts/1.ttf')
        self.font.setPointSize(32)
        self.font.setBold(True)
        self.font.setStyle(QFont.Style.StyleNormal)

    def initBg(self):
        self.bg_label=QLabel(self)
        # 设置背景图片
        self.background_pixmap = QPixmap("bg1.jpg").scaled(880+500,550+250)
        # 暂存当前现实背景图片
        self.background_pixmap_tmp=QPixmap("bg1.jpg")
        self.tmp_x=0
        self.tmp_y=0
        self.dx=2
        self.dy=1
        # 设置定时器,每隔一段时间触发重绘事件
        self.bg_timer = QTimer(self)
        self.bg_timer.timeout.connect(self.update_background)
        self.bg_timer.start(50)  # 调整移动速度,单位为毫秒
        # 添加毛玻璃模糊滤镜
        blur_effect = QGraphicsBlurEffect()
        blur_effect.setBlurRadius(20)
        self.bg_label.setGraphicsEffect(blur_effect)

    def update_background(self):
        self.bg_label.setGeometry(self.rect())
        self.bg_label.setPixmap(self.background_pixmap_tmp)
        if self.tmp_x<0 or self.tmp_x>self.background_pixmap.width()-880:
            self.dx,self.dy=-self.dx,-self.dy
        self.tmp_x+=self.dx
        self.tmp_y+=self.dy
        self.background_pixmap_tmp = self.background_pixmap.copy(self.tmp_x,self.background_pixmap.height()-550-self.tmp_y,880,550)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    widget = LoginWidget()
    widget.show()
    sys.exit(app.exec())
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QGridLayout, QCheckBox, QGraphicsOpacityEffect
from PyQt6.QtCore import Qt, QRect, QPropertyAnimation, QParallelAnimationGroup,QSize
from PyQt6.QtGui import QPixmap, QMovie
class LoginWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Login")        
        self.initBg()
        self.initUI()

    def mousePressEvent(self, event):
        # 鼠标按压,判断是否是鼠标左键并且点击点在窗口内
        if event.button() == Qt.MouseButton.LeftButton and self.geometry().contains(self.mapToGlobal(event.pos())):
            self.dis = self.mapToGlobal(event.pos()) - self.pos()
            print(self.mapToGlobal(event.pos()),event.pos(),self.pos(),self.dis)
            self.dragging = True
            self.setCursor(Qt.CursorShape.ClosedHandCursor)
    def mouseMoveEvent(self, event):
        # 鼠标移动的时候判断是否是拖拽状态,如果是的话就移动窗口
        if self.dragging:
            # self.move(event.pos()-self.dis)
            self.move(self.mapToGlobal(event.pos()) - self.dis)
    def mouseReleaseEvent(self, event):
        # 鼠标释放的时候接触拖拽状态并且改变鼠标样式
        if event.button() == Qt.MouseButton.LeftButton and self.dragging:
            self.dragging = False
            self.setCursor(Qt.CursorShape.OpenHandCursor)

    def initBg(self):
        # 设置背景图片
        self.setFixedSize(880, 550)
        background_label = QLabel(self)
        background_label.setGeometry(self.rect())
        movie = QMovie("./assets/imgs/bg/bg.gif")
        movie.setScaledSize(QSize(880,550))
        background_label.setMovie(movie)
        movie.start()

    def initUI(self):
        self.setWindowFlag(Qt.WindowType.FramelessWindowHint)
        # 创建布局和部件
        main_layout = QVBoxLayout(self)
        close_layout = QHBoxLayout()
        top_layout = QHBoxLayout()
        center_layout = QVBoxLayout()
        bottom_layout=QHBoxLayout()

        logo_label = QLabel(self)
        logo_pixmap = QPixmap("logo.png").scaled(70,70)
        logo_label.setPixmap(logo_pixmap)
        logo_label.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft)

        software_label = QLabel("派森斗罗", self)
        software_label.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
        software_label.setStyleSheet("font-size: 20px; font-weight: bold; color: white;")

        close_button = QPushButton("×", self)
        close_button.setFixedSize(50,50)
        close_button.setStyleSheet("QPushButton {background-color: rgba(0, 0, 0, 0); color: #616F77;font-size:25px;}\
                                   QPushButton:hover {background-color: #E22A27; color: white;}")
        close_button.clicked.connect(self.close)

        username_label = QLabel("账号:", self)
        password_label = QLabel("密码:", self)
        username_label.setStyleSheet("color:white;font-weight:bold;font-size:15px;")
        password_label.setStyleSheet("color:white;font-weight:bold;font-size:15px;")

        username_input = QLineEdit(self)
        password_input = QLineEdit(self)
        username_input.setFixedSize(180,30)
        password_input.setFixedSize(180,30)
        username_input.setStyleSheet("QLineEdit{border:0;background-color:rgba(0, 0, 0, 100);padding:5px;color:white;font-weight:bold;}\
                                     QLineEdit:hover{background-color:rgba(0, 0, 0, 50);}")

        password_input.setEchoMode(QLineEdit.EchoMode.Password)
        password_input.setStyleSheet("QLineEdit{border:0;background-color:rgba(0, 0, 0, 100);padding:5px;color:white;font-weight:bold;}\
                                     QLineEdit:hover{background-color:rgba(0, 0, 0, 50);}")

        remember_me_checkbox = QCheckBox("记住密码", self)
        remember_me_checkbox.setStyleSheet("color:white;")

        login_button = QPushButton("登录", self)
        login_button.setFixedSize(100,25)
        login_button.setStyleSheet("QPushButton{border:0;color:white;background-color:rgba(0, 0, 255, 150);font-weight:bold;}\
                                     QPushButton:hover{background-color:rgba(0, 0, 255, 80);}")
        login_button.clicked.connect(lambda x:print('登录'))

        register_label = QLabel("还没有账号?  ", self)
        register_label.setStyleSheet("color:white;")
        register_button = QPushButton("去注册", self)
        font=register_button.font()
        font.setUnderline(True)
        register_button.setFont(font)
        register_button.setStyleSheet("border:0;color:white;")

        register_button.clicked.connect(lambda x:print('注册'))

        # 添加部件到布局
        close_layout.addStretch(1)
        close_layout.addWidget(close_button)

        top_layout.addWidget(logo_label)
        top_layout.addWidget(software_label)
        top_layout.addStretch(1)

        center_layout.addWidget(username_label)
        center_layout.addWidget(username_input)
        center_layout.addWidget(password_label)
        center_layout.addWidget(password_input)
        center_layout.addWidget(remember_me_checkbox)
        center_layout.addWidget(login_button, alignment=Qt.AlignmentFlag.AlignCenter)
        center_layout.setAlignment(Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter)

        bottom_layout.addStretch(10)
        bottom_layout.addWidget(register_label)
        bottom_layout.addWidget(register_button)
        bottom_layout.addStretch(1)

        main_layout.addLayout(close_layout)
        main_layout.addLayout(top_layout)
        main_layout.addStretch(1)
        main_layout.addLayout(center_layout)
        main_layout.addStretch(5)
        main_layout.addLayout(bottom_layout)
        main_layout.addStretch(3)

if __name__ == '__main__':
    app = QApplication([])
    login_window = LoginWindow()
    login_window.show()
    app.exec()

窗口自定义拖拽功能

def mousePressEvent(self, event):
        # 鼠标按压,判断是否是鼠标左键并且点击点在窗口内
        if event.button() == Qt.MouseButton.LeftButton and self.geometry().contains(self.mapToGlobal(event.pos())):
            self.dis = self.mapToGlobal(event.pos()) - self.pos()
            print(self.mapToGlobal(event.pos()),event.pos(),self.pos(),self.dis)
            self.dragging = True
            self.setCursor(Qt.CursorShape.ClosedHandCursor)
def mouseMoveEvent(self, event):
    # 鼠标移动的时候判断是否是拖拽状态,如果是的话就移动窗口
    if self.dragging:
        # self.move(event.pos()-self.dis)
        self.move(self.mapToGlobal(event.pos()) - self.dis)
def mouseReleaseEvent(self, event):
    # 鼠标释放的时候接触拖拽状态并且改变鼠标样式
    if event.button() == Qt.MouseButton.LeftButton and self.dragging:
        self.dragging = False
        self.setCursor(Qt.CursorShape.OpenHandCursor)
import sys
from PyQt6.QtWidgets import QApplication, QWidget
from PyQt6.QtGui import QScreen, QGuiApplication,QIcon
from PyQt6.QtCore import Qt, QRect, QPropertyAnimation, QParallelAnimationGroup,QSize
class MyApplication(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()
    def mousePressEvent(self, event):
        # 鼠标按压,判断是否是鼠标左键并且点击点在窗口内
        if event.button() == Qt.MouseButton.LeftButton and self.geometry().contains(self.mapToGlobal(event.pos())):
            self.dis = self.mapToGlobal(event.pos()) - self.pos()
            print(self.mapToGlobal(event.pos()),event.pos(),self.pos(),self.dis)
            self.dragging = True
            self.setCursor(Qt.CursorShape.ClosedHandCursor)
    def mouseMoveEvent(self, event):
        # 鼠标移动的时候判断是否是拖拽状态,如果是的话就移动窗口
        if self.dragging:
            # self.move(event.pos()-self.dis)
            self.move(self.mapToGlobal(event.pos()) - self.dis)
    def mouseReleaseEvent(self, event):
        # 鼠标释放的时候接触拖拽状态并且改变鼠标样式
        if event.button() == Qt.MouseButton.LeftButton and self.dragging:
            self.dragging = False
            self.setCursor(Qt.CursorShape.OpenHandCursor)

    def initUI(self):
        self.setGeometry(0, 0, 300, 200)  # Set window size
        self.setWindowTitle('派森斗罗')
        self.setWindowIcon(QIcon('logo.png'))

        self.center()  # Center the window on the screen
    def center(self):
        qr=self.frameGeometry()
        cp=QGuiApplication.primaryScreen().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApplication()
    ex.show()
    sys.exit(app.exec())

窗口双击更换背景

import sys
import typing
from PyQt6.QtWidgets import QApplication, QMainWindow,QSystemTrayIcon,QMenu,QFrame,QHBoxLayout,QVBoxLayout,QLineEdit, QPushButton, QLabel,QListWidget, QMenuBar, QWidget, QStackedWidget,QLabel,QListWidgetItem
from PyQt6.QtGui import (QIcon,QAction,QScreen, QGuiApplication,QColor,QResizeEvent,QDragMoveEvent,QMoveEvent,
QPixmap, QMovie)
from PyQt6.QtCore import (Qt,pyqtSignal,QRect,QPropertyAnimation,
QParallelAnimationGroup, QSequentialAnimationGroup, QPauseAnimation, QEasingCurve,QSize)
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel, QLineEdit, QPushButton,QCheckBox,
QVBoxLayout, QHBoxLayout, QGridLayout,
QGraphicsOpacityEffect)

class LoginWindow(QWidget):
    loginSuccessSignal = pyqtSignal()  # 登录成功的信号

    def __init__(self):
        super().__init__()
        self.configSize=(880,550)
        self.configBg=['bg.gif','bg1.gif','bg2.gif','bg3.gif','bg4.gif','bg5.gif',]

        self.initBg()
        self.initUI()
        self.center()
        self.fadeIn()

    def changeBg(self):
        movie_path='./assets/imgs/bg/'+self.configBg[
        (self.configBg.index(
            self.background_label.movie().fileName().split('/')[-1]
        )+1)
        %len(self.configBg)
        ]
        print(movie_path)
        movie=QMovie(movie_path)
        self.background_label.setMovie(movie)
        movie.setScaledSize(QSize(*self.configSize))
        movie.start()

    def mouseDoubleClickEvent(self,event):
        self.changeBg()
    def initBg(self):
        # 设置窗口无框架,设置大小
        self.setWindowFlag(Qt.WindowType.FramelessWindowHint)
        self.setFixedSize(*self.configSize)
        # 设置背景
        self.background_label = QLabel(self)
        self.background_label.setGeometry(self.rect())
        movie = QMovie('./assets/imgs/bg/'+self.configBg[0])
        # movie = QMovie("bg.gif")
        movie.setScaledSize(QSize(*self.configSize))
        self.background_label.setMovie(movie)
        movie.start()

    def mousePressEvent(self, event):
        # 鼠标按压,判断是否是鼠标左键并且点击点在窗口内
        if event.button() == Qt.MouseButton.LeftButton and self.geometry().contains(self.mapToGlobal(event.pos())):
            self.dis = self.mapToGlobal(event.pos()) - self.pos()
            self.dragging = True
            self.setCursor(Qt.CursorShape.ClosedHandCursor)
    def mouseMoveEvent(self, event):
        # 鼠标移动的时候判断是否是拖拽状态,如果是的话就移动窗口
        if self.dragging:
            self.move(self.mapToGlobal(event.pos()) - self.dis)
    def mouseReleaseEvent(self, event):
        # 鼠标释放的时候接触拖拽状态并且改变鼠标样式
        if event.button() == Qt.MouseButton.LeftButton and self.dragging:
            self.dragging = False
            self.setCursor(Qt.CursorShape.OpenHandCursor)

    def initUI(self):
        # 创建布局和部件
        main_layout = QVBoxLayout(self)
        close_layout = QHBoxLayout()
        top_layout = QHBoxLayout()
        center_layout = QVBoxLayout()
        bottom_layout=QHBoxLayout()

        logo_label = QLabel(self)
        logo_pixmap = QPixmap("logo.png").scaled(70,70)
        logo_label.setPixmap(logo_pixmap)
        logo_label.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft)

        software_label = QLabel("派森斗罗", self)
        software_label.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
        software_label.setStyleSheet("font-size: 20px; font-weight: bold; color: white;")

        close_button = QPushButton("×", self)
        close_button.setFixedSize(50,50)
        close_button.setStyleSheet("QPushButton {background-color: rgba(0, 0, 0, 0); color: #616F77;font-size:25px;}\
                                   QPushButton:hover {background-color: #E22A27; color: white;}")
        close_button.clicked.connect(self.close)

        username_label = QLabel("账号:", self)
        password_label = QLabel("密码:", self)
        username_label.setStyleSheet("color:white;font-weight:bold;font-size:15px;")
        password_label.setStyleSheet("color:white;font-weight:bold;font-size:15px;")

        username_input = QLineEdit(self)
        password_input = QLineEdit(self)
        username_input.setFixedSize(180,30)
        password_input.setFixedSize(180,30)
        username_input.setStyleSheet("QLineEdit{border:0;background-color:rgba(80,100,100,150);padding:5px;color:white;font-weight:bold;}\
                                     QLineEdit:hover{background-color:rgba(0, 0, 0, 100);}")

        password_input.setEchoMode(QLineEdit.EchoMode.Password)
        password_input.setStyleSheet("QLineEdit{border:0;background-color:rgba(80,100,100,150);padding:5px;color:white;font-weight:bold;}\
                                     QLineEdit:hover{background-color:rgba(0, 0, 0, 100);}")

        remember_me_checkbox = QCheckBox("记住密码", self)
        remember_me_checkbox.setStyleSheet("color:white;")

        login_button = QPushButton("登录", self)
        login_button.setFixedSize(100,25)
        login_button.setStyleSheet("QPushButton{border:0;color:white;background-color:rgba(0, 0, 255, 150);font-weight:bold;}\
                                     QPushButton:hover{background-color:rgba(0, 0, 255, 80);}")
        login_button.clicked.connect(self.login)
        # login_button.clicked.connect(lambda x:print('登录'))

        register_label = QLabel("还没有账号?  ", self)
        register_label.setStyleSheet("color:white;")
        register_button = QPushButton("去注册", self)
        font=register_button.font()
        font.setUnderline(True)
        register_button.setFont(font)
        register_button.setStyleSheet("border:0;color:white;")

        register_button.clicked.connect(lambda x:print('注册'))

        # 添加部件到布局
        close_layout.addStretch(1)
        close_layout.addWidget(close_button)

        top_layout.addWidget(logo_label)
        top_layout.addWidget(software_label)
        top_layout.addStretch(1)

        center_layout.addWidget(username_label)
        center_layout.addWidget(username_input)
        center_layout.addWidget(password_label)
        center_layout.addWidget(password_input)
        center_layout.addWidget(remember_me_checkbox)
        center_layout.addWidget(login_button, alignment=Qt.AlignmentFlag.AlignCenter)
        center_layout.setAlignment(Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter)

        bottom_layout.addStretch(10)
        bottom_layout.addWidget(register_label)
        bottom_layout.addWidget(register_button)
        bottom_layout.addStretch(1)

        main_layout.addLayout(close_layout)
        main_layout.addLayout(top_layout)
        main_layout.addStretch(1)
        main_layout.addLayout(center_layout)
        main_layout.addStretch(5)
        main_layout.addLayout(bottom_layout)
        main_layout.addStretch(3)

        self.setWindowOpacity(0.0)

    def fadeIn(self):
        self.animation = QPropertyAnimation(self, b"windowOpacity")
        self.animation.setStartValue(0.0)
        self.animation.setEndValue(1.0)
        self.animation.setDuration(1000)
        self.animation.start()

    def fadeOut(self):
        self.animation = QPropertyAnimation(self, b"windowOpacity")
        self.animation.setStartValue(1.0)
        self.animation.setEndValue(0.0)
        self.animation.setDuration(1000)
        self.animation.finished.connect(self.quit)
        self.animation.start()
    
    def quit(self):
        self.loginSuccessSignal.emit()  # 发送登录成功信号
        self.close()
    
    def center(self):
        qr=self.frameGeometry()
        cp=QGuiApplication.primaryScreen().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def login(self):
        self.fadeOut()
        # if self.username_input.text() == '1' and self.password_input.text() == '1':
        #     self.fadeOut()

多软件图标排布

from PyQt6 import QtGui
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QScrollArea, QLabel, QGridLayout, QPushButton
from PyQt6.QtGui import QPixmap
import sys
import typing
from PyQt6.QtWidgets import QApplication, QMainWindow,QSystemTrayIcon,QMenu,QFrame,QHBoxLayout,QVBoxLayout,QLineEdit, QPushButton, QLabel,QListWidget, QMenuBar, QWidget, QStackedWidget,QLabel,QListWidgetItem
from PyQt6.QtGui import (QIcon,QAction,QScreen, QGuiApplication,QColor,QResizeEvent,QDragMoveEvent,QMoveEvent,
                         QPixmap, QMovie)
from PyQt6.QtCore import (Qt,pyqtSignal,QRect,QPropertyAnimation,
                          QParallelAnimationGroup, QSequentialAnimationGroup, QPauseAnimation, QEasingCurve,QSize)
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel, QLineEdit, QPushButton,QCheckBox,
                             QVBoxLayout, QHBoxLayout, QGridLayout,
                             QGraphicsOpacityEffect)
class SoftwareWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()
        self.initSoftList()

    def initUI(self):
        self.setWindowTitle('多软件窗口')
        self.setGeometry(100, 100, 700, 100)
        self.show()

    def initSoftList(self):
        # 模拟软件数据
        self.software_data = [
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
            {"name": "软件1", "icon_path": "assets/imgs/icons/sun.png"},
        ]
        self.setSoftBoxs(con=self)

    def setSoftBoxs(self,con,box_width=120,box_height=160):
        # 创建包含软件图标和名称的布局
        layout = QGridLayout()
        print(con.width())
        row, col = 0, 0  # 行和列的起始位置
        # 能够容纳的行
        row_allow=self.width()//120
        for software in self.software_data:
            icon_path = software["icon_path"]
            name = software["name"]
            des='这是软件一ahhah哈哈哈哈哈'
            box=self.getSoftBox(name,icon_path,des,box_width=box_width,box_height=box_height)
            layout.addWidget(box, row, col)
            col += 1
            if col == row_allow:
                col = 0
                row += 1
        con.setLayout(layout)

    def getSoftBox(self,name,logo_path,des,box_width,box_height):
        box=QWidget()
        box.setFixedSize(box_width,box_height)
        box.setToolTip(des)
        # box.setStyleSheet("QWidget{background-color:pink}")
        box.setStyleSheet("QWidget{border:1px solid black;background-color:#FDF6E3;}")
        layout=QVBoxLayout()
        logo_label=QLabel()
        logo_label.setPixmap(QPixmap(logo_path).scaledToWidth(50))
        logo_label.setFixedSize(50,50)
        name_label=QLabel(name)
        des_label=QLabel(des)
        btn=QPushButton('打开')
        layout.addWidget(logo_label)
        layout.addWidget(name_label)
        layout.addWidget(des_label)
        layout.addWidget(btn)
        layout.setAlignment(logo_label,Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)

        box.setLayout(layout)
        return box


if __name__ == '__main__':
    app = QApplication([])
    ex = SoftwareWindow()
    app.exec()

点击按钮打开新页面

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QDialog, QVBoxLayout, QLabel

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

        # 创建主窗口
        self.setWindowTitle("派森斗罗")
        self.setGeometry(100, 100, 400, 200)

        # 创建按钮并连接点击信号与槽
        self.button = QPushButton("打开新窗口", self)
        self.button.clicked.connect(self.open_dialog)

    def open_dialog(self):
        # 创建对话框
        self.dialog = MyDialog()
        self.dialog.show()
        self.dialog.exec()

class MyDialog(QDialog):
    def __init__(self):
        super().__init__()

        # 创建对话框中的控件
        layout = QVBoxLayout(self)
        label = QLabel("这是新窗口!", self)
        layout.addWidget(label)

        self.setWindowTitle("派森斗罗")
        self.setGeometry(200, 200, 300, 150)


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

窗口中画一个框

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget
from PyQt6.QtGui import QPainter, QBrush, QPen
from PyQt6.QtCore import Qt, QRect, QPoint


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

        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 800, 600)
        self.setWindowTitle('Draw Rectangle')

        self.canvas = DrawingCanvas(self)
        self.setCentralWidget(self.canvas)

        self.show()


class DrawingCanvas(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.setGeometry(0, 0, parent.width(), parent.height())

        self.origin = QPoint(0, 0)  # 初始化为 (0, 0)
        self.end = QPoint(0, 0)     # 初始化为 (0, 0)

    def paintEvent(self, event):
        painter = QPainter(self)
        # 设置绘制选项,启用抗锯齿。
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)

        rect = QRect(self.origin, self.end)
        painter.drawRect(rect)

    def mousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self.origin = event.pos()
            self.end = event.pos()

    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.MouseButton.LeftButton:
            self.end = event.pos()
            self.update()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self.end = event.pos()
            self.update()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = DrawingApp()
    sys.exit(app.exec())

介绍一下QGraphicsScene和QGraphicsView

QGraphicsSceneQGraphicsView 是 PyQt 中用于创建图形用户界面的两个关键类,它们一起协同工作,提供了一种灵活的图形表示方法。以下是它们的主要介绍:

QGraphicsScene

QGraphicsScene 是一个二维图形场景,它允许你在其中添加、移动和交互多个 2D 图形项(QGraphicsItem)。图形项可以是简单的图形元素,如矩形、椭圆和文本,也可以是自定义的图形元素。QGraphicsScene 提供了以下主要功能:

  1. 管理图形项: QGraphicsScene 维护了一个图形项的列表,你可以在其中添加、移除和操纵图形项。
  2. 场景坐标系: 每个图形项都有自己的局部坐标系,而 QGraphicsScene 提供了一个全局坐标系,使你能够在场景中的不同图形项之间执行坐标转换。
  3. 事件处理: QGraphicsScene 可以接收鼠标、键盘和其他事件,你可以通过重写相应的事件处理方法来响应这些事件。
  4. 图形项选择: 你可以选择一个或多个图形项,执行相应的操作,比如拖动、删除等。

QGraphicsView

QGraphicsView 是用于在窗口中显示 QGraphicsScene 的视图类。它提供了以下主要功能:

  1. 显示场景: QGraphicsView 提供一个用于显示 QGraphicsScene 内容的视图窗口。你可以在一个窗口中显示多个 QGraphicsView,每个视图显示同一个或不同的场景。
  2. 视图变换: 通过视图变换,你可以对场景进行平移、缩放、旋转等操作。这使得你可以轻松地实现图形的缩放和平移效果。
  3. 视图更新: 当场景中的图形项发生变化时,QGraphicsView 负责更新视图,以便反映这些变化。
  4. 事件转发: QGraphicsView 接收鼠标、键盘等事件,并将它们传递给场景中的图形项进行处理。
  5. 交互支持: QGraphicsView 提供了一些方便的方法来支持用户的交互,比如启用鼠标拖拽、缩放等。

通过将 QGraphicsSceneQGraphicsView 结合使用,你可以创建出富有交互性的图形界面,用于显示和操作图形元素。这对于图形编辑器、CAD 应用、数据可视化等领域非常有用。

图片浏览,可以放大缩小拖拽

import sys
from PyQt6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QMainWindow
from PyQt6.QtCore import Qt, QPointF
from PyQt6.QtGui import QPixmap, QWheelEvent, QPainter


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

        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 800, 600)
        self.setWindowTitle('Image Viewer')

        self.scene = QGraphicsScene(self)
        self.view = GraphicsView(self.scene, self)
        self.setCentralWidget(self.view)

        # Load an example image
        image_path = 'letter.png'  # Replace with the actual path to your image
        pixmap = QPixmap(image_path)
        item = QGraphicsPixmapItem(pixmap)
        self.scene.addItem(item)

        self.show()


class GraphicsView(QGraphicsView):
    def __init__(self, scene, parent):
        super().__init__(scene, parent)
        self.setRenderHint(QPainter.RenderHint.Antialiasing, True)
        self.setStyleSheet('GraphicsView{background-color:#FDF6E3;}')

        self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)  # Enable hand-drag mode

    def wheelEvent(self, event: QWheelEvent):
        modifiers = event.modifiers()
        if modifiers == Qt.KeyboardModifier.ControlModifier:
            # Zoom only if Ctrl key is pressed
            factor = 1.2  # Zoom factor
            if event.angleDelta().y() < 0:
                factor = 1.0 / factor  # Zoom out for a negative wheel event

            self.scale(factor, factor)

def main():
    app = QApplication(sys.argv)
    viewer = ImageViewer()
    sys.exit(app.exec())


if __name__ == '__main__':
    main()

图片浏览,ctrl+滚轮放大缩小,左键按压拖拽,右键按压画框,框显示坐标信息

import sys
from PyQt6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QGraphicsRectItem, QMainWindow, QGraphicsTextItem
from PyQt6.QtCore import Qt, QRectF
from PyQt6.QtGui import QPixmap, QPainter, QFont

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

        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 800, 600)
        self.setWindowTitle('Image Viewer')

        self.scene = QGraphicsScene(self)
        self.view = GraphicsView(self.scene, self)
        self.setCentralWidget(self.view)

        # Load an example image
        image_path = 'letter.png'  # Replace with the actual path to your image
        pixmap = QPixmap(image_path)
        item = QGraphicsPixmapItem(pixmap)
        self.scene.addItem(item)

        self.show()

class GraphicsView(QGraphicsView):
    def __init__(self, scene, parent):
        super().__init__(scene, parent)
        
        self.setStyleSheet('GraphicsView{background-color:#FDF6E3;}')
        self.setRenderHint(QPainter.RenderHint.Antialiasing, True)
        self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)  # 启用拖拽模式

        self.drawing_rect = None
        self.origin = None
        self.is_drawing = False
        self.coordinate_text_items = {}  # 存储坐标信息的字典,以矩形为键

    def wheelEvent(self, event):
        modifiers = event.modifiers()
        if modifiers == Qt.KeyboardModifier.ControlModifier:
            # 只有在按下 Ctrl 键时才缩放
            factor = 1.2  # 缩放因子
            if event.angleDelta().y() < 0:
                factor = 1.0 / factor  # 对于负的滚轮事件进行缩小

            self.scale(factor, factor)

    def mouseDoubleClickEvent(self, event):
        super().mouseDoubleClickEvent(event)

        if event.button() == Qt.MouseButton.LeftButton:
            # 获取鼠标双击的位置
            double_click_position = event.pos()

            # 获取双击位置相对于原图的像素位置
            double_click_scene_position = self.mapToScene(double_click_position)

            # 获取点击位置相对于原图的像素位置
            item = self.scene().itemAt(double_click_scene_position, self.transform())
            if isinstance(item, QGraphicsRectItem):
                # 删除被点击的矩形的坐标信息
                rect_key = id(item)
                if rect_key in self.coordinate_text_items:
                    self.removeCoordinateTextItems(self.coordinate_text_items[rect_key])

                # 删除被点击的矩形
                self.scene().removeItem(item)

    def mouseMoveEvent(self, event):
        super().mouseMoveEvent(event)

        if event.buttons() & Qt.MouseButton.RightButton:
            if self.is_drawing and self.origin is not None:
                # 获取鼠标当前位置
                current_position = event.pos()

                # 获取当前位置相对于原图的像素位置
                current_scene_position = self.mapToScene(current_position)

                # 更新矩形的大小
                self.drawing_rect.setRect(QRectF(self.origin, current_scene_position))

        # 实时显示图像
        scene_rect = self.sceneRect()
        self.setSceneRect(scene_rect)

    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)

        if event.button() == Qt.MouseButton.RightButton:
            if self.is_drawing and self.origin is not None:
                self.is_drawing = False

                # 获取鼠标释放的位置
                release_position = event.pos()

                # 获取释放位置相对于原图的像素位置
                release_scene_position = self.mapToScene(release_position)

                # 更新矩形的大小
                self.drawing_rect.setRect(QRectF(self.origin, release_scene_position))

                # 显示矩形的坐标信息
                self.showRectCoordinates(self.drawing_rect)

    def mousePressEvent(self, event):
        super().mousePressEvent(event)

        if event.button() == Qt.MouseButton.RightButton:
            if not self.is_drawing:
                # 获取鼠标点击的位置
                click_position = event.pos()

                # 获取点击位置相对于原图的像素位置
                scene_position = self.mapToScene(click_position)
                self.origin = scene_position
                self.is_drawing = True

                # 创建一个新的矩形
                self.drawing_rect = QGraphicsRectItem(QRectF(self.origin, self.origin))
                self.scene().addItem(self.drawing_rect)

    def showRectCoordinates(self, rect_item):
        # 获取矩形的左上角和右下角相对于图片的坐标
        rect_top_left = rect_item.rect().topLeft()
        rect_bottom_right = rect_item.rect().bottomRight()

        # 将坐标转换为整数
        rect_top_left = rect_top_left.toPoint()
        rect_bottom_right = rect_bottom_right.toPoint()

        # 在矩形的左上角显示坐标信息
        text_item_top_left = QGraphicsTextItem(f"({rect_top_left.x()}, {rect_top_left.y()})")
        text_item_top_left.setPos(rect_top_left.x(), rect_top_left.y() - 15)
        self.scene().addItem(text_item_top_left)

        # 在矩形的右下角显示坐标信息
        text_item_bottom_right = QGraphicsTextItem(f"({rect_bottom_right.x()}, {rect_bottom_right.y()})")
        text_item_bottom_right.setPos(rect_bottom_right.x() - 60, rect_bottom_right.y() + 5)
        self.scene().addItem(text_item_bottom_right)

        # 存储矩形和坐标信息的关联
        rect_key = id(rect_item)
        self.coordinate_text_items[rect_key] = [text_item_top_left, text_item_bottom_right]

    def removeCoordinateTextItems(self, items):
        # 删除与矩形关联的坐标信息
        for item in items:
            self.scene().removeItem(item)

def main():
    app = QApplication(sys.argv)
    viewer = ImageViewer()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()
给出这样一个pyqt6程序,左边是刚才的窗口,窗口右边有按钮和输入框,分别可以输入:
背景图像选择框,字体选择框,字体大小,字体颜色设置,文字区域左顶点,
右顶点,字间隔,行间距,行间距随机扰动值,字体大小随机扰动值,字间距随机扰动值
    font=ImageFont.truetype("hand.ttf", size=100),
    line_spacing=150,
    fill=0,  # 字体“颜色”
    left_margin=100,
    top_margin=100,
    right_margin=100,
    bottom_margin=100,
    word_spacing=15,
    # line_spacing_sigma=6,  # 行间距随机扰动
    line_spacing_sigma=0,  # 行间距随机扰动
    # font_size_sigma=20,  # 字体大小随机扰动
    # font_size_sigma=2,  # 字体大小随机扰动
    font_size_sigma=0,  # 字体大小随机扰动
    word_spacing_sigma=0,  # 字间距随机扰动
    # word_spacing_sigma=3,  # 字间距随机扰动
    start_chars="“([<",  # 特定字符提前换行,防止出现在行尾
    end_chars=",。",  # 防止特定字符因排版算法的自动换行而出现在行首
    perturb_x_sigma=0,  # 笔画横向偏移随机扰动
    # perturb_x_sigma=4,  # 笔画横向偏移随机扰动
    perturb_y_sigma=0,  # 笔画纵向偏移随机扰动
    # perturb_y_sigma=4,  # 笔画纵向偏移随机扰动
    perturb_theta_sigma=0,  # 笔画旋转偏移随机扰动

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/190881.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【漏洞复现】OpenTSDB 2.4.0 命令注入(CVE-2020-35476)漏洞复现

漏洞描述 官方文档这样描述:OpenTSDB is a distributed, scalable Time Series Database (TSDB) written ontop of HBase; 翻译过来就是,基于Hbase的分布式的,可伸缩的时间序列数据库。 主要用途,就是做监控系统;譬如收集大规模集群(包括网络设备、操作系统、应用程序…

官网IDM下载和安装的详细步骤

目录 一、IDM是什么 二、下载安装 三、解决下载超时的问题 四、谷歌浏览器打开IDM插件 谷歌浏览器下载官网&#x1f447; 五、测试 六、资源包获取 一、IDM是什么 IDM&#xff08;internet download manager&#xff09;是一个互联网下载工具插件&#xff0c;常见于用…

C语言数据类型和变量

# C语言数据类型和变量 # 数据类型介绍 C语⾔提供了丰富的数据类型来描述⽣活中的各种数据。使⽤整型类型来描述整数&#xff0c;使⽤字符类型来描述字符&#xff0c;使⽤浮点型类型来描述⼩数。所谓“类型”&#xff0c;就是相似的数据所拥有的共同特征&#xff0c;编译器只有…

可以在Playgrounds或Xcode Command Line Tool开始学习Swift

一、用Playgrounds 1. App Store搜索并安装Swift Playgrounds 2. 打开Playgrounds&#xff0c;点击 文件-新建图书。然后就可以编程了&#xff0c;如下&#xff1a; 二、用Xcode 1. 安装Xcode 2. 打开Xcode&#xff0c;选择Creat New Project 3. 选择macOS 4. 选择Comman…

使用Rust开发小游戏

本文是对 使用 Rust 开发一个微型游戏【已完结】[1]的学习与记录. cargo new flappy 在Cargo.toml的[dependencies]下方增加: bracket-lib "~0.8.7" main.rs中: use bracket_lib::prelude::*;struct State {}impl GameState for State { fn tick(&mut self,…

高校大学校园后勤移动报修系统 微信小程序uniapp+vue

本文主要是针对线下校园后勤移动报修传统管理方式中管理不便与效率低的缺点&#xff0c;将电子商务和计算机技术结合起来&#xff0c;开发出管理便捷&#xff0c;效率高的基于app的大学校园后勤移动报修app。该系统、操作简单、界面友好、易于管理和维护&#xff1b;而且对后勤…

微机11111

一、填空题&#xff08;共15分&#xff0c;每空1分&#xff09; 1、十六进制数30A.5转换为二进制是__________&#xff0c;转换为十进制是_________ 001100001010.0101B 778.3125 十六进制转换二进制 将一位十六进制分解成四位二进制 十六进制转换十进制 3X1620X16110X1605X1…

解决Vue编程式导航路由跳转不显示目标路径问题

我们配置一个编程式导航的路由跳转&#xff0c;跳转到 /search 页面&#xff0c;并且携带categoryName和categoryId两个query参数。 this.$router.push({path: "/search",query: {categoryName: dataset.categoryname,categoryId: dataset.categoryid} }) 如果我们…

Qt 网络通信

获取本机网络信息 &#xff08;1&#xff09;在 .pro 文件中加入 QT network&#xff08;2&#xff09; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> #include <QLabel> #include <QLineEdit> #include <QPu…

C语言学习笔记之函数篇

与数学意义上的函数不同&#xff0c;C语言中的函数又称为过程&#xff0c;接口&#xff0c;具有极其重要的作用。教科书上将其定义为&#xff1a;程序中的子程序。 在计算机科学中&#xff0c;子程序&#xff08;英语&#xff1a;Subroutine, procedure, function, routine, me…

【Spring】Spring事务详解

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

基于springboot+vue的学生宿舍管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

单片机学习6——定时器/计数功能的概念

在8051单片机中有两个定时器/计数器&#xff0c;分别是定时器/计数器0和定时器/计数器1。 T/C0: 定时器/计数器0 T/C1: 定时器/计数器1 T0: 定时器0 T1: 定时器1 C0: 计数器0 C1: 计数器1 如果是对内部振荡源12分频的脉冲信号进行计数&#xff0c;对每个机器周期计数&am…

苹果的未来:分析其成长策略和 2 兆美元以上的野心

Apple正在蕴育新的创新增长。作为世界上最有价值的公司&#xff0c;苹果公司拥有超过2万亿美元的市值和超过1000亿美元的年利润&#xff0c;并成功用十几年实践去打造和培育了一个硬件、软件和服务“三位一体”的商业生态&#xff0c;始终坚持以用户体验为先&#xff0c;创新极…

地铁在线售票vue票务系统uniAPP+vue 微信小程序

功能介绍 管理员 &#xff08;1&#xff09;管理员登录功能 &#xff08;2&#xff09;查看和修改线路信息 &#xff08;3&#xff09;减少线路 &#xff08;4&#xff09;修改价格&#xff08;5站3元 5-10 5元 10-15站6元 往上8元&#xff09; &#xff08;5&#xff09;删除用…

手摸手vue2+Element-ui整合Axios

后端WebAPI准备 跨域问题 为了保证浏览器的安全,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源,称为同源策略,同源策略是浏览器安全的基石 同源策略( Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能 所谓同源(即指在同一个域)就是两个页面具…

TDA笔记:夏克林老师,南洋理工大学

TDA比传统的统计方法有优势&#xff1a;benchmark中展现了这种优势 laplacian矩阵 多种单纯复形构造方式&#xff0c;可以构造出不同表征 二部图&#xff1a;Dowker complex Tor algebra可以用到多大数据 目前较新

竞赛选题 题目:基于卷积神经网络的手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…

@Async注解的坑,小心

背景 前段时间&#xff0c;一个同事小姐姐跟我说她的项目起不来了&#xff0c;让我帮忙看一下&#xff0c;本着助人为乐的精神&#xff0c;这个忙肯定要去帮。 于是&#xff0c;我在她的控制台发现了如下的异常信息&#xff1a; Exception in thread "main" org.s…

传奇,全职业刀刀烈火原理揭秘

相信很多朋友都玩过传奇, 今天我们来揭秘一下,刀刀烈火的实现原理, 其实非常简单. 烈火作为一个技能,使用流程是先释放技能, 获得一个烈火附加的状态,那么下一次攻击就会带烈火效果了. 这里我们拿烈火附加状态,当突破口,进行扫描即可. 绝大部分情况应该是有状态为1(真),没状…