如何在GtkGrid中移动小部件?
我现在在用gtk-rs编写一些Gtk程序。我试图通过删除并重新附着来移动网格中的控件,但在重新附着子控件时,界面上它根本没有移动,尽管从网格中查询位置时位置已经改变。
gtk = { version = "0.11.3", package = "gtk4", features = ["v4_22"] }
gtk-layer-shell = { version = "0.8.0", package = "gtk4-layer-shell" }
use gtk::glib;
use gtk::glib::{CLONE_MACRO_LOG_DOMAIN, clone};
use gtk::{Application, ApplicationWindow, Button, GestureDrag, Grid, prelude::*};
use gtk_layer_shell::{Layer, LayerShell};
use std::cell::{Cell};
use std::env;
const CELL_SIZE: i32 = 80;
const CELL_GAP: i32 = 16;
const COLS: i32 = 4;
const ROWS: i32 = 8;
fn main() -> gtk::glib::ExitCode {
unsafe {
env::set_var("G_MESSAGES_DEBUG", CLONE_MACRO_LOG_DOMAIN);
env::set_var("G_MESSAGES_DEBUG", "all");
}
let application = Application::builder()
.application_id("application")
.build();
application.connect_activate(build_ui);
application.run()
}
// convert col/row count into width/height
fn widget_size(cols: i32, rows: i32) -> (i32, i32) {
(
CELL_GAP * (cols - 1) + CELL_SIZE * cols,
CELL_GAP * (rows - 1) + CELL_SIZE * rows,
)
}
// build window
fn build_ui(app: &Application) {
let window = ApplicationWindow::builder()
.application(app)
.can_focus(false)
.title("Grid Layout")
.build();
// doesn't matter here, the problem is no different with or without layer shell
window.init_layer_shell();
window.set_layer(Layer::Top);
// calculate a 4x8 grid widget size,
// that is (4 cols + 3 gaps) x (8 rows + 7 gaps)
let (grid_width, grid_height) = widget_size(4, 8);
let grid = Grid::builder()
.row_spacing(CELL_GAP)
.column_spacing(CELL_GAP)
.width_request(grid_width)
.height_request(grid_height)
.build();
let button = Button::builder()
.label("drag")
.width_request(CELL_SIZE)
.height_request(CELL_SIZE)
.build();
// button position
let position = Cell::new((0, 0));
let (x, y) = position.get();
// the original position
grid.attach(&button, x, y, 1, 1);
let drag = GestureDrag::new();
// on drag end, calculates how many col/row should offset from relative position
drag.connect_drag_end(clone!(
#[weak]
button,
#[weak]
grid,
move |_, offset_x, offset_y| {
let (c, r, _, _) = grid.query_child(&button); // the original position
println!("origin {} {}", c, r);
grid.remove(&button);
let x_movement = (offset_x / (CELL_SIZE + CELL_GAP) as f64) as i32;
let y_movement = (offset_y / (CELL_SIZE + CELL_GAP) as f64) as i32;
println!("offset {} {}", x_movement, y_movement);
position.update(|(x, y)| (x + x_movement, y + y_movement)); // cache the position
let (x, y) = position.get();
println!("new {} {}", x, y); // new position
grid.attach(&button, x, y, 1, 1);
let (c, r, _, _) = grid.query_child(&button); // confirm result of re-attaching
println!("result {} {}", c, r);
grid.queue_draw();
}
));
button.add_controller(drag);
window.set_child(Some(&grid));
window.present();
}
按钮一开始显示在窗口的左上角。然后我把它向下拖动一格,输出是:
origin 0 0
offset 0 1
new 0 1
result 0 1
但它仍然停留在左上角。然后再拖动一次,输出:
origin 0 1
offset 0 1
new 0 2
result 0 2
仍然停留在左上角,但从网格查询到的原始位置是 (0,1),所以重新附着可能是起作用的。如何才能让它真正工作?
解决方案
在构建网格时添加 column_homogeneous (true) 和 row_homogeneous (true):
let grid = Grid::builder()
.row_spacing(CELL_GAP)
.column_spacing(CELL_GAP)
.width_request(grid_width)
.height_request(grid_height)
.column_homogeneous (true)
.row_homogeneous (true)
.build();
默认情况下,网格中的每一行和每一列都有各自的大小。由于其他行和列都是空的,这些大小被设为零,因此按钮总是出现在左上角,尽管它之前的行和列可能是零尺寸。
将 *_homogeneous 设置为 true 可以让所有行和列即使为空时也具有相同的大小。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。