1. 程式人生 > >.NET Core 跨平臺 GUI 開發之 GTtkSharp 初級篇

.NET Core 跨平臺 GUI 開發之 GTtkSharp 初級篇

.NET Core 跨平臺 GUI 開發之 GTtkSharp 初級篇

  • 本文作為初級篇,適合已經安裝好.NET Core 環境以及 Gtk 環境,並具備了 C#開發基礎知識,能跑一些簡單的例子,希望更深入瞭解開發 GTK 程式的同學。本文主要內容包括 GTK 的深入介紹、介面佈局、響應式程式設計等
  • 參考 1:x11 gtk qt gnome kde 之間的區別和聯絡(最後有圖) https://blog.csdn.net/lanmayi003/article/details/6584521
  • 參考 2:x11 gtk qt gnome kde 之間的區別和聯絡(講得很明白) https://blog.csdn.net/zhanglianpin/article/details/6441879
  • 參考 3:GtkSharp 教程 https://www.mono-project.com/docs/gui/gtksharp/tutorials/

GTK 來龍去脈

  1. Linux 上的圖形介面可有可無,有需要的話是可以安裝的,作為一個軟體安裝到系統。比如常見的桌面環境有 KDE 和 GNOME,它們不僅是個視窗管理器,還提供了桌面、選單等功能,。桌面管理器顧名思義了,沒有它的話就不能開啟多個視窗不能最大最小化沒有邊框等,所以希望整個系統只跑一個桌面程式的情況就可以不用安裝視窗管理器。windows 使用者按 https://zhidao.baidu.com/question/1372025356510156779.html 這個操作可以體驗一下,請先好儲存當前工作再操作
  2. KDE 和 GNOME 分別基於 Qt 和 Gtk 實現。它們通過一種叫 X11 的協議來通訊,不僅控制視窗最大最小化縮放和邊框,還提供桌面、工具狀態列等
  3. X11 可用於幾乎所有已有的現代作業系統,基於客戶端——伺服器模型。跟常規理解不一樣,此處從應用程式視角看:本地主機 X 顯示程式提供顯示服務,遠端應用使用了該顯示服務,所謂它是客戶端。就像遠端控制桌面一樣,本地提供顯示,遠端伺服器作為客戶端。當它們都在同一主機,看起來就是一個整體。比如蘋果電腦,X 協議整合在系統核心,所以效能好很多
  4. 層次關係:linux 本身-->X 伺服器<--通過 X 協議交談-->視窗管理器-->X 應用程式。X 服務實現有 Xfree86、Xorg、Xnest 等,KDE 和 GNOME 屬於 X 客戶端。我們開發的桌面程式屬於 X 客戶端
  5. 為了方便開發人員,將 X 協議封裝,於是有了 XLib。類似於 windows 上的 關於通訊功能的 ws2_32.dll,提供了訪問系統功能的 api,比如監聽埠和從系統緩衝區讀取埠接收的資料。很多常用功能為了方便使用,於是有了 C 函式庫 GLib,類似於 C#裡面的 System 空間的很多函式,包括字串處理、list 資料結構等。接著是 Gdk,結合 GLib,將 XLib 函式庫封裝得更友好,比如 C#中將 ws2_32.dll 一些功能封裝成 UdpClient。再往上就是 Gtk 了,依賴於 Gdk,提供基礎的工具包和 widget,是上層 GUI 派生的基礎。類似於 NewLife 的 X 元件裡面的 ApiClient 這種網路庫,基於 UdpClient 等封裝。Gtk 獲得了面向物件特性和可擴充套件性之後,就是 Gtk+,翻譯成 CSharp 就是 GtkSharp。類似於 X 元件,提供了很多功能和工具,提供給各個應用系統做業務。層次關係:x 協議-->XLib,GLib-->Gdk-->Gtk+

介面佈局

  • Gtk#有被稱為容器物件的東西,用於指導視窗或其他容器內的佈局和放置。此技術不同於使用 System.Windows.Forms 工具箱定位的常用方法。GTK#和 System.Windows.Forms 之間的主要區別在於:使用 GTK#的應用程式不使用絕對座標或固定座標來定位視窗小部件。使用 GTK 工具包的應用程式通過佈局和包裝容器物件為其介面建立正確的佈局
  • 目前,最常用的就是水平和垂直包裝盒,即 HBox 和 VBox

Box

  • 對齊控制元件的首選方法。優點:與螢幕尺寸無關、更容易國際化
  • 水平盒子(HBox)和垂直(VBox)盒子,對於 VBox,PackStart 將從頂部開始包裝盒子,PackEnd 將從底部開始包裝盒子。對於 HBox,PackStart 將從左到右打包盒子,PackEnd 將從右到左打包盒子。
  • 使用如下,child 引數是要打包到框中的物件。expand 引數控制框是否填充分配給它的區域(true),否則縮小框使其恰好合適框中物件大小。fill 引數控制物件是否填滿框,僅當 expand 為 true 時生效。比如日誌文字框,縮放的時候,文字框跟隨視窗大小變化
