我的主应用程序窗口需要一个具有不同小部件的网格。由于我刚接触Gtk,因此我决定从创建一个简单的布局开始,以便我可以更好地理解其背后的逻辑。
以下图像是我要获取的布局:
如您所见,我已经有一个菜单 (Archivo | Preferencias | Ayuda)和一个工具栏 (Nuevo | Abrir | Deshacer | Pantalla completa)。
因此,在红色矩形中,我尝试获取一个 scrolledwindow (滚动窗口)(假设我在大列中有一个图像名称列表),GREEN线将是 separator ,最后,BLUE矩形将是一个小部件,用于在选择滚动窗口的图像时显示图像。
下图是当前输出。请注意,滚动窗口位于工具栏的右下方,占据所有垂直空间和宽度的99%,而左侧宽度的1%则是在窗口的右边缘显示分隔符的位置(因此,白色部分在工具栏的右侧)
最后,如果您要运行它,则这是此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"><Primary>o</attribute>
</item>
</section>
<section>
<item>
<attribute name ="label" translatable="yes">Guardar</attribute>
<attribute name="action">app.save</attribute>
<attribute name="accel"><Primary>s</attribute>
</item>
<item>
<attribute name ="label" translatable="yes">Guardar Como...</attribute>
<attribute name="action">app.save-as</attribute>
<!--<attribute name="accel"><Primary>a</attribute>-->
</item>
</section>
<section>
<item>
<attribute name ="label" translatable="yes">Salir</attribute>
<attribute name="action">app.quit</attribute>
<attribute name="accel"><Primary>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>
答案 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>