从 Tkinter Tcl 回调 python 函数在 Windows 中崩溃

2023-12-10

这不完全是我的应用程序,但非常相似。我创建了这个测试代码来显示问题。基本上我试图从 python 线程调用 tcl proc。当结果准备好时,Tcl proc 将回调到 python 函数。该结果将作为事件发布到 wx 框架。当我作为纯 python 代码运行时,它工作得很好。当我使用 tcl proc 时,整个应用程序崩溃,没有任何信息。如果我增加 wait_time (比如 100),那么即使使用 tcl 也能正常工作。是回调率高有问题还是我错过了其他东西。顺便说一句,这个应用程序在 Windows 上运行。

import wx
from Tkinter import Tcl
from threading import Thread
import wx.lib.newevent
from time import sleep

CountUpdateEvent, EVT_CNT_UPDATE = wx.lib.newevent.NewEvent()

tcl_code = 'proc tcl_worker {name max_count delay_time callback} { while {$max_count>0} {after $delay_time; $callback $name $max_count; incr max_count -1}}'

# Option to use Tcl or not for counter
# When enabled, Tcl will callback to python to upate counter value
use_tcl = True

# Option to create tcl interpreter per thread. 
# Test shows single interpreter for all threads will fail.
use_per_thread_tcl = True 

count = 5000 
wait_time = 1 ;# in milliseconds

class Worker:
    def __init__(self,name,ui,tcl):
        global use_per_thread_tcl
        self.name = name
        self.ui = ui
        if use_per_thread_tcl:
            self.tcl = Tcl()
            self.tcl.eval(tcl_code)
        else:
            self.tcl = tcl
        self.target = ui.add_textbox(name)
        self.thread = Thread(target=self.run)
        self.thread.daemon = True
        self.thread.start()

    def callback(self, name, val):
        evt = CountUpdateEvent(name=self.name, val=val, target=self.target)
        wx.PostEvent(self.ui,evt)        
    def run(self):
        global count, wait_time, use_tcl

        if use_tcl:
            # Register a python function to be called back from tcl
            tcl_cmd = self.tcl.register(self.callback)

            # Now call tcl proc
            self.tcl.call('tcl_worker', self.name, str(count), str(wait_time), tcl_cmd)
        else:
            # Convert milliseconds to seconds for sleep
            py_wait_time = wait_time / 1000
            while count > 0:
                # Directly call the callback from here
                self.callback(self.name, str(count))
                count -= 1
                sleep(py_wait_time)


class MainWindow(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, title="Decrement Counter", size=(600, 100))

        self._DoLayout()
        self.Bind(EVT_CNT_UPDATE, self.on_count_update)

    def _DoLayout(self):
        self.sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.panels = []
        self.tbs = []
        self.xpos = 0

    def add_textbox(self,name):
        panel = wx.Panel(self, pos=(self.xpos, 0), size=(60,40))
        self.panels.append(panel)
        tb = wx.StaticText(panel, label=name)
        tb.SetFont(wx.Font(16,wx.MODERN,wx.NORMAL,wx.NORMAL))
        self.sizer.Add(panel, 1, wx.EXPAND, 7)
        self.tbs.append(tb)
        self.xpos = self.xpos + 70
        return tb

    def on_count_update(self,ev):
        ev.target.SetLabel(ev.val)
        del ev

if __name__ == '__main__':
    app = wx.App(False)
    frame = MainWindow(None)
    tcl = Tcl()
    tcl.eval(tcl_code)
    w1 = Worker('A', frame, tcl)
    w2 = Worker('B', frame, tcl)
    w3 = Worker('C', frame, tcl)
    w4 = Worker('D', frame, tcl)
    w5 = Worker('E', frame, tcl)
    w6 = Worker('F', frame, tcl)
    w7 = Worker('G', frame, tcl)
    w8 = Worker('H', frame, tcl)
    frame.Show()
    app.MainLoop()

每个 Tcl 解释器对象(即知道如何运行 Tcl 过程的上下文)只能从创建它的操作系统线程安全地使用。这是因为 Tcl 不像 Python 那样使用全局解释器锁,而是大量使用线程特定的数据来减少内部所需的锁数量。 (编写良好的 Tcl 代码可以利用这一点在合适的硬件上进行大规模扩展。)

正因为如此,你must确保您只从单个线程运行 Tcl 命令或 Tkinter 操作;这通常是主线程,但我不确定这是否是与 Python 集成的真正要求。如果需要,您可以启动工作线程,但它们将无法使用 Tcl 或 Tkinter(好吧,如果没有非常特殊的预防措施,这会带来更多麻烦,而不是可能值得的)。相反,他们需要向主线程发送消息,以便它处理与 GUI 的交互;有很多不同的方法可以做到这一点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 Tkinter Tcl 回调 python 函数在 Windows 中崩溃 的相关文章

