Gtkmm:如何将静态列 headers 添加到 Gtk::ListBox
Gtkmm: how to add static column headers to a Gtk::ListBox
我的应用程序中有一个 Gtk::ListBox
,目前包含 Gtk::ListBoxRow
objects,它们本身包含:
- A
Gtk::Entry
(也称为编辑框)。
- 一个
Gtk::ColorButton
.
小部件的当前视觉布局如下:
-------------------------
| Entry1 | ColorButton1 |
-------------------------
| Entry2 | ColorButton2 |
-------------------------
...
我想在两列中添加一个 static header(我不需要在执行期间更改它)。类似于:
-------------------------
| Title1 | Title2 | <-- Notice how the headers are aligned to the columns below.
-------------------------
| Entry1 | ColorButton1 |
-------------------------
| Entry2 | ColorButton2 |
-------------------------
...
其中 Title1
和 Title2
只是某种标签。我还没有找到任何关于如何在线执行此操作的示例,并且文档在涉及 Gtk::ListBox
es.
时缺乏清晰度(在我看来)
我该怎么做?
P.S。我也会接受 C 或 Python 中的答案,或者 link 到一个清晰的在线示例。
我遇到了同样的问题。我使用 vala 解决了这个问题,而且我确信使用 c++ 可以轻松实现相同的方法,因为这里使用的所有 oop 功能在 c++ 中也可用:
一个ListBoxRow可以有一个表头,所以我们可以在第一行添加一个表头。从 ListBoxRow 定义派生的 class,并填充其中的行小部件。
public class ListBoxRowWithData: ListBoxRow{
public int id;
public int email;
public int name;
public Gtk.Label label_id;
public Gtk.Entry entry_email;
public Gtk.Entry entry_name;
// these static variables will hold widths of your widgets in your row
public static int id_width;
public static int em_width;
public static int nm_width;
...
public ListBoxRowWithData (int _id, string _email, string _name) {
id = _id; // you can also use an initializer list in c++
email = _email;
name = _name;
//create your widgets
label_id = new Gtk.Label(id.to_string());
entry_email = new Gtk.Entry(); entry_email.set_text(email);
entry_name = new Gtk.Entry(); entry_name.set_text(name);
// pack your widgets in a box
Gtk.Box rbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
rbox.pack_start (label_id, true, true, 0); // trues and falses must match with headers' trues and falses
rbox.pack_start (entry_email, true, true, 0);
rbox.pack_start (entry_name, true, true, 0);
...
this.add(rbox);
}
// using below method, we will get widths of the first row, and set them
// as widths of the header labels.
public void init_widths(){
// in vala and c++ static ints are automatically set to 0 when you declare them
if(id_width == 0){
id_width = label_id.get_allocated_width();
em_width = entry_email.get_allocated_width();
nm_width = entry_name.get_allocated_width();
}
}
}
并在包含您的列表框的 window class 中定义以下方法:
public void align_my_header(){
// listbox has no built-in something like a table header
// my solution is to set a row header to the first row,
// by updating title sizes based on row contents.
// an arrow function is used here. you can use class methods.
listbox.set_header_func((_row, _before)=>{
// Dynamic Type Casting from base class to derived class
var row = _row as ListBoxRowWithData;
// create your "fake" header here.
var fake_header = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
// those below are header labels
var id = new Gtk.Label("id");
var em = new Gtk.Label("email");
var nm = new Gtk.Label("name");
fake_header.pack_start (id, true, true, 0); // trues and falses must match with row widgets' trues and falses
fake_header.pack_start (em, true, true, 0);
fake_header.pack_start (nm, true, true, 0);
//check if the row is the first one (invariant to sort operations which is nice), we don't want other rows having headers
if(row.get_index()==0){
// When realize signal is emmitted, widgets allocates their widths already
fake_header.realize.connect(()=>{
// we get widgets' widths, and set them as header widths here
row.init_widths();
id.set_size_request(ListBoxRowWithData.id_width, -1);// access static varibles here
em.set_size_request(ListBoxRowWithData.em_width, -1);
nm.set_size_request(ListBoxRowWithData.nm_width, -1);
});
row.set_header(fake_header);
fake_header.show_all();
}else{
row.set_header(null);
}
});
}
// populate your listbox in your window class where you need, in a loop for instance:
listbox.add (new ListBoxRowWithData(id, email, name));
最后在创建列表框后在 window class 的构造函数中调用 align_my_header() 方法。
完整的实现可以在这里看到:https://gitlab.com/aferust/sqlitewtview/blob/master/src/window2.vala
https://gitlab.com/aferust/sqlitewtview/blob/master/win_res/sshot2.png
我的应用程序中有一个 Gtk::ListBox
,目前包含 Gtk::ListBoxRow
objects,它们本身包含:
- A
Gtk::Entry
(也称为编辑框)。 - 一个
Gtk::ColorButton
.
小部件的当前视觉布局如下:
-------------------------
| Entry1 | ColorButton1 |
-------------------------
| Entry2 | ColorButton2 |
-------------------------
...
我想在两列中添加一个 static header(我不需要在执行期间更改它)。类似于:
-------------------------
| Title1 | Title2 | <-- Notice how the headers are aligned to the columns below.
-------------------------
| Entry1 | ColorButton1 |
-------------------------
| Entry2 | ColorButton2 |
-------------------------
...
其中 Title1
和 Title2
只是某种标签。我还没有找到任何关于如何在线执行此操作的示例,并且文档在涉及 Gtk::ListBox
es.
我该怎么做?
P.S。我也会接受 C 或 Python 中的答案,或者 link 到一个清晰的在线示例。
我遇到了同样的问题。我使用 vala 解决了这个问题,而且我确信使用 c++ 可以轻松实现相同的方法,因为这里使用的所有 oop 功能在 c++ 中也可用:
一个ListBoxRow可以有一个表头,所以我们可以在第一行添加一个表头。从 ListBoxRow 定义派生的 class,并填充其中的行小部件。
public class ListBoxRowWithData: ListBoxRow{
public int id;
public int email;
public int name;
public Gtk.Label label_id;
public Gtk.Entry entry_email;
public Gtk.Entry entry_name;
// these static variables will hold widths of your widgets in your row
public static int id_width;
public static int em_width;
public static int nm_width;
...
public ListBoxRowWithData (int _id, string _email, string _name) {
id = _id; // you can also use an initializer list in c++
email = _email;
name = _name;
//create your widgets
label_id = new Gtk.Label(id.to_string());
entry_email = new Gtk.Entry(); entry_email.set_text(email);
entry_name = new Gtk.Entry(); entry_name.set_text(name);
// pack your widgets in a box
Gtk.Box rbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
rbox.pack_start (label_id, true, true, 0); // trues and falses must match with headers' trues and falses
rbox.pack_start (entry_email, true, true, 0);
rbox.pack_start (entry_name, true, true, 0);
...
this.add(rbox);
}
// using below method, we will get widths of the first row, and set them
// as widths of the header labels.
public void init_widths(){
// in vala and c++ static ints are automatically set to 0 when you declare them
if(id_width == 0){
id_width = label_id.get_allocated_width();
em_width = entry_email.get_allocated_width();
nm_width = entry_name.get_allocated_width();
}
}
}
并在包含您的列表框的 window class 中定义以下方法:
public void align_my_header(){
// listbox has no built-in something like a table header
// my solution is to set a row header to the first row,
// by updating title sizes based on row contents.
// an arrow function is used here. you can use class methods.
listbox.set_header_func((_row, _before)=>{
// Dynamic Type Casting from base class to derived class
var row = _row as ListBoxRowWithData;
// create your "fake" header here.
var fake_header = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
// those below are header labels
var id = new Gtk.Label("id");
var em = new Gtk.Label("email");
var nm = new Gtk.Label("name");
fake_header.pack_start (id, true, true, 0); // trues and falses must match with row widgets' trues and falses
fake_header.pack_start (em, true, true, 0);
fake_header.pack_start (nm, true, true, 0);
//check if the row is the first one (invariant to sort operations which is nice), we don't want other rows having headers
if(row.get_index()==0){
// When realize signal is emmitted, widgets allocates their widths already
fake_header.realize.connect(()=>{
// we get widgets' widths, and set them as header widths here
row.init_widths();
id.set_size_request(ListBoxRowWithData.id_width, -1);// access static varibles here
em.set_size_request(ListBoxRowWithData.em_width, -1);
nm.set_size_request(ListBoxRowWithData.nm_width, -1);
});
row.set_header(fake_header);
fake_header.show_all();
}else{
row.set_header(null);
}
});
}
// populate your listbox in your window class where you need, in a loop for instance:
listbox.add (new ListBoxRowWithData(id, email, name));
最后在创建列表框后在 window class 的构造函数中调用 align_my_header() 方法。
完整的实现可以在这里看到:https://gitlab.com/aferust/sqlitewtview/blob/master/src/window2.vala https://gitlab.com/aferust/sqlitewtview/blob/master/win_res/sshot2.png