2

总结问题

我希望使用 tkinter 来分别实现制表符和使用空格键来循环和激活 UI 元素的操作。我希望以模仿 OSX 的本机行为的方式这样做,如下面的附件所示。这适用于 ttk 中的大多数其他小部件。

我没有足够的声望来嵌入这张图片

这由以下内容组成:

  1. 允许用户使用 tab 键“聚焦”组件
  2. 聚焦时使组件在视觉上突出显示
  3. 聚焦时可以使用空格键触发组件
  4. 棘手的部分是,它使用(接近)操作系统的原生 GUI 外观

关于此的其他 StackOverflow 问题

我能在这个网站上找到的最接近的答案是这个问题需要注意的是,这个问题是关于 Python 2.7.9 的。这个问题很有趣,因为它表明将 tk.Button() 更改为 ttk.Button() 可以缓解该问题,而在测试代码时,我发现情况正好相反。tk.Button() 将(不雅地)在 OSX 上突出显示,而 ttk.Button() 不提供视觉反馈。以下是代码(修改为在 2021 年在 Python 3.X 上运行的导入)

import tkinter as tk
from tkinter import ttk

class App(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.master = master

        entry1 = tk.Entry(self)
        entry1.pack()

        entry2 = tk.Entry(self)
        entry2.pack()

        # CHANGE BELOW LINE TO A ttk.Button() TO TEST
        button1 = tk.Button(self, text="Test", command=self.yup)
        button1.pack()

    def yup(self):
        print("yup")

root = tk.Tk()
app = App(root).pack()

root.mainloop()

我尝试的解决方案

解决方案一:正常使用ttk.Button()和ttk.Style()实现按钮来表示焦点

优点:

  • 使用本机操作系统风格
  • 通过选项卡接受焦点并通过空格键激活

缺点:

  • 除非强制使用 ttk.Style(),否则不会在视觉上指示焦点
  • 据我所知,ttk.Style() 无法给高亮边框,所以我们必须满足于彩色文本

示例代码:

from tkinter import Tk
from tkinter import ttk

root = Tk()

def one():
    print("one")
def two():
    print("two")

style = ttk.Style()
style.configure('C.TButton')

style.map('C.TButton',
    foreground = [('pressed','red'),('focus','blue')],
    background = [('pressed','!disabled','red'),('focus','white')],
    relief=[('pressed', 'sunken'),
            ('!pressed', 'raised')])
# Define lower GUI
B1 = ttk.Button(root, text='Button One', command=one, style='C.TButton')
B1.pack(padx=20, pady=(20,0))
B2 = ttk.Button(root, text='Button Two', command=two, style='C.TButton')
B2.pack(padx=20, pady=10)

root.mainloop()

解决方案二:改用 tk.Button()

优点:

  • 通过选项卡接受焦点并通过空格键激活
  • 使用边框本机突出显示按钮

缺点:

  • 看起来不那么吸引人,边框未对齐并且是一个普通的矩形
  • 我无法让许多参数在 OSX 上正常工作,特别是 activebackgroundhighlightthickness,限制了美学选项。

示例代码:

import tkinter as tk
from tkinter import ttk

root = tk.Tk()

def one():
    print("one")
def two():
    print("two")
B1 = tk.Button(root, text='Button One', command=one)
B1.pack(padx=20, pady=(20,0))
B2 = tk.Button(root, text='Button Two', command=two)
B2.pack(padx=20, pady=10)

root.mainloop()

解决方案三:使用tkmacosx库的 Button()

优点:

  • 针对这个问题定制
  • 类似 OSX 风格的 tab-press 上的亮点
  • 真的,只是我正在寻找的一切

缺点:

  • 不会触发空格键上的按钮

最后一部分很有趣,因为根据文档 (takefocus),这应该是预期的行为。在我的机器上,情况并非如此(Catalina 10.15.7)

示例代码:

from tkinter import Tk
from tkmacosx import Button

root = Tk()

def one():
    print("one")
def two():
    print("two")
B1 = Button(root, text='Button One', command=one)
B1.pack(padx=20, pady=(20,0))
B2 = Button(root, text='Button Two', command=two)
B2.pack(padx=20, pady=10)

root.mainloop()

结束语

从历史上看,我知道 tkinter 和 OSX 并不总是完美地结合在一起,如果我想要更精确的原生控制,我可能会切换到 QT。我非常感谢 tkinter 的存在,希望我没有要求太多。

但是,我确实想确保在尝试分叉回购或寻求其他解决方案之前我没有犯错误。

关于 tkmacosx,似乎这个解决方案应该按照文档中描述的方式工作,我希望从另一个用户那里得到这个问题的确认,看看是否适合在 github 页面上提出问题。

非常感谢您阅读这篇文章。请随时询问任何其他信息!

4

0 回答 0