Програми для обліку

Українське програмне забезпечення з відкритим кодом

Gtk4

Дописи

Gtk / Gtk4

19.07.2025 13:17 Gtk4

Розробка програм на C# з графічним інтерфейсом Gtk4 | ColumnView - Табличний список

Приклад використання віджету ColumnView - Табличний список

Gtk4 ColumnView

Для програмування використовую Visual Studio Code.
В програмі Visual Studio Code створюємо новий проект
dotnet new console

Додаємо до проекту пакети: GirCore.Gtk та GirCore.GObject
dotnet add package GirCore.Gtk-4.0
dotnet add package GirCore.GObject-2.0.Integration

Запуск програми
dotnet run

Program.cs
using Gtk;
using Gdk;

class Program
{
    static void Main()
    {
        var app = Application.New("ua.org.accounting.factory", Gio.ApplicationFlags.FlagsNone);

        app.OnActivate += (_, args) =>
        {
            FactoryWindow factoryWindow = new(app);
            factoryWindow.Show();
        };

        //Css
        {
            string styleDefaultFile = Path.Combine(AppContext.BaseDirectory, "Default.css");
            var displayDefault = Display.GetDefault();

            if (File.Exists(styleDefaultFile) && displayDefault != null)
            {
                CssProvider provider = CssProvider.New();
                provider.LoadFromPath(styleDefaultFile);
                StyleContext.AddProviderForDisplay(displayDefault, provider, 800);
            }
        }

        app.RunWithSynchronizationContext(null);
    }
}

FactoryWindow.cs
using Gtk;
using GObject;

using static Gtk.Orientation;

partial class FactoryWindow : Window
{
    [Subclass<GObject.Object>]
    partial class Record
    {
        public Guid Uid { get; set; } = Guid.Empty;
        public string? Назва { get; set; }
        public string? Опис { get; set; }
        public int? Кількість { get; set; }
        public Record(string? Назва, string? Опис, int Кількість, Guid Uid) : this()
        {
            this.Назва = Назва;
            this.Опис = Опис;
            this.Кількість = Кількість;
            this.Uid = Uid;
        }
    }

    public FactoryWindow(Application? app) : base()
    {
        Application = app;
        Title = "Перегляд стовпців та фабрика";
        SetDefaultSize(900, 900);

        Box vBox = Box.New(Vertical, 0);
        vBox.MarginTop = vBox.MarginBottom = vBox.MarginStart = vBox.MarginEnd = 10;
        Child = vBox;

        var store = Gio.ListStore.New(Record.GetGType());

        for (int i = 1; i < 100_000; i++)
            store.Append(new Record($"Назва {i}", $"Текст {i} текст {i} \nТекст {i} текст {i}", i, Guid.NewGuid()));

        SingleSelection model = SingleSelection.New(store);
        model.Autoselect = true;

        ColumnView columnView = ColumnView.New(model);

        //1
        {
            SignalListItemFactory factory = SignalListItemFactory.New();
            factory.OnSetup += (factory, e) =>
            {
                ListItem listitem = (ListItem)e.Object;
                listitem.SetChild(new LabelControl());
            };

            factory.OnBind += (factory, e) =>
            {
                ListItem listitem = (ListItem)e.Object;

                LabelControl? label = (LabelControl?)listitem.GetChild();
                label?.SetText(((Record?)listitem.Item)?.Назва);
            };

            ColumnViewColumn column = ColumnViewColumn.New("Назва", factory);
            column.Resizable = true;

            columnView.AppendColumn(column);
        }

        //2
        {
            SignalListItemFactory factory = SignalListItemFactory.New();
            factory.OnSetup += (factory, e) =>
            {
                ListItem listitem = (ListItem)e.Object;
                listitem.SetChild(new LabelControl2());
            };

            factory.OnBind += (factory, e) =>
            {
                ListItem listitem = (ListItem)e.Object;
                Record? record = (Record?)listitem.Item;

                LabelControl2? label = (LabelControl2?)listitem.GetChild();
                label?.SetText(record?.Назва, record?.Кількість.ToString());
            };

            ColumnViewColumn column = ColumnViewColumn.New("Назва\nКількість", factory);
            column.Resizable = true;

            columnView.AppendColumn(column);
        }

        //3
        {
            SignalListItemFactory factory = SignalListItemFactory.New();
            factory.OnSetup += (factory, e) =>
            {
                ListItem listitem = (ListItem)e.Object;
                listitem.SetChild(new LabelControl3());
            };

            factory.OnBind += (factory, e) =>
            {
                ListItem listitem = (ListItem)e.Object;
                Record? record = (Record?)listitem.Item;

                LabelControl3? label = (LabelControl3?)listitem.GetChild();
                label?.SetText(record?.Назва, record?.Опис, record?.Кількість.ToString(), record?.Uid.ToString());
            };

            ColumnViewColumn column = ColumnViewColumn.New("Назва\nОпис\nКількість / Id", factory);
            column.Resizable = true;

            columnView.AppendColumn(column);
        }

        ScrolledWindow scroll = ScrolledWindow.New();
        scroll.SetPolicy(PolicyType.Automatic, PolicyType.Automatic);
        scroll.Vexpand = true;
        scroll.Child = columnView;

        vBox.Append(scroll);
    }
}

