开发者生态
morning
在 Haskell 中制作 GTK 应用程序,第 1 部分
摘要
In this series, we are going to build a todo-list application using Haskell, GTK 4, and the Adwaita library. Adwaita will provide us with many useful widgets and styles. Let's dive in! This series' in...
the
GTK
and
Adwaita
will
with
that
Haskell
you
main
2026-10-06
1 阅读
约5分钟阅读
Vosporos
字号:
在本系列中,我们将使用 Haskell、GTK 4 和 Adwaita 库构建一个待办事项列表应用程序。 Adwaita 将为我们提供许多有用的小部件和样式。让我们深入了解吧!本系列的目标受众是具有该语言开发经验的中级 Haskellers。 GTK 4, Adwaita Adwaita 是一个 GTK 组件库,用作 GNOME 项目的设计语言。简而言之:GNOME 项目在可访问性和风格(人机界面指南,HIG)方面做出的每项决定都编码在 libadwaita 中。 Libawaita 为您提供了许多功能:例如,它允许您创建具有响应式设计的应用程序,当桌面在浅色和深色主题之间切换时,这些应用程序会在运行时重新着色。 Haskell 和 GTK 在整个系列中,我们将使用 haskell-gi 工具包,它从 GTK 库自动生成 Haskell 绑定,并允许我们获得 GTK 的 Haskell 接口,您仍然可以将其与 C API 相关联。为了保持这篇文章的可读性,您将看到的代码将不完整,以便我强调主要概念。您可以在 https://github.com/Floreal-Technologies/adwaita-todo 找到整个项目。您的第一个窗口 首先,这里是 GTK 4 / Adwaita 应用程序结构的独立示例。让我们创建一个 adwaita“Application ”,它将为我们处理资源管理(包括非常酷的 Adwaita 样式表): module Main ( main ) where import GI.Awdqualified as Adw import GI.Gioqualified as Gio import GI.GTKqualified as Gtk main :: IO () main = do -- `new X [#attribute := value]` 语法创建一个 Gtk 对象 -- 及其属性。哈希语法称为 OverloadedLabels。 app <- 新广告。 Application [ # applicationId := "tech.floreal.TodoApp" ] -- 我们将“activate”信号连接到“activate”处理程序。 on app # activate ( activate app ) -- 我们运行主应用程序循环。吉奥. applicationRun app Nothing pure() activate :: Adw。应用程序 -> IO() activate app = do header <- new Adw. HeaderBar [] 工具栏 <- new Adw. ToolbarView [] Adw。 toolbarViewAddTopBar 工具栏标题窗口 <- new Adw. ApplicationWindow [ # application := app , # title := "Todos" , # defaultWidth := 480 , # defaultHeight := 640 , # content :=toolbar ] Gtk.窗口呈现窗口 瞧!一个显示“Todos”作为标题的空窗口,其尺寸为 480 x 640。 模型-视图-更新:Elm 架构 Elm 架构(或 TEA)是一种用于构建交互式程序的模式。其核心是三个概念: 模型 应用程序的状态 视图 将模型转换为用户界面(HTML、GTK 等)的方法 更新 基于消息更新模型的方法 除了这些概念之外,我们还可以找到消息 用户与应用程序的所有可能交互的枚举 效果 更新函数不仅返回更新的模型,而且还返回要在侧面执行的操作列表,称为效果。这种方法被 Elm 广泛普及,并且非常适合驯服 GTK 工具包的命令性质。 Todo 应用程序 现在是时候代表我们的应用程序状态及其操作了。本着 Elm 架构的精神,一切都将被建模为数据结构,以便我们对触发的操作及其需要的内容有绝对的可见性。模型 newtype TodoId = TodoId Word 派生 stock ( Show ) 派生 newtype ( Eq , Ord ) data Todo = Todo { id :: TodoId , title :: Text , did :: Bool } 派生 stock ( Eq , Show ) data Model = Model { todos :: Map TodoId Todo , nextId :: TodoId } 派生 stock ( Eq , Show ) -- 在我们的例子中,效果如下代表——将待办事项列表保存在磁盘上。 data Effect = Save [ Todo ] deriving stock ( Eq , Show ) init :: Model init = Model { todos = Map. empty , nextId = TodoId 0 } 消息 用户与应用程序的交互被建模为消息:一组已知的操作,我们有明确的操作来修改模型。让我们从用户可能触发更新模型的几条消息开始: data Message = Add Text | SetDoneStatus TodoId Bool 派生库存 ( Eq , Ord ) 到目前为止还没有太多,但我们会继续添加更多。更新模型 update::Message -> Model -> ( Model , [ Effect ]) update message model = Add raw 的 case message -> let text = Text.剥离原始 todoId @( TodoId n ) = model 。 if Text 中的 nextId todo = Todo { id = todoId , title = text , done = False } 。 null text then ( model , []) else withTodos ( Map.insert todo . id todo ) model { nextId = TodoId ( n + 1 )} SetDoneStatus todoId value -> withTodos ( Map. adjustment ( \ todo -> todo { did = value }) todoId ) model where -- 这是我们确定待办事项是否已更改的地方, -- 以便我们可以保存它们。 withTodos f 更改 = 让结果 = 更改 { todos = f 更改 . if result 中的 todos } 。待办事项==模型。 todos then ( result , []) else ( result , [ Save ( Map.elems result . todos )]) 让我们 n
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