[英]Templating overflowing content with glade and pygtk?
我正在尝试开发“多轨” GUI(类似于多轨音频编辑器); 不过,我想开发它在glade
首先,检查内容如何四溢(在这种情况下,多个“轨道”)将与scollbars行为。 然后,在Python中实例化时,我首先要将这些“多个轨道”中的第一个作为“模板”,然后删除所有这些多个“轨道”-然后允许用户基于“模板”添加新的例如,点击“添加”按钮。
从Gtk调色板中,在我看来, handlebox
是用作“轨道”基础的正确对象(我想最终绘制这些轨道)。 到目前为止,我设法解决的唯一一件事(考虑到在glade
UI的用法上找不到多少教程)是使滚动条在GUI中起作用-这是仅滚动窗口部分的屏幕截图(下面是相应的文件) :
正确的结构似乎是:
scrolled window
viewport
vbox
handlebox
drawingarea
handlebox ...
...,而我要做的就是将(所有) handlebox
的“高度请求”设置为150px(我想要一个恒定的高度,并根据窗口缩放宽度); 并将其“打包/展开”设置为“否”。 另外,将scrolledwindow
水平和垂直滚动条策略设置为“始终”-否则,滚动条将不会显示(否则我错误地尝试放置其他滚动条以查看它)。 最后,要使滚动条正常工作,请完全单击其箭头-从Glade内部拖动滚动条不起作用(至少在我使用的Ubuntu 11.04上的glade3 3.8.0上无效)。
到目前为止,一切都很好-至少我可以看到林间glade
内容表现出我想要的glade
,但是:
glade
UI结构吗? 我看到了一个Layout对象和一个Frame对象-这些在这里是否更合适? (尝试过,无法真正弄清楚它们) .glade
文件在Python阅读,如何将在“提取”从模板进行handlebox1
,并复制它的需求呢? 还有一个附带的问题-是否有一种方法可以直接从Glade快速“预览” Glade对象(仅在“空窗口”中),而无需编写实例化脚本-也许可以使用一些快捷方式?
这是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>
伙计,这有点...好吧,要进行适当的模板编程,您需要递归地复制不易进行deep_clone_widget
复制的Gtk对象...所以我写了一个这样的函数deep_clone_widget
,包含在下面的源代码中; 以供参考:
当然,未经广泛测试,但似乎对我有用。 有趣的是,直到人们对把手箱和绘图区域进行了完整的“深度克隆”,把手箱才能够拉伸以适应窗口的宽度!
好东西是-可以直接添加到Vbox,而无需对其进行管理; 但似乎拖动行为将是一个挑战...但是我仍然想知道这是否是使用的正确的Gtk / Glade UI层次结构(以及是否存在从Glade预览的快捷方式)
以下代码还将输出起始层次结构:
window1 :: GtkWindow
-scrolledwindow1 :: GtkScrolledWindow
--viewport1 :: GtkViewport
---vbox1 :: GtkVBox
----handlebox1 :: GtkHandleBox
-----drawingarea1 :: GtkDrawingArea
----handlebox2 :: GtkHandleBox
----handlebox3 :: GtkHandleBox
...以及结束层级:
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
...希望确认深度克隆代码是可以的。
这是代码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.