box1.PackStart(Widget child, bool expand, bool fill, int padding);
  • 建立函式如下,homogeneous 表示框中的每個物件是否具有相同的大小(即,HBox 中的寬度相同或 vBox 中的高度相同),等效於 Pack 方法中 expand 為 true。spacing 表示框中物件間距,而 padding 會在物件兩側都新增
HBox hbox1 = new HBox(bool homogeneous, int  spacing);
  • 參考:https://www.mono-project.com/docs/gui/gtksharp/widgets/packing-with-boxes/

Table

  • 除了使用 HBox 和 VBox 進行打包外,還可以使用 Table 物件進行打包。這個有點像 html 的 table,適合方方正正大小差不多的空間集合,比如計算器。
  • Table 的宣告如下,rows、columns 分別指要建立的行和列。homogeneous 為 true 表示所有的表框大小設定為大小最大那個控制元件,為 false 則各行和列的大小根據各行列中大小最大那個控制元件決定
Table table1 = new Table(int rows, int columns, bool homogeneous);

// 假如建立2*2的表格
 0          1          2
0+----------+----------+
 |          |          |
1+----------+----------+
 |          |          |
2+----------+----------+
  • 新增控制元件方式如下,leftAttach,rightAttach,topAttach,bottomAttachach 分別代表表中控制元件的左右上下邊所在位置。例如,希望某個控制元件佔據第一行兩個格子,那麼 leftAttach=0,rightAttach=2,topAttach=0,bottomAttachach=1。
  • xOptions 和 yOptions 指定打包選項
    • Gtk.AttachOptions.Fill:如果表框大於視窗小部件,並且指定了 Fill,則視窗小部件將展開以使用所有可用空間
    • Gtk.AttachOptions.Shrink:如果為 Table 中控制元件分配了較少的空間,然後又請求了空間(通常是由使用者調整視窗大小),則通常將視窗小部件推離視窗底部並消失。如果指定了 Shrink ,則小部件將隨表格收縮
    • Gtk.AttachOptions.Expand:這將導致 Table 擴充套件以佔用視窗中的所有剩餘空間
  • xPadding 和 yPadding 分別控制 Table 內控制元件在原位置基礎上表框到控制元件的左右或者上下距離
table1.Attach (        Widget            child,
                       int               leftAttach,
                       int               rightAttach,
                       int               topAttach,
                       int               bottomAttach,
                       Gtk.AttachOptions xOptions,
                       Gtk.AttachOptions yOptions,
                       int               xPadding,
                       int               yPadding );
  • 參考:https://www.mono-project.com/docs/gui/gtksharp/widgets/packing-with-tables/

其它佈局

  • 固定容器 fixed,容器內控制元件相對於視窗左上角位置,並且位置可動態修改
Fixed fixed1 = new Fixed();
fixed1.Put(widget, x, y);
fixed1.Move(widget, x, y);
  • 佈局容器 layout,實現了無限的滾動區域,適合動態載入很多空間的情況,比如相簿
Layout layout1 = new Layout(hadjustment, vadjustment);
layout1.Put(widget, x, y);
layout1.Move(widget, x, y);
  • 框架 frame,類似於 winform 的 groupbox,框上有個標籤。LabelXalign 和 LabelYalign 屬性分別表示 Label 在框上的水平和垂直位置,範圍是 0-1。LabelXalign 預設 0,標籤位於左邊,LabelYalign 未使用。ShadowType 屬性決定外框樣式 Gtk.Shadow.EtchedIn 為預設值
Frame frame1 = new Frame("Label");
frame1.LabelXalign = 0.3;
frame1.ShadowType = ShadowType.Out;

響應式程式設計

  • 本節介紹多執行緒 GTK#程式設計以及如何保持 GTK#應用程式的響應速度
  • 和 winform 一樣,更新 UI 應該由建立 UI 的執行緒來執行,否則可能會崩潰。可用 Gtk.Application.Invoke 來請求 GUI 執行緒完成更新
using Gtk;

class Demo {
  static Label label;

  static void Main ()
  {
    Application.Init ();
    Window w = new Window ("Cray on a Window");
    label = new Label ("Busy computing");

    Thread thr = new Thread (new ThreadStart (ThreadRoutine));
    thr.Start ();
    Application.Run ();
  }

  static void ThreadRoutine ()
  {
        LargeComputation ();
        Gtk.Application.Invoke (delegate {
              label.Text = "Done";
        });
  }

  static void LargeComputation ()
  {
    // lots of processing here
  }
}
  • 定時器 GLib.Timeout,類似 System.Windows.Forms.Timer。不同之處在於,GLib.Timeout 總是在擁有 Gtk 主迴圈的執行緒上被呼叫
 void StartClock ()
     {
         // 每秒呼叫一次update_status

         GLib.Timeout.Add (1000, new GLib.TimeoutHandler (update_status));
     }

     bool update_status ()
     {
         time_label.Text = DateTime.Now.ToString ();

         // 返回true則在下一次超時時間到達後再次呼叫update_status
         // 返回false則終止定時器

         return true;
     }

最後

  • 本文介紹了 Gtk 在整個 Linux 桌面開發所處位置、列舉了幾個佈局容器、以及響應式程式設計。掌握以上知識,可大大提高程式設計效率,全部操作一遍即可理解並掌握