Python3 Gtk +如何获取以下网格布局? (图片)

时间:2019-10-03 21:13:28

标签: python-3.x gtk3 grid-layout

我的主应用程序窗口需要一个具有不同小部件的网格。由于我刚接触Gtk,因此我决定从创建一个简单的布局开始,以便我可以更好地理解其背后的逻辑。

以下图像是我要获取的布局:

enter image description here

如您所见,我已经有一个菜单 (Archivo | Preferencias | Ayuda)和一个工具栏 (Nuevo | Abrir | Deshacer | Pantalla completa)

因此,在红色矩形中,我尝试获取一个 scrolledwindow (滚动窗口)(假设我在大列中有一个图像名称列表),GREEN线将是 separator ,最后,BLUE矩形将是一个小部件,用于在选择滚动窗口的图像时显示图像。

下图是当前输出。请注意,滚动窗口位于工具栏的右下方,占据所有垂直空间和宽度的99%,而左侧宽度的1%则是在窗口的右边缘显示分隔符的位置(因此,白色部分在工具栏的右侧)

enter image description here

最后,如果您要运行它,则这是此UI的代码。 网格是在Window类的初始化中构建的。

application.py

# -*- encoding: utf-8 -*-

# Author:
# Diego Suárez García, d.suarez@udc.es

# ## ## ## ## ## ## ## ## ## ## ## ## # ## ## ## ## ## ## ## ## ## ## ## ## # 
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ #
#                                                                           #
#   application.py :                                                        #
#                                                                           #
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # 
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##

import json

import sys

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

# Constants
MENU_FILE = "menubar.ui"

## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ #
# ~                             Window Class                              ~ #
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # 
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##

class Window(Gtk.ApplicationWindow):

    def __init__(self, app):

        # Main window initialization
        super(Window, self).__init__(title="FreeComet 1.0", application=app)
        self.set_default_size(800, 600)

        # The project filename
        self.project_filename = None

        # The grid to attach the toolbar
        grid = Gtk.Grid()
        # The toolbar
        toolbar = self.__create_toolbar()
        toolbar.set_hexpand(True)               # with extra horizontal space

        # The Toolbar Actions
        undo_action = Gio.SimpleAction.new("undo", None)
        undo_action.connect("activate", self.undo_callback)
        self.add_action(undo_action)

        fullscreen_action = Gio.SimpleAction.new("fullscreen", None)
        fullscreen_action.connect("activate", self.fullscreen_callback)
        self.add_action(fullscreen_action)

        new_action = Gio.SimpleAction.new("new-project", None)
        new_action.connect("activate", self.new_project_callback)
        self.add_action(new_action)

        open_project_action = Gio.SimpleAction.new("open-project", None)
        open_project_action.connect("activate", self.open_project_callback)
        self.add_action(open_project_action)

        # The scrolledwindow
        scrolled_window = Gtk.ScrolledWindow()
        scrolled_window.set_border_width(10)
        scrolled_window.set_vexpand(True)
        scrolled_window.set_hexpand(False)
        # there is always the scrollbar (otherwise: AUTOMATIC - only if needed
        # - or NEVER)
        scrolled_window.set_policy(
            Gtk.PolicyType.ALWAYS, Gtk.PolicyType.ALWAYS)

        # a horizontal separator
        hseparator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
        # a vertical separator
        vseparator = Gtk.Separator(orientation=Gtk.Orientation.VERTICAL)

        # Build grid
        grid.add(toolbar)
        grid.attach(scrolled_window, 0, 1, 1, 1)
        grid.attach(vseparator, 1, 1, 1, 1)
        grid.attach(Gtk.Button(), 2, 1, 1, 1)
        # Add the grid to the window
        self.add(grid)




    def __create_toolbar(self):

        # Toolbar initialization (primary toolbar of the application)
        toolbar = Gtk.Toolbar()
        toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)

        # Button for the 'new' action
        new_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_NEW)
        new_button.set_property("has-tooltip", True)
        new_button.connect("query-tooltip", self.new_project_tooltip_callback)
        new_button.set_is_important(True)
        toolbar.insert(new_button, 0)
        new_button.set_action_name("win.new-project")

        # Button for the 'open' action
        open_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_OPEN)
        open_button.set_property("has-tooltip", True)
        open_button.connect("query-tooltip", self.open_project_tooltip_callback)
        open_button.set_is_important(True)
        toolbar.insert(open_button, 1)
        open_button.set_action_name("win.open-project")

        # Button for the 'undo' action
        undo_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_UNDO)
        undo_button.set_property("has-tooltip", True)
        undo_button.connect("query-tooltip", self.undo_tooltip_callback)
        undo_button.set_is_important(True)
        toolbar.insert(undo_button, 2)
        undo_button.set_action_name("win.undo")

        # Button for the 'fullscreen/leave fullscreen' action
        self.fullscreen_button = Gtk.ToolButton.new_from_stock(
            Gtk.STOCK_FULLSCREEN)
        self.fullscreen_button.set_property("has-tooltip", True)
        self.fullscreen_button.connect("query-tooltip", 
            self.fullscreen_tooltip_callback)
        self.fullscreen_button.set_is_important(True)
        toolbar.insert(self.fullscreen_button, 3)
        self.fullscreen_button.set_action_name("win.fullscreen")

        # return the complete toolbar
        return toolbar


## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ #
# ~                               Callbacks                               ~ #
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # 
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## 

    #                                            #
    # #       Toolbar Tooltips Callbacks       # #
    #                                            #

    def new_project_tooltip_callback(self, widget, x, y, keyboard_mode, tooltip):
        tooltip.set_text("Crear un nuevo proyecto")
        tooltip.set_icon_from_stock("gtk-new", Gtk.IconSize.MENU)
        return True

    def open_project_tooltip_callback(self, widget, x, y, keyboard_mode, tooltip):
        tooltip.set_text("Abrir un proyecto existente")
        tooltip.set_icon_from_stock("gtk-open", Gtk.IconSize.MENU)
        return True

    def undo_tooltip_callback(self, widget, x, y, keyboard_mode, tooltip):
        tooltip.set_text("Deshacer la última acción")
        tooltip.set_icon_from_stock("gtk-undo", Gtk.IconSize.MENU)
        return True

    def fullscreen_tooltip_callback(self, widget, x, y, keyboard_mode, tooltip):
        tooltip.set_text("Modo pantalla completa")
        tooltip.set_icon_from_stock("gtk-fullscreen", Gtk.IconSize.MENU)
        return True

    #                                            #
    # #           Toolbar Callbacks            # #
    #                                            #

    def new_project_callback(self, action, parameter):
        print("You clicked \"New Project\".")

    def open_project_callback(self, action, parameter):
        # Create a filechooserdialog to open:
        # The arguments are: title of the window, parent_window, action,
        # (buttons, response)
        open_project_dialog = Gtk.FileChooserDialog("Seleccione un proyecto", self,
                                            Gtk.FileChooserAction.OPEN,
                                           (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                                            Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT))

        # Not only local files can be selected in the file selector
        open_project_dialog.set_local_only(False)
        # Connect the dialog with the callback function open_response_callback_response()
        open_project_dialog.connect("response", self.__open_project_callback_response)
        # Show the dialog
        open_project_dialog.show()

    def __open_project_callback_response(self, dialog, response_id):

        open_project_dialog = dialog
        if response_id == Gtk.ResponseType.ACCEPT:
            # Filename we get from the FileChooserDialog
            self.project_filename = open_project_dialog.get_filename()

        dialog.destroy()

        # Read project
        #data = json.load(self.project_filename)

    def undo_callback(self, action, parameter):
        print("You clicked \"Undo\".")

    def fullscreen_callback(self, action, parameter):
        # check if the state is the same as Gdk.WindowState.FULLSCREEN, which
        # is a bit flag
        is_fullscreen = self.get_window().get_state(
        ) & Gdk.WindowState.FULLSCREEN != 0
        if not is_fullscreen:
            self.fullscreen_button.set_stock_id(Gtk.STOCK_LEAVE_FULLSCREEN)
            self.fullscreen()
        else:
            self.fullscreen_button.set_stock_id(Gtk.STOCK_FULLSCREEN)
            self.unfullscreen()


## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ #
# ~                           Application Class                           ~ #
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # 
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##    