LabelControl.cs
using Gtk;

public class LabelControl : Box
{
    Label label;

    public LabelControl() : base()
    {
        SetOrientation(Orientation.Horizontal);
        Valign = Align.Start;

        label = Label.New(null);
        label.Halign = Align.Start;

        Append(label);
    }

    public void SetText(string? text)
    {
        label.SetText(text ?? "");
    }
}

public class LabelControl2 : Box
{
    Label label1;
    Label label2;

    public LabelControl2() : base()
    {
        SetOrientation(Orientation.Vertical);
        Valign = Align.Start;

        {
            label1 = Label.New(null);
            label1.Halign = Align.Start;

            Append(label1);
        }

        {
            Separator separator = Separator.New(Orientation.Vertical);
            Append(separator);
        }

        {
            label2 = Label.New(null);
            label2.Halign = Align.Start;

            Append(label2);
        }
    }

    public void SetText(string? text1, string? text2)
    {
        label1.SetText(text1 ?? "");
        label2.SetText(text2 ?? "");
    }
}

public class LabelControl3 : Box
{
    Label label1;
    Label label2;
    Label label3;
    Label label4;

    public LabelControl3() : base()
    {
        SetOrientation(Orientation.Vertical);
        Valign = Align.Start;

        {
            label1 = Label.New(null);
            label1.Halign = Align.Start;

            Append(label1);
        }

        {
            Separator separator = Separator.New(Orientation.Vertical);
            Append(separator);
        }

        {
            label2 = Label.New(null);
            label2.Halign = Align.Start;

            Expander expander = Expander.New("Опис");
            expander.Child = label2;

            Append(expander);
        }

        {
            Separator separator = Separator.New(Orientation.Vertical);
            Append(separator);
        }

        {
            Box hBox = Box.New(Orientation.Horizontal, 0);
            Append(hBox);

            label3 = Label.New(null);
            label3.Halign = Align.Start;
            hBox.Append(label3);

            Separator separator = Separator.New(Orientation.Horizontal);
            separator.MarginStart = separator.MarginEnd = 10;
            hBox.Append(separator);

            label4 = Label.New(null);
            label4.Halign = Align.Start;
            hBox.Append(label4);
        }
    }

    public void SetText(string? text1, string? text2, string? text3, string? text4)
    {
        label1.SetText(text1 ?? "");
        label2.SetText(text2 ?? "");
        label3.SetText(text3 ?? "");
        label4.SetText(text4 ?? "");
    }
}

Factory.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="GirCore.Gtk-4.0" Version="0.7.0-preview.1" />
    <PackageReference Include="GirCore.GObject-2.0.Integration" Version="0.7.0-preview.1" />
  </ItemGroup>

  <ItemGroup>
    <Content Include="Default.css" CopyToOutputDirectory="PreserveNewest" />
  </ItemGroup>

</Project>

Default.css
label {
    font-family: Arial, Helvetica, sans-serif;
    font-size: 12px;
}

columnview listview row cell:not(:first-child) {
    border-left: 1px solid shade(#9b9ea1, 1.2);
}

Довідка: Як встановити Gtk4 для Linux та Windows

Gtk4 - кросплатформовий набір інструментів для створення графічних інтерфейсів користувача
Gir.Core - обгортка над бібліотеками Gtk4 для мови програмування C#

Visual Studio Code
Віджети Gtk 4
NuGet пакет GirCore.Gtk-4.0
Приклад на GitHub


© accounting.org.ua - 2025