簡體   English   中英

使用 Select Widget 時我是如何設法恐慌的

[英]How did I manage to panic when using the Select Widget

Go 和 Fyne 的新手,並且在試圖從 Fyne 那里得到我需要的東西時跌跌撞撞。 對不起,這會很長。

我的問題是這個。 我正在編寫一個從服務器獲取命令列表的應用程序,告訴它創建一系列小部件並顯示它們。 它們有多種類型——標簽、按鈕、條目、選擇等。

但這些不是標准的小部件; 我需要稍微擴展一下他們的行為。 一方面,當由用戶操作時,他們每個人都需要訪問一些每個小部件的信息。 例如,按鈕單擊必須引用特定於該按鈕的一些數據,以便它知道要做什么。 我們將此附加信息稱為 About 結構。

其次,每個小部件都需要能夠右鍵單擊並下拉特定於小部件的菜單。 是的,即使是按鈕和標簽也需要能夠提供下拉菜單。 對於像 Entry 這樣的小部件,我知道這種設計會讓我不得不為粘貼、復制和 Entry 通常在右鍵單擊時提供的其他操作編寫自己的菜單選項,但我對此沒有意見。

我已經完成了所有這些工作,但是在此過程中我破壞了 Select(並且其他小部件可能會損壞。)並且我不知道如何修復它。

問題:嘗試發送 Select 小部件會導致恐慌:界面轉換:fyne.Canvas 為零,而不是 *glfw.glCanvas

方法:

type GenericWidget struct {
    fyne.Widget //I’m some kind of widget
    about *About //here’s my personal “About” data

    //function pointers
    OnRightClickp func(gw *GenericWidget, pe *fyne.PointEvent)
    OnLeftClickp func(gw *GenericWidget, pe *fyne.PointEvent)
    …other “function pointers” for OnRunep and so on…
}

現在我必須捕獲所有“事件”,以便 GenericWidget 會看到它們:

func (gw *GenericWidget) TappedSecondary(pe *fyne.PointEvent) {
    if (gw.OnRightClickp != nil) {gw.OnRightClickp(gw, pe)}
}
func (gw *GenericWidget) Tapped(pe *fyne.PointEvent) {
    if (gw.OnLeftClickp != nil){gw.OnLeftClickp(gw, pe)}
}
//type Focusable interface
//etc….

這應該代表任何單個小部件,無論類型如何。 這並不復雜:當驅動程序調用 Tapped 時,將調用 GenericWidget.Tapped。 如果此小部件設置了“OnLeftClickp”的函數指針,則調用它。 至關重要的是,當發生這種情況時,我們會傳遞一個指向小部件本身的指針,因為我編寫的所有事件處理程序都需要訪問 *About 以及我添加到 GenericWidget 的任何其他內容。

創建很簡單:

func NewGenericWidget(w fyne.Widget, about *About) *GenericWidget {
    gw := GenericWidget{w, about, nil, nil, nil, nil, nil, nil, nil, nil}
    return &gw
}

當需要創建標簽時,我會這樣做並將其折疊成一個 GenericWidget

func NewExtendedLabelWithStyle( //Label with catachable left and right click
 text string, 
 about *About, 
 alignment fyne.TextAlign, 
 style fyne.TextStyle, 
 tappedLeft func(*GenericWidget, *fyne.PointEvent), 
 tappedRight func(*GenericWidget, *fyne.PointEvent)) *GenericWidget {
    e := NewGenericWidget(widget.NewLabelWithStyle(text, alignment, style), about)
    e.OnLeftClickp = tappedLeft
    e.OnRightClickp = tappedRight
   return e
}

所有這些 GenericWidgets 都可以正常工作——我將它們添加到適當的 Box 中,並按照我的預期繪制窗口。 我可以右鍵單擊一個標簽,如果設置了 OnRightClickp,通常是這樣,代碼被調用並被授予訪問 *GenericWidget 的權限,這會導致 *About,這意味着被放置的菜單可以提供所有正確的內容這個標簽里有什么。

當然,標簽通常不關心點擊,所以我竊取了 Tappable 中所有調用的事實並不重要。

但是 Select 小部件確實關心左鍵單擊,因此 GenericWidget 攔截對 Tapped() 的調用這一事實意味着我永遠不會看到下拉列表出現。

沒問題,我想。 當我創建 Select 小部件和周圍的 GenericWidget 時,我將指定我想自己調用 Select 的 Tapped:

func NewExtendedSelect(about *About, sel func(*GenericWidget, string)) *GenericWidget {
    //build the options. NewSelect demands a slice of strings, so...
    st := make([]string, 64)
    for e := about.theList.Front(); e != nil; e = e.Next() {
        st = append(st, e.Value.(string))
    }
    s := widget.NewSelect(st, func(c string){})
    //make sure it selects the text it should, initially
    s.SetSelected(about.value)
    //wrap it
    e := NewGenericWidget(s, about)
    //e.OnChangedp = sel //not set up yet (and don’t know how)

    //HERE BE DRAGONS --------------

    //But we don't want to break left click. So when we intercept it, 
    // pass it down to the actual Selection widget:
    e.OnLeftClickp = func(me* GenericWidget, pe *fyne.PointEvent) {
        fmt.Println("select tapped")
        //call the Tapped that Select knows about:
        s.Tapped(pe) //PANIC!
    }
    // -----------------------------

    //Handle right click with our usual menu magic
    e.OnRightClickp =func(me* GenericWidget, pe *fyne.PointEvent) {
        //defer used because not sure what to do with the return value, so make it Go's problem
        defer widget.NewPopUpMenuAtPosition(me.GetRightClickMenu(), 
            me.about.sheet.window.Canvas(), pe.AbsolutePosition)
    }
    return e //here's your GenericWidget, ready to drop into a Fyne container.
}

編譯正常,選擇顯示,但是當我左鍵單擊時,它會打印預期的“選擇點擊”,然后立即恐慌:

select tapped
panic: interface conversion: fyne.Canvas is nil, not *glfw.glCanvas

我迷路了。 我的 GenericWidget 只是一個小部件; 我認為這就是組合所做的,並且我創建的所有 GenericWidgets 都放在一個 Box 中,該 Box 位於一個 Box 中,該 Box 是窗口中的 SetContent。 但是錯誤提示我不知何故這個 Select 對象沒有正確設置,當它去繪制選項時,缺少一些東西。 我做錯了什么?

我的整個方法可能是錯誤的(我做了很多 C++ 和 Python,並且我對事物采取了面向對象的觀點)。 在這種情況下,我該怎么做呢?

事實證明這是一個 Fyne 錯誤,此后已修復。

它看起來不像是在組合選擇 - 您的擴展選擇只是創建一個新的,稍后點擊它。

崩潰來自它試圖在畫布上找不到的選擇旁邊顯示彈出窗口。

如果您正在擴展內置小部件,您還需要調用 ExtendBaseWidget 以便驅動程序可以查找您的小部件而不是默認小部件。 也就是說,可以擴展任何其他類型的小部件類型的單個小部件與 Fyne API 的強類型設計背道而馳,您可能會遇到麻煩。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM