第一步,新建一个自定义组件的python文件

from PySide6.QtWidgets import QPlainTextEdit
from PySide6.QtCore import Signal,Qt

class CustomPlainTextEdit(QPlainTextEdit):
    enterPressed = Signal(str)

    def __init__(self, parent=None):
        super().__init__(parent)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Return:
            self.enterPressed.emit(self.toPlainText())
            self.setPlainText("")#清空发送框文本
        else:
            super().keyPressEvent(event)

我这里新建了一个按回车键可以将文本框中信息发送出去的自定义文本框。
我不知道Qt Designer是不是可以直接用界面生成自定义组件类的模板代码,所以只能手敲了。

我们自定义的类是在QPlainTextEdit的基础上派生的,所以接下来要在Qt Designer上新建一个QPlainTextEdit
如果不涉及信号槽等交互功能的话,只建立一个组件即可,我这里因为涉及到两个文本框之间通信,所以干脆建立了两个QPlainTextEdit
如图:

在需要转化为自定义组件的组件上右键,点击“提升到”,如图:

在弹出的对话框中,选择基类(取决于我们从哪个官方组件进行的派生),手动填写提升后的类名以及头文件,如图:

**这里需要万分注意:**头文件一般会自动生成,不过这个生成的是C++代码的头文件,通常以".h"结尾,而我们需要的却是python的头文件。所以,在这个头文件的地方要填写我们之前自定义类的文件名(不含后缀),如图:

全局包含的选项貌似不用勾。
完了就点击添加。
接下来就会看到提升的类列表里面出现了我们刚才填写的信息,此时提升按钮才由灰色不可点击变为可点击状态,点击它:

别搞错了,是点击最下面的提升按钮。

接着保存这个ui文件。
将它编译成py文件。

为什么要这样做,而不是直接就用代码自定义组件?
因为这样我们就不需要手敲布局和大小这些和UI强相关的代码了,直接在Qt Designer中调整好布局,然后一键编译,就得到对应的.py文件了。这是我生成出来的自定义组件布局代码:

至于生成出来的自定义组件代码怎么使用。
在主页/入口代码的顶部,from XXX import YYY
其中XXX填的是这个自动生成并编译后的.py文件的名字(不含后缀),YYY填的是该自定义组件的类名
注意,这种是单独使用自定义组件的情况。我们实际使用的时候,更多的情况应该是一个窗口里面有多个自定义组件。这就需要你给每一个打算自定义的组件都先给它自定义一个类。
在导入的时候,就不用单独导入自定义组件了,把总的那个UI文件的类导入即可。
比如,默认的啥都不改的情况下,导入可能长这样:

最后再讲讲如果涉及到信号槽的自定义组件怎么搞。
可以看到,我们最开始自定义的那个组件的代码中,有定义一个信号:enterPressed = Signal(str)
在Qt Designer中按F4(或者Edit→编辑信号/槽),进入信号槽设置界面,左键点击要发送信号的组件,拖拽箭头到要接收信号的组件(或者说要设置槽的组件)

单击左键会进入到这个界面中:

点击编辑按钮进行编辑。
如果信号里面有现成自己需要的,那就直接选择即可,没有的话才需要点编辑

点击绿色加号,如图:

填入我们的信号名,如图:

可能有人注意到,Qt Designer中给了带字符串参数的示例参考,但我这里却填的str而非QString,这是因为QString是qt5以及之前的标准,咱们这里用的是pyside6,而pyside6已经跟python本身的字符串表示保持一致了,直接用str即可。
点击OK就创建好了自定义的信号,不过,要把信号与槽关联起来,还需要在下面这个界面中,依次选择信号和要触发的槽函数:

左边是信号,右边是槽,可以看到槽的列表是灰色不可编辑状态,这是因为该组件我们还没有提升为自定义组件,一旦将其提升为自定义组件,该组件的槽便可编辑了。

产生了触发关系的信号与槽长这样,记得保存ui文件。

顺便提一下信号和槽可以同时存在多个,比如我既可以设置按回车触发文字上屏,也可以设置按小键盘enter进行换行而非文字上屏。
信号与槽的这种关系是一一对应的,可以直接在Qt Designer中通过拖拽箭头进行快速关联,而不用费劲儿去手敲代码。
整个触发的顺序链应该是这样的:事件→信号→槽
可以参考我一开始的这个自定义组件的代码:

from PySide6.QtWidgets import QPlainTextEdit
from PySide6.QtCore import Signal,Qt

class CustomPlainTextEdit(QPlainTextEdit):
    enterPressed = Signal(str)

    def __init__(self, parent=None):
        super().__init__(parent)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Return:
            self.enterPressed.emit(self.toPlainText())
            self.setPlainText("")#清空发送框文本
        else:
            super().keyPressEvent(event)

我是通过keyPressEvent事件,检测到按键,然后判断按下的是回车键,再手动发起了一个信号self.enterPressed.emit(self.toPlainText())
如果没有什么字符串需要传给槽函数组件,那就不用在括号里加字符串:
self.enterPressed.emit()
记得在Qt Designer当中信号要和这个保持一致,如果不发送字符串,创建信号的时候就不要在里面填str