class Application(Gtk.Application):

    def __init__(self):
        super(Application, self).__init__()

    def do_activate(self):    
        self._win_main = Window(self)
        self._win_main.show_all()

    def do_startup(self):
        # FIRST THING TO DO: do_startup()
        Gtk.Application.do_startup(self)

        # The Application Menubar
        builder = Gtk.Builder()
        try:
            builder.add_from_file(MENU_FILE)
        except:
            print("ERROR: " + MENU_FILE +" not found")
            sys.exit()
        self.set_menubar(builder.get_object("menubar"))

        # [2] The Menubar Actions
        new_project_action = Gio.SimpleAction.new("new", None)
        new_project_action.connect("activate", self.new_project_callback)
        self.add_action(new_project_action)

        open_project_action = Gio.SimpleAction.new("open", None)
        open_project_action.connect("activate", self.open_project_callback)
        self.add_action(open_project_action)

        save_action = Gio.SimpleAction.new("save", None)
        save_action.connect("activate", self.save_callback)
        self.add_action(save_action)

        save_as_action = Gio.SimpleAction.new("save-as", None)
        save_as_action.connect("activate", self.save_as_callback)
        self.add_action(save_as_action)

        quit_action = Gio.SimpleAction.new("quit", None)
        quit_action.connect("activate", self.quit_callback)
        self.add_action(quit_action)


    #                                   #
    # #       Menubar Callbacks       # #
    #                                   #

    def new_project_callback(self, action, parameter):
        print("You clicked \"New\"")

    def open_project_callback(self, action, parameter):
        self._win_main.open_project_callback(action, parameter)

    def save_callback(self, action, parameter):
        print("You clicked \"Save\"") 

    def save_as_callback(self, action, parameter):
        print("You clicked \"Save as..\"") 

    def quit_callback(self, action, parameter):
        self.quit()  


if __name__ == "__main__":
    app = Application()
    app.run(sys.argv)

menubar.ui

<?xml version="1.0" encoding="UTF-8"?>

<interface>
  <menu id="menubar">
    <submenu>
      <attribute name="label" translatable="yes">_Archivo</attribute>
      <section>
        <item>
          <attribute name="label" translatable="yes">Nuevo</attribute>
          <attribute name="action">app.new</attribute>
        </item>
        <item>
          <attribute name="label" translatable="yes">Abrir...</attribute>
          <attribute name="action">app.open</attribute>
          <attribute name="accel">&lt;Primary&gt;o</attribute>
        </item>
      </section>
      <section>
        <item>
          <attribute name ="label" translatable="yes">Guardar</attribute>
          <attribute name="action">app.save</attribute>
          <attribute name="accel">&lt;Primary&gt;s</attribute>
        </item>
        <item>
          <attribute name ="label" translatable="yes">Guardar Como...</attribute>
          <attribute name="action">app.save-as</attribute>
          <!--<attribute name="accel">&lt;Primary&gt;a</attribute>-->
        </item>
      </section>
      <section>
        <item>
          <attribute name ="label" translatable="yes">Salir</attribute>
          <attribute name="action">app.quit</attribute>
          <attribute name="accel">&lt;Primary&gt;q</attribute>
        </item>
      </section>
    </submenu>
    <submenu>
      <attribute name="label" translatable="yes">_Preferencias</attribute>
      <section>
        <item>
          <attribute name="label" translatable="yes">_Idioma</attribute>
          <attribute name="action">app.language</attribute>
        </item>
      </section>
    </submenu>
    <submenu>
      <attribute name="label" translatable="yes">A_yuda</attribute>
      <section>
        <item>
          <attribute name="label" translatable="yes">Acerca de FreeComet</attribute>
          <attribute name="action">app.about</attribute>
        </item>
      </section>
    </submenu>
  </menu>
</interface>

1 个答案:

答案 0 :(得分:1)

这是一个可能需要快速组合的.ui文件。作为旁注,我将所有可以放入的小部件都放到了.ui文件中,因为我可以在Glade中查看层次结构。

我没有使用网格(最适合多行和多列窗口小部件),而是使用Gtk.Box将不同行的窗口小部件放入其中,然后使用Gtk.Paned来分隔网格从右侧的图像查看器向左滚动窗口。 Gtk.Paned的额外好处是具有可拖动的分隔线。

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkApplicationWindow">
    <property name="can_focus">False</property>
    <child>
      <placeholder/>
    </child>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkMenuBar">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkMenuItem">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">_File</property>
                <property name="use_underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-new</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-open</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-save</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-save-as</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkSeparatorMenuItem">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-quit</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">_Edit</property>
                <property name="use_underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-cut</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-copy</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-paste</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-delete</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">_View</property>
                <property name="use_underline">True</property>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">_Help</property>
                <property name="use_underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-about</property>
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkToolbar">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkToolButton">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="is_important">True</property>
                <property name="action_name">win.new-project</property>
                <property name="label" translatable="yes">toolbutton</property>
                <property name="use_underline">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="homogeneous">True</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkPaned">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="position">100</property>
            <property name="position_set">True</property>
            <child>
              <object class="GtkScrolledWindow">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="shadow_type">in</property>
                <child>
                  <placeholder/>
                </child>
              </object>
              <packing>
                <property name="resize">False</property>
                <property name="shrink">True</property>
              </packing>
            </child>
            <child>
              <placeholder/>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>