日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

【.NET Core 跨平台 GUI 开发】第二篇:Gtk# 布局入门,初识HBox 和 VBox

發(fā)布時間:2023/12/4 asp.net 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【.NET Core 跨平台 GUI 开发】第二篇:Gtk# 布局入门,初识HBox 和 VBox 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這是 Gtk# 系列博文的第二篇。在上一篇博文《編寫你的第一個 Gtk# 應用》中,我們提到“一個 Gtk.Window 只能直接包含一個部件”。這意味著,在不做其他額外操作的情況下,如果你向一個 GtkWindow 中添加了一個 GtkLabel (就像上一篇博文中的 Hello World一樣)那么你將不能再添加一個按鈕進去。

如過你嘗試這么做,你會發(fā)現(xiàn)按鈕并不會顯示在窗體上,同時在控制臺會輸出一個警告:嘗試將一個 GtkButton 類型的部件添加到 GtkWindow 中,但是 GtkWindow 作為 GtkBin 的子類型每次只能容納一個部件,它現(xiàn)在已經(jīng)容納了一個 GtkLabel 類型的部件。

Attempting to add a widget with type GtkButton to a GtkWindow, but as a GtkBin subclass a GtkWindow can only contain one widget at a time; it already contains a widget of type GtkLabel 。

如果我們的 GUI 程序只能顯示一個部件,那么就太尷尬了,只能包含一個部件的窗口也沒有意義。其實我們有很多現(xiàn)成的部件可以解決這個尷尬的問題,常見的比如:VBox、HBox?和?Table?。

在 WinForm 開發(fā)中,我們使用坐標來定位控件。在 Gtk# 中當然也支持使用這種方式布局控件,但是首選的方式還是使用盒子(Box)。盒子是不可見的容器部件,他們有兩種形式:水平(HBox)和垂直(VBox)。你可以把所有的部件(Widget)想象成一個又一個的盒子,然后他們整齊的排列好,塞滿一個更大的盒子,而這個更大的盒子外面也可以有盒子。這種布局方式與屏幕無關(guān)且能更好的支持國際化。

1、準備項目

和上一篇博文類似,創(chuàng)建一個名為“Gtk.Layouts”的 .NET Core 控制臺應用程序并引入 GtkSharp 組件后,在 Program.cs 文件中鍵入以下代碼:

using System;namespace Gtk.Layouts{
class Program
{
static void Main(string[] args)
{
Application.Init();
var win = new Window("Gtk.Layouts");
win.SetDefaultSize(300, 300);
win.WindowPosition = WindowPosition.Center;
win.DeleteEvent += (s, e) =>
{
Application.Quit();
};
win.ShowAll();
Application.Run();
}
}}

以上代碼在運行后會在屏幕中心展示一個標題為“Gtk.Layouts”大小是 300* 300 的空白 GtkWindow 。

2、HBox 和 VBox

HBox 容器中所有的控件都會水平排列在一行上,現(xiàn)在把 HBox 添加到窗體中,新建一個 InitializeWindow 方法,把窗體的初始化代碼放到這個方法里:

using System;namespace Gtk.Layouts{
class Program
{
static void Main(string[] args)
{
Application.Init();
var win = new Window("Gtk.Layouts");
win.SetDefaultSize(300, 300);
win.WindowPosition = WindowPosition.Center;
win.DeleteEvent += (s, e) =>
{
Application.Quit();
};
InitializeWindow(win);
win.ShowAll();
Application.Run();
}
private static void InitializeWindow(Window window)
{
var hBox = new HBox();
window.Add(hBox);
}
}}

程序運行起來之后,窗體似乎沒什么變化?別緊張,前面說過盒子是不可見的容器,并不會被直接展示出來,現(xiàn)在添加一個按鈕進去看看:

private static void InitializeWindow(Window window)
{
var hBox = new HBox();
window.Add(hBox);
hBox.Add(new Button("我是按鈕"));
}

加入按鈕以后:

按鈕被展示了出來,而且充滿了整個窗體。目前的效果和直接在 GtkWindows 下新增 GtkButton 差不多,再多加幾個按鈕看看:

private static void InitializeWindow(Window window)
{
var hBox = new HBox();
window.Add(hBox);
for (int i = 0; i < 4; i++)
{
hBox.Add(new Button($"我是按鈕{i + 1}號"));
}
}

我們使用 for 循環(huán)添加的 4 個按鈕被整齊的展示在了窗體上,每個按鈕的寬度和高度都相同,而且整個 GtkWindow 的寬度變長了。回想一下上面提到過的:整齊和塞滿。GtkWindow 可以根據(jù)其內(nèi)部控件的需要拓展自身的大小,最大寬度不能超過 32767 像素。如果嘗試調(diào)整窗體的大小會怎么樣?我?guī)湍銍L試了一下,調(diào)整到最小尺寸時是這個模樣:

從 Widget 中派生的 Button 繼承了 Widget 的 SetSizeRequest 方法,這個方法可以設(shè)置部件所需的布局大小。在實際實踐中,通常也不會使用 HBox 的 Add 方法來添加子部件,而是采用功能更加強大的 PackStart 或 PackEnd 方法。與 Add 方法相比,這兩個方法提供了更豐富的控制。

PackStart:

public void PackStart(Widget child, bool expand, bool fill, uint padding)

PackEnd:

public void PackEnd(Widget child, bool expand, bool fill, uint padding)

改動一下代碼,看看會發(fā)生什么事情:????????

private static void InitializeWindow(Window window)
{
var hBox = new HBox();
window.Add(hBox);
for (int i = 0; i < 4; i++)
{
var btn = new Button($"{i + 1}");
btn.SetSizeRequest(30 * (i + 1), 50);
hBox.PackStart(btn, false, false, 3);
}
}

以上代碼設(shè)置了按鈕的大小,并且規(guī)定了內(nèi)邊距:

可以看到按鈕的寬度設(shè)置 padding 都生效了,按鈕變得寬窄不一且與容器和臨近元素拉開了距離。那么 PackStart 和 PackEnd 有什么區(qū)別呢?為了可以更清楚的解釋這個問題,需要引入 VBox 。VBox 和 HBox 相似,兩者最大的區(qū)別就是 VBox 的子部件是從上到下排列的,HBox 是從左到右。

試試使用 VBox 把窗體分為上下兩個部分,并對比一下 PackStar 和 PackEnd 有什么區(qū)別:

private static void InitializeWindow(Window window)
{
var vBox = new VBox();
window.Add(vBox);
var hBox1 = new HBox();
var hBox2 = new HBox();
vBox.PackStart(hBox1, false, false, 5);
vBox.PackStart(hBox2, false, false, 5);
for (int i = 0; i < 4; i++)
{
var btn = new Button($"{i + 1}");
btn.SetSizeRequest(30 * (i + 1), 50);
hBox1.PackStart(btn, false, false, 3);
}
for (int i = 0; i < 4; i++)
{
var btn = new Button($"{i + 1}");
btn.SetSizeRequest(30 * (i + 1), 50);
hBox2.PackEnd(btn, false, false, 3);
}
}

以上的代碼創(chuàng)建了一個 VBox 并添加到了 Window 中,之后新建了兩個 HBox 分別命名為 hBox1 和 hBox2 并添加到了 VBox 中,這個很像我們在組裝鞋架,現(xiàn)在,這個鞋架現(xiàn)在有兩層。兩個 for 循環(huán)分別向 hBox1 和 hBox2 中添加了 4 個按鈕,按鈕添加的順序和文字均相同,唯一的區(qū)別是分別調(diào)用了 PackStart 和 PackEnd 兩種不同的方法:

程序運行后可以看到,第一行按鈕的顯示順序和第二行是相反的。

如何理解這個事情呢?想象一下你現(xiàn)在要把鞋子放在鞋架的其中一層上,并且你只從剩余空間的左邊或者右邊開始擺放鞋子,那么 PackStart 相當于把這個鞋子擺在了剩余空間的最左邊,而 PackEnd 則相當于擺放在最右邊。VBox 中對應的方法也類似,只是將方向換成了上和下,驗證一下看看:

