什么是ComboBox.new_with_model_and_entry的林间空地?

时间:2018-04-20 11:58:17

标签: python gtk3 glade

我希望将Ghini(一个Python桌面程序)从GTK2移植到GTK3,即从静态import gtk到动态from gi import Gtk

Ghini基于林间空地文件,而且我遇到ComboBox个元素的问题 - 与关联的Entry有关。我已经搜索了关于Gtk2和Gtk3之间差异的文档和教程,并且有很多,但我找到的没有一个详细描述了这个特例。移植脚本处理python源代码,我没有找到任何解决glade文件的问题。

在将问题简化为最小限定问题的过程中,我已在此example 13中选择Gtk tutorial

所以我把原来的程序剥离了:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class ComboBoxWindow:

    def on_name_combo_changed(self, combo):
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            row_id, name = model[tree_iter][:2]
            print("Selected: ID=%d, name=%s" % (row_id, name))
        else:
            entry = combo.get_child()
            print("Entered: %s" % entry.get_text())

    def on_country_combo_changed(self, combo):
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            country = model[tree_iter][0]
            print("Selected: country=%s" % country)

    def on_currency_combo_changed(self, combo):
        text = combo.get_active_text()
        if text is not None:
            print("Selected: currency=%s" % text)

    def __init__(self, builder):
        builder.add_from_file("/tmp/ex13.glade")
        builder.connect_signals(self)
        self.window = builder.get_object("window1")
        self.window.connect("destroy", Gtk.main_quit)

    def show_all(self):
        self.window.show_all()

builder = Gtk.Builder()
win = ComboBoxWindow(builder)
win.show_all()
Gtk.main()

我使用Glade将整个接口定义放在这个ex13.glade文件中:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkListStore" id="country_store">
    <columns>
      <!-- column-name gchararray1 -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row><col id="0" translatable="yes">Austria</col></row>
      <row><col id="0" translatable="yes">Brazil</col></row>
      <row><col id="0" translatable="yes">Belgium</col></row>
      <row><col id="0" translatable="yes">France</col></row>
      <row><col id="0" translatable="yes">Germany</col></row>
      <row><col id="0" translatable="yes">Switzerland</col></row>
      <row><col id="0" translatable="yes">United Kingdom</col></row>
      <row><col id="0" translatable="yes">United States</col></row>
      <row><col id="0" translatable="yes">Uruguay</col></row>
    </data>
  </object>
  <object class="GtkListStore" id="name_store">
    <columns>
      <!-- column-name gint1 -->
      <column type="gint"/>
      <!-- column-name gchararray1 -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row>
        <col id="0">1</col>
        <col id="1" translatable="yes">Billy Bobo</col>
      </row>
      <row>
        <col id="0">2</col>
        <col id="1" translatable="yes">Joey Jojo</col>
      </row>
      <row>
        <col id="0">3</col>
        <col id="1" translatable="yes">Rob McRoberts</col>
      </row>
      <row>
        <col id="0">11</col>
        <col id="1" translatable="yes">Billy Bob Junior</col>
      </row>
      <row>
        <col id="0">12</col>
        <col id="1" translatable="yes">Sue Bob</col>
      </row>
      <row>
        <col id="0">31</col>
        <col id="1" translatable="yes">Xavier McRoberts</col>
      </row>
    </data>
  </object>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">Combobox Example</property>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">6</property>
        <child>
          <object class="GtkComboBox" id="name_combo">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="model">name_store</property>
            <property name="has_entry">True</property>
            <property name="entry_text_column">1</property>
            <signal name="changed" handler="on_name_combo_changed" swapped="no"/>
            <child>
              <object class="GtkCellRendererText" id="name_renderer"/>
              <attributes>
                <attribute name="text">1</attribute>
              </attributes>
            </child>
            <child internal-child="entry">
              <object class="GtkEntry">
                <property name="can_focus">True</property>
                <property name="placeholder_text" translatable="yes">type, or choose</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="GtkComboBox" id="country_combo">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="model">country_store</property>
            <property name="id_column">0</property>
            <signal name="changed" handler="on_country_combo_changed" swapped="no"/>
            <child>
              <object class="GtkCellRendererText" id="country_renderer"/>
              <attributes>
                <attribute name="text">0</attribute>
              </attributes>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkComboBoxText" id="currencies_combo">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <items>
              <item translatable="yes">Euro</item>
              <item translatable="yes">US Dollars</item>
              <item translatable="yes">British Pound</item>
              <item translatable="yes">Japanese Yen</item>
              <item translatable="yes">Russian Ruble</item>
              <item translatable="yes">Mexican peso</item>
              <item translatable="yes">Swiss franc</item>
            </items>
            <signal name="changed" handler="on_currency_combo_changed" swapped="no"/>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
      </object>
    </child>
  </object>
</interface>

但是,这并不等同于原始示例,我也不知道我错过了什么。特别是带有Entry的ComboBox正在执行此操作:

  • 下拉列表显示内容两次

enter image description here

提示和批评非常受欢迎。

一小时后:

当我设置<property name="has_entry">True</property>时 - 下拉列表显示两列,这不会链接到包含两列的列表库:我已在country_combo中启用它(关联到单个列列表库),我得到一个空列和一个列表库中的值。

