【发布时间】:2022-06-19 01:02:03
【问题描述】:
更新 2:上次更新中的潜在修复未解决问题。 正如 tkinter 文档中所建议的那样,我已经对“如何在纯 tk 中做到这一点”进行了更多研究,并且我对导致问题的原因以及如何解决问题有了新的理论。关于实施修复的指导和/或关于我是否以正确的方式思考它的建议是我正在寻找的作为该主题的解决方案。
关于问题原因的新理论:
声明 1:在 tkinter 中调用以获取剪贴板内容的方法似乎返回一个函数调用,而不是返回一个包含剪贴板内容的值。
声明 2:在 tk 中,每个命令都在它自己的 tk 解释器实例中调用和执行。
语句 3:由于语句 1 和 2,在 tkinter 中调用获取剪贴板内容的方法会生成一堆 tk 解释器,如下所示:
python 步骤 0. 将全局变量的值分配给 tkinter 方法 Tk.clipboard_get 的输出。这会创建 tk 脚本的入口
tk step 0. tk 脚本的入口点
tk step 1. 实例化一个变量来存储剪贴板内容。
tk step 2. 获取剪贴板内容
tk 步骤 3. 将在 1 中实例化的变量设置为步骤 2 的输出
tk 步骤 4. tk 脚本的退出点:在步骤 3 中分配给变量的返回值作为 tk 脚本的输出
python step 1 打印在 python step 0 中创建的全局变量的内容。
声明 4:问题,如最初帖子中的示例代码所示,python 步骤 1 在 tk 堆栈中的所有步骤完成之前就开始执行。
我的假设:问题在于 tkinter 中用于 clipboard_get 的方法是返回对 tk 脚本的调用,而不是将输出返回到 tk 脚本。
我目前寻找解决方案的方向:
创建一个在文本模式下运行的单独 python 脚本,以获取剪贴板内容并将其输出返回给程序。然后,代替调用clipboardText = self.clipboard_get(),使用子进程模块的方法popen调用脚本,并使用popen内置的选项等待popen执行的脚本完成,然后在python解释器中继续前进。
可能解决问题的替代方法:
Alt 方法 #1:在 tk StringVar 上使用跟踪以防止在 python 解释器中进一步执行。
Alt 方法 #2:修改源代码 tkinter._init_ 使其返回一个值,而不是通过更改此方法来调用 tk 方法:
# Clipboard handling:
def clipboard_get(self, **kw):
"""Retrieve data from the clipboard on window's display.
The window keyword defaults to the root window of the Tkinter
application.
The type keyword specifies the form in which the data is
to be returned and should be an atom name such as STRING
or FILE_NAME. Type defaults to STRING, except on X11, where the default
is to try UTF8_STRING and fall back to STRING.
This command is equivalent to:
selection_get(CLIPBOARD)
"""
if 'type' not in kw and self._windowingsystem == 'x11':
try:
kw['type'] = 'UTF8_STRING'
return self.tk.call(('clipboard', 'get') + self._options(kw))
except TclError:
del kw['type']
return self.tk.call(('clipboard', 'get') + self._options(kw))
到这里:
# Clipboard handling:
def clipboard_get(self, **kw):
"""Retrieve data from the clipboard on window's display.
The window keyword defaults to the root window of the Tkinter
application.
The type keyword specifies the form in which the data is
to be returned and should be an atom name such as STRING
or FILE_NAME. Type defaults to STRING, except on X11, where the default
is to try UTF8_STRING and fall back to STRING.
This command is equivalent to:
selection_get(CLIPBOARD)
"""
if 'type' not in kw and self._windowingsystem == 'x11':
try:
kw['type'] = 'UTF8_STRING'
val = self.tk.call(('clipboard', 'get') + self._options(kw))
return val
except TclError:
del kw['type']
val = self.tk.call(('clipboard', 'get') + self._options(kw))
return val
我将尝试这些潜在的解决方案,返回此处查看反馈,如果找到解决方案,请更新。
更新 1: 经过更多的故障排除后,我认为问题在于我从 Tk 应用程序的 mainloop 方法中调用了 tk 的获取剪贴板方法。我将尝试使用 tk.Tk.after 方法来避免这个问题。我将在我的代码中添加带有注释标记的行以反映此更改。如果这能解决问题,我会在这里报告。
一般说明: 使用 pyautogui 选择,然后复制文本,如果我尝试在函数内使用 tk.clipboard_get() 访问剪贴板内容(复制到剪贴板之后),有时会出现如下所示的异常。但是之后,我再次检查剪贴板,或者通过在终端中再次调用 app.clipboard_get(),或者通过“ctrl”+“v”,我可以访问剪贴板内容而不会引发异常,并且它不为空或不见了。
这里是例外
line 26, in highlight_then_copy_then_print
clipboardText = self.clipboard_get()
File "C:\Users\XisUnknown\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 801, in clipboard_get
return self.tk.call(('clipboard', 'get') + self._options(kw))
_tkinter.TclError: CLIPBOARD selection doesn't exist or form "STRING" not defined
这里是示例代码...
import tkinter as tk # tk.TkVersion == tk.TclVersion == 8.6
import pyautogui as pg # pg.__version__ == '0.9.36'
#running with Python 3.6.1 in Windows 10
class App(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('200x200+300+400')
actionButton = tk.Button(self,
text='highlight, then copy, then print',
## command=self.highlight_then_copy_then_print())#OLD COMMAND
command=self.call_function_outside_main_loop())#NEW COMMAND for Update
actionButton.pack()
###New Code Section For Update###
def call_function_outside_main_loop(self):
self.after(5, self.highlight_then_copy_then_print())
###End Code Section For Update###
def highlight_then_copy_then_print(self):
#I have also tried adding
#self.clipboard_clear()
#then,
#self.clipboard_append('')
#to the beginning of the function...
pg.moveTo(100,150)
pg.dragRel(200,40,
duration=1.5,
pause=.2)
pg.hotkey('ctrl', 'c',pause=.2)
#I have also tried
## pg.rightClick(238,160, pause=.15)#right click on selected text
## pg.typewrite('c',pause=.15)#press C (as shortcut to copy option)
clipboardText = self.clipboard_get()
print(clipboardText)
return None
if __name__ == '__main__':
app = App()
作为一种变通方法,我采用了以下方法,并取得了不同程度的成功: 首先,实例化一个变量,然后使用 while 循环通过 Try/Except statementList 项定期测试 clipboard_get 函数。例如
s = None
while s == None:
try:
s = self.clipboard_get()
except:
#I have tried the below commented out lines in various combinations
tk.time.sleep(.2)
## self.update_idletasks()
## self.update()
## self.clipboard_clear()
## self.clipboard_append('')
## tk.time.sleep(.2)
## self.separateFunction# a separate function that just highlights and then does ctrl+c without the use of tkinter...
## tk.time.sleep(.2)
补充说明:
- 添加 while 循环有时会有所帮助,增加函数之间的暂停似乎也有帮助。尽管我注意到无论我尝试什么似乎都似乎的实例,但在退出函数之前,我无法可靠地使用 tk.clipboard_get()。
- 我注意到从 Excel 等不同的应用程序复制文本时问题会更严重。就本文而言,假设我正在从 Notepad++ .txt 文档中选择和复制文本。
- 在我自己理解这个问题的尝试中,我发现app.clipboard_get()函数实际上是一个使用Win32.h库的ctypes调用。这就是我添加这些标签的原因。
【问题讨论】:
标签: tkinter winapi clipboard ctypes