private static void InitializeWindow(Window window)
{
var vBox = new VBox();
window.Add(vBox);
var hBox1 = new HBox();
var hBox2 = new HBox();
vBox.PackStart(hBox1, false, false, 5);
vBox.PackStart(hBox2, false, false, 5);
for (int i = 0; i < 4; i++)
{
var btn = new Button($"{i + 1}");
btn.SetSizeRequest(30 * (i + 1), 50);
hBox1.PackStart(btn, false, false, 3);
}
for (int i = 0; i < 4; i++)
{
var btn = new Button($"{i + 1}");
btn.SetSizeRequest(30 * (i + 1), 50);
hBox2.PackEnd(btn, false, false, 3);
}
var btnBtm = new Button("Bottom");
btnBtm.SetSizeRequest(50, 50);
vBox.PackEnd(btnBtm,false,false,5);
}

以上代碼新創(chuàng)建了一個名為 btnBtm 的按鈕,并通過 PackEnd 方法將其添加到了 VBox 中:

可以看到,名為 btnBtm 的按鈕確實被放在了剩余空間的底部。

3、expand 和?fill 參數(shù)

PackStart 和 PackEnd 方法還有兩個參數(shù),分別為 expand 和 fill 。

expand 就是當 Box 給我們的 Widget 分配了額外的空間后,我們的 Widget 會占住這個空間,不會讓給別人。

fill 就是當 expand 為 TRUE 的時候,我們不僅占用 Box 給我們分配的空間,而且會把自己的界面擴大到這個空間上。

所以,簡單來說,expand = TRUE, fill = FALSE 就是占住空間但是控件本身大小不變;兩個都是TRUE,就是不僅占住空間而且控件也會變得和這個空間一樣大;expand = FALSE,fill就沒了意義。

GtkHBox 中只要 expand 是TRUE,那么,水平方向上一定 fill,所以 fill 參數(shù)此時只影響垂直上是否 fill 。

GtkVBox 中只要 expand 是TRUE,那么,垂直方向上一定 fill,所以 fill 參數(shù)此時只影響水平上是否 fill 。

以上關(guān)于 expand 和 fill 參數(shù)的解釋引用自:Super的博客?中的博文?GTK Box(hbox&vbox)的expand和fill兩個屬性的實踐理解?。是否有些難以理解?言語都很蒼白,幸好我們可以用代碼說話。

現(xiàn)在,可以將窗體寬度調(diào)大一些,比如 500*300 :

win.SetDefaultSize(500, 300);

窗體變大后,我們的 HBox 中出現(xiàn)了空白:

目前代碼中 expand 和 fill 參數(shù)均為 false 所以并不會出現(xiàn)“占滿”和“填充”的現(xiàn)象。當 expand = false 時,fill 參數(shù)沒有意義,那么我們就可以嘗試下,當 expand = true 時,fill 分別為 true 和 false 時在 HBox 下會是什么效果:

private static void InitializeWindow(Window window)
{
var vBox = new VBox();
window.Add(vBox);
var hBox1 = new HBox();
var hBox2 = new HBox();
vBox.PackStart(hBox1, false, false, 5);
vBox.PackStart(hBox2, false, false, 5);
for (int i = 0; i < 4; i++)
{
var btn = new Button($"{i + 1}");
btn.SetSizeRequest(30 * (i + 1), 50);
hBox1.PackStart(btn, true, true, 3);
}
for (int i = 0; i < 4; i++)
{
var btn = new Button($"{i + 1}");
btn.SetSizeRequest(30 * (i + 1), 50);
hBox2.PackEnd(btn, true, false, 3);
}
var btnBtm = new Button("Bottom");
btnBtm.SetSizeRequest(50, 50);
vBox.PackEnd(btnBtm, false, false, 5);
}

代碼中將第一行的按鈕設(shè)置為:沾滿并填充,將第二行的按鈕設(shè)置為:沾滿不填充。

可以看到,“占滿”并“填充”的按鈕將所有的空白區(qū)域全部占領(lǐng)了,而不填充的按鈕則會在分配給他的空白區(qū)域中居中。如果嘗試將 btnBtm 設(shè)置為“占滿”且“填充”,那么畫風會是下面這樣:

總結(jié)

以上是生活随笔為你收集整理的【.NET Core 跨平台 GUI 开发】第二篇:Gtk# 布局入门,初识HBox 和 VBox的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。