稍后编辑:似乎双重表示是由GtkCellRendererText引起的,我可以安全删除。

2 个答案:

答案 0 :(得分:0)

我找到了答案,我在这里分享:

首先,我通过一般回调减少了代码。

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk


class ComboBoxWindow:

    def on_combo_changed(self, combo):
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            print("row: [%s]" % ', '.join("%s(%s)" % (type(i), str(i)) for i in model[tree_iter]))
        else:
            entry = combo.get_child()
            print("Entered: %s" % entry.get_text())

    def __init__(self, builder):
        import os.path
        path, name = os.path.split(__file__)
        builder.add_from_file(os.path.join(path, "ex13.glade"))
        builder.connect_signals(self)
        self.window = builder.get_object("window1")
        self.window.connect("destroy", Gtk.main_quit)

    def show_all(self):
        self.window.show_all()


builder = Gtk.Builder()
win = ComboBoxWindow(builder)
win.show_all()
Gtk.main()

然后是界面文件,我还将其剥离为只有一个ComboBox,与多列ListStore模型相关联,它有一个内部(无内容)Entry

下拉以两种不同的方式发生,一种是在您输入Entry时,这种情况发生在与Entry相关联的GtkEntryCompletion上有自己的GtkCellRendererText

另一个是常规下拉菜单,它至少显示一列和其他列。在这个例子中,我使用额外的渲染器来展示它是如何工作的。我无法关闭第一个默认列。

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkListStore" id="epithet_store">
    <columns>
      <column type="gint"/>        <!-- column-name id -->
      <column type="gchararray"/>  <!-- column-name epithet -->
      <column type="gchararray"/>  <!-- column-name family -->
      <column type="gchararray"/>  <!-- column-name phonetic -->
    </columns>
    <data>
      <row><col id="0">0</col><col id="1">Cocos</col><col id="2">Arecaceae</col><col id="3">kukus</col></row>
      <row><col id="0">1</col><col id="1">Cheilopsis</col><col id="2">Acanthaceae</col><col id="3">kilupsis</col></row>
      <row><col id="0">2</col><col id="1">Haplanthoides</col><col id="2">Acanthaceae</col><col id="3">aplantidis</col></row>
      <row><col id="0">3</col><col id="1">Haplanthus</col><col id="2">Acanthaceae</col><col id="3">aplantus</col></row>
      <row><col id="0">4</col><col id="1">Indoneesiella</col><col id="2">Acanthaceae</col><col id="3">indunisila</col></row>
      <row><col id="0">5</col><col id="1">Ancalanthus</col><col id="2">Acanthaceae</col><col id="3">ankalantus</col></row>
    </data>
  </object>
  <object class="GtkEntryCompletion" id="epithet_entrycompletion">
    <property name="model">epithet_store</property>
    <property name="text_column">1</property>
    <property name="inline_selection">True</property>
    <property name="popup_completion">True</property>
    <child>
      <object class="GtkCellRendererText" id="epithet_completion_renderer"/>
      <attributes>
        <attribute name="text">1</attribute>
      </attributes>
    </child>
  </object>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">Combobox Example</property>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">6</property>
        <child>
          <object class="GtkComboBox" id="epithet_combo">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="model">epithet_store</property>
            <property name="has_entry">True</property>
            <property name="entry_text_column">1</property>
            <property name="id_column">0</property>
            <signal name="changed" handler="on_combo_changed" swapped="no"/>
            <child>
              <object class="GtkCellRendererText" id="epithet_renderer"/>
              <attributes>
                <attribute name="text">2</attribute>
              </attributes>
            </child>
            <child internal-child="entry">
              <object class="GtkEntry">
                <property name="can_focus">True</property>
                <property name="completion">epithet_entrycompletion</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">4</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

如果我不想将信息保存在ListStore模型中,并且只需要处理文本并有条目,那么以下内容也可以使用,从某种意义上说,可以让我输入并区分案例&# 34;它被选中&#34; /&#34;它被输入&#34;:

      <object class="GtkComboBoxText">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="has_entry">True</property>
        <items>
          <item id="1" translatable="yes">Aitano</item>
          <item id="2" translatable="yes">Aniello</item>
          <item id="3" translatable="yes">Antonio</item>
          <item id="4" translatable="yes">Fiorentino</item>
          <item id="5" translatable="yes">Peppino</item>
          <item id="6" translatable="yes">Strato</item>
        </items>
        <signal name="changed" handler="on_combo_changed" swapped="no"/>
        <child internal-child="entry">
          <object class="GtkEntry">
            <property name="can_focus">True</property>
            <property name="placeholder_text" translatable="yes">type, or choose</property>
          </object>
        </child>
      </object>

关联的回调与上述完整解决方案相同

答案 1 :(得分:0)

到目前为止,我理解你在做什么:对于从gtk2迁移到gtk3的新应用程序的测试,你超越http://python-gtk-3-tutorial.readthedocs.io/en/latest/combobox.html并尝试以不同的方式(不仅仅是脚本,而是使用简化的脚本)并使用单独的GLADE文件)。你测试过http://python-gtk-3-tutorial.readthedocs.io/en/latest/combobox.html了吗? (我个人不会完全依赖WWW中的代码;但是在修改脚本之前先对其进行测试)。我个人直到现在才使用组合作为被动窗口,从不与信号连接。