为了学习,我编写了一个工具框架类(gtk 3.24.20),工具框架是可移动和可扩展的。所有的工具框架都被附加到Gtk中。固定部件。
关于Gtk的文档。GtkFixed小部件是一个容器,它可以将子部件放置在固定的位置和固定的大小,以像素为单位。GtkFixed不执行自动布局管理">
如果我使用Gtk的实例方法。固定放置和移动将工具框放置到(100,100),有时gtk布局计算将工具框放回原始位置(0,0)。例如,如果我正在调整窗口的大小。或者点击按钮
如果我使用widget方法size_allocate并设置x,y,宽度和高度,它也会发生,宽度突然改变x,y回到0,0
我必须观察信号大小分配,每次,如果GTK布局改变了我的工具框架的x,y,宽度和高度尺寸,我必须覆盖分配,把它放回我的位置,宽度和高度。
我想知道,因为文档说。Gtk。固定没有布局管理执行。当为我的工具框触发size-allocate信号时,我真的必须总是覆盖分配吗?还是我出了什么问题?
另一个问题-如果我想销毁一个GOBJECT,我是否必须在销毁之前断开所有信号处理程序,或者我可以简单地销毁它,而不断开连接(关于内存泄漏)
类的示例:
#!/usr/bin/gjs
const Gtk= imports.gi.Gtk,
Gio= imports.gi.Gio,
Gdk= imports.gi.Gdk,
GdkPixbuf= imports.gi.GdkPixbuf;
Gtk.init(null);
const window= new Gtk.Window(),
fixed_container= new Gtk.Fixed();
/* ==================================================================================================================================
CLASS ToolFrame (fixed_container, x, y, image_URL_orPATH_orICON, title, tooltip_text, content)
==================================================================================================================================
gtk version: 3.24.20 - depends on Gtk, Gio, Gdk, GdkPixbuf
--------------------
creates a moveable toolframe with titlebar and content, the toolframe can be minimized only showing the titlebar or can be expanded
most of the toolframe style can be changed over static object ToolFrame.standards (for explaination look at ToolFrame.standards)
before creation. In standard the toolframe has four buttons, a minimize button, an expand button, a pin button, and a close button
Gtk widget structure:
---------------------
eventbox_for_vbox (root widget) -> vbox -> eventbox_for_hbox -> hbox (titlebar)-> image, label, buttons
-> scrolled window -> content
parameters:
-----------
fixed_container GOBJ ... a Gtk.Fixed widget - parent container for all ToolFrame instances
x NUMB (INT) ... x position of the ToolFrame instance relative to parent container origin
y NUMB (INT) ... y position of the ToolFrame instance relative to parent container origin
image_URL_orPATH_orICON STR ... can be an URL or a PATH or an ICON name, icon names have to start with "icon://",
null or undefined, means no image
title STR ... the title of the ToolFrame instance
tool_tip STR ... tooltip text (hovering title) - null or undefined means no tooltip
content GOBJ ... a Gtk widget which is shown, when the ToolFrame instance is expanded
for detailed explainations look inside Gnome JavaScript class comments!
public instance properties:
---------------------------
fixed_container, root_widget, widgets, style_contexts, isPinned, isExpanded
public prototype properties:
----------------------------
toolframes, toolframe_inAction
public instance methods:
------------------------
set_AsLastChild, move, get_expanded_size, set_expanded_size
-----------------------------------------------------------------------------------------------------------------------------------*/
{ //-----> blockscope Class ToolFrame
//-----------------------------------------------------------------------
//----------------- CONSTRUCTOR
var ToolFrame=function ToolFrame (fixed_container, x, y, image_URL_orPATH_orICON, title, tooltip_text, content)
{
const widgets=new Object (), standards=ToolFrame.standards, style_contexts=new Object ();
var width, height, cssProvider;
widgets.eventbox_for_hbox= new Gtk.EventBox(); //-- eventbox parent of hbox
widgets.eventbox_for_vbox= new Gtk.EventBox(); //-- eventbox parent of vbox -> ToolFrame instance root_widget!
widgets.hbox= new Gtk.Box({ spacing: standards.titlebar_spacing, valign:3 }); //-- titlebar = hbox
widgets.vbox= new Gtk.Box({ orientation:1, spacing: standards.toolframe_spacing}); //-- children hbox (titlebar) and scrolled_window (holds content)
widgets.scrolled_window= new Gtk.ScrolledWindow ({ vexpand:true }); //-- content added to scrolled_window
//-- references to toolframe instance used by signals functions (circular references)
widgets.eventbox_for_vbox.toolframe=this;
widgets.hbox.toolframe=this;
//-- creating titlebar image and pixbuf, width and height defined in ToolFrame.standards
if (image_URL_orPATH_orICON)
{
widgets.image= new Gtk.Image({ halign:3, valign:3 }); //-- vertical center
//-- ICON case
if (image_URL_orPATH_orICON.indexOf("icon://")==0) widgets.image.set_from_icon_name (image_URL_orPATH_orICON.slice (7,image_URL_orPATH_orICON.length), standards.icon_size);
//-- URL or PATH
else
{
widgets.imagePixBuf=get_pixbuf_from_URLorPATH (image_URL_orPATH_orICON);
if (widgets.imagePixBuf)
{
if (standards.image_width.constructor === Number)
{
width=standards.image_width;
if (standards.image_height =="auto") height=Math.round (width/widgets.imagePixBuf.width*widgets.imagePixBuf.height);
}
if (standards.image_height.constructor === Number)
{
height=standards.image_height;
if (standards.image_width == "auto") width=Math.round (height/widgets.imagePixBuf.height*widgets.imagePixBuf.width);
}
widgets.image.set_from_pixbuf (widgets.imagePixBuf.scale_simple (width, height, GdkPixbuf.InterpType.BILINEAR));
}
}
widgets.hbox.pack_start(widgets.image,false,false,0);
}
//-- titlebar title
widgets.label= new Gtk.Label ({ label:title }); widgets.hbox.pack_start(widgets.label,false,false,0);
cssProvider=new Gtk.CssProvider();
cssProvider.load_from_data ("* "+standards.title_css_STR);
widgets.label.get_style_context().add_provider (cssProvider,0);
if (tooltip_text) widgets.label.set_tooltip_text (tooltip_text);
//-- determine titlebar buttons width and height, defined in ToolFrame.standards
if (standards.button_width.constructor === Number) width=standards.button_width; else width=-1;
if (standards.button_height.constructor === Number) height=standards.button_height; else height=-1;
//-- creating titlebar buttons according to ToolFrame.standards
cssProvider=new Gtk.CssProvider();
cssProvider.load_from_data ("* "+standards.buttons_css_STR);
if (standards.buttons_creation.close)
{
widgets.button_close= new Gtk.Button ({ label:standards.button_close_char, halign:3, valign:3 }),
widgets.button_close.connect("clicked", button_close_clicked);
widgets.hbox.pack_end(widgets.button_close,false,false,0);
widgets.button_close.set_size_request (width, height);
widgets.button_close.get_style_context().add_provider(cssProvider,0);
if (standards.button_tooltip) widgets.button_close.set_tooltip_text("close");
}
if (standards.buttons_creation.pin)
{
if (standards.isPinned) widgets.button_pin=new Gtk.Button ({ label:standards.button_pinned_char, halign:3, valign:3 });
else widgets.button_pin=new Gtk.Button ({label:standards.button_pin_char, halign:3, valign:3 });
widgets.button_pin.connect("clicked", button_pin_clicked);
widgets.hbox.pack_end(widgets.button_pin,false,false,0);
widgets.button_pin.set_size_request (width, height);
widgets.button_pin.get_style_context().add_provider(cssProvider,0);
if (standards.button_tooltip) widgets.button_pin.set_tooltip_text("pin");
}
if (standards.buttons_creation.minimize_expand)
{
widgets.button_expand= new Gtk.Button ({ label:standards.button_expand_char, halign:3, valign:3 }),
widgets.button_expand.connect("clicked", button_expand_clicked);
widgets.hbox.pack_end(widgets.button_expand,false,false,0);
widgets.button_expand.set_size_request (width, height);
widgets.button_expand.get_style_context().add_provider(cssProvider,0);
if (standards.button_tooltip) widgets.button_expand.set_tooltip_text("expand");
widgets.button_minimize= new Gtk.Button ({label:standards.button_minimize_char, halign:3, valign:3 }),
widgets.button_minimize.connect("clicked", button_minimize_clicked);
widgets.hbox.pack_end(widgets.button_minimize,false,false,0);
widgets.button_minimize.set_size_request (width, height);
widgets.button_minimize.get_style_context().add_provider(cssProvider,0);
if (standards.button_tooltip) widgets.button_minimize.set_tooltip_text("minimize");
//-- sensitivity button_minimize, button_expand
if (standards.content_visible_atStart) widgets.button_expand.set_sensitive(false);
else widgets.button_minimize.set_sensitive(false);
}
/* setting references for ToolFrame instance; fixed_container -> stage container for all ToolFrame instances
root_widget -> representing ToolFrame instance on screen; widgets -> folder for all widgets including image pixbuffer;
style_contexts -> holds the style context of vbox and hbox and some button chars */
widgets.content=content;
this.fixed_container=fixed_container; //-- the parent of all ToolFrame instances, a Gtk.Fixed
this.root_widget=widgets.eventbox_for_vbox; //-- the ToolFrame instance root widget, an eventbox (for vbox)
this.widgets=widgets; //-- an object, which holds references to all widgets inclusive imagePixBuf
this.style_contexts=style_contexts; //-- an object, which holds references to style contexts (hbox, vbox)
//-- adding buttons_pin.. characters to style_contexts
style_contexts.button_pin_char=standards.button_pin_char;
style_contexts.button_pinned_char=standards.button_pinned_char;
//-- css, style of hbox
cssProvider=new Gtk.CssProvider();
cssProvider.load_from_data(".divider "+standards.divider_css_borderSTR);
style_contexts.hbox=widgets.hbox.get_style_context();
if (standards.content_visible_atStart) style_contexts.hbox.add_class("divider");
style_contexts.hbox.add_provider(cssProvider,0);
if (standards.titlebar_spacing.constructor === Number) widgets.hbox.spacing=standards.titlebar_spacing;
if (standards.titlebar_margin_start.constructor === Number) widgets.hbox.margin_start=standards.titlebar_margin_start; //--set margin values
if (standards.titlebar_margin_end.constructor === Number) widgets.hbox.margin_end=standards.titlebar_margin_end;
if (standards.titlebar_margin_top.constructor === Number) widgets.hbox.top_right=standards.titlebar_margin_top;
if (standards.titlebar_margin_bottom.constructor === Number) widgets.hbox.bottom_right=standards.titlebar_margin_bottom;
//-- css, style of vbox
cssProvider=new Gtk.CssProvider();
cssProvider.load_from_data("* "+standards.toolframe_css_STR+" .moving "+standards.toolframe_move_css_STR);
style_contexts.vbox=widgets.vbox.get_style_context ();
style_contexts.vbox.add_provider (cssProvider,0);
widgets.vbox.override_background_color (Gtk.StateFlags.NORMAL, standards.toolframe_backgroundColor);
if (standards.toolframe_spacing.constructor === Number) widgets.vbox.spacing=standards.toolframe_spacing;
//-- set content margin values
if (standards.content_margin_start.constructor === Number) widgets.scrolled_window.margin_start=standards.content_margin_start; //--set margin values
if (standards.content_margin_end.constructor === Number) widgets.scrolled_window.margin_end=standards.content_margin_end;
if (standards.content_margin_top.constructor === Number) widgets.scrolled_window.top_right=standards.content_margin_top;
if (standards.content_margin_bottom.constructor === Number) widgets.scrolled_window.bottom_right=standards.content_margin_bottom;
//-- PRIVATE folder on instance - holds x,y (actual position), expanded_width and expanded_height
this[private_key]={
_x:x, _y:y,
_expanded_width:standards.toolframe_expanded_width,
_expanded_height:standards.toolframe_expanded_height}
//-- set toolframe minimum width and height
if (standards.toolframe_minimum_width.constructor === Number) width=standards.toolframe_minimum_width; else width=-1;
if (standards.toolframe_minimum_height.constructor === Number) height=standards.toolframe_minimum_height; else height=-1;
this.root_widget.set_size_request (width, height);
//-- build widget tree
widgets.eventbox_for_hbox.add (widgets.hbox);
widgets.vbox.add (widgets.eventbox_for_hbox);
widgets.scrolled_window.add (content);
widgets.vbox.add (widgets.scrolled_window);
widgets.eventbox_for_vbox.add (widgets.vbox);
fixed_container.add (widgets.eventbox_for_vbox);
//-- instance properties isPinned, isExpanded, push to toolframes prototype array collection
this.isPinned=standards.isPinned; //-- indicates, that the toolframe is pinned
if (standards.content_visible_atStart) this.isExpanded=true; //-- indicates, that the toolframe is expanded
else this.isExpanded=false;
ToolFrame.prototype.toolframes.push(this);
//-- connect to hbox, vbox signals
widgets.eventbox_for_hbox.connect("button-press-event",start_moving);
widgets.eventbox_for_hbox.connect("button-release-event",stop_moving);
widgets.eventbox_for_vbox.connect ("button-press-event",this.set_AsLastChild.bind(this));
widgets.eventbox_for_vbox.connect ("size-allocate",observe_root_widget.bind(this));
//-- in this handler the scrolled_window visibility is set to standards.content_visible_atStart at first show signal
this[private_key].handler_first_show_signal=widgets.scrolled_window.connect("show", observe_first_show_signal);
}
//----------------- CONSTRUCTOR -- END
//-----------------------------------------------------------------------
//------------------PROTOTYPE
ToolFrame.prototype.toolframes=[]; //-- a collection of all toolframes created
ToolFrame.prototype.toolframe_inAction=null; //-- the toolframe, which is moved, when moving takes place
//-- put the ToolFrame instance as last child of the fixed_container, its like increasing zIndex, to bring it on top
ToolFrame.prototype.set_AsLastChild=function ()
{
const children=this.fixed_container.get_children(), l=children.length;
if (this.root_widget !== children[l-1])
{
this.fixed_container.remove (this.root_widget);
this.fixed_container.add (this.root_widget);
}
}
//-- moves the toolframe to x,y (INT) position
ToolFrame.prototype.move=function (x,y)
{
const allocation=this.root_widget.get_allocation (), PRIVATE=this[private_key];
PRIVATE._x=allocation.x=x; PRIVATE._y=allocation.y=y;
observing_size_allocation=false;
this.root_widget.size_allocate (allocation);
observing_size_allocation=true;
}
/* sets the expanded_width and expanded_height, which are stored in a PRIVATE instance folder - width, height INT
you can set minimum_width and minimum_height over set_size_request on root_widget */
ToolFrame.prototype.set_expanded_size=function (width,height)
{
const PRIVATE=this[private_key];
PRIVATE._expanded_width=width; PRIVATE._expanded_height=height;
if (this.isExpanded) observe_root_widget.call (this, this.widgets.eventbox_for_vbox);
}
//-- gets the expanded_width and expanded_height stored in the PRIVATE instance folder
ToolFrame.prototype.get_expanded_size=function ()
{
const PRIVATE=this[private_key];
return { expanded_width: PRIVATE._expanded_width, expanded_height: PRIVATE._expanded_height };
}
//------------------PROTOTYPE -- END
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------
//----------------- PRIVATE objects, properties, methods
let private_key=Symbol (), //-- PRIVATE instance folder key
observing_size_allocation=true, //-- indicates, that the "size-allocate" signal shall be observed for uncontrollable automatic gtk allocation changes on the root widget
isMoving=false, //-- indicates, when moving shall happen inside window "motion-notify-event" signal
move_allocation=null, //-- holds the actual allocation during movement
moveStart_allocation=null, //-- saves the ToolFrame instance allocation (x,y,width,height) at move start
moveStart_eventCoords=null, //-- saves the pointer coordinates at move start -> difference in pointer coordinates equals difference in instance allocation (x,y)
titlebar_margin=0, content_margin=0, //-- saves standards titlebar_margin and content_margin
//-----------------------------------------------------------------------
//------------------------------------------------------ Signal functions
button_minimize_clicked=function (button)
{
const actual_toolframe=button.get_parent().toolframe, PRIVATE=actual_toolframe[private_key],
widgets=actual_toolframe.widgets;
widgets.scrolled_window.set_visible (false);
widgets.button_minimize.set_sensitive (false);
widgets.button_expand.set_sensitive (true);
actual_toolframe.style_contexts.hbox.remove_class ("divider");
actual_toolframe.isExpanded=false;
actual_toolframe.set_AsLastChild ();
},
button_expand_clicked=function (button)
{
const actual_toolframe=button.get_parent().toolframe, PRIVATE=actual_toolframe[private_key],
widgets=actual_toolframe.widgets;
widgets.scrolled_window.set_visible (true);
widgets.button_minimize.set_sensitive (true);
widgets.button_expand.set_sensitive (false);
actual_toolframe.style_contexts.hbox.add_class ("divider");
actual_toolframe.isExpanded=true;
actual_toolframe.set_AsLastChild ();
},
button_pin_clicked=function (button)
{
const actual_toolframe=button.get_parent().toolframe;
actual_toolframe.isPinned=!actual_toolframe.isPinned;
if (actual_toolframe.isPinned) actual_toolframe.widgets.button_pin.label=actual_toolframe.style_contexts.button_pinned_char;
else actual_toolframe.widgets.button_pin.label=actual_toolframe.style_contexts.button_pin_char;
actual_toolframe.set_AsLastChild ();
},
button_close_clicked=function (button) { button.get_parent().toolframe.root_widget.set_visible (false); },
//-- connected to eventbox_for_hbox signal "button-press-event" , initiate moving
start_moving=function (eventbox_for_hbox, event)
{
const actual_toolframe=eventbox_for_hbox.get_children()[0].toolframe;
var eventCoords;
if (actual_toolframe.isPinned) return;
eventCoords=event.get_root_coords(); //-- coords relative to eventbox_for_hbox origin (hbox)
isMoving=true;
move_allocation=actual_toolframe.widgets.eventbox_for_vbox.get_allocation ();
moveStart_allocation=actual_toolframe.widgets.eventbox_for_vbox.get_allocation ();
moveStart_eventCoords={
x: Math.trunc(eventCoords[1]),
y: Math.trunc(eventCoords[2])};
actual_toolframe.style_contexts.vbox.add_class("moving");
ToolFrame.prototype.toolframe_inAction=actual_toolframe;
},
//-- connected to eventbox_for_hbox signal "button-release-event", stops moving, set necessary values back to null
stop_moving=function (eventbox_for_hbox)
{
const actual_toolframe=eventbox_for_hbox.get_children()[0].toolframe;
isMoving=false;
move_allocation=null;
moveStart_allocation=null;
moveStart_eventCoords=null;
ToolFrame.prototype.toolframe_inAction=null;
actual_toolframe.style_contexts.vbox.remove_class("moving");
},
//-- connected to window signal "motion-notify-event", moves the toolframe with pointer device
move_toolframe=function (window, event)
{
var actual_toolframe, PRIVATE, eventCoords;
if (isMoving)
{
actual_toolframe=ToolFrame.prototype.toolframe_inAction, PRIVATE=actual_toolframe[private_key];
eventCoords=event.get_root_coords();
PRIVATE._x=move_allocation.x=Math.trunc(eventCoords[1])-moveStart_eventCoords.x+moveStart_allocation.x;
PRIVATE._y=move_allocation.y=Math.trunc(eventCoords[2])-moveStart_eventCoords.y+moveStart_allocation.y;
observing_size_allocation=false;
actual_toolframe.root_widget.size_allocate (move_allocation);
observing_size_allocation=true;
}
},
/* connected to eventbox_for_vbox signal "size-allocate", overwrites the gtk layout coords, dimensions
gtk layout replaces the tool frame and its dimensions according to its inner rules,
thats not very helpful, if the tool frame should be placed at different position, or should show up with different width and height, than gtk layout calculates.
so to force gtk to accept different dimensions, the gtk signal "size allocate" for the tool frame (eventbox_for_vbox) is observed */
observe_root_widget=function (eventbox_for_vbox)
{
var gtk_allocation, replacing, PRIVATE;
if (observing_size_allocation)
{
gtk_allocation=eventbox_for_vbox.get_allocation (), replacing=false, PRIVATE=eventbox_for_vbox.toolframe[private_key];
if (gtk_allocation.x != PRIVATE._x)
{
replacing=true;
gtk_allocation.x=PRIVATE._x;
}
if (gtk_allocation.y != PRIVATE._y)
{
replacing=true;
gtk_allocation.y=PRIVATE._y;
}
if (eventbox_for_vbox.toolframe.isExpanded)
{
if (PRIVATE._expanded_width.constructor === Number && gtk_allocation.width!=PRIVATE._expanded_width)
{
replacing=true;
gtk_allocation.width=PRIVATE._expanded_width;
}
if (PRIVATE._expanded_height.constructor === Number && gtk_allocation.height!=PRIVATE._expanded_height)
{
replacing=true;
gtk_allocation.height=PRIVATE._expanded_height;
}
}
if (replacing)
{
observing_size_allocation=false; //-- prohibit calls of size_allocate to infinity, because next line is causing another size-allocate event, which is immediately worked through
this.root_widget.size_allocate (gtk_allocation); //-- causes again a size-allocate event
this.root_widget.set_clip (gtk_allocation);
observing_size_allocation=true; //-- additionally size-allocate event is now worked through, allow observing again
}
}
},
/* connected to scrolled_window (holds content) signal "show"; is needed to set the visibility according to standards content_visible_atStart property at first show signal
after executing one time the handler is disconnected */
observe_first_show_signal=function (scrolled_window)
{
var PRIVATE=scrolled_window.get_parent().get_parent().toolframe[private_key];
scrolled_window.set_visible(ToolFrame.standards.content_visible_atStart);
scrolled_window.disconnect (PRIVATE.handler_first_show_signal);
PRIVATE.handler_first_show_signal=null
},
//------------------------------------------------------ Signal functions -- END
//-----------------------------------------------------------------------
//-- returns the image pixelbuffer from URL or PATH
get_pixbuf_from_URLorPATH=function (URLorPATH)
{
var file, pixbuf=null;
//-- URL contains //
if (URLorPATH.indexOf("//")>-1)
{
file=Gio.File.new_for_uri (URLorPATH);
try { pixbuf=GdkPixbuf.Pixbuf.new_from_stream (file.read (null), null); }
catch (error) { log (error+" - "+URLorPATH) }
return pixbuf;
}
else return GdkPixbuf.new_from_file (URLorPATH);
};
//-- connect to window signals
window.connect ("motion-notify-event", move_toolframe);
//----------------- PRIVATE objects, properties, methods
//------------------------------------------------------------------------------------------------------------------------------------
//----------------- STATIC object ToolFrame standards
ToolFrame.standards={
isPinned: false, //-- indicates, if the tool frame can move
toolframe_minimum_width: "auto", //-- minimum width of tool frame in minimize appearance
toolframe_minimum_height: "auto", //-- minimum height of tool frame in minimize apperance
toolframe_expanded_width: "auto", //-- width of tool frame in expand appearance
toolframe_expanded_height: "auto", //-- height of tool frame in expand appearance
image_width: "auto", //-- image minimum width and height
image_height: 24,
icon_size: Gtk.IconSize.LARGE_titlebar, //-- Look at Gtk.IconSize (24px)
button_width: "auto", //-- button minimum width and height
button_height: "auto",
toolframe_spacing: 2, titlebar_spacing: 2, //-- vbox, hbox spacing
titlebar_margin_start: 2, titlebar_margin_end:2, titlebar_margin_top:2, titlebar_margin_bottom:2, //-- hbox margin values
content_margin_start: 2, content_margin_end:2, content_margin_top:2, content_margin_bottom:2, //-- content margin values
content_visible_atStart: false, //-- indicates, if content shall be visible at start
buttons_creation: { minimize_expand:true, pin:true, close:true }, //-- indicates, which buttons shall be created
button_minimize_char: "u25B4", //-- button characters
button_expand_char: "u25BE",
button_pin_char: "u21C4",
button_pinned_char: "u21B9",
button_close_char: "X",
button_tooltip: true, //-- indicates, if tooltips shall be shown by hovering buttons
//-- css style strings
toolframe_css_STR: "{ border:1px solid black }",
toolframe_move_css_STR: "{ border-style:dashed }",
toolframe_backgroundColor: new Gdk.RGBA ({ red:1, green:1, blue:1, alpha:1}), //-- toolframe background color
title_css_STR: "{ font-weight:bold }",
buttons_css_STR: "{}",
divider_css_borderSTR: "{ border-bottom-width:1px; border-bottom-style:solid; border-bottom-color:black }", //-- divider between titlebar and content -> hbox border bottom
}
//-- standards titlebar_margin, content_margin
Object.defineProperties (ToolFrame.standards,{
titlebar_margin : { get: () => titlebar_margin, set: function (value) {
titlebar_margin=value;
this.titlebar_margin_start=value; this.titlebar_margin_end=value;
this.titlebar_margin_top=value;this.titlebar_margin_bottom=value;}, enumerable:true, configurable:false },
content_margin : { get: () => content_margin, set: function (value) {
content_margin=value;
this.content_margin_start=value; this.content_margin_end=value;
this.content_margin_top=value;this.content_margin_bottom=value;}, enumerable:true, configurable:false }});
//----------------- STATIC object ToolFrame standards -- END
//------------------------------------------------------------------------------------------------------------------------------------
} //-----> blockscope Class ToolFrame
/* ==================================================================================================================================
CLASS ToolFrame -- END
================================================================================================================================== */
let file=Gio.File.new_for_uri("https://i.ytimg.com/vi/fa5e_r6ZPoM/maxresdefault.jpg"),
image=Gtk.Image.new_from_pixbuf (GdkPixbuf.Pixbuf.new_from_stream(file.read(null),null));
new ToolFrame(fixed_container,20, 20, "http://www.iconeasy.com/icon/png/File%20Type/Software%20Files/Txt.png", "Text Viewer", "view text", new Gtk.Label ({label:"hello Worldn Hello World Hello World"}));
ToolFrame.standards.toolframe_expanded_width=500;
ToolFrame.standards.toolframe_expanded_height=300;
ToolFrame.standards.buttons_width=24;
new ToolFrame(fixed_container,20, 60, "http://icons.iconseeker.com/png/fullsize/glaze/folder-image.png", "Image Viewer", "view image", image);
window.add(fixed_container);
window.set_title("Toolframe Example");
window.connect('destroy', () => { Gtk.main_quit(); });
window.set_size_request (740, 600);
window.show_all(); Gtk.main();
这是我的错。
为了在绘图动作(zIndex)上带来一个小部件,每次点击发生在小部件内部,我从固定容器中删除它,并在最后一个子添加它,这导致了奇怪的动作。
我现在使用Gtk。覆盖zIndex和每个工具框架都有自己的Gtk。固定容器作为舞台,并添加到Gtk.Overlay.
我有一个更简单的图像示例。类MovingImages。
但是如何将容器(图像周围的虚线框)更改为小于图像的定义宽度和高度?
#!/usr/bin/gjs
const Gtk= imports.gi.Gtk,
Gio= imports.gi.Gio,
GdkPixbuf= imports.gi.GdkPixbuf;
Gtk.init(null);
const window= new Gtk.Window(),
box= new Gtk.Box (),
overlay= new Gtk.Overlay();
box.add (new Gtk.Label ({ label:"Drag The Images!", hexpand:true, halign:3, valign:3 }))
//-- class MovingImage
{
var MovingImage=function (overlay, x, y, image_url)
{
let file=Gio.File.new_for_uri (image_url),
image=Gtk.Image.new_from_pixbuf (GdkPixbuf.Pixbuf.new_from_stream(file.read(null),null)),
cssProvider=new Gtk.CssProvider(), allocation;
this.overlay=overlay;
this.stage=new Gtk.Fixed ();
this.container=new Gtk.EventBox ();
this.image=image;
this.container.movingImage=this; //-- circular reference
cssProvider.load_from_data("* {border:1px dashed black;}");
this.container.get_style_context().add_provider (cssProvider,0);
this.container.add (image);
this.stage.put (this.container,x,y);
overlay.add_overlay (this.stage);
overlay.set_overlay_pass_through(this.stage,true);
this.container.connect ("button-press-event", container_button_down);
this.container.connect ("button-release-event", container_button_up);
}
MovingImage.prototype.instance_inAction=null;
let isMoving=false,
moveStart_allocation=null,
moveStart_event_coords=null,
container_button_down=function (container, event)
{
const event_coords=event.get_root_coords();
isMoving=true;
MovingImage.prototype.instance_inAction=container.movingImage;
moveStart_allocation=container.get_allocation ();
moveStart_event_coords={
x: Math.trunc(event_coords[1]),
y: Math.trunc(event_coords[2])};
container.movingImage.overlay.reorder_overlay (container.movingImage.stage,-1);
},
container_button_up=function ()
{
isMoving=false;
MovingImage.prototype.instance_inAction=null;
moveStart_allocation=null;
moveStart_event_coords=null;
},
container_move=function (window, event)
{
var event_coords, movingImage;
if (isMoving)
{
event_coords=event.get_root_coords();
movingImage=MovingImage.prototype.instance_inAction;
movingImage.stage.move (movingImage.container,
Math.trunc(event_coords[1]-moveStart_event_coords.x+moveStart_allocation.x),
Math.trunc(event_coords[2]-moveStart_event_coords.y+moveStart_allocation.y));
}
};
window.connect ("motion-notify-event", container_move);
}
//-- class MovingImage -- END
overlay.add (box);
window.add (overlay);
let image1=new MovingImage (overlay,20,20,"https://icons.iconarchive.com/icons/shrikant-rawa/animals/128/dog-icon.png"),
image2=new MovingImage (overlay,100,60,"https://icons.iconarchive.com/icons/martin-berube/square-animal/128/Bull-icon.png");
window.set_title("MovingImage Example");
window.connect('destroy', () => { Gtk.main_quit(); });
window.set_size_request (640, 480);
window.show_all(); Gtk.main();
要改变宽度和高度,我必须连接到"size-allocate"信号,并始终覆盖分配this.container.connect ("size-allocate", reallocate_container);
reallocate_container=function (container)
{
const allocation=container.get_allocation ();
allocation.width=50;
allocation.height=50;
container.set_allocation(allocation);
container.set_clip (allocation);
}
没有办法设置宽度和高度没有这个?完整的更改示例:
#!/usr/bin/gjs
const Gtk= imports.gi.Gtk,
Gio= imports.gi.Gio,
GdkPixbuf= imports.gi.GdkPixbuf;
Gtk.init(null);
const window= new Gtk.Window(),
box= new Gtk.Box (),
overlay= new Gtk.Overlay();
box.add (new Gtk.Label ({ label:"Drag The Images!", hexpand:true, halign:3, valign:3 }))
//-- class MovingImage
{
var MovingImage=function (overlay, x, y, image_url)
{
let file=Gio.File.new_for_uri (image_url),
image=Gtk.Image.new_from_pixbuf (GdkPixbuf.Pixbuf.new_from_stream(file.read(null),null)),
cssProvider=new Gtk.CssProvider(), allocation;
this.overlay=overlay;
this.stage=new Gtk.Fixed ();
this.container=new Gtk.EventBox ();
this.image=image;
this.container.movingImage=this; //-- circular reference
cssProvider.load_from_data("* {border:1px dashed black;}");
this.container.get_style_context().add_provider (cssProvider,0);
this.container.add (image);
this.stage.put (this.container,x,y);
overlay.add_overlay (this.stage);
overlay.set_overlay_pass_through(this.stage,true);
this.container.connect ("size-allocate", reallocate_container);
this.container.connect ("button-press-event", container_button_down);
this.container.connect ("button-release-event", container_button_up);
}
MovingImage.prototype.instance_inAction=null;
let isMoving=false,
moveStart_allocation=null,
moveStart_event_coords=null,
container_button_down=function (container, event)
{
const event_coords=event.get_root_coords();
isMoving=true;
MovingImage.prototype.instance_inAction=container.movingImage;
moveStart_allocation=container.get_allocation ();
moveStart_event_coords={
x: Math.trunc(event_coords[1]),
y: Math.trunc(event_coords[2])};
container.movingImage.overlay.reorder_overlay (container.movingImage.stage,-1);
},
container_button_up=function ()
{
isMoving=false;
MovingImage.prototype.instance_inAction=null;
moveStart_allocation=null;
moveStart_event_coords=null;
},
container_move=function (window, event)
{
var event_coords, movingImage;
if (isMoving)
{
event_coords=event.get_root_coords();
movingImage=MovingImage.prototype.instance_inAction;
movingImage.stage.move (movingImage.container,
Math.trunc(event_coords[1]-moveStart_event_coords.x+moveStart_allocation.x),
Math.trunc(event_coords[2]-moveStart_event_coords.y+moveStart_allocation.y));
}
},
reallocate_container=function (container)
{
const allocation=container.get_allocation ();
allocation.width=50;
allocation.height=50;
container.set_allocation(allocation);
container.set_clip (allocation);
}
window.connect ("motion-notify-event", container_move);
}
//-- class MovingImage -- END
overlay.add (box);
window.add (overlay);
let image1=new MovingImage (overlay,20,20,"https://icons.iconarchive.com/icons/shrikant-rawa/animals/128/dog-icon.png"),
image2=new MovingImage (overlay,100,60,"https://icons.iconarchive.com/icons/martin-berube/square-animal/128/Bull-icon.png");
window.set_title("MovingImage Example");
window.connect('destroy', () => { Gtk.main_quit(); });
window.set_size_request (640, 480);
window.show_all(); Gtk.main();