随机推荐

  • 查找字符串中出现次数最多的字符?

    例如 我有一个字符串 abbbbccd b出现次数最多 使用 C 时 处理此问题的最简单方法是将每个字符插入到map lt gt 我必须在 C 中做同样的事情吗 有没有一种使用 LINQ 的优雅方法 input GroupBy x gt x
  • 对角积乘法

    我想要每组日期的对角线乘法 主要数据集 date Bucket D 1 31 2013 bkt 0 NA 1 31 2013 bkt 1 10 20 NA 1 31 2013 bkt 2 20 30 NA 1 31 2013 bkt 3 3
  • jQuery:如果所有子div的html为空,则隐藏父div

    我有一个父 div 包含三个子 div 我想检查子 div 以查看它们是否为空 如果它们都为空 我想隐藏父 div 以便背景在我的设计中消失 div class main div class tot1 div div class tot2
  • 矩形之间的二维碰撞检测

    我正在为我的游戏编写碰撞检测引擎 但遇到一些问题 事实上 由于我有几个固定的矩形和一个移动的 玩家 我需要知道固定矩形的哪一侧首先被玩家碰撞 以正确地替换他 固定矩形不在网格中 因此它们可以放置在地图上的任何位置 并且可以具有不同的大小 它
  • Spring LDAP - 如何管理编码(SHA)密码

    我想使用 Spring LDAP 及其对象目录映射 ODM 的概念来实现一个基本的用户存储库 我的用户类非常简单 Entry objectClasses inetOrgPerson organizationalPerson person s
  • 异构列表 / HList l -> [e]?

    感谢您对我另一个问题的回答 如何在HList上编写异构列表 我可以开始使用HList 异构列表 主要是 APIhttps hackage haskell org package HList 0 5 2 0 docs Data HList H
  • 为 Asha 303 创建风景游戏画布

    我搜索了所有论坛 从未找到任何答案可以满足我的问题 我想为诺基亚 Asha 303 创建一个横向游戏 有没有办法将游戏画布旋转 90 度 使方向变成横向 因为我看了这个视频愤怒的小鸟阿莎303 该游戏具有横向方向 所以我很好奇如何在 j2m
  • 使用 GWT 读取剪贴板数据[重复]

    这个问题在这里已经有答案了 我有这个代码来处理CTRL V从浏览器 工作正常 但我需要像这样获取剪贴板数据 Event addNativePreviewHandler new Event NativePreviewHandler Overr
  • 如何找到连续数字串的索引?

    我有一个数据框 我想在其中找到 5 个或更多零值的每个组合的开始和结束索引 基本上 如果字符串是 1 2 0 0 0 0 0 0 4 2 22 41 0 0 0 0 0 5 6 0 0 0 4 我希望有 startindiex endind
  • Delphi:for循环期间函数结果未清空

    这是正常的吗 for a 1 to 10 do x test x test x test x test function test string begin IFDEF DEBUG DebugMessage result check Res
  • 单击按钮后一定时间后执行某些操作

    我试图让一个对象在点击按钮后一定时间后从视图中消失 我对如何让对象在点击后执行某些操作有点困惑 我不确定我是否应该使用run loop or NSTimer 即使我知道该使用什么 我仍然很困惑如何在点击按钮后的某个时间让某些事情发生 在按下
  • 旧浏览器的真正占位符文本修复?

    我想使用 jQuery 代码来模拟旧浏览器的占位符文本 我找到了一些非常适合的人选 而且工作效果很好 然而 一个问题是解决方案倾向于输入占位符文本作为单元格值 直到用户输入 这意味着 如果提交 html 表单时任何字段均未更改 则占位符文本
  • Spring Cloud Stream 3.0存在生产者问题

    我阅读了有关spring cloud Stream 3 0的文档 了解了新使用java util function Supplier Function Consumer 来表示生产者 消耗者和生产者 消费者 这应该是正确的 但我不明白供应商
  • HashMap 冲突会导致调整大小吗?

    当放入 HashMap 期间发生冲突时 是否会调整映射大小 或者是否将条目添加到该特定存储桶中的列表中 当你说 碰撞 时 你指的是相同的哈希码吗 hashcode用于确定HashMap中使用哪个bucket bucket由所有具有相同has
  • 苹果单例查询示例?

    我对这段代码 在 CocoaFundamentals 指南中介绍 感到有点困惑 它在创建单例实例时覆盖了一些方法 static id sharedReactor nil id sharedInstance if sharedReactor
  • 字符串 - 克隆、复制和标准影响之间的区别

    我在浏览遗留代码时刚刚遇到这样的块 object exeName connectionSettings ApplicationName Clone RandomFunction exeName 起初这对我来说似乎没什么用 但它让我感到好奇
  • R 4.0.0及更高版本下使用向量动态更新公式

    我想使用 R 4 0 0 或更高版本下的向量动态更新公式 因此 一切都与此链接下的相同 R 动态更新公式 但 x 现在是一个向量 并且 R 版本 gt 4 0 简而言之 我有一个公式 例如y 1 并且希望通过字符标量 myvar1 或字符向
  • 我可以在 iOS 上使用 google Drive sdk 以及来自 google Sign-in sdk 的身份验证信息吗?

    我们已经有一个使用 Google Sign In sdk 的登录模块 Google 登录给出了GID认证登录成功后的对象 现在我想使用 googledrive sdk 访问用户的 googledrive 它需要 GTMOAuth2Authe
  • 我应该在 href="" 中使用 & 还是在 HTML4 和 HTML5 中 & 就足够了?

    我应该使用 amp in href or HTML4 和 HTML5 就够了吗 大多数浏览器都没有问题 但是应该如何完成呢 a href param1 1 param2 2 Call a Or a href quest param1 1 a
  • 从 Tkinter Tcl 回调 python 函数在 Windows 中崩溃

    这不完全是我的应用程序 但非常相似 我创建了这个测试代码来显示问题 基本上我试图从 python 线程调用 tcl proc 当结果准备好时 Tcl proc 将回调到 python 函数 该结果将作为事件发布到 wx 框架 当我作为纯 p