0

我正在尝试使用基于 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 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)

我还做了一个类来处理 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)

在我按下停止然后重新开始之后会发生什么,输出类似于:

  • PyBot 登录
  • PyBot 登录
4

1 回答 1

2

问题是 sig_slot_handler 是所有 MyBot 的单个对象,因此您多次连接相同的信号,因此当发出信号时,将多次调用插槽。解决办法是把类的一个属性设置为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)
        self.sig_slot_handler = q_signal_slot_handler()
        self.add_commands()
        self.add_events()
于 2021-06-15T16:04:06.737 回答