You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将PyQt5 QInputDialog返回值传入AI助手主程序函数?

解决PyQt5中QInputDialog替代原生input()的输入传递问题

问题分析

  1. 直接在techna2.py的Main函数中调用QInputDialog相关函数,导入时会重复启动GUI进程,引发报错。
  2. 通过GUI按钮触发QInputDialog后,无法将输入值传递给运行在子线程的techna2.Main()函数。

可行方案

核心思路是利用Qt信号槽机制实现GUI线程与子线程的跨线程通信,结合线程同步工具实现阻塞式输入,替代原生input()函数。具体步骤如下:

步骤1:修改techna.py,添加输入通信逻辑

  1. 导入线程同步模块,在GuiStart类中定义请求输入的信号、线程同步事件和输入结果存储变量。
  2. 实现弹窗输入的槽函数,以及供子线程调用的阻塞式输入获取方法。
  3. 修改子线程初始化逻辑,传入GUI实例引用,动态绑定输入函数到techna2模块。

修改后的techna.py关键代码:

from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QMovie, QTextBlock
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from gui.technaui2 import Ui_technaui2
import sys
import threading  # 新增:导入线程同步模块


class MainThread(QThread):
    def __init__(self, gui_instance):
        super(MainThread, self).__init__()
        self.gui = gui_instance  # 保存GUI实例引用

    def run(self):
        self.TaskGui()

    def TaskGui(self):
        import techna2
        # 动态绑定输入函数到techna2模块
        techna2.get_user_input = self.gui.get_input
        while True:
            techna2.Main()


class GuiStart(QMainWindow):
    # 定义请求输入的信号,参数为提示文本
    request_input = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.technaui2 = Ui_technaui2()
        self.technaui2.setupUi(self)
        self.technaui2.pushButton.clicked.connect(self.startFunc)
        self.technaui2.pushButton_2.clicked.connect(self.close)
        self.technaui2.btn1.clicked.connect(self.userInput2)
        sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
        
        # 线程安全的输入同步工具
        self.input_ready = threading.Event()
        self.input_result = ""
        # 连接信号到弹窗槽函数
        self.request_input.connect(self.show_input_dialog)

    def __del__(self):
        sys.stdout = sys.__stdout__

    def normalOutputWritten(self, text):
        cursor = self.technaui2.textEdit.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.insertText(text)
        self.technaui2.textEdit.setTextCursor(cursor)
        self.technaui2.textEdit.ensureCursorVisible()

    def startFunc(self):
        self.technaui2.movies = QtGui.QMovie(
            "C:\Users\Hp\Desktop\SP\techna2\gui\images\gif\ai2.gif"
        )
        self.technaui2.gif.setMovie(self.technaui2.movies)
        self.technaui2.movies.start()

        # 创建线程时传入当前GUI实例
        global startFunction
        startFunction = MainThread(self)
        startFunction.start()

    def show_input_dialog(self, prompt):
        # 在GUI线程中显示输入弹窗
        text, ok = QtWidgets.QInputDialog.getText(self, "用户输入", prompt)
        if ok:
            self.input_result = str(text)
        else:
            self.input_result = ""
        # 标记输入完成,唤醒等待的子线程
        self.input_ready.set()

    def get_input(self, prompt="请输入:"):
        # 重置同步事件和输入结果
        self.input_ready.clear()
        self.input_result = ""
        # 发送信号触发弹窗
        self.request_input.emit(prompt)
        # 阻塞等待输入完成
        self.input_ready.wait()
        return self.input_result

    def userInput2(self):
        # 保留原按钮功能,可将输入结果直接输出到文本框
        text, ok = QtWidgets.QInputDialog.getText(self, "输入值", "请输入:")
        if ok:
            self.technaui2.textEdit.appendPlainText(f"用户输入:{text}")
        else:
            self.technaui2.textEdit.appendPlainText("输入无效")


class EmittingStream(QtCore.QObject):
    textWritten = QtCore.pyqtSignal(str)

    def write(self, text):
        self.textWritten.emit(str(text))


guiApp = QApplication(sys.argv)
guiTechna = GuiStart()
guiTechna.show()
exit(guiApp.exec_())

步骤2:修改techna2.py,替换原生input()

将Main函数中原生的input()调用替换为动态绑定的get_user_input()函数:

# ... 其他代码保持不变 ...
    def Main():
        sentence = Listen()
        result = str(sentence)

        sentence = tokenize(sentence)
        X = bag_of_words(sentence, all_words)
        X = X.reshape(1, X.shape[0])
        X = torch.from_numpy(X).to(device)

        output = model(X)
        _, predicted = torch.max(output, dim=1)
        tag = tags[predicted.item()]
        probs = torch.softmax(output, dim=1)
        prob = probs[0][predicted.item()]

        if prob.item() > 0.75:
            for intent in intents["intents"]:
                if tag == intent["tag"]:
                    reply = random.choice(intent["responses"])

                    if "time" in reply:
                        NonInputExecution(reply)

                    elif "alarm" in reply:
                        Say("For what time?")
                        # 替换原生input()为自定义输入函数
                        time = get_user_input("请输入闹钟时间(例如:08:30)")
                        if time:  # 仅当输入有效时执行闹钟设置
                            Alarm(time)

                    else:
                        Say(reply)

方案说明

  1. 跨线程通信:通过request_input信号将输入请求从子线程发送到GUI线程,确保弹窗在GUI线程中创建,避免线程安全问题。
  2. 阻塞式输入:使用threading.Event实现子线程的阻塞等待,直到用户完成输入并触发事件唤醒,完美替代原生input()的阻塞行为。
  3. 避免重复启动GUI:通过动态绑定函数的方式,让techna2模块无需导入GUI相关代码,彻底解决导入时重复启动GUI的问题。

内容的提问来源于stack exchange,提问作者Lily Johnson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 07:33:07