File Picker
Keywords: iced::widget::button
, rfd::AsyncFileDialog
本节在窗口上添加一个按钮,点击后弹出文件选择对话框,选择文件后将文件内容显示在窗口上。首先需要添加rfd
库的依赖,用于文件选择对话框。
首先需要编写用于显示文件选择窗口的函数。注意rfd::AsyncFileDialog
会返回一个异常,因此需要自定义异常类型。
#[derive(Debug, Clone)]
enum Error {
DialogClosed ,
IO ( io ::ErrorKind )
}
async fn pick_file () -> Result < Arc < String > , Error > {
let handler = rfd ::AsyncFileDialog ::new ()
. set_title ( "Choose a text file..." )
. pick_file ()
. await
. ok_or ( Error ::DialogClosed ) ? ; // If error, return DialogClosed error
load_file ( handler . path ()). await
}
调整窗口布局,在窗口上添加一个按钮。
impl Application for Editor {
// ...
fn view ( & self ) -> Element <' _ , Message > {
let controls = row ! [ button ( "Open" )];
// ...
container ( column! [ controls , editor , status_bar ]. spacing ( 10 )). padding ( 10 ). into ()
}
}
之后需要添加按钮的点击事件处理,调用pick_file
函数。
enum Message {
// ...
OpenButtonPressed
}
impl Application for Editor {
// ...
fn update ( & mut self , message : Message ) -> Command < Message > {
// Handle messages here
match message {
// ...
Message ::OpenButtonPressed => {
Command ::perform ( pick_file (), Message ::FileOpened )
}
}
}
fn view ( & self ) -> Element <' _ , Message > {
let controls = row ! [ button ( "Open" ). on_press ( Message ::OpenButtonPressed )];
// ...
}
}
以下为完整的main.rs
文件内容:
Download source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 use std ::io ;
use std ::path ::Path ;
use std ::sync ::Arc ;
use iced ::{ executor , Application , Command , Element , Length , Settings , Theme };
use iced ::widget ::{ button , column , container , horizontal_space , row , text , text_editor };
fn main () -> iced ::Result {
Editor ::run ( Settings ::default ())
}
struct Editor {
content : text_editor ::Content ,
error : Option < Error >
}
#[derive(Debug, Clone)]
enum Message {
EditorEdit ( text_editor ::Action ),
FileOpened ( Result < Arc < String > , Error > ),
OpenButtonPressed
}
impl Application for Editor {
type Message = Message ; // Define the type of messages
type Theme = Theme ;
type Executor = executor ::Default ; // Engine for running async tasks
type Flags = ();
fn new ( _flags : Self ::Flags ) -> ( Self , Command < Message > ) {
(
Self {
content : text_editor ::Content ::new (),
error : None
},
Command ::perform (
load_file ( format! ( "{}/src/main.rs" , env! ( "CARGO_MANIFEST_DIR" ))),
Message ::FileOpened
)
)
}
fn title ( & self ) -> String {
String ::from ( "A text editor" )
}
fn update ( & mut self , message : Message ) -> Command < Message > {
// Handle messages here
match message {
Message ::EditorEdit ( action ) => {
self . content . edit ( action );
Command ::none ()
},
Message ::FileOpened ( Ok ( result )) => {
self . content = text_editor ::Content ::with ( & result );
Command ::none ()
},
Message ::FileOpened ( Err ( error )) => {
self . error = Some ( error );
Command ::none ()
},
Message ::OpenButtonPressed => {
Command ::perform ( pick_file (), Message ::FileOpened )
}
}
}
fn view ( & self ) -> Element <' _ , Message > {
// Create the user interface here
let editor = text_editor ( & self . content ). on_edit ( Message ::EditorEdit );
let controls = row ! [ button ( "Open" ). on_press ( Message ::OpenButtonPressed )];
// Query cursor position
let cursor_indicator = {
let ( line , column ) = self . content . cursor_position ();
text ( format! ( "Line: {}, Column: {}" , line + 1 , column + 1 ))
};
let status_bar = row ! [ horizontal_space ( Length ::Fill ), cursor_indicator ];
container ( column! [ controls , editor , status_bar ]. spacing ( 10 )). padding ( 10 ). into ()
}
fn theme ( & self ) -> Theme {
Theme ::Dark
}
}
async fn pick_file () -> Result < Arc < String > , Error > {
let file_handle = rfd ::AsyncFileDialog ::new ()
. set_title ( "Choose a text file..." )
. pick_file ()
. await
. ok_or ( Error ::DialogClosed ) ? ;
load_file ( file_handle . path ()). await
}
async fn load_file ( path : impl AsRef < Path > ) -> Result < Arc < String > , Error > {
tokio ::fs ::read_to_string ( path )
. await
. map ( Arc ::new )
. map_err ( | err | err . kind ())
. map_err ( Error ::IO )
}
#[derive(Debug, Clone)]
enum Error {
DialogClosed ,
IO ( io ::ErrorKind )
}