用glade和pygtk模板化溢出的内容?

2024-10-02 20:29:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试开发一个“multitrack”GUI(类似于multitrack audio editors);但是,我想先在glade中开发它,并检查溢出的内容(在本例中是多个“tracks”)在scollbar中的行为。然后,在Python中实例化时,我想首先将这些“多个轨迹”中的第一个作为“模板”,然后删除所有这些多个“轨迹”——然后允许用户根据“模板”添加新的轨迹,比如单击“添加”按钮。在

在Gtk调色板中,我觉得handlebox是作为“track”基础的正确对象(我希望最终绘制这些轨迹)。到目前为止,我所能完成的唯一一件事(考虑到关于gladeUI用法的教程非常少),就是让滚动条在GUI中正常工作——以下是滚动窗口部分的屏幕截图(对应的文件如下所示):

multitrack.glade.png

正确的结构似乎是:

scrolled window
  viewport
    vbox
      handlebox 
        drawingarea
      handlebox ...

。。。我所要做的就是将(all)handlebox的“Height request”设置为150px(我想要一个恒定的高度,并根据窗口调整宽度);并将其Packing/Expand设置为“No”。另外,将scrolledwindow水平和垂直滚动条策略设置为“总是”—否则滚动条不会显示(另外,我错误地尝试放置一个额外的滚动条来查看它)。最后,要想让滚动条正常工作,就直接点击它的箭头——在Glade中拖动滚动条是不起作用的(至少在我使用的Ubuntu11.04上的glade3 3.8.0上不起作用)。在

到目前为止还不错-至少我可以看到溢出内容在glade中的行为,但是:

  • 这是使用正确的gladeUI结构吗?我看到一个Layout对象,还有一个Frame对象-这些可能更适合这里吗?(试过了,真的搞不懂)
  • 一旦在Python中读取了.glade文件,如何从handlebox1中“提取”模板并按需复制它?在
  • 在添加/删除曲目时,我是否还必须更改vbox的分区?如果是这样的话,有没有办法在不使用vbox的情况下实现添加/删除曲目的相同布局?在
  • 目前我很满意轨道的宽度随着窗口的宽度而变化;但如果我决定让它们固定的宽度大于窗口的宽度,我试着把把手箱的宽度请求设置为1000,水平滚动条在空地上似乎能正常工作;宽度请求是否就是全部?在
  • 如果我想让用户通过拖动重新排列垂直轨迹顺序,是否需要特殊的处理程序?在

还有一个附带的问题-有没有一种方法可以直接从Glade快速“预览”Glade对象(只在“空窗口”中),而不需要编写实例化脚本-也许可以使用一些快捷方式?在

以下是multitrack.glade(在GtkBuilder中)的代码:

^{pr2}$

Tags: 文件对象实例用户模板内容宽度轨迹
1条回答
网友
1楼 · 发布于 2024-10-02 20:29:46

天啊,这真是。。。好吧,为了用编程的方式做一个正确的模板,你需要递归地复制Gtk对象,这些对象不易受deepcopy的影响。。。因此,我编写了一个这样的函数deep_clone_widget,包含在下面的源代码中;供参考:

当然,没有经过广泛的测试,但似乎对我有用。有趣的是,直到一个人做了一个完整的“深克隆”车把和绘图区,车把不伸展到适合窗口的宽度!在

好在-只需添加到Vbox中,无需管理它;但似乎拖动行为将是一个挑战。。。但我还是想知道这是否是正确的Gtk/gladeui层次结构(以及是否有一个从Glade预览的快捷方式)

下面的代码还将输出起始层次结构:

window1 :: GtkWindow
-scrolledwindow1 :: GtkScrolledWindow
 viewport1 :: GtkViewport
 -vbox1 :: GtkVBox
  handlebox1 :: GtkHandleBox
  -drawingarea1 :: GtkDrawingArea
  handlebox2 :: GtkHandleBox
  handlebox3 :: GtkHandleBox

。。。最后的层次结构:

^{pr2}$

。。。希望能确认深层克隆代码没问题。在

下面是代码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()

相关问题 更多 >