如何将任意小部件添加到 Canvas?
how to add arbitrary widgets to a Canvas?
我正在尝试构建一个 GUI 以使用 PySimpleGUI 标记文件。在主要预览小部件下方,我想放置一个小部件来显示当前标签。我制作了一个 TagWidget
子类 sg.Column
并包含一个 sg.Text
作为标签名称和一个 sg.Combo
作为当前值和建议的替代方案:
class TagWidget(_Widget, sg.Column):
''' A Display for a `Tag`.
'''
@typechecked
def __init__(self, tags: TagSet, tag_name: str, alt_values=None):
if alt_values is None:
alt_values = set()
self.tags = tags
self.tag_name = tag_name
self.alt_values = alt_values
layout = [
[
sg.Text(tag_name + ("" if tag_name in tags else " (missing)")),
sg.Combo(
list(self.alt_values),
default_value=tags.get(tag_name),
)
]
]
super().__init__(layout=layout, finalize=True)
我遇到的困难是制作一个小部件来显示其中的几个。我不想要网格,因为标签+值的宽度非常可变。理想情况下,我会使用 canvas 之类的东西,或包含 canvas 的窗格,其中包含一组标签小部件。理想情况下,它会像线一样流动。
我使用 create_text()
为每个小部件制作了一个成功的 canvas 文本。我可以继续进行并在编辑标签时重新绘制,但我想使用我的复合标签小部件而不是纯文本。
所以...每个 PySimpleGUI 小部件都有一个指向底层 Tk 小部件的 .Widget
属性。 canvas .create_window
方法看起来应该接受 Tk 小部件。但是,在呈现我的复合标签小部件之前,没有 .Widget
传递给 .create_window
,并且在呈现 canvas 之前无法呈现它。
我当前的(无效的)尝试如下所示:
def set_tags(self, tags):
super().set_tags(tags)
canvas = self.tk_canvas
canvas.delete(canvas.find_all())
for tag in self.tags:
X("TagsView_Canvas.set_tags: add tag=%s", tag)
tagw = self._get_tag_widget(tag)
X("tagw = %s", tagw)
X("tagw.Widget = %s", tagw.Widget)
canvas.create_window(0, 0, window=tagw.Widget)
X("added canvas window")
当然,此时 tagw.Widget
是 None
,什么都没有创建。
是否有一种干净的方法来准备我的复合标签小部件,以便我可以将其应用到 canvas?我应该换一种方式吗?
修正
评论的格式似乎过于受限。按照 Jason 的示例代码,我想做的是稍后在程序中创建一个新的小部件并将其添加到 canvas(或图形,我不介意哪个)中。我一直在摆弄 Jason 的主循环,通过单击其中一个按钮进行新的迭代。我还没有设法向图表添加额外的小部件,至少看不到任何东西。
以 sg.Text
为例,我在他的主循环中使用了这个:
while True:
print("window.read...")
event, values = window.read()
print("event", event)
if event == sg.WINDOW_CLOSED:
break
print(event, values)
G = window['-GRAPH-']
print("graph =", G)
new_text = sg.Text("foo")
layout[0][1] = new_text
print("dir(graph)", dir(G))
window.finalize()
print("new_text.Widget =", new_text.Widget)
graph.create_window(
width // 4, height // 2, anchor=sg.tk.CENTER, window=new_text.Widget
)
当前版本(以上)似乎没有初始化 new_text
小部件,因此 new_text.Widget
仍然是 None
而 graph.create_window
似乎什么也没做。
没有提供将新元素添加到布局中的方法,但是 window.extend_layout
。它将新行添加到布局中,但在 graph.Widget.create_window
.
中不起作用
一个简单的演示代码,展示如何将sg.Column
移动到sg.Graph
,请记住布局时sg.Graph
和sg.Column
应放在同一行。
import io
import base64
from PIL import Image
import PySimpleGUI as sg
sg.theme("DarkBlue3")
sg.set_options(font=("Courier New", 12))
bg = 'green'
column_layout = [
[sg.Text("Hello World", key="-LABEL-")],
[sg.Button('Hello'), sg.Button('World')]
]
width, height = size = (320, 240)
buffer = io.BytesIO()
image_data = base64.b64decode(sg.EMOJI_BASE64_HAPPY_LAUGH)
im = Image.open(io.BytesIO(image_data))
new_img = im.resize(size, resample=Image.CUBIC)
new_img.save(buffer, format="PNG")
im_b64 = base64.b64encode(buffer.getvalue())
layout = [
[sg.Graph(size, (0, 0), size, background_color=bg, key='-GRAPH-'),
sg.Column(column_layout, background_color=bg, key='-COLUMN-')],
[sg.Button('New')],
]
window = sg.Window('Title', layout, finalize=True)
graph = window['-GRAPH-']
column = window['-COLUMN-']
figure = graph.draw_image(data=im_b64, location=(0, height))
graph.Widget.create_window(width//2, height//2, anchor=sg.tk.CENTER, window=column.Widget)
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
elif event == 'New':
new_element = sg.Text("foo")
window.extend_layout(column, [[new_element]])
window.close()
看起来不太好,因为 sg.Canvas
的 background_color 会遮住背景。
我正在尝试构建一个 GUI 以使用 PySimpleGUI 标记文件。在主要预览小部件下方,我想放置一个小部件来显示当前标签。我制作了一个 TagWidget
子类 sg.Column
并包含一个 sg.Text
作为标签名称和一个 sg.Combo
作为当前值和建议的替代方案:
class TagWidget(_Widget, sg.Column):
''' A Display for a `Tag`.
'''
@typechecked
def __init__(self, tags: TagSet, tag_name: str, alt_values=None):
if alt_values is None:
alt_values = set()
self.tags = tags
self.tag_name = tag_name
self.alt_values = alt_values
layout = [
[
sg.Text(tag_name + ("" if tag_name in tags else " (missing)")),
sg.Combo(
list(self.alt_values),
default_value=tags.get(tag_name),
)
]
]
super().__init__(layout=layout, finalize=True)
我遇到的困难是制作一个小部件来显示其中的几个。我不想要网格,因为标签+值的宽度非常可变。理想情况下,我会使用 canvas 之类的东西,或包含 canvas 的窗格,其中包含一组标签小部件。理想情况下,它会像线一样流动。
我使用 create_text()
为每个小部件制作了一个成功的 canvas 文本。我可以继续进行并在编辑标签时重新绘制,但我想使用我的复合标签小部件而不是纯文本。
所以...每个 PySimpleGUI 小部件都有一个指向底层 Tk 小部件的 .Widget
属性。 canvas .create_window
方法看起来应该接受 Tk 小部件。但是,在呈现我的复合标签小部件之前,没有 .Widget
传递给 .create_window
,并且在呈现 canvas 之前无法呈现它。
我当前的(无效的)尝试如下所示:
def set_tags(self, tags):
super().set_tags(tags)
canvas = self.tk_canvas
canvas.delete(canvas.find_all())
for tag in self.tags:
X("TagsView_Canvas.set_tags: add tag=%s", tag)
tagw = self._get_tag_widget(tag)
X("tagw = %s", tagw)
X("tagw.Widget = %s", tagw.Widget)
canvas.create_window(0, 0, window=tagw.Widget)
X("added canvas window")
当然,此时 tagw.Widget
是 None
,什么都没有创建。
是否有一种干净的方法来准备我的复合标签小部件,以便我可以将其应用到 canvas?我应该换一种方式吗?
修正
评论的格式似乎过于受限。按照 Jason 的示例代码,我想做的是稍后在程序中创建一个新的小部件并将其添加到 canvas(或图形,我不介意哪个)中。我一直在摆弄 Jason 的主循环,通过单击其中一个按钮进行新的迭代。我还没有设法向图表添加额外的小部件,至少看不到任何东西。
以 sg.Text
为例,我在他的主循环中使用了这个:
while True:
print("window.read...")
event, values = window.read()
print("event", event)
if event == sg.WINDOW_CLOSED:
break
print(event, values)
G = window['-GRAPH-']
print("graph =", G)
new_text = sg.Text("foo")
layout[0][1] = new_text
print("dir(graph)", dir(G))
window.finalize()
print("new_text.Widget =", new_text.Widget)
graph.create_window(
width // 4, height // 2, anchor=sg.tk.CENTER, window=new_text.Widget
)
当前版本(以上)似乎没有初始化 new_text
小部件,因此 new_text.Widget
仍然是 None
而 graph.create_window
似乎什么也没做。
没有提供将新元素添加到布局中的方法,但是 window.extend_layout
。它将新行添加到布局中,但在 graph.Widget.create_window
.
一个简单的演示代码,展示如何将sg.Column
移动到sg.Graph
,请记住布局时sg.Graph
和sg.Column
应放在同一行。
import io
import base64
from PIL import Image
import PySimpleGUI as sg
sg.theme("DarkBlue3")
sg.set_options(font=("Courier New", 12))
bg = 'green'
column_layout = [
[sg.Text("Hello World", key="-LABEL-")],
[sg.Button('Hello'), sg.Button('World')]
]
width, height = size = (320, 240)
buffer = io.BytesIO()
image_data = base64.b64decode(sg.EMOJI_BASE64_HAPPY_LAUGH)
im = Image.open(io.BytesIO(image_data))
new_img = im.resize(size, resample=Image.CUBIC)
new_img.save(buffer, format="PNG")
im_b64 = base64.b64encode(buffer.getvalue())
layout = [
[sg.Graph(size, (0, 0), size, background_color=bg, key='-GRAPH-'),
sg.Column(column_layout, background_color=bg, key='-COLUMN-')],
[sg.Button('New')],
]
window = sg.Window('Title', layout, finalize=True)
graph = window['-GRAPH-']
column = window['-COLUMN-']
figure = graph.draw_image(data=im_b64, location=(0, height))
graph.Widget.create_window(width//2, height//2, anchor=sg.tk.CENTER, window=column.Widget)
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
elif event == 'New':
new_element = sg.Text("foo")
window.extend_layout(column, [[new_element]])
window.close()
看起来不太好,因为 sg.Canvas
的 background_color 会遮住背景。