Discord Python,在 client.close() 调用后,我希望能够再次调用 client.start(),但客户端不知何故多次登录

Discord Python, After a client.close() call i want to be able to call client.start() again, but somehow the client loggs in multiple times

我正在尝试使用基于 Qt 的 GUI 构建 Discord Bot。我想要两个按钮,一个启动 Bot,一个停止它。当我在 client.close() 之后重新启动时,Bot 以多个实例登录,我不知道如何修复它。

代码:

import bot # some discord bot that can login on a server and send a message
import asyncio
from PySide6.QtWidgets import QLabel, QWidget, QPushButton, QTextBrowser, QComboBox
from qasync import QEventLoop, asyncSlot, QApplication
from PySide6.QtCore import QFile
from PySide6.QtUiTools import QUiLoader
import PySide6.QtGui as QtGui

class main(QWidget):
    def __init__(self):
        super(main, self).__init__(Parent=None)
        self.load_ui()
        self.btn_startbot = self.findChild(QPushButton, 'btn_startbot')
        self.btn_startbot.clicked.connect(self.on_btn_startbot_clicked)
        self.btn_stopbot = self.findChild(QPushButton, 'btn_stopbot')
        self.btn_stopbot.clicked.connect(self.on_btn_stopbot_clicked)

    def load_ui(self):
        loader = QUiLoader()
        ui_file = QFile("form.ui") # some ui, that has buttons
        ui_file.open(QFile.ReadOnly)
        loader.load(ui_file, self)
        ui_file.close()


    @asyncSlot()
    async def on_btn_startbot_clicked(self):
        print("clicked start bot")
        self.bot = bot.MyBot(command_prefix='-', self_bot=False)
        self.bot.sig_slot_handler.sig_send_log.connect(self.slot_log_msg)
        await self.bot.start('Token') 
    
    @asyncSlot()
    async def on_btn_stopbot_clicked(self):
        await self.bot.close()

    @asyncSlot(str)
    async def slot_log_msg(self, logmsg):
        print(logmsg) 

我不知道这是否与事件循环有关,但我需要使用 qasync,因为 Qt 事件循环和 Discord 的 async 事件循环冲突。

if __name__ == "__main__":
    app = QApplication([])
    loop = QEventLoop(app)
    asyncio.set_event_loop(loop)
    widget = main()
    widget.show()
    loop.run_forever()

最小机器人 class:

class MyBot(commands.Bot):
    sig_slot_handler = q_signal_slot_handler()

    def __init__(self, command_prefix, self_bot, parent=None):
        commands.Bot.__init__(self, command_prefix=command_prefix, self_bot=self_bot)
        self.add_commands()
        self.add_events()
    
    def add_events(self):

        @self.event
        async def on_ready():
            self.sig_slot_handler.send_log_signal(f'PyBot login') 

    def add_commands(self):
        @self.command(brief="Send a Message", usage="<MESSAGE WORDS>", help="Send a Message in your active Text Channel. Type: -send <MESSAGE WORDS>")
        async def send(ctx, *, message):
            await ctx.message.delete()
            self.sig_slot_handler.send_log_signal(f'{ctx.author} used send in {ctx.message.channel}.')
            await ctx.send(message)

我还制作了一个 class 来处理 Qt 信号和槽:

class q_signal_slot_handler(QObject):
    sig_send_log    = Signal(str)

    def __init__(self, Parent=None):
        super(q_signal_slot_handler, self).__init__(Parent=Parent)
    
    def send_log_signal(self, logmsg):
        self.sig_send_log.emit(logmsg)

在我按下停止然后重新开始后,会发生什么,输出是这样的:

问题是 sig_slot_handler 是所有 MyBot 的单个对象,因此您多次连接同一个信号,因此当发出信号时,槽将被调用多次。解决方案是将 class 的属性设置为 sig_slot_handler:

class MyBot(commands.Bot):
    def __init__(self, command_prefix, self_bot, parent=None):
        commands.Bot.__init__(self, command_prefix=command_prefix, self_bot=self_bot)
        <b>self.sig_slot_handler = q_signal_slot_handler()</b>
        self.add_commands()
        self.add_events()