[英]Templating overflowing content with glade and pygtk?
I'm trying to develop a "multitrack" GUI (similar to multitrack audio editors); 我正在尝试开发“多轨” GUI(类似于多轨音频编辑器); however, I'd like to develop it in glade
first, and check how overflowing content (in this case, multiple "tracks") will behave with scollbars. 不过,我想开发它在glade
首先,检查内容如何四溢(在这种情况下,多个“轨道”)将与scollbars行为。 Then, upon instantiation in Python, I'd first like to take the first of these "multiple tracks" as a "template", then delete all these multiple "tracks" - then allow the user to add new ones based on the "template" by, say, clicking an "Add" button. 然后,在Python中实例化时,我首先要将这些“多个轨道”中的第一个作为“模板”,然后删除所有这些多个“轨道”-然后允许用户基于“模板”添加新的例如,点击“添加”按钮。
From the Gtk palette, it seems to me that handlebox
is the right object to use as a base for a "track" (I'd want to draw in these tracks eventually). 从Gtk调色板中,在我看来, handlebox
是用作“轨道”基础的正确对象(我想最终绘制这些轨道)。 The only thing I managed to get through so far (given how few tutorials can be found on glade
UI usage), is to get the scrollbars to behave within the GUI - here's a screenshot of the scrolled window section only (corresponding file is below): 到目前为止,我设法解决的唯一一件事(考虑到在glade
UI的用法上找不到多少教程)是使滚动条在GUI中起作用-这是仅滚动窗口部分的屏幕截图(下面是相应的文件) :
The right structure seems to be: 正确的结构似乎是:
scrolled window
viewport
vbox
handlebox
drawingarea
handlebox ...
... and all I have to do is set the "Height request" of (all) handlebox
to 150px (I want a constant height, and width scaling according to window); ...,而我要做的就是将(所有) handlebox
的“高度请求”设置为150px(我想要一个恒定的高度,并根据窗口缩放宽度); and set its Packing/Expand to "No". 并将其“打包/展开”设置为“否”。 Also, set the scrolledwindow
Horizontal and Vertical Scrollbar Policy to "Always" - otherwise the scrollbars are not shown (and I was otherwise wrongly trying to place an additional scrollbar to get to see it). 另外,将scrolledwindow
水平和垂直滚动条策略设置为“始终”-否则,滚动条将不会显示(否则我错误地尝试放置其他滚动条以查看它)。 Finally, to get the scrollbar to work, click exactly on its arrowheads - dragging the scroll bar doesn't work from within Glade (at least not on glade3 3.8.0 on Ubuntu 11.04 I use). 最后,要使滚动条正常工作,请完全单击其箭头-从Glade内部拖动滚动条不起作用(至少在我使用的Ubuntu 11.04上的glade3 3.8.0上无效)。
So far so good - at least I can see the overflowing content behave as I want in glade
, but: 到目前为止,一切都很好-至少我可以看到林间glade
内容表现出我想要的glade
,但是:
glade
UI structure to use? 这是使用的正确的glade
UI结构吗? I see a Layout object, and a Frame object too - would those maybe be more appropriate here? 我看到了一个Layout对象和一个Frame对象-这些在这里是否更合适? (tried them, couldn't really figure them out) (尝试过,无法真正弄清楚它们) .glade
file is read in Python, how to a proceed in "extracting" a template from handlebox1
, and duplicating it on demand? 一旦.glade
文件在Python阅读,如何将在“提取”从模板进行handlebox1
,并复制它的需求呢? And a side question - is there a way to quickly "preview" a Glade object directly from Glade (just in an "empty window"), without writing an instantiation script - maybe by using some shortcut? 还有一个附带的问题-是否有一种方法可以直接从Glade快速“预览” Glade对象(仅在“空窗口”中),而无需编写实例化脚本-也许可以使用一些快捷方式?
Here's the code of multitrack.glade
(in GtkBuilder): 这是multitrack.glade
的代码(在GtkBuilder中):
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkHandleBox" id="handlebox1">
<property name="height_request">150</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkDrawingArea" id="drawingarea1">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHandleBox" id="handlebox2">
<property name="height_request">150</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkHandleBox" id="handlebox3">
<property name="height_request">150</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
Boy, this was something... well, to do a proper templating programaticaly, you'd need to recursively copy Gtk Objects, which are not susceptible to deepcopy... So I wrote one such function, deep_clone_widget
, included in the source below; 伙计,这有点...好吧,要进行适当的模板编程,您需要递归地复制不易进行deep_clone_widget
复制的Gtk对象...所以我写了一个这样的函数deep_clone_widget
,包含在下面的源代码中; for reference: 以供参考:
Of course, not extensively tested, but seems to work for me. 当然,未经广泛测试,但似乎对我有用。 Interestengly, until one does a full "deep clone" of handlebox and drawing area, the handleboxes do not stretch to fit the width of the window! 有趣的是,直到人们对把手箱和绘图区域进行了完整的“深度克隆”,把手箱才能够拉伸以适应窗口的宽度!
Good thing is - can just add to Vbox, no need to manage it; 好东西是-可以直接添加到Vbox,而无需对其进行管理; but it seems the dragging behavior will be a challenge... But I'd still like to know if this is the right Gtk/Glade UI hierarchy to use (and if there is a shortcut to preview from Glade) 但似乎拖动行为将是一个挑战...但是我仍然想知道这是否是使用的正确的Gtk / Glade UI层次结构(以及是否存在从Glade预览的快捷方式)
The code below will also output the starting hierarchy: 以下代码还将输出起始层次结构:
window1 :: GtkWindow
-scrolledwindow1 :: GtkScrolledWindow
--viewport1 :: GtkViewport
---vbox1 :: GtkVBox
----handlebox1 :: GtkHandleBox
-----drawingarea1 :: GtkDrawingArea
----handlebox2 :: GtkHandleBox
----handlebox3 :: GtkHandleBox
... and the ending hierarchy: ...以及结束层级:
window1 :: GtkWindow
-scrolledwindow1 :: GtkScrolledWindow
--viewport1 :: GtkViewport
---vbox1 :: GtkVBox
----hb1_template :: GtkHandleBox
-----drawingarea1 :: GtkDrawingArea
----hb1_template :: GtkHandleBox
-----drawingarea1 :: GtkDrawingArea
----hb1_template :: GtkHandleBox
-----drawingarea1 :: GtkDrawingArea
----hb1_template :: GtkHandleBox
-----drawingarea1 :: GtkDrawingArea
... hopefully confirming that the deep clone code is ok. ...希望确认深度克隆代码是可以的。
Here's the code multitrack.py
, that uses the multitrack.glade
above: 这是代码multitrack.py
,它使用上面的multitrack.glade
:
# needs gtk-builder (not for libglade)
import pygtk
pygtk.require("2.0")
import gtk
import copy
from pprint import pprint
import inspect
def main():
global window
gladefile = "/tmp/multitrack.glade"
wTree = gtk.Builder()
wTree.add_from_file(gladefile)
window = wTree.get_object("window1")
if not(window): return
print "E: " + str( get_descendant(window, "nofind", level=0, doPrint=True) )
doCopy()
print "E: " + str( get_descendant(window, "nofind", level=0, doPrint=True) )
window.connect("destroy", gtk.main_quit)
window.set_size_request(600, 300)
window.show_all() # must have!
gtk.main()
def doCopy():
global window
# get template object
hb1_ref = get_descendant(window, "handlebox1", level=0, doPrint=False)
#hb1_template = copy.deepcopy(hb1_ref) # GObject non-copyable
hb1_template = deep_clone_widget(hb1_ref)
gtk.Buildable.set_name(hb1_template, "hb1_template")
# get the container to be cleared
vb1 = get_descendant(window, "vbox1", level=0, doPrint=False)
# delete pre-existing in vbox (incl. hb1_ref)
for i in vb1.get_children():
vb1.remove(i)
# create new content
hb1_a = deep_clone_widget(hb1_template)
vb1.pack_start(hb1_a, expand=False, fill=True, padding=0)
hb1_b = deep_clone_widget(hb1_template)
vb1.pack_start(hb1_b, expand=False, fill=True, padding=0)
hb1_c = deep_clone_widget(hb1_template)
vb1.pack_start(hb1_c, expand=False, fill=True, padding=0)
hb1_d = deep_clone_widget(hb1_template)
vb1.pack_start(hb1_d, expand=False, fill=True, padding=0)
if 0: #small deep_clone_test
print ".....>"
vb1_ref = get_descendant(window, "vbox1", level=0, doPrint=False)
vb1_copy = deep_clone_widget(vb1_ref)
print "EEEEE "+ str( get_descendant(vb1_copy, "nofind", level=0, doPrint=True) )
print ".....<"
# https://stackoverflow.com/questions/20461464/how-do-i-iterate-through-all-gtk-children-in-pygtk-recursively
def get_descendant(widget, child_name, level, doPrint=False):
if widget is not None:
if doPrint: print("-"*level + str(gtk.Buildable.get_name(widget)) + " :: " + widget.get_name())
else:
if doPrint: print("-"*level + "None")
return None
if(gtk.Buildable.get_name(widget) == child_name):
return widget;
if (hasattr(widget, 'get_child') and callable(getattr(widget, 'get_child')) and child_name != ""):
child = widget.get_child()
if child is not None:
return get_descendant(child, child_name,level+1,doPrint)
elif (hasattr(widget, 'get_children') and callable(getattr(widget, 'get_children')) and child_name !=""):
children = widget.get_children()
found = None
for child in children:
if child is not None:
found = get_descendant(child, child_name,level+1,doPrint)
if found: return found
def deep_clone_widget(widget, inparent=None):
dbg = 0
widget2 = clone_widget(widget)
if inparent is None: inparent = widget2
if (hasattr(widget, 'get_child') and callable(getattr(widget, 'get_child'))):
child = widget.get_child()
if child is not None:
if dbg: print "A1 inp", inparent.get_name(), "w2", widget2.get_name()
childclone = deep_clone_widget(child, widget2)
if dbg: print "A2", childclone.get_name()
widget2.add( childclone )
#return inparent
elif (hasattr(widget, 'get_children') and callable(getattr(widget, 'get_children')) ):
children = widget.get_children()
for child in children:
if child is not None:
if dbg: print "B1 inp", inparent.get_name(), "w2", widget2.get_name()
childclone = deep_clone_widget(child, widget2)
if dbg: print "B2", childclone.get_name()
inparent.add( childclone )
#return childclone
return widget2
# https://stackoverflow.com/questions/1321655/how-to-use-the-same-widget-twice-in-pygtk
def clone_widget(widget):
print(" > clone_widget in: " + str(gtk.Buildable.get_name(widget)) + " :: " + widget.get_name() )
widget2=widget.__class__()
# these must go first, else they override set_name from next stage
for pspec in widget.props:
if pspec.name not in ['window', 'child', 'composite-child', 'child-detached', 'parent']:
#print(" > " + pspec.name)
try:
widget2.set_property(pspec.name, widget.get_property(pspec.name))
except Exception as e:
print e
# here set_name is obtained
for prop in dir(widget):
if prop.startswith("set_") and prop not in ["set_buffer"]:
#print(" ! " + prop + " ")
prop_value=None
try:
prop_value=getattr(widget, prop.replace("set_","get_") )()
except:
try:
prop_value=getattr(widget, prop.replace("set_","") )
except:
continue
if prop_value == None:
continue
try:
#print(" > " + prop + " " + prop_value )
if prop != "set_parent": # else pack_start complains: assertion `child->parent == NULL' failed
getattr(widget2, prop)( prop_value )
except:
pass
gtk.Buildable.set_name(widget2, gtk.Buildable.get_name(widget))
## style copy:
#for pspec in gtk.widget_class_list_style_properties(widget):
# print pspec, widget.style_get_property(pspec.name)
# #gtk.widget_class_install_style_property(widget2, pspec) #nope, for class only, not instances!
# none of these below seem to change anything - still getting a raw X11 look after them:
widget2.ensure_style()
widget2.set_style(widget.get_style().copy())
widget2.set_style(gtk.widget_get_default_style())
widget2.modify_style(widget.get_modifier_style())
#widget2.set_default_style(widget.get_default_style().copy()) # noexist; evt. deprecated? https://stackoverflow.com/questions/19740162/how-to-set-default-style-for-widgets-in-pygtk
# this is the right one, so we don't get raw X11 look:
widget2.set_style(widget.rc_get_style())
return widget2
if __name__ == "__main__":
main()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.