Skip to content
On this page

数值输入

在传统意义上,GUI程序使用回调来定制小部件的操作。Fyne不公开插入自定义回调来捕获小部件上的事件,但它不需要

相反,我们可以简单地使用Type Embedding并扩展小部件,使其仅能输入数值。

首先创建一个新的类型结构,我们将其称为numericEntry。

go
type numericalEntry struct {
    widget.Entry
}

正如在扩展现有小部件中所提到的,我们遵循了良好的实践,并创建了一个扩展BaseWidget的构造函数。

go
func newNumericalEntry() *numericalEntry {
    entry := &numericalEntry{}
    entry.ExtendBaseWidget(entry)
    return entry
}

现在我们需要使条目只接受数字。这可以通过重写作为fyne.Focusable接口一部分的TypedRune(rune)方法来实现。这将允许我们拦截从按键接收的符文的标准处理,并只通过我们想要的符文。在这个方法中,我们将使用一个条件来检查符文是否匹配0到9之间的任何数字。如果是,我们将其委托给嵌入条目的标准TypedRune(rune)方法。如果没有,我们就忽略输入。这个实现将只允许输入整数,但如果需要,可以很容易地扩展到将来检查其他键。

go
func (e *numericalEntry) TypedRune(r rune) {
	if r >= '0' && r <= '9' {
		e.Entry.TypedRune(r)
	}
}

如果我们想更新实现以允许十进制数字,我们可以简单地添加。以及,添加到允许的符文列表中(某些语言在小数点上使用逗号)。

go
func (e *numericalEntry) TypedRune(r rune) {
	if (r >= '0' && r <= '9') || r == '.' || r == ',' {
			e.Entry.TypedRune(r)
	}
}

这样,输入现在只允许用户在按键时输入数值。但是,粘贴快捷方式仍然允许输入文本。为了解决这个问题,我们可以覆盖作为fyne.Shortcutable接口一部分的TypedShortcut(fyne.S快捷方式)方法。首先,我们需要执行一个类型断言,以检查给定的快捷方式是否为*fyne.ShortcutPaste类型。如果不是,我们可以将快捷方式委托回嵌入的条目。如果是,我们使用strconv.ParseFloat()检查剪贴板内容是否是数字的(如果您只允许整数,strconv.Atoi()就可以了),然后如果剪贴板内容可以无错误地解析,则将快捷方式委派回嵌入的条目。

go
func (e *numericalEntry) TypedShortcut(shortcut fyne.Shortcut) {
	paste, ok := shortcut.(*fyne.ShortcutPaste)
	if !ok {
		e.Entry.TypedShortcut(shortcut)
		return
	}

	content := paste.Clipboard.Content()
	if _, err := strconv.ParseFloat(content, 64); err == nil {
		e.Entry.TypedShortcut(shortcut)
	}
}

另外,我们还可以确保移动操作系统打开数字键盘,而不是默认键盘。这可以通过首先导入fyne.io/fyne/v2/driver/mobile包,然后覆盖作为m?mobile.Keyboardable接口一部分的Keyboard()mobile.Keyboard Type方法来实现。在函数内部,我们只需返回mobile.NumberKeyboard类型。

go
func (e *numericalEntry) Keyboard() mobile.KeyboardType {
	return mobile.NumberKeyboard
}

最后,生成的代码可能看起来像这样:

go
package main

import (
	"strconv"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/driver/mobile"
	"fyne.io/fyne/v2/widget"
)

type numericalEntry struct {
	widget.Entry
}

func newNumericalEntry() *numericalEntry {
	entry := &numericalEntry{}
	entry.ExtendBaseWidget(entry)
	return entry
}

func (e *numericalEntry) TypedRune(r rune) {
	if (r >= '0' && r <= '9') || r == '.' || r == ',' {
		e.Entry.TypedRune(r)
	}
}

func (e *numericalEntry) TypedShortcut(shortcut fyne.Shortcut) {
	paste, ok := shortcut.(*fyne.ShortcutPaste)
	if !ok {
		e.Entry.TypedShortcut(shortcut)
		return
	}

	content := paste.Clipboard.Content()
	if _, err := strconv.ParseFloat(content, 64); err == nil {
		e.Entry.TypedShortcut(shortcut)
	}
}

func (e *numericalEntry) Keyboard() mobile.KeyboardType {
	return mobile.NumberKeyboard
}

func main() {
	a := app.New()
	w := a.NewWindow("Numerical")

	entry := newNumericalEntry()

	w.SetContent(entry)
	w.ShowAndRun()
}